diff --git a/.hgtags b/.hgtags index cb3ba5ed43e..db502a72772 100644 --- a/.hgtags +++ b/.hgtags @@ -269,3 +269,5 @@ c5495e25c7258ab5f96a1ae14610887d76d2be63 jdk9-b18 d9ce05f36ffec3e5e8af62a92455c1c66a63c320 jdk9-b24 13a5c76976fe48e55c9727c25fae2d2ce7c05da0 jdk9-b25 cd6f4557e7fea5799ff3762ed7a80a743e75d5fd jdk9-b26 +d06a6d3c66c08293b2a9650f3cc01fd55c620e65 jdk9-b27 +f4269e8f454eb77763ecee228a88ae102a9aef6e jdk9-b28 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index d0fc930890e..b1a11dc3634 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -269,3 +269,5 @@ ee4fd72b2ec3d92497f37163352f294aa695c6fb jdk9-b20 1d4a293fbec19dc2d5790bbb2c7dd0ed8f265484 jdk9-b24 aefd8899a8d6615fb34ba99b2e38996a7145baa8 jdk9-b25 d3ec8d048e6c3c46b6e0ee011cc551ad386dfba5 jdk9-b26 +ba5645f2735b41ed085d07ba20fa7b322afff318 jdk9-b27 +ea2f7981236f3812436958748ab3d26e80a35130 jdk9-b28 diff --git a/Makefile b/Makefile index 1e574940964..6827fd615f3 100644 --- a/Makefile +++ b/Makefile @@ -136,10 +136,12 @@ help: $(info . make docs # Create all docs) $(info . make docs-javadoc # Create just javadocs, depends on less than full docs) $(info . make profiles # Create complete j2re compact profile images) - $(info . make bootcycle-images # Build images twice, second time with newly build JDK) + $(info . make bootcycle-images # Build images twice, second time with newly built JDK) $(info . make install # Install the generated images locally) $(info . make clean # Remove all files generated by make, but not those) - $(info . # generated by configure) + $(info . # generated by configure. Do not run clean and other) + $(info . # targets together as that might behave in an) + $(info . # unexpected way.) $(info . make dist-clean # Remove all files, including configuration) $(info . make help # Give some help on using make) $(info . make test # Run tests, default is all tests (see TEST below)) diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index 79d54a231ee..1a8cb100d94 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -377,7 +377,6 @@ AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS], BASIC_REQUIRE_PROGS(CMP, cmp) BASIC_REQUIRE_PROGS(COMM, comm) BASIC_REQUIRE_PROGS(CP, cp) - BASIC_REQUIRE_PROGS(CPIO, cpio) BASIC_REQUIRE_PROGS(CUT, cut) BASIC_REQUIRE_PROGS(DATE, date) BASIC_REQUIRE_PROGS(DIFF, [gdiff diff]) @@ -427,6 +426,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS], BASIC_PATH_PROGS(READLINK, [greadlink readlink]) BASIC_PATH_PROGS(DF, df) BASIC_PATH_PROGS(SETFILE, SetFile) + BASIC_PATH_PROGS(CPIO, [cpio bsdcpio]) ]) # Setup basic configuration paths, and platform-specific stuff related to PATHs. @@ -849,7 +849,12 @@ AC_DEFUN([BASIC_CHECK_FIND_DELETE], if test -f $DELETEDIR/TestIfFindSupportsDelete; then # No, it does not. rm $DELETEDIR/TestIfFindSupportsDelete - FIND_DELETE="-exec rm \{\} \+" + if test "x$OPENJDK_TARGET_OS" = "xaix"; then + # AIX 'find' is buggy if called with '-exec {} \+' and an empty file list + FIND_DELETE="-print | xargs rm" + else + FIND_DELETE="-exec rm \{\} \+" + fi AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) @@ -954,7 +959,7 @@ AC_DEFUN([BASIC_CHECK_DIR_ON_LOCAL_DISK], # not be the case in cygwin in certain conditions. AC_DEFUN_ONCE([BASIC_CHECK_SRC_PERMS], [ - if test x"$OPENJDK_BUILD_OS" = xwindows; then + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then file_to_test="$SRC_ROOT/LICENSE" if test `$STAT -c '%a' "$file_to_test"` -lt 400; then AC_MSG_ERROR([Bad file permissions on src files. This is usually caused by cloning the repositories with a non cygwin hg in a directory not created in cygwin.]) diff --git a/common/autoconf/basics_windows.m4 b/common/autoconf/basics_windows.m4 index 0d43553fd95..1bcb6151486 100644 --- a/common/autoconf/basics_windows.m4 +++ b/common/autoconf/basics_windows.m4 @@ -266,6 +266,14 @@ AC_DEFUN([BASIC_FIXUP_EXECUTABLE_MSYS], BASIC_WINDOWS_REWRITE_AS_UNIX_PATH(new_path) 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" + BASIC_WINDOWS_REWRITE_AS_UNIX_PATH(new_path) + fi if test "x$new_path" = x; then # It's still not found. Now this is an unrecoverable error. diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4 index 872e33fb609..fbfa15c7b06 100644 --- a/common/autoconf/boot-jdk.m4 +++ b/common/autoconf/boot-jdk.m4 @@ -370,18 +370,27 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], # Maximum amount of heap memory. # Maximum stack size. + JVM_MAX_HEAP=`expr $MEMORY_SIZE / 2` if test "x$BUILD_NUM_BITS" = x32; then - JVM_MAX_HEAP=1100M + if test "$JVM_MAX_HEAP" -gt "1100"; then + JVM_MAX_HEAP=1100 + elif test "$JVM_MAX_HEAP" -lt "512"; then + JVM_MAX_HEAP=512 + fi STACK_SIZE=768 else # Running Javac on a JVM on a 64-bit machine, takes more space since 64-bit # pointers are used. Apparently, we need to increase the heap and stack # space for the jvm. More specifically, when running javac to build huge # jdk batch - JVM_MAX_HEAP=1600M + if test "$JVM_MAX_HEAP" -gt "1600"; then + JVM_MAX_HEAP=1600 + elif test "$JVM_MAX_HEAP" -lt "512"; then + JVM_MAX_HEAP=512 + fi STACK_SIZE=1536 fi - ADD_JVM_ARG_IF_OK([-Xmx$JVM_MAX_HEAP],boot_jdk_jvmargs_big,[$JAVA]) + ADD_JVM_ARG_IF_OK([-Xmx${JVM_MAX_HEAP}M],boot_jdk_jvmargs_big,[$JAVA]) ADD_JVM_ARG_IF_OK([-XX:ThreadStackSize=$STACK_SIZE],boot_jdk_jvmargs_big,[$JAVA]) AC_MSG_RESULT([$boot_jdk_jvmargs_big]) diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4 index 7d4b8abb8da..8425d744990 100644 --- a/common/autoconf/build-performance.m4 +++ b/common/autoconf/build-performance.m4 @@ -131,8 +131,8 @@ AC_DEFUN_ONCE([BPERF_SETUP_BUILD_JOBS], if test "x$with_jobs" = x; then # Number of jobs was not specified, calculate. AC_MSG_CHECKING([for appropriate number of jobs to run in parallel]) - # Approximate memory in GB, rounding up a bit. - memory_gb=`expr $MEMORY_SIZE / 1100` + # Approximate memory in GB. + memory_gb=`expr $MEMORY_SIZE / 1024` # Pick the lowest of memory in gb and number of cores. if test "$memory_gb" -lt "$NUM_CORES"; then JOBS="$memory_gb" @@ -291,16 +291,11 @@ AC_DEFUN_ONCE([BPERF_SETUP_SMART_JAVAC], AC_MSG_ERROR([Could not execute server java: $SJAVAC_SERVER_JAVA]) fi else - SJAVAC_SERVER_JAVA="" - # Hotspot specific options. - ADD_JVM_ARG_IF_OK([-verbosegc],SJAVAC_SERVER_JAVA,[$JAVA]) - # JRockit specific options. - ADD_JVM_ARG_IF_OK([-Xverbose:gc],SJAVAC_SERVER_JAVA,[$JAVA]) - SJAVAC_SERVER_JAVA="$JAVA $SJAVAC_SERVER_JAVA" + SJAVAC_SERVER_JAVA="$JAVA" fi AC_SUBST(SJAVAC_SERVER_JAVA) - if test "$MEMORY_SIZE" -gt "2500"; then + if test "$MEMORY_SIZE" -gt "3000"; then ADD_JVM_ARG_IF_OK([-d64],SJAVAC_SERVER_JAVA,[$SJAVAC_SERVER_JAVA]) if test "$JVM_ARG_OK" = true; then JVM_64BIT=true @@ -308,34 +303,33 @@ AC_DEFUN_ONCE([BPERF_SETUP_SMART_JAVAC], fi fi + MX_VALUE=`expr $MEMORY_SIZE / 2` if test "$JVM_64BIT" = true; then - if test "$MEMORY_SIZE" -gt "17000"; then - ADD_JVM_ARG_IF_OK([-Xms10G -Xmx10G],SJAVAC_SERVER_JAVA,[$SJAVAC_SERVER_JAVA]) + # Set ms lower than mx since more than one instance of the server might + # get launched at the same time before they figure out which instance won. + MS_VALUE=512 + if test "$MX_VALUE" -gt "2048"; then + MX_VALUE=2048 fi - if test "$MEMORY_SIZE" -gt "10000" && test "$JVM_ARG_OK" = false; then - ADD_JVM_ARG_IF_OK([-Xms6G -Xmx6G],SJAVAC_SERVER_JAVA,[$SJAVAC_SERVER_JAVA]) - fi - if test "$MEMORY_SIZE" -gt "5000" && test "$JVM_ARG_OK" = false; then - ADD_JVM_ARG_IF_OK([-Xms1G -Xmx3G],SJAVAC_SERVER_JAVA,[$SJAVAC_SERVER_JAVA]) - fi - if test "$MEMORY_SIZE" -gt "3800" && test "$JVM_ARG_OK" = false; then - ADD_JVM_ARG_IF_OK([-Xms1G -Xmx2500M],SJAVAC_SERVER_JAVA,[$SJAVAC_SERVER_JAVA]) + else + MS_VALUE=256 + if test "$MX_VALUE" -gt "1500"; then + MX_VALUE=1500 fi fi - if test "$MEMORY_SIZE" -gt "2500" && test "$JVM_ARG_OK" = false; then - ADD_JVM_ARG_IF_OK([-Xms1000M -Xmx1500M],SJAVAC_SERVER_JAVA,[$SJAVAC_SERVER_JAVA]) - fi - if test "$MEMORY_SIZE" -gt "1000" && test "$JVM_ARG_OK" = false; then - ADD_JVM_ARG_IF_OK([-Xms400M -Xmx1100M],SJAVAC_SERVER_JAVA,[$SJAVAC_SERVER_JAVA]) - fi - if test "$JVM_ARG_OK" = false; then - ADD_JVM_ARG_IF_OK([-Xms256M -Xmx512M],SJAVAC_SERVER_JAVA,[$SJAVAC_SERVER_JAVA]) + if test "$MX_VALUE" -lt "512"; then + MX_VALUE=512 fi + ADD_JVM_ARG_IF_OK([-Xms${MS_VALUE}M -Xmx${MX_VALUE}M],SJAVAC_SERVER_JAVA,[$SJAVAC_SERVER_JAVA]) - AC_MSG_CHECKING([whether to use sjavac]) AC_ARG_ENABLE([sjavac], [AS_HELP_STRING([--enable-sjavac], [use sjavac to do fast incremental compiles @<:@disabled@:>@])], [ENABLE_SJAVAC="${enableval}"], [ENABLE_SJAVAC='no']) + if test "x$JVM_ARG_OK" = "xfalse"; then + AC_MSG_WARN([Could not set -Xms${MS_VALUE}M -Xmx${MX_VALUE}M, disabling sjavac]) + ENABLE_SJAVAC=no; + fi + AC_MSG_CHECKING([whether to use sjavac]) AC_MSG_RESULT([$ENABLE_SJAVAC]) AC_SUBST(ENABLE_SJAVAC) diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index ec0d7490d59..ca373c859f1 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -142,7 +142,6 @@ JDKOPT_SETUP_JDK_VERSION_NUMBERS ############################################################################### BOOTJDK_SETUP_BOOT_JDK -BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS ############################################################################### # @@ -233,6 +232,9 @@ BPERF_SETUP_BUILD_CORES BPERF_SETUP_BUILD_MEMORY BPERF_SETUP_BUILD_JOBS +# Setup arguments for the boot jdk (after cores and memory have been setup) +BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS + # Setup smart javac (after cores and memory have been setup) BPERF_SETUP_SMART_JAVAC diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index 6f69f0c53a2..7a62d93ea7f 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -342,17 +342,15 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], # no adjustment ;; fastdebug ) - # Add compile time bounds checks. - CFLAGS_DEBUG_OPTIONS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1" - CXXFLAGS_DEBUG_OPTIONS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1" + # no adjustment ;; slowdebug ) - # Add runtime bounds checks and symbol info. - CFLAGS_DEBUG_OPTIONS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-all --param ssp-buffer-size=1" - CXXFLAGS_DEBUG_OPTIONS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-all --param ssp-buffer-size=1" + # Add runtime stack smashing and undefined behavior checks + CFLAGS_DEBUG_OPTIONS="-fstack-protector-all --param ssp-buffer-size=1" + CXXFLAGS_DEBUG_OPTIONS="-fstack-protector-all --param ssp-buffer-size=1" if test "x$HAS_CFLAG_DETECT_UNDEFINED_BEHAVIOR" = "xtrue"; then CFLAGS_DEBUG_OPTIONS="$CFLAGS_DEBUG_OPTIONS $CFLAG_DETECT_UNDEFINED_BEHAVIOR_FLAG" - CXXFLAGS_DEBUG_OPTIONS="$CXXFLAGS_DEBUG_OPTIONS $CFLAG_DETECT_UNDEFINED_BEHAVIOR_FLAG" + CXXFLAGS_DEBUG_OPTIONS="$CXXFLAGS_DEBUG_OPTIONS $CFLAG_DETECT_UNDEFINED_BEHAVIsOR_FLAG" fi ;; esac @@ -900,7 +898,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], case "${TOOLCHAIN_TYPE}" in microsoft) - CFLAGS_WARNINGS_ARE_ERRORS="/WX" + CFLAGS_WARNINGS_ARE_ERRORS="-WX" ;; solstudio) CFLAGS_WARNINGS_ARE_ERRORS="-errtags -errwarn=%all" diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 5b044dc241d..d24edd39c20 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -634,6 +634,10 @@ USE_PRECOMPILED_HEADER SJAVAC_SERVER_DIR ENABLE_SJAVAC SJAVAC_SERVER_JAVA +JAVA_TOOL_FLAGS_SMALL +JAVA_FLAGS_SMALL +JAVA_FLAGS_BIG +JAVA_FLAGS JOBS MEMORY_SIZE NUM_CORES @@ -805,10 +809,6 @@ JAXWS_TOPDIR JAXP_TOPDIR CORBA_TOPDIR LANGTOOLS_TOPDIR -JAVA_TOOL_FLAGS_SMALL -JAVA_FLAGS_SMALL -JAVA_FLAGS_BIG -JAVA_FLAGS JAVAC_FLAGS BOOT_JDK_SOURCETARGET JARSIGNER @@ -920,12 +920,14 @@ OPENJDK_TARGET_CPU_ENDIAN OPENJDK_TARGET_CPU_BITS OPENJDK_TARGET_CPU_ARCH OPENJDK_TARGET_CPU +OPENJDK_TARGET_OS_ENV OPENJDK_TARGET_OS_API OPENJDK_TARGET_OS OPENJDK_BUILD_CPU_ENDIAN OPENJDK_BUILD_CPU_BITS OPENJDK_BUILD_CPU_ARCH OPENJDK_BUILD_CPU +OPENJDK_BUILD_OS_ENV OPENJDK_BUILD_OS_API OPENJDK_BUILD_OS OPENJDK_BUILD_AUTOCONF_NAME @@ -942,6 +944,7 @@ build_os build_vendor build_cpu build +CPIO SETFILE DF READLINK @@ -980,7 +983,6 @@ DIRNAME DIFF DATE CUT -CPIO CP COMM CMP @@ -1062,7 +1064,6 @@ with_update_version with_user_release_suffix with_build_number with_boot_jdk -with_boot_jdk_jvmargs with_add_source_root with_override_source_root with_adds_and_overrides @@ -1104,6 +1105,7 @@ with_dxsdk_include with_num_cores with_memory_size with_jobs +with_boot_jdk_jvmargs with_sjavac_server_java enable_sjavac enable_precompiled_headers @@ -1120,7 +1122,6 @@ CHMOD CMP COMM CP -CPIO CUT DATE DIFF @@ -1159,6 +1160,7 @@ CYGPATH READLINK DF SETFILE +CPIO UNZIP ZIP LDD @@ -1902,10 +1904,6 @@ Optional Packages: number is not set.[username_builddateb00] --with-build-number Set build number value for build [b00] --with-boot-jdk path to Boot JDK (used to bootstrap build) [probed] - --with-boot-jdk-jvmargs specify JVM arguments to be passed to all java - invocations of boot JDK, overriding the default - values, e.g --with-boot-jdk-jvmargs="-Xmx8G - -enableassertions" --with-add-source-root for each and every source directory, look in this additional source root for the same directory; if it exists and have files in it, include it in the build @@ -1977,6 +1975,10 @@ Optional Packages: --with-memory-size=1024 [probed] --with-jobs number of parallel jobs to let make run [calculated based on cores and memory] + --with-boot-jdk-jvmargs specify JVM arguments to be passed to all java + invocations of boot JDK, overriding the default + values, e.g --with-boot-jdk-jvmargs="-Xmx8G + -enableassertions" --with-sjavac-server-java use this java binary for running the sjavac background server [Boot JDK java] @@ -1990,7 +1992,6 @@ Some influential environment variables: CMP Override default value for CMP COMM Override default value for COMM CP Override default value for CP - CPIO Override default value for CPIO CUT Override default value for CUT DATE Override default value for DATE DIFF Override default value for DIFF @@ -2029,6 +2030,7 @@ Some influential environment variables: READLINK Override default value for READLINK DF Override default value for DF SETFILE Override default value for SETFILE + CPIO Override default value for CPIO UNZIP Override default value for UNZIP ZIP Override default value for ZIP LDD Override default value for LDD @@ -4319,7 +4321,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1407143049 +DATE_WHEN_GENERATED=1409311712 ############################################################################### # @@ -5721,199 +5723,6 @@ $as_echo "$tool_specified" >&6; } - # Publish this variable in the help. - - - if test "x$CPIO" = x; then - # The variable is not set by user, try to locate tool using the code snippet - for ac_prog in cpio -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CPIO+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $CPIO in - [\\/]* | ?:[\\/]*) - ac_cv_path_CPIO="$CPIO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_CPIO="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -CPIO=$ac_cv_path_CPIO -if test -n "$CPIO"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPIO" >&5 -$as_echo "$CPIO" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CPIO" && break -done - - else - # The variable is set, but is it from the command line or the environment? - - # Try to remove the string !CPIO! from our list. - try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!CPIO!/} - if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then - # If it failed, the variable was not from the command line. Ignore it, - # but warn the user (except for BASH, which is always set by the calling BASH). - if test "xCPIO" != xBASH; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of CPIO from the environment. Use command line variables instead." >&5 -$as_echo "$as_me: WARNING: Ignoring value of CPIO from the environment. Use command line variables instead." >&2;} - fi - # Try to locate tool using the code snippet - for ac_prog in cpio -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CPIO+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $CPIO in - [\\/]* | ?:[\\/]*) - ac_cv_path_CPIO="$CPIO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_CPIO="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -CPIO=$ac_cv_path_CPIO -if test -n "$CPIO"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPIO" >&5 -$as_echo "$CPIO" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CPIO" && break -done - - else - # If it succeeded, then it was overridden by the user. We will use it - # for the tool. - - # First remove it from the list of overridden variables, so we can test - # for unknown variables in the end. - CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var" - - # Check if the provided tool contains a complete path. - tool_specified="$CPIO" - tool_basename="${tool_specified##*/}" - if test "x$tool_basename" = "x$tool_specified"; then - # A command without a complete path is provided, search $PATH. - { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool CPIO=$tool_basename" >&5 -$as_echo "$as_me: Will search for user supplied tool CPIO=$tool_basename" >&6;} - # Extract the first word of "$tool_basename", so it can be a program name with args. -set dummy $tool_basename; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CPIO+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $CPIO in - [\\/]* | ?:[\\/]*) - ac_cv_path_CPIO="$CPIO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_CPIO="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -CPIO=$ac_cv_path_CPIO -if test -n "$CPIO"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPIO" >&5 -$as_echo "$CPIO" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - if test "x$CPIO" = x; then - as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5 - fi - else - # Otherwise we believe it is a complete path. Use it as it is. - { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool CPIO=$tool_specified" >&5 -$as_echo "$as_me: Will use user supplied tool CPIO=$tool_specified" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CPIO" >&5 -$as_echo_n "checking for CPIO... " >&6; } - if test ! -x "$tool_specified"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - as_fn_error $? "User supplied tool CPIO=$tool_specified does not exist or is not executable" "$LINENO" 5 - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5 -$as_echo "$tool_specified" >&6; } - fi - fi - fi - - - - if test "x$CPIO" = x; then - as_fn_error $? "Could not find required tool for CPIO" "$LINENO" 5 - fi - - - - - # Publish this variable in the help. @@ -13386,6 +13195,192 @@ $as_echo "$tool_specified" >&6; } + # Publish this variable in the help. + + + if test "x$CPIO" = x; then + # The variable is not set by user, try to locate tool using the code snippet + for ac_prog in cpio bsdcpio +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_CPIO+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $CPIO in + [\\/]* | ?:[\\/]*) + ac_cv_path_CPIO="$CPIO" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_CPIO="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +CPIO=$ac_cv_path_CPIO +if test -n "$CPIO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPIO" >&5 +$as_echo "$CPIO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CPIO" && break +done + + else + # The variable is set, but is it from the command line or the environment? + + # Try to remove the string !CPIO! from our list. + try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!CPIO!/} + if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then + # If it failed, the variable was not from the command line. Ignore it, + # but warn the user (except for BASH, which is always set by the calling BASH). + if test "xCPIO" != xBASH; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of CPIO from the environment. Use command line variables instead." >&5 +$as_echo "$as_me: WARNING: Ignoring value of CPIO from the environment. Use command line variables instead." >&2;} + fi + # Try to locate tool using the code snippet + for ac_prog in cpio bsdcpio +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_CPIO+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $CPIO in + [\\/]* | ?:[\\/]*) + ac_cv_path_CPIO="$CPIO" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_CPIO="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +CPIO=$ac_cv_path_CPIO +if test -n "$CPIO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPIO" >&5 +$as_echo "$CPIO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CPIO" && break +done + + else + # If it succeeded, then it was overridden by the user. We will use it + # for the tool. + + # First remove it from the list of overridden variables, so we can test + # for unknown variables in the end. + CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var" + + # Check if the provided tool contains a complete path. + tool_specified="$CPIO" + tool_basename="${tool_specified##*/}" + if test "x$tool_basename" = "x$tool_specified"; then + # A command without a complete path is provided, search $PATH. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool CPIO=$tool_basename" >&5 +$as_echo "$as_me: Will search for user supplied tool CPIO=$tool_basename" >&6;} + # Extract the first word of "$tool_basename", so it can be a program name with args. +set dummy $tool_basename; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_CPIO+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $CPIO in + [\\/]* | ?:[\\/]*) + ac_cv_path_CPIO="$CPIO" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_CPIO="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +CPIO=$ac_cv_path_CPIO +if test -n "$CPIO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPIO" >&5 +$as_echo "$CPIO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$CPIO" = x; then + as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5 + fi + else + # Otherwise we believe it is a complete path. Use it as it is. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool CPIO=$tool_specified" >&5 +$as_echo "$as_me: Will use user supplied tool CPIO=$tool_specified" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CPIO" >&5 +$as_echo_n "checking for CPIO... " >&6; } + if test ! -x "$tool_specified"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + as_fn_error $? "User supplied tool CPIO=$tool_specified does not exist or is not executable" "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5 +$as_echo "$tool_specified" >&6; } + fi + fi + fi + + + + # Now we can determine OpenJDK build and target platforms. This is required to # have early on. # Make sure we can run config.sub. @@ -13644,6 +13639,7 @@ test -n "$target_alias" && + { $as_echo "$as_me:${as_lineno-$LINENO}: checking openjdk-build os-cpu" >&5 $as_echo_n "checking openjdk-build os-cpu... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU" >&5 @@ -13775,6 +13771,7 @@ $as_echo "$OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking openjdk-target os-cpu" >&5 $as_echo_n "checking openjdk-target os-cpu... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU" >&5 @@ -15611,6 +15608,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -15967,6 +15981,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -16320,6 +16351,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -16678,6 +16726,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -17030,6 +17095,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -17202,7 +17284,12 @@ $as_echo_n "checking if find supports -delete... " >&6; } if test -f $DELETEDIR/TestIfFindSupportsDelete; then # No, it does not. rm $DELETEDIR/TestIfFindSupportsDelete - FIND_DELETE="-exec rm \{\} \+" + if test "x$OPENJDK_TARGET_OS" = "xaix"; then + # AIX 'find' is buggy if called with '-exec {} \+' and an empty file list + FIND_DELETE="-print | xargs rm" + else + FIND_DELETE="-exec rm \{\} \+" + fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else @@ -26233,197 +26320,6 @@ $as_echo "$tool_specified" >&6; } - ############################################################################## - # - # Specify jvm options for anything that is run with the Boot JDK. - # Not all JVM:s accept the same arguments on the command line. - # - -# Check whether --with-boot-jdk-jvmargs was given. -if test "${with_boot_jdk_jvmargs+set}" = set; then : - withval=$with_boot_jdk_jvmargs; -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command " >&5 -$as_echo_n "checking flags for boot jdk java command ... " >&6; } - - # Disable special log output when a debug build is used as Boot JDK... - - $ECHO "Check if jvm arg is ok: -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput" >&5 - $ECHO "Command: $JAVA -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput -version" >&5 - OUTPUT=`$JAVA -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs="$boot_jdk_jvmargs -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - # Apply user provided options. - - $ECHO "Check if jvm arg is ok: $with_boot_jdk_jvmargs" >&5 - $ECHO "Command: $JAVA $with_boot_jdk_jvmargs -version" >&5 - OUTPUT=`$JAVA $with_boot_jdk_jvmargs -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs="$boot_jdk_jvmargs $with_boot_jdk_jvmargs" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs" >&5 -$as_echo "$boot_jdk_jvmargs" >&6; } - - # For now, general JAVA_FLAGS are the same as the boot jdk jvmargs - JAVA_FLAGS=$boot_jdk_jvmargs - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command for big workloads" >&5 -$as_echo_n "checking flags for boot jdk java command for big workloads... " >&6; } - - # Starting amount of heap memory. - - $ECHO "Check if jvm arg is ok: -Xms64M" >&5 - $ECHO "Command: $JAVA -Xms64M -version" >&5 - OUTPUT=`$JAVA -Xms64M -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -Xms64M" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - # Maximum amount of heap memory. - # Maximum stack size. - if test "x$BUILD_NUM_BITS" = x32; then - JVM_MAX_HEAP=1100M - STACK_SIZE=768 - else - # Running Javac on a JVM on a 64-bit machine, takes more space since 64-bit - # pointers are used. Apparently, we need to increase the heap and stack - # space for the jvm. More specifically, when running javac to build huge - # jdk batch - JVM_MAX_HEAP=1600M - STACK_SIZE=1536 - fi - - $ECHO "Check if jvm arg is ok: -Xmx$JVM_MAX_HEAP" >&5 - $ECHO "Command: $JAVA -Xmx$JVM_MAX_HEAP -version" >&5 - OUTPUT=`$JAVA -Xmx$JVM_MAX_HEAP -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -Xmx$JVM_MAX_HEAP" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - $ECHO "Check if jvm arg is ok: -XX:ThreadStackSize=$STACK_SIZE" >&5 - $ECHO "Command: $JAVA -XX:ThreadStackSize=$STACK_SIZE -version" >&5 - OUTPUT=`$JAVA -XX:ThreadStackSize=$STACK_SIZE -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -XX:ThreadStackSize=$STACK_SIZE" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_big" >&5 -$as_echo "$boot_jdk_jvmargs_big" >&6; } - - JAVA_FLAGS_BIG=$boot_jdk_jvmargs_big - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command for small workloads" >&5 -$as_echo_n "checking flags for boot jdk java command for small workloads... " >&6; } - - # Use serial gc for small short lived tools if possible - - $ECHO "Check if jvm arg is ok: -XX:+UseSerialGC" >&5 - $ECHO "Command: $JAVA -XX:+UseSerialGC -version" >&5 - OUTPUT=`$JAVA -XX:+UseSerialGC -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -XX:+UseSerialGC" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - $ECHO "Check if jvm arg is ok: -Xms32M" >&5 - $ECHO "Command: $JAVA -Xms32M -version" >&5 - OUTPUT=`$JAVA -Xms32M -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -Xms32M" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - $ECHO "Check if jvm arg is ok: -Xmx512M" >&5 - $ECHO "Command: $JAVA -Xmx512M -version" >&5 - OUTPUT=`$JAVA -Xmx512M -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -Xmx512M" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_small" >&5 -$as_echo "$boot_jdk_jvmargs_small" >&6; } - - JAVA_FLAGS_SMALL=$boot_jdk_jvmargs_small - - - JAVA_TOOL_FLAGS_SMALL="" - for f in $JAVA_FLAGS_SMALL; do - JAVA_TOOL_FLAGS_SMALL="$JAVA_TOOL_FLAGS_SMALL -J$f" - done - - - ############################################################################### # # Configure the sources to use. We can add or override individual directories. @@ -27493,6 +27389,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -28136,6 +28049,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -28576,6 +28506,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -29842,6 +29789,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -30282,6 +30246,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -31127,6 +31108,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -31525,6 +31523,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -31852,6 +31867,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -32330,6 +32362,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -32941,6 +32990,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -33460,6 +33526,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -33911,6 +33994,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -34235,6 +34335,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -34555,6 +34672,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -34857,6 +34991,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -35311,6 +35462,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -35762,6 +35930,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -36213,6 +36398,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -36665,6 +36867,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -37228,6 +37447,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -37789,6 +38025,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -38359,6 +38612,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -38926,6 +39196,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -39402,6 +39689,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -39853,6 +40157,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -40304,6 +40625,23 @@ $as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" 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. @@ -41991,17 +42329,15 @@ $as_echo "$ac_cv_c_bigendian" >&6; } # no adjustment ;; fastdebug ) - # Add compile time bounds checks. - CFLAGS_DEBUG_OPTIONS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1" - CXXFLAGS_DEBUG_OPTIONS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1" + # no adjustment ;; slowdebug ) - # Add runtime bounds checks and symbol info. - CFLAGS_DEBUG_OPTIONS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-all --param ssp-buffer-size=1" - CXXFLAGS_DEBUG_OPTIONS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-all --param ssp-buffer-size=1" + # Add runtime stack smashing and undefined behavior checks + CFLAGS_DEBUG_OPTIONS="-fstack-protector-all --param ssp-buffer-size=1" + CXXFLAGS_DEBUG_OPTIONS="-fstack-protector-all --param ssp-buffer-size=1" if test "x$HAS_CFLAG_DETECT_UNDEFINED_BEHAVIOR" = "xtrue"; then CFLAGS_DEBUG_OPTIONS="$CFLAGS_DEBUG_OPTIONS $CFLAG_DETECT_UNDEFINED_BEHAVIOR_FLAG" - CXXFLAGS_DEBUG_OPTIONS="$CXXFLAGS_DEBUG_OPTIONS $CFLAG_DETECT_UNDEFINED_BEHAVIOR_FLAG" + CXXFLAGS_DEBUG_OPTIONS="$CXXFLAGS_DEBUG_OPTIONS $CFLAG_DETECT_UNDEFINED_BEHAVIsOR_FLAG" fi ;; esac @@ -42629,7 +42965,7 @@ $as_echo "$supports" >&6; } case "${TOOLCHAIN_TYPE}" in microsoft) - CFLAGS_WARNINGS_ARE_ERRORS="/WX" + CFLAGS_WARNINGS_ARE_ERRORS="-WX" ;; solstudio) CFLAGS_WARNINGS_ARE_ERRORS="-errtags -errwarn=%all" @@ -48711,12 +49047,22 @@ $as_echo "$as_me: Found msvcr100.dll at $POSSIBLE_MSVCR_DLL using $METHOD" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: checking found msvcr100.dll architecture" >&5 $as_echo_n "checking found msvcr100.dll architecture... " >&6; } MSVCR_DLL_FILETYPE=`$FILE -b "$POSSIBLE_MSVCR_DLL"` - if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then - CORRECT_MSVCR_ARCH=386 + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + # The MSYS 'file' command returns "PE32 executable for MS Windows (DLL) (GUI) Intel 80386 32-bit" + # on x32 and "PE32+ executable for MS Windows (DLL) (GUI) Mono/.Net assembly" on x64 systems. + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH="PE32 executable" + else + CORRECT_MSVCR_ARCH="PE32+ executable" + fi else - CORRECT_MSVCR_ARCH=x86-64 + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH=386 + else + CORRECT_MSVCR_ARCH=x86-64 + fi fi - if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP $CORRECT_MSVCR_ARCH 2>&1 > /dev/null; then + if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP "$CORRECT_MSVCR_ARCH" 2>&1 > /dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } MSVCR_DLL="$POSSIBLE_MSVCR_DLL" @@ -48767,12 +49113,22 @@ $as_echo "$as_me: Found msvcr100.dll at $POSSIBLE_MSVCR_DLL using $METHOD" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: checking found msvcr100.dll architecture" >&5 $as_echo_n "checking found msvcr100.dll architecture... " >&6; } MSVCR_DLL_FILETYPE=`$FILE -b "$POSSIBLE_MSVCR_DLL"` - if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then - CORRECT_MSVCR_ARCH=386 + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + # The MSYS 'file' command returns "PE32 executable for MS Windows (DLL) (GUI) Intel 80386 32-bit" + # on x32 and "PE32+ executable for MS Windows (DLL) (GUI) Mono/.Net assembly" on x64 systems. + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH="PE32 executable" + else + CORRECT_MSVCR_ARCH="PE32+ executable" + fi else - CORRECT_MSVCR_ARCH=x86-64 + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH=386 + else + CORRECT_MSVCR_ARCH=x86-64 + fi fi - if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP $CORRECT_MSVCR_ARCH 2>&1 > /dev/null; then + if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP "$CORRECT_MSVCR_ARCH" 2>&1 > /dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } MSVCR_DLL="$POSSIBLE_MSVCR_DLL" @@ -48805,12 +49161,22 @@ $as_echo "$as_me: Found msvcr100.dll at $POSSIBLE_MSVCR_DLL using $METHOD" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: checking found msvcr100.dll architecture" >&5 $as_echo_n "checking found msvcr100.dll architecture... " >&6; } MSVCR_DLL_FILETYPE=`$FILE -b "$POSSIBLE_MSVCR_DLL"` - if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then - CORRECT_MSVCR_ARCH=386 + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + # The MSYS 'file' command returns "PE32 executable for MS Windows (DLL) (GUI) Intel 80386 32-bit" + # on x32 and "PE32+ executable for MS Windows (DLL) (GUI) Mono/.Net assembly" on x64 systems. + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH="PE32 executable" + else + CORRECT_MSVCR_ARCH="PE32+ executable" + fi else - CORRECT_MSVCR_ARCH=x86-64 + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH=386 + else + CORRECT_MSVCR_ARCH=x86-64 + fi fi - if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP $CORRECT_MSVCR_ARCH 2>&1 > /dev/null; then + if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP "$CORRECT_MSVCR_ARCH" 2>&1 > /dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } MSVCR_DLL="$POSSIBLE_MSVCR_DLL" @@ -48853,12 +49219,22 @@ $as_echo "$as_me: Found msvcr100.dll at $POSSIBLE_MSVCR_DLL using $METHOD" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: checking found msvcr100.dll architecture" >&5 $as_echo_n "checking found msvcr100.dll architecture... " >&6; } MSVCR_DLL_FILETYPE=`$FILE -b "$POSSIBLE_MSVCR_DLL"` - if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then - CORRECT_MSVCR_ARCH=386 + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + # The MSYS 'file' command returns "PE32 executable for MS Windows (DLL) (GUI) Intel 80386 32-bit" + # on x32 and "PE32+ executable for MS Windows (DLL) (GUI) Mono/.Net assembly" on x64 systems. + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH="PE32 executable" + else + CORRECT_MSVCR_ARCH="PE32+ executable" + fi else - CORRECT_MSVCR_ARCH=x86-64 + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH=386 + else + CORRECT_MSVCR_ARCH=x86-64 + fi fi - if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP $CORRECT_MSVCR_ARCH 2>&1 > /dev/null; then + if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP "$CORRECT_MSVCR_ARCH" 2>&1 > /dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } MSVCR_DLL="$POSSIBLE_MSVCR_DLL" @@ -48906,12 +49282,22 @@ $as_echo "$as_me: Found msvcr100.dll at $POSSIBLE_MSVCR_DLL using $METHOD" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: checking found msvcr100.dll architecture" >&5 $as_echo_n "checking found msvcr100.dll architecture... " >&6; } MSVCR_DLL_FILETYPE=`$FILE -b "$POSSIBLE_MSVCR_DLL"` - if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then - CORRECT_MSVCR_ARCH=386 + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + # The MSYS 'file' command returns "PE32 executable for MS Windows (DLL) (GUI) Intel 80386 32-bit" + # on x32 and "PE32+ executable for MS Windows (DLL) (GUI) Mono/.Net assembly" on x64 systems. + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH="PE32 executable" + else + CORRECT_MSVCR_ARCH="PE32+ executable" + fi else - CORRECT_MSVCR_ARCH=x86-64 + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH=386 + else + CORRECT_MSVCR_ARCH=x86-64 + fi fi - if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP $CORRECT_MSVCR_ARCH 2>&1 > /dev/null; then + if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP "$CORRECT_MSVCR_ARCH" 2>&1 > /dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } MSVCR_DLL="$POSSIBLE_MSVCR_DLL" @@ -48955,12 +49341,22 @@ $as_echo "$as_me: Found msvcr100.dll at $POSSIBLE_MSVCR_DLL using $METHOD" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: checking found msvcr100.dll architecture" >&5 $as_echo_n "checking found msvcr100.dll architecture... " >&6; } MSVCR_DLL_FILETYPE=`$FILE -b "$POSSIBLE_MSVCR_DLL"` - if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then - CORRECT_MSVCR_ARCH=386 + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + # The MSYS 'file' command returns "PE32 executable for MS Windows (DLL) (GUI) Intel 80386 32-bit" + # on x32 and "PE32+ executable for MS Windows (DLL) (GUI) Mono/.Net assembly" on x64 systems. + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH="PE32 executable" + else + CORRECT_MSVCR_ARCH="PE32+ executable" + fi else - CORRECT_MSVCR_ARCH=x86-64 + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH=386 + else + CORRECT_MSVCR_ARCH=x86-64 + fi fi - if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP $CORRECT_MSVCR_ARCH 2>&1 > /dev/null; then + if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP "$CORRECT_MSVCR_ARCH" 2>&1 > /dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } MSVCR_DLL="$POSSIBLE_MSVCR_DLL" @@ -49300,8 +49696,8 @@ fi # Number of jobs was not specified, calculate. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for appropriate number of jobs to run in parallel" >&5 $as_echo_n "checking for appropriate number of jobs to run in parallel... " >&6; } - # Approximate memory in GB, rounding up a bit. - memory_gb=`expr $MEMORY_SIZE / 1100` + # Approximate memory in GB. + memory_gb=`expr $MEMORY_SIZE / 1024` # Pick the lowest of memory in gb and number of cores. if test "$memory_gb" -lt "$NUM_CORES"; then JOBS="$memory_gb" @@ -49327,6 +49723,208 @@ $as_echo "$JOBS" >&6; } +# Setup arguments for the boot jdk (after cores and memory have been setup) + + ############################################################################## + # + # Specify jvm options for anything that is run with the Boot JDK. + # Not all JVM:s accept the same arguments on the command line. + # + +# Check whether --with-boot-jdk-jvmargs was given. +if test "${with_boot_jdk_jvmargs+set}" = set; then : + withval=$with_boot_jdk_jvmargs; +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command " >&5 +$as_echo_n "checking flags for boot jdk java command ... " >&6; } + + # Disable special log output when a debug build is used as Boot JDK... + + $ECHO "Check if jvm arg is ok: -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput" >&5 + $ECHO "Command: $JAVA -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput -version" >&5 + OUTPUT=`$JAVA -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs="$boot_jdk_jvmargs -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + # Apply user provided options. + + $ECHO "Check if jvm arg is ok: $with_boot_jdk_jvmargs" >&5 + $ECHO "Command: $JAVA $with_boot_jdk_jvmargs -version" >&5 + OUTPUT=`$JAVA $with_boot_jdk_jvmargs -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs="$boot_jdk_jvmargs $with_boot_jdk_jvmargs" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs" >&5 +$as_echo "$boot_jdk_jvmargs" >&6; } + + # For now, general JAVA_FLAGS are the same as the boot jdk jvmargs + JAVA_FLAGS=$boot_jdk_jvmargs + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command for big workloads" >&5 +$as_echo_n "checking flags for boot jdk java command for big workloads... " >&6; } + + # Starting amount of heap memory. + + $ECHO "Check if jvm arg is ok: -Xms64M" >&5 + $ECHO "Command: $JAVA -Xms64M -version" >&5 + OUTPUT=`$JAVA -Xms64M -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -Xms64M" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + # Maximum amount of heap memory. + # Maximum stack size. + JVM_MAX_HEAP=`expr $MEMORY_SIZE / 2` + if test "x$BUILD_NUM_BITS" = x32; then + if test "$JVM_MAX_HEAP" -gt "1100"; then + JVM_MAX_HEAP=1100 + elif test "$JVM_MAX_HEAP" -lt "512"; then + JVM_MAX_HEAP=512 + fi + STACK_SIZE=768 + else + # Running Javac on a JVM on a 64-bit machine, takes more space since 64-bit + # pointers are used. Apparently, we need to increase the heap and stack + # space for the jvm. More specifically, when running javac to build huge + # jdk batch + if test "$JVM_MAX_HEAP" -gt "1600"; then + JVM_MAX_HEAP=1600 + elif test "$JVM_MAX_HEAP" -lt "512"; then + JVM_MAX_HEAP=512 + fi + STACK_SIZE=1536 + fi + + $ECHO "Check if jvm arg is ok: -Xmx${JVM_MAX_HEAP}M" >&5 + $ECHO "Command: $JAVA -Xmx${JVM_MAX_HEAP}M -version" >&5 + OUTPUT=`$JAVA -Xmx${JVM_MAX_HEAP}M -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -Xmx${JVM_MAX_HEAP}M" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + $ECHO "Check if jvm arg is ok: -XX:ThreadStackSize=$STACK_SIZE" >&5 + $ECHO "Command: $JAVA -XX:ThreadStackSize=$STACK_SIZE -version" >&5 + OUTPUT=`$JAVA -XX:ThreadStackSize=$STACK_SIZE -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -XX:ThreadStackSize=$STACK_SIZE" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_big" >&5 +$as_echo "$boot_jdk_jvmargs_big" >&6; } + + JAVA_FLAGS_BIG=$boot_jdk_jvmargs_big + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command for small workloads" >&5 +$as_echo_n "checking flags for boot jdk java command for small workloads... " >&6; } + + # Use serial gc for small short lived tools if possible + + $ECHO "Check if jvm arg is ok: -XX:+UseSerialGC" >&5 + $ECHO "Command: $JAVA -XX:+UseSerialGC -version" >&5 + OUTPUT=`$JAVA -XX:+UseSerialGC -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -XX:+UseSerialGC" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + $ECHO "Check if jvm arg is ok: -Xms32M" >&5 + $ECHO "Command: $JAVA -Xms32M -version" >&5 + OUTPUT=`$JAVA -Xms32M -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -Xms32M" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + $ECHO "Check if jvm arg is ok: -Xmx512M" >&5 + $ECHO "Command: $JAVA -Xmx512M -version" >&5 + OUTPUT=`$JAVA -Xmx512M -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -Xmx512M" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_small" >&5 +$as_echo "$boot_jdk_jvmargs_small" >&6; } + + JAVA_FLAGS_SMALL=$boot_jdk_jvmargs_small + + + JAVA_TOOL_FLAGS_SMALL="" + for f in $JAVA_FLAGS_SMALL; do + JAVA_TOOL_FLAGS_SMALL="$JAVA_TOOL_FLAGS_SMALL -J$f" + done + + + # Setup smart javac (after cores and memory have been setup) @@ -49343,44 +49941,11 @@ fi as_fn_error $? "Could not execute server java: $SJAVAC_SERVER_JAVA" "$LINENO" 5 fi else - SJAVAC_SERVER_JAVA="" - # Hotspot specific options. - - $ECHO "Check if jvm arg is ok: -verbosegc" >&5 - $ECHO "Command: $JAVA -verbosegc -version" >&5 - OUTPUT=`$JAVA -verbosegc -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -verbosegc" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - # JRockit specific options. - - $ECHO "Check if jvm arg is ok: -Xverbose:gc" >&5 - $ECHO "Command: $JAVA -Xverbose:gc -version" >&5 - OUTPUT=`$JAVA -Xverbose:gc -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -Xverbose:gc" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - SJAVAC_SERVER_JAVA="$JAVA $SJAVAC_SERVER_JAVA" + SJAVAC_SERVER_JAVA="$JAVA" fi - if test "$MEMORY_SIZE" -gt "2500"; then + if test "$MEMORY_SIZE" -gt "3000"; then $ECHO "Check if jvm arg is ok: -d64" >&5 $ECHO "Command: $SJAVAC_SERVER_JAVA -d64 -version" >&5 @@ -49402,85 +49967,31 @@ fi fi fi + MX_VALUE=`expr $MEMORY_SIZE / 2` if test "$JVM_64BIT" = true; then - if test "$MEMORY_SIZE" -gt "17000"; then - - $ECHO "Check if jvm arg is ok: -Xms10G -Xmx10G" >&5 - $ECHO "Command: $SJAVAC_SERVER_JAVA -Xms10G -Xmx10G -version" >&5 - OUTPUT=`$SJAVAC_SERVER_JAVA -Xms10G -Xmx10G -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -Xms10G -Xmx10G" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - + # Set ms lower than mx since more than one instance of the server might + # get launched at the same time before they figure out which instance won. + MS_VALUE=512 + if test "$MX_VALUE" -gt "2048"; then + MX_VALUE=2048 fi - if test "$MEMORY_SIZE" -gt "10000" && test "$JVM_ARG_OK" = false; then - - $ECHO "Check if jvm arg is ok: -Xms6G -Xmx6G" >&5 - $ECHO "Command: $SJAVAC_SERVER_JAVA -Xms6G -Xmx6G -version" >&5 - OUTPUT=`$SJAVAC_SERVER_JAVA -Xms6G -Xmx6G -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -Xms6G -Xmx6G" - JVM_ARG_OK=true else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - fi - if test "$MEMORY_SIZE" -gt "5000" && test "$JVM_ARG_OK" = false; then - - $ECHO "Check if jvm arg is ok: -Xms1G -Xmx3G" >&5 - $ECHO "Command: $SJAVAC_SERVER_JAVA -Xms1G -Xmx3G -version" >&5 - OUTPUT=`$SJAVAC_SERVER_JAVA -Xms1G -Xmx3G -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -Xms1G -Xmx3G" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - fi - if test "$MEMORY_SIZE" -gt "3800" && test "$JVM_ARG_OK" = false; then - - $ECHO "Check if jvm arg is ok: -Xms1G -Xmx2500M" >&5 - $ECHO "Command: $SJAVAC_SERVER_JAVA -Xms1G -Xmx2500M -version" >&5 - OUTPUT=`$SJAVAC_SERVER_JAVA -Xms1G -Xmx2500M -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -Xms1G -Xmx2500M" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - + MS_VALUE=256 + if test "$MX_VALUE" -gt "1500"; then + MX_VALUE=1500 fi fi - if test "$MEMORY_SIZE" -gt "2500" && test "$JVM_ARG_OK" = false; then + if test "$MX_VALUE" -lt "512"; then + MX_VALUE=512 + fi - $ECHO "Check if jvm arg is ok: -Xms1000M -Xmx1500M" >&5 - $ECHO "Command: $SJAVAC_SERVER_JAVA -Xms1000M -Xmx1500M -version" >&5 - OUTPUT=`$SJAVAC_SERVER_JAVA -Xms1000M -Xmx1500M -version 2>&1` + $ECHO "Check if jvm arg is ok: -Xms${MS_VALUE}M -Xmx${MX_VALUE}M" >&5 + $ECHO "Command: $SJAVAC_SERVER_JAVA -Xms${MS_VALUE}M -Xmx${MX_VALUE}M -version" >&5 + OUTPUT=`$SJAVAC_SERVER_JAVA -Xms${MS_VALUE}M -Xmx${MX_VALUE}M -version 2>&1` FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -Xms1000M -Xmx1500M" + SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -Xms${MS_VALUE}M -Xmx${MX_VALUE}M" JVM_ARG_OK=true else $ECHO "Arg failed:" >&5 @@ -49488,44 +49999,7 @@ fi JVM_ARG_OK=false fi - fi - if test "$MEMORY_SIZE" -gt "1000" && test "$JVM_ARG_OK" = false; then - $ECHO "Check if jvm arg is ok: -Xms400M -Xmx1100M" >&5 - $ECHO "Command: $SJAVAC_SERVER_JAVA -Xms400M -Xmx1100M -version" >&5 - OUTPUT=`$SJAVAC_SERVER_JAVA -Xms400M -Xmx1100M -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -Xms400M -Xmx1100M" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - fi - if test "$JVM_ARG_OK" = false; then - - $ECHO "Check if jvm arg is ok: -Xms256M -Xmx512M" >&5 - $ECHO "Command: $SJAVAC_SERVER_JAVA -Xms256M -Xmx512M -version" >&5 - OUTPUT=`$SJAVAC_SERVER_JAVA -Xms256M -Xmx512M -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - SJAVAC_SERVER_JAVA="$SJAVAC_SERVER_JAVA -Xms256M -Xmx512M" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use sjavac" >&5 -$as_echo_n "checking whether to use sjavac... " >&6; } # Check whether --enable-sjavac was given. if test "${enable_sjavac+set}" = set; then : enableval=$enable_sjavac; ENABLE_SJAVAC="${enableval}" @@ -49533,6 +50007,13 @@ else ENABLE_SJAVAC='no' fi + if test "x$JVM_ARG_OK" = "xfalse"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not set -Xms${MS_VALUE}M -Xmx${MX_VALUE}M, disabling sjavac" >&5 +$as_echo "$as_me: WARNING: Could not set -Xms${MS_VALUE}M -Xmx${MX_VALUE}M, disabling sjavac" >&2;} + ENABLE_SJAVAC=no; + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use sjavac" >&5 +$as_echo_n "checking whether to use sjavac... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_SJAVAC" >&5 $as_echo "$ENABLE_SJAVAC" >&6; } @@ -49903,7 +50384,7 @@ $as_echo "no, disabling ccaching of precompiled headers" >&6; } # Check for some common pitfalls - if test x"$OPENJDK_BUILD_OS" = xwindows; then + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then file_to_test="$SRC_ROOT/LICENSE" if test `$STAT -c '%a' "$file_to_test"` -lt 400; then as_fn_error $? "Bad file permissions on src files. This is usually caused by cloning the repositories with a non cygwin hg in a directory not created in cygwin." "$LINENO" 5 diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index ead832d5050..4eacb397cbe 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -173,6 +173,7 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD], OPENJDK_BUILD_CPU_ENDIAN="$VAR_CPU_ENDIAN" AC_SUBST(OPENJDK_BUILD_OS) AC_SUBST(OPENJDK_BUILD_OS_API) + AC_SUBST(OPENJDK_BUILD_OS_ENV) AC_SUBST(OPENJDK_BUILD_CPU) AC_SUBST(OPENJDK_BUILD_CPU_ARCH) AC_SUBST(OPENJDK_BUILD_CPU_BITS) @@ -194,6 +195,7 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD], OPENJDK_TARGET_CPU_ENDIAN="$VAR_CPU_ENDIAN" AC_SUBST(OPENJDK_TARGET_OS) AC_SUBST(OPENJDK_TARGET_OS_API) + AC_SUBST(OPENJDK_TARGET_OS_ENV) AC_SUBST(OPENJDK_TARGET_CPU) AC_SUBST(OPENJDK_TARGET_CPU_ARCH) AC_SUBST(OPENJDK_TARGET_CPU_BITS) diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 315c10615e4..e85c830783c 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -106,6 +106,7 @@ OPENJDK_TARGET_OS_EXPORT_DIR:=@OPENJDK_TARGET_OS_EXPORT_DIR@ # When not cross-compiling, it is the same as the target. OPENJDK_BUILD_OS:=@OPENJDK_BUILD_OS@ OPENJDK_BUILD_OS_API:=@OPENJDK_BUILD_OS_API@ +OPENJDK_BUILD_OS_ENV:=@OPENJDK_BUILD_OS_ENV@ OPENJDK_BUILD_CPU:=@OPENJDK_BUILD_CPU@ OPENJDK_BUILD_CPU_ARCH:=@OPENJDK_BUILD_CPU_ARCH@ diff --git a/common/autoconf/toolchain_windows.m4 b/common/autoconf/toolchain_windows.m4 index b4888a46ac5..bdd110582c9 100644 --- a/common/autoconf/toolchain_windows.m4 +++ b/common/autoconf/toolchain_windows.m4 @@ -244,12 +244,22 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_MSVCR_DLL], # Need to check if the found msvcr is correct architecture AC_MSG_CHECKING([found msvcr100.dll architecture]) MSVCR_DLL_FILETYPE=`$FILE -b "$POSSIBLE_MSVCR_DLL"` - if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then - CORRECT_MSVCR_ARCH=386 + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + # The MSYS 'file' command returns "PE32 executable for MS Windows (DLL) (GUI) Intel 80386 32-bit" + # on x32 and "PE32+ executable for MS Windows (DLL) (GUI) Mono/.Net assembly" on x64 systems. + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH="PE32 executable" + else + CORRECT_MSVCR_ARCH="PE32+ executable" + fi else - CORRECT_MSVCR_ARCH=x86-64 + if test "x$OPENJDK_TARGET_CPU_BITS" = x32; then + CORRECT_MSVCR_ARCH=386 + else + CORRECT_MSVCR_ARCH=x86-64 + fi fi - if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP $CORRECT_MSVCR_ARCH 2>&1 > /dev/null; then + if $ECHO "$MSVCR_DLL_FILETYPE" | $GREP "$CORRECT_MSVCR_ARCH" 2>&1 > /dev/null; then AC_MSG_RESULT([ok]) MSVCR_DLL="$POSSIBLE_MSVCR_DLL" AC_MSG_CHECKING([for msvcr100.dll]) diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh index e7fbd1fe13f..5bf586bc13c 100644 --- a/common/bin/hgforest.sh +++ b/common/bin/hgforest.sh @@ -77,6 +77,11 @@ do shift done +# debug mode +if [ "${HGFOREST_DEBUG:-false}" = "true" ] ; then + global_opts="${global_opts} --debug" +fi + # silence standard output? if [ ${qflag} = "true" ] ; then global_opts="${global_opts} -q" @@ -89,14 +94,26 @@ if [ ${vflag} = "true" ] ; then fi # Make sure we have a command. -if [ $# -lt 1 -o -z "${1:-}" ] ; then - echo "ERROR: No command to hg supplied!" - usage +if [ ${#} -lt 1 -o -z "${1:-}" ] ; then + echo "ERROR: No command to hg supplied!" > ${status_output} + usage > ${status_output} fi -command="$1"; shift +# grab command +command="${1}"; shift + +if [ ${vflag} = "true" ] ; then + echo "# Mercurial command: ${command}" > ${status_output} +fi + + +# capture command options and arguments (if any) command_args="${@:-}" +if [ ${vflag} = "true" ] ; then + echo "# Mercurial command arguments: ${command_args}" > ${status_output} +fi + # Clean out the temporary directory that stores the pid files. tmp=/tmp/forest.$$ rm -f -r ${tmp} @@ -104,7 +121,8 @@ mkdir -p ${tmp} if [ "${HGFOREST_DEBUG:-false}" = "true" ] ; then - echo "DEBUG: temp files are in: ${tmp}" + # ignores redirection. + echo "DEBUG: temp files are in: ${tmp}" >&2 fi # Check if we can use fifos for monitoring sub-process completion. @@ -377,21 +395,33 @@ else fi fi done + + if [ ${have_fifos} = "true" ]; then + # done with the fifo + exec 3>&- + fi fi # Wait for all subprocesses to complete wait # Terminate with exit 0 only if all subprocesses were successful +# Terminate with highest exit code of subprocesses ec=0 if [ -d ${tmp} ]; then rcfiles="`(ls -a ${tmp}/*.pid.rc 2> /dev/null) || echo ''`" for rc in ${rcfiles} ; do exit_code=`cat ${rc} | tr -d ' \n\r'` if [ "${exit_code}" != "0" ] ; then + if [ ${exit_code} -gt 1 ]; then + # mercurial exit codes greater than "1" signal errors. repo="`echo ${rc} | sed -e 's@^'${tmp}'@@' -e 's@/*\([^/]*\)\.pid\.rc$@\1@' -e 's@_@/@g'`" echo "WARNING: ${repo} exited abnormally (${exit_code})" > ${status_output} - ec=1 + fi + if [ ${exit_code} -gt ${ec} ]; then + # assume that larger exit codes are more significant + ec=${exit_code} + fi fi done fi diff --git a/corba/.hgtags b/corba/.hgtags index d7401bcb630..346a38ca219 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -269,3 +269,5 @@ ddc07abf4307855c0dc904cc5c96cc764023a930 jdk9-b22 8a44142bb7fc8118f70f91a1b97c12dfc50563ee jdk9-b24 da08cca6b97f41b7081a3e176dcb400af6e4bb26 jdk9-b25 6c777df597bbf5abba3488d44c401edfe73c74af jdk9-b26 +7e06bf1dcb0907b80ddf59315426ce9ce775e56d jdk9-b27 +a00b04ef067e39f50b9a0fea6f1904e35d632a73 jdk9-b28 diff --git a/corba/make/GensrcCorba.gmk b/corba/make/GensrcCorba.gmk index 8b814238272..1951cd43e37 100644 --- a/corba/make/GensrcCorba.gmk +++ b/corba/make/GensrcCorba.gmk @@ -50,8 +50,9 @@ $(eval $(call SetupJavaCompilation,BUILD_IDLJ, \ INCLUDES := com/sun/tools/corba/se/idl, \ EXCLUDE_FILES := ResourceBundleUtil.java)) +# Force the language to english for predictable source code generation. TOOL_IDLJ_CMD := $(JAVA) -cp $(CORBA_OUTPUTDIR)/idlj_classes \ - com.sun.tools.corba.se.idl.toJavaPortable.Compile + -Duser.language=en com.sun.tools.corba.se.idl.toJavaPortable.Compile ################################################################################ diff --git a/corba/src/java.corba/share/classes/org/omg/CORBA/FloatSeqHelper.java b/corba/src/java.corba/share/classes/org/omg/CORBA/FloatSeqHelper.java index ad02ae3b56a..8cf9684c585 100644 --- a/corba/src/java.corba/share/classes/org/omg/CORBA/FloatSeqHelper.java +++ b/corba/src/java.corba/share/classes/org/omg/CORBA/FloatSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/get_source.sh b/get_source.sh index 5e874d1cb51..72049bdec8a 100644 --- a/get_source.sh +++ b/get_source.sh @@ -67,7 +67,7 @@ if [ "x$hgwhere" = "x" ]; then error "Could not locate Mercurial command" fi -hgversion="`hg --version 2> /dev/null | sed -n -e 's@^Mercurial Distributed SCM (version \([^+]*\).*)\$@\1@p'`" +hgversion="`LANGUAGE=en hg --version 2> /dev/null | sed -n -e 's@^Mercurial Distributed SCM (version \([^+]*\).*)\$@\1@p'`" if [ "x${hgversion}" = "x" ] ; then error "Could not determine Mercurial version of $hgwhere" fi diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 2dbb04816d9..cf882b4f365 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -429,3 +429,5 @@ dd472cdacc32e3afc7c5bfa7ef16ea0e0befb7fa jdk9-b23 dde2d03b0ea46a27650839e3a1d212c7c1f7b4c8 jdk9-b24 6de94e8693240cec8aae11f6b42f43433456a733 jdk9-b25 48b95a073d752d6891cc0d1d2836b321ecf3ce0c jdk9-b26 +f95347244306affc32ce3056f27ceff7b2100810 jdk9-b27 +657294869d7ff063e055f5492cab7ce5612ca851 jdk9-b28 diff --git a/hotspot/agent/src/os/solaris/proc/saproc.cpp b/hotspot/agent/src/os/solaris/proc/saproc.cpp index 5a910d3a357..3f0e6b25814 100644 --- a/hotspot/agent/src/os/solaris/proc/saproc.cpp +++ b/hotspot/agent/src/os/solaris/proc/saproc.cpp @@ -314,7 +314,7 @@ static void * pathmap_dlopen(const char * name, int mode) { handle = dlopen(name, mode); } if (_libsaproc_debug) { - printf("libsaproc DEBUG: pathmap_dlopen %s return 0x%x\n", name, handle); + printf("libsaproc DEBUG: pathmap_dlopen %s return 0x%lx\n", name, (unsigned long) handle); } return handle; } @@ -661,30 +661,30 @@ init_classsharing_workaround(void *cd, const prmap_t* pmap, const char* obj_name // read FileMapHeader size_t n = read(fd, pheader, sizeof(struct FileMapHeader)); if (n != sizeof(struct FileMapHeader)) { - free(pheader); - close(fd); char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "unable to read shared archive file map header from %s", classes_jsa); + close(fd); + free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } // check file magic if (pheader->_magic != 0xf00baba2) { - free(pheader); - close(fd); char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0xf00baba2", classes_jsa, pheader->_magic); + close(fd); + free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } // check version if (pheader->_version != CURRENT_ARCHIVE_VERSION) { - free(pheader); - close(fd); char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "%s has wrong shared archive version %d, expecting %d", classes_jsa, pheader->_version, CURRENT_ARCHIVE_VERSION); + close(fd); + free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java index eea5e4b7271..9ba1d2ba72b 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java @@ -45,8 +45,8 @@ import sun.jvm.hotspot.types.TypeDataBase; public class G1CollectedHeap extends SharedHeap { // HeapRegionSeq _seq; static private long hrsFieldOffset; - // MemRegion _g1_committed; - static private long g1CommittedFieldOffset; + // MemRegion _g1_reserved; + static private long g1ReservedFieldOffset; // size_t _summary_bytes_used; static private CIntegerField summaryBytesUsedField; // G1MonitoringSupport* _g1mm; @@ -68,7 +68,6 @@ public class G1CollectedHeap extends SharedHeap { Type type = db.lookupType("G1CollectedHeap"); hrsFieldOffset = type.getField("_hrs").getOffset(); - g1CommittedFieldOffset = type.getField("_g1_committed").getOffset(); summaryBytesUsedField = type.getCIntegerField("_summary_bytes_used"); g1mmField = type.getAddressField("_g1mm"); oldSetFieldOffset = type.getField("_old_set").getOffset(); @@ -76,9 +75,7 @@ public class G1CollectedHeap extends SharedHeap { } public long capacity() { - Address g1CommittedAddr = addr.addOffsetTo(g1CommittedFieldOffset); - MemRegion g1Committed = new MemRegion(g1CommittedAddr); - return g1Committed.byteSize(); + return hrs().capacity(); } public long used() { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1HeapRegionTable.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1HeapRegionTable.java index cfbea40435c..e8bbaaa0553 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1HeapRegionTable.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1HeapRegionTable.java @@ -93,19 +93,35 @@ public class G1HeapRegionTable extends VMObject { private class HeapRegionIterator implements Iterator { private long index; private long length; + private HeapRegion next; + + public HeapRegion positionToNext() { + HeapRegion result = next; + while (index < length && at(index) == null) { + index++; + } + if (index < length) { + next = at(index); + index++; // restart search at next element + } else { + next = null; + } + return result; + } @Override - public boolean hasNext() { return index < length; } + public boolean hasNext() { return next != null; } @Override - public HeapRegion next() { return at(index++); } + public HeapRegion next() { return positionToNext(); } @Override - public void remove() { /* not supported */ } + public void remove() { /* not supported */ } - HeapRegionIterator(long committedLength) { + HeapRegionIterator(long totalLength) { index = 0; - length = committedLength; + length = totalLength; + positionToNext(); } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java index 190bf56a17f..8d011ed61ea 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java @@ -43,7 +43,7 @@ public class HeapRegionSeq extends VMObject { // G1HeapRegionTable _regions static private long regionsFieldOffset; // uint _committed_length - static private CIntegerField committedLengthField; + static private CIntegerField numCommittedField; static { VM.registerVMInitializedObserver(new Observer() { @@ -57,7 +57,7 @@ public class HeapRegionSeq extends VMObject { Type type = db.lookupType("HeapRegionSeq"); regionsFieldOffset = type.getField("_regions").getOffset(); - committedLengthField = type.getCIntegerField("_committed_length"); + numCommittedField = type.getCIntegerField("_num_committed"); } private G1HeapRegionTable regions() { @@ -66,16 +66,20 @@ public class HeapRegionSeq extends VMObject { regionsAddr); } + public long capacity() { + return length() * HeapRegion.grainBytes(); + } + public long length() { return regions().length(); } public long committedLength() { - return committedLengthField.getValue(addr); + return numCommittedField.getValue(addr); } public Iterator heapRegionIterator() { - return regions().heapRegionIterator(committedLength()); + return regions().heapRegionIterator(length()); } public HeapRegionSeq(Address addr) { diff --git a/hotspot/make/bsd/makefiles/gcc.make b/hotspot/make/bsd/makefiles/gcc.make index 54d319bb1eb..b31b0cd17a1 100644 --- a/hotspot/make/bsd/makefiles/gcc.make +++ b/hotspot/make/bsd/makefiles/gcc.make @@ -508,13 +508,9 @@ endif ifeq ($(USE_CLANG),) # Enable bounds checking. - # _FORTIFY_SOURCE appears in GCC 4.0+ ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) )" "1" - # compile time size bounds checks - FASTDEBUG_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 - - # and runtime size bounds checks and paranoid stack smashing checks. - DEBUG_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-all --param ssp-buffer-size=1 + # stack smashing checks. + DEBUG_CFLAGS += -fstack-protector-all --param ssp-buffer-size=1 endif endif diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index 00db453d5f8..c28f3b9745e 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -70,7 +70,8 @@ ifeq ($(INCLUDE_CDS), false) CXXFLAGS += -DINCLUDE_CDS=0 CFLAGS += -DINCLUDE_CDS=0 - Src_Files_EXCLUDE += filemap.cpp metaspaceShared.cpp + Src_Files_EXCLUDE += filemap.cpp metaspaceShared*.cpp sharedPathsMiscInfo.cpp \ + systemDictionaryShared.cpp classLoaderExt.cpp sharedClassUtil.cpp endif ifeq ($(INCLUDE_ALL_GCS), false) @@ -119,8 +120,8 @@ ifeq ($(INCLUDE_NMT), false) CFLAGS += -DINCLUDE_NMT=0 Src_Files_EXCLUDE += \ - memBaseline.cpp memPtr.cpp memRecorder.cpp memReporter.cpp memSnapshot.cpp memTrackWorker.cpp \ - memTracker.cpp nmtDCmd.cpp + memBaseline.cpp memReporter.cpp mallocTracker.cpp virtualMemoryTracker.cpp nmtCommon.cpp \ + memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp endif -include $(HS_ALT_MAKE)/excludeSrc.make diff --git a/hotspot/make/jprt.properties b/hotspot/make/jprt.properties index a6ff452c2ce..47df3e779a1 100644 --- a/hotspot/make/jprt.properties +++ b/hotspot/make/jprt.properties @@ -356,14 +356,15 @@ jprt.make.rule.test.targets.standard.internalvmtests = \ ${jprt.my.windows.x64}-fastdebug-c2-internalvmtests jprt.make.rule.test.targets.standard.reg.group = \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.windows.i586}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c1-GROUP, \ - ${jprt.my.windows.i586}-{product|fastdebug}-c1-GROUP + ${jprt.my.solaris.sparcv9}-fastdebug-c2-GROUP, \ + ${jprt.my.solaris.x64}-fastdebug-c2-GROUP, \ + ${jprt.my.linux.i586}-fastdebug-c2-GROUP, \ + ${jprt.my.linux.x64}-fastdebug-c2-GROUP, \ + ${jprt.my.macosx.x64}-fastdebug-c2-GROUP, \ + ${jprt.my.windows.i586}-fastdebug-c2-GROUP, \ + ${jprt.my.windows.x64}-fastdebug-c2-GROUP, \ + ${jprt.my.linux.i586}-fastdebug-c1-GROUP, \ + ${jprt.my.windows.i586}-fastdebug-c1-GROUP jprt.make.rule.test.targets.standard = \ ${jprt.make.rule.test.targets.standard.client}, \ @@ -373,6 +374,7 @@ jprt.make.rule.test.targets.standard = \ ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_compiler}, \ ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_gc}, \ ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_runtime}, \ + ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_runtime_closed}, \ ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_serviceability} jprt.make.rule.test.targets.embedded = \ diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index a20e7a1c18b..2447c8d3dd6 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -365,16 +365,13 @@ endif ifeq ($(USE_CLANG),) # Enable bounds checking. - # _FORTIFY_SOURCE appears in GCC 4.0+ ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) )" "1" - # compile time size bounds checks - FASTDEBUG_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 - - # and runtime size bounds checks and paranoid stack smashing checks. - DEBUG_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-all --param ssp-buffer-size=1 + # stack smashing checks. + DEBUG_CFLAGS += -fstack-protector-all --param ssp-buffer-size=1 endif endif + # If we are building HEADLESS, pass on to VM # so it can set the java.awt.headless property ifdef HEADLESS diff --git a/hotspot/make/solaris/makefiles/dtrace.make b/hotspot/make/solaris/makefiles/dtrace.make index 5af625b54db..ad2275ce5fb 100644 --- a/hotspot/make/solaris/makefiles/dtrace.make +++ b/hotspot/make/solaris/makefiles/dtrace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 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 @@ -58,6 +58,8 @@ DTRACE_SRCDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/dtrace DTRACE_COMMON_SRCDIR = $(GAMMADIR)/src/os/posix/dtrace DTRACE = dtrace DTRACE.o = $(DTRACE).o +DTRACE_JHELPER = dtrace_jhelper +DTRACE_JHELPER.o = $(DTRACE_JHELPER).o # to remove '-g' option which causes link problems # also '-z nodefs' is used as workaround @@ -255,7 +257,10 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) endif $(DTRACE).d: $(DTRACE_COMMON_SRCDIR)/hotspot.d $(DTRACE_COMMON_SRCDIR)/hotspot_jni.d \ - $(DTRACE_COMMON_SRCDIR)/hs_private.d $(DTRACE_SRCDIR)/jhelper.d + $(DTRACE_COMMON_SRCDIR)/hs_private.d + $(QUIETLY) cat $^ > $@ + +$(DTRACE_JHELPER).d: $(DTRACE_SRCDIR)/jhelper.d $(QUIETLY) cat $^ > $@ DTraced_Files = ciEnv.o \ @@ -280,7 +285,7 @@ DTraced_Files = ciEnv.o \ vmGCOperations.o \ # Dtrace is available, so we build $(DTRACE.o) -$(DTRACE.o): $(DTRACE).d $(JVMOFFS).h $(JVMOFFS)Index.h $(DTraced_Files) +$(DTRACE.o): $(DTRACE).d $(DTraced_Files) @echo Compiling $(DTRACE).d $(QUIETLY) $(DTRACE_PROG) $(DTRACE_OPTS) -C -I. -G -xlazyload -o $@ -s $(DTRACE).d \ @@ -344,6 +349,11 @@ $(DtraceOutDir)/hs_private.h: $(DTRACE_COMMON_SRCDIR)/hs_private.d | $(DtraceOut dtrace_gen_headers: $(DtraceOutDir)/hotspot.h $(DtraceOutDir)/hotspot_jni.h $(DtraceOutDir)/hs_private.h +# The jhelper.d and hotspot probes are separated into two different SUNW_dof sections. +# Now the jhelper.d is built without the -Xlazyload flag. +$(DTRACE_JHELPER.o) : $(DTRACE_JHELPER).d $(JVMOFFS).h $(JVMOFFS)Index.h + @echo Compiling $(DTRACE_JHELPER).d + $(QUIETLY) $(DTRACE_PROG) $(DTRACE_OPTS) -C -I. -G -o $@ -s $(DTRACE_JHELPER).d .PHONY: dtraceCheck @@ -372,7 +382,7 @@ endif # ifneq ("$(patchDtraceFound)", "") ifneq ("${DTRACE_PROG}", "") ifeq ("${HOTSPOT_DISABLE_DTRACE_PROBES}", "") -DTRACE_OBJS = $(DTRACE.o) $(JVMOFFS.o) +DTRACE_OBJS = $(DTRACE.o) $(JVMOFFS.o) $(DTRACE_JHELPER.o) CFLAGS += $(DTRACE_INCL) -DDTRACE_ENABLED MAPFILE_DTRACE_OPT = $(MAPFILE_DTRACE) diff --git a/hotspot/make/solaris/makefiles/gcc.make b/hotspot/make/solaris/makefiles/gcc.make index 9ea05411166..03ba4458c12 100644 --- a/hotspot/make/solaris/makefiles/gcc.make +++ b/hotspot/make/solaris/makefiles/gcc.make @@ -240,11 +240,7 @@ ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),) endif # Enable bounds checking. -# _FORTIFY_SOURCE appears in GCC 4.0+ ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) )" "1" - # compile time size bounds checks - FASTDEBUG_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 - - # and runtime size bounds checks and paranoid stack smashing checks. - DEBUG_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-all --param ssp-buffer-size=1 + # stack smashing checks. + DEBUG_CFLAGS += -fstack-protector-all --param ssp-buffer-size=1 endif diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp index 5a1c0f1d9c8..0c8cf435aea 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp @@ -298,6 +298,7 @@ class Assembler : public AbstractAssembler { LWZ_OPCODE = (32u << OPCODE_SHIFT), LWZX_OPCODE = (31u << OPCODE_SHIFT | 23u << 1), LWZU_OPCODE = (33u << OPCODE_SHIFT), + LWBRX_OPCODE = (31u << OPCODE_SHIFT | 534 << 1), LHA_OPCODE = (42u << OPCODE_SHIFT), LHAX_OPCODE = (31u << OPCODE_SHIFT | 343u << 1), @@ -306,6 +307,7 @@ class Assembler : public AbstractAssembler { LHZ_OPCODE = (40u << OPCODE_SHIFT), LHZX_OPCODE = (31u << OPCODE_SHIFT | 279u << 1), LHZU_OPCODE = (41u << OPCODE_SHIFT), + LHBRX_OPCODE = (31u << OPCODE_SHIFT | 790 << 1), LBZ_OPCODE = (34u << OPCODE_SHIFT), LBZX_OPCODE = (31u << OPCODE_SHIFT | 87u << 1), @@ -1364,11 +1366,17 @@ class Assembler : public AbstractAssembler { inline void lwax( Register d, Register s1, Register s2); inline void lwa( Register d, int si16, Register s1); + // 4 bytes reversed + inline void lwbrx( Register d, Register s1, Register s2); + // 2 bytes inline void lhzx( Register d, Register s1, Register s2); inline void lhz( Register d, int si16, Register s1); inline void lhzu( Register d, int si16, Register s1); + // 2 bytes reversed + inline void lhbrx( Register d, Register s1, Register s2); + // 2 bytes inline void lhax( Register d, Register s1, Register s2); inline void lha( Register d, int si16, Register s1); @@ -1858,10 +1866,12 @@ class Assembler : public AbstractAssembler { inline void lwz( Register d, int si16); inline void lwax( Register d, Register s2); inline void lwa( Register d, int si16); + inline void lwbrx(Register d, Register s2); inline void lhzx( Register d, Register s2); inline void lhz( Register d, int si16); inline void lhax( Register d, Register s2); inline void lha( Register d, int si16); + inline void lhbrx(Register d, Register s2); inline void lbzx( Register d, Register s2); inline void lbz( Register d, int si16); inline void ldx( Register d, Register s2); diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp index 3b7eb5f55e5..87db4bff89d 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp @@ -263,10 +263,14 @@ inline void Assembler::lwzu( Register d, int si16, Register s1) { assert(d != inline void Assembler::lwax( Register d, Register s1, Register s2) { emit_int32(LWAX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} inline void Assembler::lwa( Register d, int si16, Register s1) { emit_int32(LWA_OPCODE | rt(d) | ds(si16) | ra0mem(s1));} +inline void Assembler::lwbrx( Register d, Register s1, Register s2) { emit_int32(LWBRX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} + inline void Assembler::lhzx( Register d, Register s1, Register s2) { emit_int32(LHZX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} inline void Assembler::lhz( Register d, int si16, Register s1) { emit_int32(LHZ_OPCODE | rt(d) | d1(si16) | ra0mem(s1));} inline void Assembler::lhzu( Register d, int si16, Register s1) { assert(d != s1, "according to ibm manual"); emit_int32(LHZU_OPCODE | rt(d) | d1(si16) | rta0mem(s1));} +inline void Assembler::lhbrx( Register d, Register s1, Register s2) { emit_int32(LHBRX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} + inline void Assembler::lhax( Register d, Register s1, Register s2) { emit_int32(LHAX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} inline void Assembler::lha( Register d, int si16, Register s1) { emit_int32(LHA_OPCODE | rt(d) | d1(si16) | ra0mem(s1));} inline void Assembler::lhau( Register d, int si16, Register s1) { assert(d != s1, "according to ibm manual"); emit_int32(LHAU_OPCODE | rt(d) | d1(si16) | rta0mem(s1));} @@ -736,10 +740,12 @@ inline void Assembler::lwzx( Register d, Register s2) { emit_int32( LWZX_OPCODE inline void Assembler::lwz( Register d, int si16 ) { emit_int32( LWZ_OPCODE | rt(d) | d1(si16));} inline void Assembler::lwax( Register d, Register s2) { emit_int32( LWAX_OPCODE | rt(d) | rb(s2));} inline void Assembler::lwa( Register d, int si16 ) { emit_int32( LWA_OPCODE | rt(d) | ds(si16));} +inline void Assembler::lwbrx(Register d, Register s2) { emit_int32( LWBRX_OPCODE| rt(d) | rb(s2));} inline void Assembler::lhzx( Register d, Register s2) { emit_int32( LHZX_OPCODE | rt(d) | rb(s2));} inline void Assembler::lhz( Register d, int si16 ) { emit_int32( LHZ_OPCODE | rt(d) | d1(si16));} inline void Assembler::lhax( Register d, Register s2) { emit_int32( LHAX_OPCODE | rt(d) | rb(s2));} inline void Assembler::lha( Register d, int si16 ) { emit_int32( LHA_OPCODE | rt(d) | d1(si16));} +inline void Assembler::lhbrx(Register d, Register s2) { emit_int32( LHBRX_OPCODE| rt(d) | rb(s2));} inline void Assembler::lbzx( Register d, Register s2) { emit_int32( LBZX_OPCODE | rt(d) | rb(s2));} inline void Assembler::lbz( Register d, int si16 ) { emit_int32( LBZ_OPCODE | rt(d) | d1(si16));} inline void Assembler::ld( Register d, int si16 ) { emit_int32( LD_OPCODE | rt(d) | ds(si16));} diff --git a/hotspot/src/cpu/ppc/vm/cppInterpreterGenerator_ppc.hpp b/hotspot/src/cpu/ppc/vm/cppInterpreterGenerator_ppc.hpp index 6e43183ea3f..94cbe0ac24a 100644 --- a/hotspot/src/cpu/ppc/vm/cppInterpreterGenerator_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/cppInterpreterGenerator_ppc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2014, 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. * @@ -26,8 +26,9 @@ #ifndef CPU_PPC_VM_CPPINTERPRETERGENERATOR_PPC_HPP #define CPU_PPC_VM_CPPINTERPRETERGENERATOR_PPC_HPP - address generate_normal_entry(void); - address generate_native_entry(void); + address generate_normal_entry(bool synchronized); + address generate_native_entry(bool synchronized); + address generate_math_entry(AbstractInterpreter::MethodKind kind) { return NULL; } void lock_method(void); void unlock_method(void); diff --git a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp index 8a9534e260d..3ff878b9328 100644 --- a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp @@ -938,8 +938,9 @@ void CppInterpreterGenerator::generate_counter_incr(Label& overflow) { // 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(void) { +address CppInterpreterGenerator::generate_native_entry(bool synchronized) { if (native_entry != NULL) return native_entry; address entry = __ pc(); @@ -1729,7 +1730,8 @@ void CppInterpreterGenerator::generate_more_monitors() { __ std(R0, BasicObjectLock::obj_offset_in_bytes(), stack_base); // Mark lock as unused } -address CppInterpreterGenerator::generate_normal_entry(void) { +// The synchronized parameter is ignored +address CppInterpreterGenerator::generate_normal_entry(bool synchronized) { if (interpreter_frame_manager != NULL) return interpreter_frame_manager; address entry = __ pc(); @@ -2789,38 +2791,6 @@ address CppInterpreterGenerator::generate_normal_entry(void) { return interpreter_frame_manager; } -// Generate code for various sorts of method entries -// -address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter::MethodKind kind) { - address entry_point = NULL; - - switch (kind) { - case Interpreter::zerolocals : break; - case Interpreter::zerolocals_synchronized : break; - case Interpreter::native : // Fall thru - case Interpreter::native_synchronized : entry_point = ((CppInterpreterGenerator*)this)->generate_native_entry(); break; - case Interpreter::empty : break; - case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break; - case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break; - // These are special interpreter intrinsics which we don't support so far. - case Interpreter::java_lang_math_sin : break; - case Interpreter::java_lang_math_cos : break; - case Interpreter::java_lang_math_tan : break; - case Interpreter::java_lang_math_abs : break; - case Interpreter::java_lang_math_log : break; - case Interpreter::java_lang_math_log10 : break; - case Interpreter::java_lang_math_sqrt : break; - case Interpreter::java_lang_math_pow : break; - case Interpreter::java_lang_math_exp : break; - case Interpreter::java_lang_ref_reference_get: entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break; - default : ShouldNotReachHere(); break; - } - - if (entry_point) { - return entry_point; - } - return ((InterpreterGenerator*)this)->generate_normal_entry(); -} InterpreterGenerator::InterpreterGenerator(StubQueue* code) : CppInterpreterGenerator(code) { 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 98c34b15a33..a47f9f56593 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp @@ -119,9 +119,15 @@ void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) // Call the Interpreter::remove_activation_preserving_args_entry() // func to get the address of the same-named entrypoint in the // generated interpreter code. +#if defined(ABI_ELFv2) + call_c(CAST_FROM_FN_PTR(address, + Interpreter::remove_activation_preserving_args_entry), + relocInfo::none); +#else call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, Interpreter::remove_activation_preserving_args_entry), relocInfo::none); +#endif // Jump to Interpreter::_remove_activation_preserving_args_entry. mtctr(R3_RET); @@ -331,29 +337,40 @@ void InterpreterMacroAssembler::empty_expression_stack() { void InterpreterMacroAssembler::get_2_byte_integer_at_bcp(int bcp_offset, Register Rdst, signedOrNot is_signed) { +#if defined(VM_LITTLE_ENDIAN) + if (bcp_offset) { + load_const_optimized(Rdst, bcp_offset); + lhbrx(Rdst, R14_bcp, Rdst); + } else { + lhbrx(Rdst, R14_bcp); + } + if (is_signed == Signed) { + extsh(Rdst, Rdst); + } +#else // Read Java big endian format. if (is_signed == Signed) { lha(Rdst, bcp_offset, R14_bcp); } else { lhz(Rdst, bcp_offset, R14_bcp); } -#if 0 - assert(Rtmp != Rdst, "need separate temp register"); - Register Rfirst = Rtmp; - lbz(Rfirst, bcp_offset, R14_bcp); // first byte - lbz(Rdst, bcp_offset+1, R14_bcp); // second byte - - // Rdst = ((Rfirst<<8) & 0xFF00) | (Rdst &~ 0xFF00) - rldimi(/*RA=*/Rdst, /*RS=*/Rfirst, /*sh=*/8, /*mb=*/48); - if (is_signed == Signed) { - extsh(Rdst, Rdst); - } #endif } void InterpreterMacroAssembler::get_4_byte_integer_at_bcp(int bcp_offset, Register Rdst, signedOrNot is_signed) { +#if defined(VM_LITTLE_ENDIAN) + if (bcp_offset) { + load_const_optimized(Rdst, bcp_offset); + lwbrx(Rdst, R14_bcp, Rdst); + } else { + lwbrx(Rdst, R14_bcp); + } + if (is_signed == Signed) { + extsw(Rdst, Rdst); + } +#else // Read Java big endian format. if (bcp_offset & 3) { // Offset unaligned? load_const_optimized(Rdst, bcp_offset); @@ -369,18 +386,26 @@ void InterpreterMacroAssembler::get_4_byte_integer_at_bcp(int bcp_offset lwz(Rdst, bcp_offset, R14_bcp); } } +#endif } + // Load the constant pool cache index from the bytecode stream. // // Kills / writes: // - Rdst, Rscratch 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)) { - get_2_byte_integer_at_bcp(bcp_offset, Rdst, Unsigned); + lhz(Rdst, bcp_offset, R14_bcp); } else if (index_size == sizeof(u4)) { - get_4_byte_integer_at_bcp(bcp_offset, Rdst, Signed); + if (bcp_offset & 3) { + load_const_optimized(Rdst, bcp_offset); + lwax(Rdst, R14_bcp, Rdst); + } else { + lwa(Rdst, bcp_offset, R14_bcp); + } assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); nand(Rdst, Rdst, Rdst); // convert to plain index } else if (index_size == sizeof(u1)) { @@ -397,6 +422,29 @@ void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, int b add(cache, R27_constPoolCache, cache); } +// Load 4-byte signed or unsigned integer in Java format (that is, big-endian format) +// from (Rsrc)+offset. +void InterpreterMacroAssembler::get_u4(Register Rdst, Register Rsrc, int offset, + signedOrNot is_signed) { +#if defined(VM_LITTLE_ENDIAN) + if (offset) { + load_const_optimized(Rdst, offset); + lwbrx(Rdst, Rdst, Rsrc); + } else { + lwbrx(Rdst, Rsrc); + } + if (is_signed == Signed) { + extsw(Rdst, Rdst); + } +#else + if (is_signed == Signed) { + lwa(Rdst, offset, Rsrc); + } else { + lwz(Rdst, offset, Rsrc); + } +#endif +} + // Load object from cpool->resolved_references(index). void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result, Register index) { assert_different_registers(result, index); 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 b4c95a6458c..37c743228e9 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp @@ -130,6 +130,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size = sizeof(u2)); + void get_u4(Register Rdst, Register Rsrc, int offset, signedOrNot is_signed); // common code diff --git a/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp b/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp index 74f6001e766..d4f53f0accc 100644 --- a/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2014, 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. * @@ -31,7 +31,12 @@ private: address generate_abstract_entry(void); - address generate_accessor_entry(void); + address generate_jump_to_normal_entry(void); + address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } + address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } address generate_Reference_get_entry(void); + // Not supported + address generate_CRC32_update_entry() { return NULL; } + address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } #endif // CPU_PPC_VM_INTERPRETERGENERATOR_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp index 96814188f03..d64da8ea17a 100644 --- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp @@ -428,6 +428,19 @@ address AbstractInterpreterGenerator::generate_result_handler_for(BasicType type return entry; } + +// Call an accessor method (assuming it is resolved, otherwise drop into +// vanilla (slow path) entry. +address InterpreterGenerator::generate_jump_to_normal_entry(void) { + address entry = __ pc(); + address normal_entry = Interpreter::entry_for_kind(Interpreter::zerolocals); + assert(normal_entry != NULL, "should already be generated."); + __ branch_to_entry(normal_entry, R11_scratch1); + __ flush(); + + return entry; +} + // Abstract method entry. // address InterpreterGenerator::generate_abstract_entry(void) { @@ -485,203 +498,6 @@ address InterpreterGenerator::generate_abstract_entry(void) { return entry; } -// Call an accessor method (assuming it is resolved, otherwise drop into -// vanilla (slow path) entry. -address InterpreterGenerator::generate_accessor_entry(void) { - if (!UseFastAccessorMethods && (!FLAG_IS_ERGO(UseFastAccessorMethods))) { - return NULL; - } - - Label Lslow_path, Lacquire; - - const Register - Rclass_or_obj = R3_ARG1, - Rconst_method = R4_ARG2, - Rcodes = Rconst_method, - Rcpool_cache = R5_ARG3, - Rscratch = R11_scratch1, - Rjvmti_mode = Rscratch, - Roffset = R12_scratch2, - Rflags = R6_ARG4, - Rbtable = R7_ARG5; - - static address branch_table[number_of_states]; - - address entry = __ pc(); - - // Check for safepoint: - // Ditch this, real man don't need safepoint checks. - - // Also check for JVMTI mode - // Check for null obj, take slow path if so. - __ ld(Rclass_or_obj, Interpreter::stackElementSize, CC_INTERP_ONLY(R17_tos) NOT_CC_INTERP(R15_esp)); - __ lwz(Rjvmti_mode, thread_(interp_only_mode)); - __ cmpdi(CCR1, Rclass_or_obj, 0); - __ cmpwi(CCR0, Rjvmti_mode, 0); - __ crorc(/*CCR0 eq*/2, /*CCR1 eq*/4+2, /*CCR0 eq*/2); - __ beq(CCR0, Lslow_path); // this==null or jvmti_mode!=0 - - // Do 2 things in parallel: - // 1. Load the index out of the first instruction word, which looks like this: - // <0x2a><0xb4>. - // 2. Load constant pool cache base. - __ ld(Rconst_method, in_bytes(Method::const_offset()), R19_method); - __ ld(Rcpool_cache, in_bytes(ConstMethod::constants_offset()), Rconst_method); - - __ lhz(Rcodes, in_bytes(ConstMethod::codes_offset()) + 2, Rconst_method); // Lower half of 32 bit field. - __ ld(Rcpool_cache, ConstantPool::cache_offset_in_bytes(), Rcpool_cache); - - // Get the const pool entry by means of . - const int codes_shift = exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord); - __ slwi(Rscratch, Rcodes, codes_shift); // (codes&0xFFFF)<print_cr("accessor_entry: branch_table[%d] = 0x%llx (opcode 0x%llx)", i, branch_table[i], *((unsigned int*)branch_table[i])); - } -#endif - - __ bind(Lslow_path); - __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), Rscratch); - __ flush(); - - return entry; -} - // Interpreter intrinsic for WeakReference.get(). // 1. Don't push a full blown frame and go on dispatching, but fetch the value // into R8 and return quickly @@ -713,7 +529,6 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // and so we don't need to call the G1 pre-barrier. Thus we can use the // regular method entry code to generate the NPE. // - // This code is based on generate_accessor_enty. address entry = __ pc(); @@ -768,7 +583,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { return entry; } else { - return generate_accessor_entry(); + return generate_jump_to_normal_entry(); } } diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index 18870359ad9..ab2d535bbc9 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -1283,8 +1283,6 @@ int Compile::ConstantTable::calculate_table_base_offset() const { bool MachConstantBaseNode::requires_postalloc_expand() const { return true; } void MachConstantBaseNode::postalloc_expand(GrowableArray *nodes, PhaseRegAlloc *ra_) { - Compile *C = ra_->C; - iRegPdstOper *op_dst = new iRegPdstOper(); MachNode *m1 = new loadToc_hiNode(); MachNode *m2 = new loadToc_loNode(); @@ -2229,7 +2227,7 @@ const bool Matcher::isSimpleConstant64(jlong value) { } /* TODO: PPC port // Make a new machine dependent decode node (with its operands). -MachTypeNode *Matcher::make_decode_node(Compile *C) { +MachTypeNode *Matcher::make_decode_node() { assert(Universe::narrow_oop_base() == NULL && Universe::narrow_oop_shift() == 0, "This method is only implemented for unscaled cOops mode so far"); MachTypeNode *decode = new decodeN_unscaledNode(); @@ -2593,7 +2591,7 @@ typedef struct { MachNode *_last; } loadConLNodesTuple; -loadConLNodesTuple loadConLNodesTuple_create(Compile *C, PhaseRegAlloc *ra_, Node *toc, immLOper *immSrc, +loadConLNodesTuple loadConLNodesTuple_create(PhaseRegAlloc *ra_, Node *toc, immLOper *immSrc, OptoReg::Name reg_second, OptoReg::Name reg_first) { loadConLNodesTuple nodes; @@ -2669,7 +2667,7 @@ encode %{ enc_class postalloc_expand_load_long_constant(iRegLdst dst, immL src, iRegLdst toc) %{ // Create new nodes. loadConLNodesTuple loadConLNodes = - loadConLNodesTuple_create(C, ra_, n_toc, op_src, + loadConLNodesTuple_create(ra_, n_toc, op_src, ra_->get_reg_second(this), ra_->get_reg_first(this)); // Push new nodes. @@ -3391,7 +3389,7 @@ encode %{ immLOper *op_repl = new immLOper((jlong)replicate_immF(op_src->constantF())); loadConLNodesTuple loadConLNodes = - loadConLNodesTuple_create(C, ra_, n_toc, op_repl, + loadConLNodesTuple_create(ra_, n_toc, op_repl, ra_->get_reg_second(this), ra_->get_reg_first(this)); // Push new nodes. @@ -3611,7 +3609,7 @@ encode %{ // Create the nodes for loading the IC from the TOC. loadConLNodesTuple loadConLNodes_IC = - loadConLNodesTuple_create(C, ra_, n_toc, new immLOper((jlong)Universe::non_oop_word()), + loadConLNodesTuple_create(ra_, n_toc, new immLOper((jlong)Universe::non_oop_word()), OptoReg::Name(R19_H_num), OptoReg::Name(R19_num)); // Create the call node. @@ -3765,7 +3763,7 @@ encode %{ #if defined(ABI_ELFv2) jlong entry_address = (jlong) this->entry_point(); assert(entry_address, "need address here"); - loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new immLOper(entry_address), + loadConLNodes_Entry = loadConLNodesTuple_create(ra_, n_toc, new immLOper(entry_address), OptoReg::Name(R12_H_num), OptoReg::Name(R12_num)); #else // Get the struct that describes the function we are about to call. @@ -3777,13 +3775,13 @@ encode %{ loadConLNodesTuple loadConLNodes_Toc; // Create nodes and operands for loading the entry point. - loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new immLOper(entry_address), + loadConLNodes_Entry = loadConLNodesTuple_create(ra_, n_toc, new immLOper(entry_address), OptoReg::Name(R12_H_num), OptoReg::Name(R12_num)); // Create nodes and operands for loading the env pointer. if (fd->env() != NULL) { - loadConLNodes_Env = loadConLNodesTuple_create(C, ra_, n_toc, new immLOper((jlong) fd->env()), + loadConLNodes_Env = loadConLNodesTuple_create(ra_, n_toc, new immLOper((jlong) fd->env()), OptoReg::Name(R11_H_num), OptoReg::Name(R11_num)); } else { loadConLNodes_Env._large_hi = NULL; @@ -3796,7 +3794,7 @@ encode %{ } // Create nodes and operands for loading the Toc point. - loadConLNodes_Toc = loadConLNodesTuple_create(C, ra_, n_toc, new immLOper((jlong) fd->toc()), + loadConLNodes_Toc = loadConLNodesTuple_create(ra_, n_toc, new immLOper((jlong) fd->toc()), OptoReg::Name(R2_H_num), OptoReg::Name(R2_num)); #endif // ABI_ELFv2 // mtctr node diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp index 051ed26e728..ea12f04124c 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp @@ -30,7 +30,6 @@ address generate_normal_entry(bool synchronized); address generate_native_entry(bool synchronized); address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_empty_entry(void); void lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded=false); void unlock_method(bool check_exceptions = true); diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp index b787fecc7d5..c53d73ec890 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp @@ -176,8 +176,12 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, const Register size = R12_scratch2; __ get_cache_and_index_at_bcp(cache, 1, index_size); - // Big Endian (get least significant byte of 64 bit value): + // Get least significant byte of 64 bit value: +#if defined(VM_LITTLE_ENDIAN) + __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()), cache); +#else __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()) + 7, cache); +#endif __ sldi(size, size, Interpreter::logStackElementSize); __ add(R15_esp, R15_esp, size); __ dispatch_next(state, step); @@ -598,48 +602,6 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call, Regist // End of helpers -// ============================================================================ -// Various method entries -// - -// Empty method, generate a very fast return. We must skip this entry if -// someone's debugging, indicated by the flag -// "interp_mode" in the Thread obj. -// Note: empty methods are generated mostly methods that do assertions, which are -// disabled in the "java opt build". -address TemplateInterpreterGenerator::generate_empty_entry(void) { - if (!UseFastEmptyMethods) { - NOT_PRODUCT(__ should_not_reach_here();) - return Interpreter::entry_for_kind(Interpreter::zerolocals); - } - - Label Lslow_path; - const Register Rjvmti_mode = R11_scratch1; - address entry = __ pc(); - - __ lwz(Rjvmti_mode, thread_(interp_only_mode)); - __ cmpwi(CCR0, Rjvmti_mode, 0); - __ bne(CCR0, Lslow_path); // jvmti_mode!=0 - - // Noone's debuggin: Simply return. - // Pop c2i arguments (if any) off when we return. -#ifdef ASSERT - __ ld(R9_ARG7, 0, R1_SP); - __ ld(R10_ARG8, 0, R21_sender_SP); - __ cmpd(CCR0, R9_ARG7, R10_ARG8); - __ asm_assert_eq("backlink", 0x545); -#endif // ASSERT - __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started. - - // And we're done. - __ blr(); - - __ bind(Lslow_path); - __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1); - __ flush(); - - return entry; -} // Support abs and sqrt like in compiler. // For others we can use a normal (native) entry. @@ -858,7 +820,9 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // Our signature handlers copy required arguments to the C stack // (outgoing C args), R3_ARG1 to R10_ARG8, and FARG1 to FARG13. __ mr(R3_ARG1, R18_locals); +#if !defined(ABI_ELFv2) __ ld(signature_handler_fd, 0, signature_handler_fd); +#endif __ call_stub(signature_handler_fd); @@ -1020,8 +984,13 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // native result across 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); @@ -1278,45 +1247,6 @@ address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { return entry; } -// ============================================================================= -// Entry points - -address AbstractInterpreterGenerator::generate_method_entry( - AbstractInterpreter::MethodKind kind) { - // Determine code generation flags. - bool synchronized = false; - address entry_point = NULL; - - switch (kind) { - case Interpreter::zerolocals : break; - case Interpreter::zerolocals_synchronized: synchronized = true; break; - case Interpreter::native : entry_point = ((InterpreterGenerator*) this)->generate_native_entry(false); break; - case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*) this)->generate_native_entry(true); break; - case Interpreter::empty : entry_point = ((InterpreterGenerator*) this)->generate_empty_entry(); break; - case Interpreter::accessor : entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry(); break; - case Interpreter::abstract : entry_point = ((InterpreterGenerator*) this)->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 = ((InterpreterGenerator*) this)->generate_math_entry(kind); break; - case Interpreter::java_lang_ref_reference_get - : entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break; - default : ShouldNotReachHere(); break; - } - - if (entry_point) { - return entry_point; - } - - return ((InterpreterGenerator*) this)->generate_normal_entry(synchronized); -} - // These should never be compiled since the interpreter will prefer // the compiled version to the intrinsic version. bool AbstractInterpreter::can_be_compiled(methodHandle m) { @@ -1344,7 +1274,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 AbstractInterpreterGenerator::generate_method_entry. + // in InterpreterGenerator::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) : diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp index 0b375da582e..6a34053a496 100644 --- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp @@ -189,8 +189,12 @@ void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Reg assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); assert(load_bc_into_bc_reg, "we use bc_reg as temp"); __ get_cache_and_index_at_bcp(Rtemp /* dst = cache */, 1); - // Big Endian: ((*(cache+indices))>>((1+byte_no)*8))&0xFF + // ((*(cache+indices))>>((1+byte_no)*8))&0xFF: +#if defined(VM_LITTLE_ENDIAN) + __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 1 + byte_no, Rtemp); +#else __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (1 + byte_no), Rtemp); +#endif __ cmpwi(CCR0, Rnew_bc, 0); __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc); __ beq(CCR0, L_patch_done); @@ -1839,8 +1843,8 @@ void TemplateTable::tableswitch() { __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt)); // Load lo & hi. - __ lwz(Rlow_byte, BytesPerInt, Rdef_offset_addr); - __ lwz(Rhigh_byte, BytesPerInt * 2, Rdef_offset_addr); + __ get_u4(Rlow_byte, Rdef_offset_addr, BytesPerInt, InterpreterMacroAssembler::Unsigned); + __ get_u4(Rhigh_byte, Rdef_offset_addr, 2 *BytesPerInt, InterpreterMacroAssembler::Unsigned); // Check for default case (=index outside [low,high]). __ cmpw(CCR0, R17_tos, Rlow_byte); @@ -1854,12 +1858,17 @@ void TemplateTable::tableswitch() { __ profile_switch_case(Rindex, Rhigh_byte /* scratch */, Rscratch1, Rscratch2); __ sldi(Rindex, Rindex, LogBytesPerInt); __ addi(Rindex, Rindex, 3 * BytesPerInt); +#if defined(VM_LITTLE_ENDIAN) + __ lwbrx(Roffset, Rdef_offset_addr, Rindex); + __ extsw(Roffset, Roffset); +#else __ lwax(Roffset, Rdef_offset_addr, Rindex); +#endif __ b(Ldispatch); __ bind(Ldefault_case); __ profile_switch_default(Rhigh_byte, Rscratch1); - __ lwa(Roffset, 0, Rdef_offset_addr); + __ get_u4(Roffset, Rdef_offset_addr, 0, InterpreterMacroAssembler::Signed); __ bind(Ldispatch); @@ -1875,12 +1884,11 @@ void TemplateTable::lookupswitch() { // Table switch using linear search through cases. // Bytecode stream format: // Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ... -// Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value. +// Note: Everything is big-endian format here. void TemplateTable::fast_linearswitch() { transition(itos, vtos); - Label Lloop_entry, Lsearch_loop, Lfound, Lcontinue_execution, Ldefault_case; - + Label Lloop_entry, Lsearch_loop, Lcontinue_execution, Ldefault_case; Register Rcount = R3_ARG1, Rcurrent_pair = R4_ARG2, Rdef_offset_addr = R5_ARG3, // Is going to contain address of default offset. @@ -1894,47 +1902,40 @@ void TemplateTable::fast_linearswitch() { __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt)); // Setup loop counter and limit. - __ lwz(Rcount, BytesPerInt, Rdef_offset_addr); // Load count. + __ get_u4(Rcount, Rdef_offset_addr, BytesPerInt, InterpreterMacroAssembler::Unsigned); __ addi(Rcurrent_pair, Rdef_offset_addr, 2 * BytesPerInt); // Rcurrent_pair now points to first pair. - // Set up search loop. - __ cmpwi(CCR0, Rcount, 0); - __ beq(CCR0, Ldefault_case); - __ mtctr(Rcount); + __ cmpwi(CCR0, Rcount, 0); + __ bne(CCR0, Lloop_entry); - // linear table search - __ bind(Lsearch_loop); - - __ lwz(Rvalue, 0, Rcurrent_pair); - __ lwa(Roffset, 1 * BytesPerInt, Rcurrent_pair); - - __ cmpw(CCR0, Rvalue, Rcmp_value); - __ beq(CCR0, Lfound); - - __ addi(Rcurrent_pair, Rcurrent_pair, 2 * BytesPerInt); - __ bdnz(Lsearch_loop); - - // default case + // Default case __ bind(Ldefault_case); - - __ lwa(Roffset, 0, Rdef_offset_addr); + __ get_u4(Roffset, Rdef_offset_addr, 0, InterpreterMacroAssembler::Signed); if (ProfileInterpreter) { __ profile_switch_default(Rdef_offset_addr, Rcount/* scratch */); - __ b(Lcontinue_execution); + } + __ b(Lcontinue_execution); + + // Next iteration + __ bind(Lsearch_loop); + __ bdz(Ldefault_case); + __ addi(Rcurrent_pair, Rcurrent_pair, 2 * BytesPerInt); + __ bind(Lloop_entry); + __ get_u4(Rvalue, Rcurrent_pair, 0, InterpreterMacroAssembler::Unsigned); + __ cmpw(CCR0, Rvalue, Rcmp_value); + __ bne(CCR0, Lsearch_loop); + + // Found, load offset. + __ get_u4(Roffset, Rcurrent_pair, BytesPerInt, InterpreterMacroAssembler::Signed); + // Calculate case index and profile + __ mfctr(Rcurrent_pair); + if (ProfileInterpreter) { + __ sub(Rcurrent_pair, Rcount, Rcurrent_pair); + __ profile_switch_case(Rcurrent_pair, Rcount /*scratch*/, Rdef_offset_addr/*scratch*/, Rscratch); } - // Entry found, skip Roffset bytecodes and continue. - __ bind(Lfound); - if (ProfileInterpreter) { - // Calc the num of the pair we hit. Careful, Rcurrent_pair points 2 ints - // beyond the actual current pair due to the auto update load above! - __ sub(Rcurrent_pair, Rcurrent_pair, Rdef_offset_addr); - __ addi(Rcurrent_pair, Rcurrent_pair, - 2 * BytesPerInt); - __ srdi(Rcurrent_pair, Rcurrent_pair, LogBytesPerInt + 1); - __ profile_switch_case(Rcurrent_pair, Rcount /*scratch*/, Rdef_offset_addr/*scratch*/, Rscratch); - __ bind(Lcontinue_execution); - } + __ bind(Lcontinue_execution); __ add(R14_bcp, Roffset, R14_bcp); __ dispatch_next(vtos); } @@ -1990,7 +1991,7 @@ void TemplateTable::fast_binaryswitch() { // initialize i & j __ li(Ri,0); - __ lwz(Rj, -BytesPerInt, Rarray); + __ get_u4(Rj, Rarray, -BytesPerInt, InterpreterMacroAssembler::Unsigned); // and start. Label entry; @@ -2007,7 +2008,11 @@ void TemplateTable::fast_binaryswitch() { // i = h; // } __ sldi(Rscratch, Rh, log_entry_size); +#if defined(VM_LITTLE_ENDIAN) + __ lwbrx(Rscratch, Rscratch, Rarray); +#else __ lwzx(Rscratch, Rscratch, Rarray); +#endif // if (key < current value) // Rh = Rj @@ -2039,20 +2044,20 @@ void TemplateTable::fast_binaryswitch() { // Ri = value offset __ sldi(Ri, Ri, log_entry_size); __ add(Ri, Ri, Rarray); - __ lwz(Rscratch, 0, Ri); + __ get_u4(Rscratch, Ri, 0, InterpreterMacroAssembler::Unsigned); Label not_found; // Ri = offset offset __ cmpw(CCR0, Rkey, Rscratch); __ beq(CCR0, not_found); // entry not found -> j = default offset - __ lwz(Rj, -2 * BytesPerInt, Rarray); + __ get_u4(Rj, Rarray, -2 * BytesPerInt, InterpreterMacroAssembler::Unsigned); __ b(default_case); __ bind(not_found); // entry found -> j = offset __ profile_switch_case(Rh, Rj, Rscratch, Rkey); - __ lwz(Rj, BytesPerInt, Ri); + __ get_u4(Rj, Ri, BytesPerInt, InterpreterMacroAssembler::Unsigned); if (ProfileInterpreter) { __ b(continue_execution); @@ -2147,8 +2152,11 @@ void TemplateTable::resolve_cache_and_index(int byte_no, Register Rcache, Regist assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); // We are resolved if the indices offset contains the current bytecode. - // Big Endian: +#if defined(VM_LITTLE_ENDIAN) + __ lbz(Rscratch, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + byte_no + 1, Rcache); +#else __ lbz(Rscratch, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (byte_no + 1), Rcache); +#endif // Acquire by cmp-br-isync (see below). __ cmpdi(CCR0, Rscratch, (int)bytecode()); __ beq(CCR0, Lresolved); diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 75047c7cb42..0e66115a3f8 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -29,6 +29,7 @@ #include "compiler/disassembler.hpp" #include "memory/resourceArea.hpp" #include "runtime/java.hpp" +#include "runtime/os.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/defaultStream.hpp" #include "vm_version_ppc.hpp" @@ -108,7 +109,7 @@ void VM_Version::initialize() { (has_vand() ? " vand" : "") // Make sure number of %s matches num_features! ); - _features_str = strdup(buf); + _features_str = os::strdup(buf); NOT_PRODUCT(if (Verbose) print_features();); // PPC64 supports 8-byte compare-exchange operations (see diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp index e5325211b5a..4a84b6c3387 100644 --- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -29,6 +29,7 @@ #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" @@ -68,9 +69,7 @@ bool CppInterpreter::contains(address pc) { #define STATE(field_name) Lstate, in_bytes(byte_offset_of(BytecodeInterpreter, field_name)) #define __ _masm-> -Label frame_manager_entry; -Label fast_accessor_slow_entry_path; // fast accessor methods need to be able to jmp to unsynchronized - // c++ interpreter entry point this holds that entry point label. +Label frame_manager_entry; // c++ interpreter entry point this holds that entry point label. static address unctrap_frame_manager_entry = NULL; @@ -452,110 +451,6 @@ address InterpreterGenerator::generate_empty_entry(void) { return NULL; } -// Call an accessor method (assuming it is resolved, otherwise drop into -// vanilla (slow path) entry - -// Generates code to elide accessor methods -// Uses G3_scratch and G1_scratch as scratch -address InterpreterGenerator::generate_accessor_entry(void) { - - // Code: _aload_0, _(i|a)getfield, _(i|a)return or any rewrites thereof; - // parameter size = 1 - // Note: We can only use this code if the getfield has been resolved - // and if we don't have a null-pointer exception => check for - // these conditions first and use slow path if necessary. - address entry = __ pc(); - Label slow_path; - - if ( UseFastAccessorMethods) { - // Check if we need to reach a safepoint and generate full interpreter - // frame if so. - 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, slow_path); - __ delayed()->nop(); - - // Check if local 0 != NULL - __ ld_ptr(Gargs, G0, Otos_i ); // get local 0 - __ tst(Otos_i); // check if local 0 == NULL and go the slow path - __ brx(Assembler::zero, false, Assembler::pn, slow_path); - __ delayed()->nop(); - - - // read first instruction word and extract bytecode @ 1 and index @ 2 - // get first 4 bytes of the bytecodes (big endian!) - __ ld_ptr(Address(G5_method, in_bytes(Method::const_offset())), G1_scratch); - __ ld(Address(G1_scratch, in_bytes(ConstMethod::codes_offset())), G1_scratch); - - // move index @ 2 far left then to the right most two bytes. - __ sll(G1_scratch, 2*BitsPerByte, G1_scratch); - __ srl(G1_scratch, 2*BitsPerByte - exact_log2(in_words( - ConstantPoolCacheEntry::size()) * BytesPerWord), G1_scratch); - - // get constant pool cache - __ ld_ptr(G5_method, in_bytes(Method::const_offset()), G3_scratch); - __ ld_ptr(G3_scratch, in_bytes(ConstMethod::constants_offset()), G3_scratch); - __ ld_ptr(G3_scratch, ConstantPool::cache_offset_in_bytes(), G3_scratch); - - // get specific constant pool cache entry - __ add(G3_scratch, G1_scratch, G3_scratch); - - // Check the constant Pool cache entry to see if it has been resolved. - // If not, need the slow path. - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - __ ld_ptr(G3_scratch, in_bytes(cp_base_offset + ConstantPoolCacheEntry::indices_offset()), G1_scratch); - __ srl(G1_scratch, 2*BitsPerByte, G1_scratch); - __ and3(G1_scratch, 0xFF, G1_scratch); - __ cmp(G1_scratch, Bytecodes::_getfield); - __ br(Assembler::notEqual, false, Assembler::pn, slow_path); - __ delayed()->nop(); - - // Get the type and return field offset from the constant pool cache - __ ld_ptr(G3_scratch, in_bytes(cp_base_offset + ConstantPoolCacheEntry::flags_offset()), G1_scratch); - __ ld_ptr(G3_scratch, in_bytes(cp_base_offset + ConstantPoolCacheEntry::f2_offset()), G3_scratch); - - Label xreturn_path; - // Need to differentiate between igetfield, agetfield, bgetfield etc. - // because they are different sizes. - // Get the type from the constant pool cache - __ srl(G1_scratch, ConstantPoolCacheEntry::tos_state_shift, G1_scratch); - // Make sure we don't need to mask G1_scratch after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - __ cmp(G1_scratch, atos ); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->ld_ptr(Otos_i, G3_scratch, Otos_i); - __ cmp(G1_scratch, itos); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->ld(Otos_i, G3_scratch, Otos_i); - __ cmp(G1_scratch, stos); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->ldsh(Otos_i, G3_scratch, Otos_i); - __ cmp(G1_scratch, ctos); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->lduh(Otos_i, G3_scratch, Otos_i); -#ifdef ASSERT - __ cmp(G1_scratch, btos); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->ldsb(Otos_i, G3_scratch, Otos_i); - __ should_not_reach_here(); -#endif - __ ldsb(Otos_i, G3_scratch, Otos_i); - __ bind(xreturn_path); - - // _ireturn/_areturn - __ retl(); // return from leaf routine - __ delayed()->mov(O5_savedSP, SP); - - // Generate regular method entry - __ bind(slow_path); - __ ba(fast_accessor_slow_entry_path); - __ delayed()->nop(); - return entry; - } - return NULL; -} - address InterpreterGenerator::generate_Reference_get_entry(void) { #if INCLUDE_ALL_GCS if (UseG1GC) { @@ -573,7 +468,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_accessor_entry(); + return generate_jump_to_normal_entry(); } // @@ -1870,23 +1765,6 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { __ ba(call_interpreter_2); __ delayed()->st_ptr(O1, STATE(_stack)); - - // Fast accessor methods share this entry point. - // This works because frame manager is in the same codelet - // This can either be an entry via call_stub/c1/c2 or a recursive interpreter call - // we need to do a little register fixup here once we distinguish the two of them - if (UseFastAccessorMethods && !synchronized) { - // Call stub_return address still in O7 - __ bind(fast_accessor_slow_entry_path); - __ set((intptr_t)return_from_native_method - 8, Gtmp1); - __ cmp(Gtmp1, O7); // returning to interpreter? - __ brx(Assembler::equal, true, Assembler::pt, re_dispatch); // yep - __ delayed()->nop(); - __ ba(re_dispatch); - __ delayed()->mov(G0, prevState); // initial entry - - } - // interpreter returning to native code (call_stub/c1/c2) // convert result and unwind initial activation // L2_scratch - scaled result type index diff --git a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp b/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp index 0558b7b3c3c..de4997bce7a 100644 --- a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, 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 @@ -32,9 +32,11 @@ 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_empty_entry(void); - address generate_accessor_entry(void); + // there are no math intrinsics on sparc + address generate_math_entry(AbstractInterpreter::MethodKind kind) { return NULL; } + address generate_jump_to_normal_entry(void); + address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } + address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } address generate_Reference_get_entry(void); void lock_method(void); void save_native_result(void); @@ -43,4 +45,7 @@ void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); void generate_counter_overflow(Label& Lcontinue); + // Not supported + address generate_CRC32_update_entry() { return NULL; } + address generate_CRC32_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 debdaeae7a4..f8d8f590c99 100644 --- a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp @@ -241,6 +241,15 @@ void InterpreterGenerator::generate_counter_overflow(Label& Lcontinue) { // Various method entries +address InterpreterGenerator::generate_jump_to_normal_entry(void) { + address entry = __ pc(); + assert(Interpreter::entry_for_kind(Interpreter::zerolocals) != NULL, "should already be generated"); + AddressLiteral al(Interpreter::entry_for_kind(Interpreter::zerolocals)); + __ jump_to(al, G3_scratch); + __ delayed()->nop(); + return entry; +} + // Abstract method entry // Attempt to execute abstract method. Throw exception // @@ -255,159 +264,6 @@ address InterpreterGenerator::generate_abstract_entry(void) { } - -//---------------------------------------------------------------------------------------------------- -// Entry points & stack frame layout -// -// Here we generate the various kind of entries into the interpreter. -// The two main entry type are generic bytecode methods and native call method. -// These both come in synchronized and non-synchronized versions but the -// frame layout they create is very similar. The other method entry -// types are really just special purpose entries that are really entry -// and interpretation all in one. These are for trivial methods like -// accessor, empty, or special math methods. -// -// When control flow reaches any of the entry types for the interpreter -// the following holds -> -// -// C2 Calling Conventions: -// -// The entry code below assumes that the following registers are set -// when coming in: -// G5_method: holds the Method* of the method to call -// Lesp: points to the TOS of the callers expression stack -// after having pushed all the parameters -// -// The entry code does the following to setup an interpreter frame -// pop parameters from the callers stack by adjusting Lesp -// set O0 to Lesp -// compute X = (max_locals - num_parameters) -// bump SP up by X to accomadate the extra locals -// compute X = max_expression_stack -// + vm_local_words -// + 16 words of register save area -// save frame doing a save sp, -X, sp growing towards lower addresses -// set Lbcp, Lmethod, LcpoolCache -// set Llocals to i0 -// set Lmonitors to FP - rounded_vm_local_words -// set Lesp to Lmonitors - 4 -// -// The frame has now been setup to do the rest of the entry code - -// Try this optimization: Most method entries could live in a -// "one size fits all" stack frame without all the dynamic size -// calculations. It might be profitable to do all this calculation -// statically and approximately for "small enough" methods. - -//----------------------------------------------------------------------------------------------- - -// C1 Calling conventions -// -// Upon method entry, the following registers are setup: -// -// g2 G2_thread: current thread -// g5 G5_method: method to activate -// g4 Gargs : pointer to last argument -// -// -// Stack: -// -// +---------------+ <--- sp -// | | -// : reg save area : -// | | -// +---------------+ <--- sp + 0x40 -// | | -// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) -// | | -// +---------------+ <--- sp + 0x5c -// | | -// : free : -// | | -// +---------------+ <--- Gargs -// | | -// : arguments : -// | | -// +---------------+ -// | | -// -// -// -// AFTER FRAME HAS BEEN SETUP for method interpretation the stack looks like: -// -// +---------------+ <--- sp -// | | -// : reg save area : -// | | -// +---------------+ <--- sp + 0x40 -// | | -// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) -// | | -// +---------------+ <--- sp + 0x5c -// | | -// : : -// | | <--- Lesp -// +---------------+ <--- Lmonitors (fp - 0x18) -// | VM locals | -// +---------------+ <--- fp -// | | -// : reg save area : -// | | -// +---------------+ <--- fp + 0x40 -// | | -// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) -// | | -// +---------------+ <--- fp + 0x5c -// | | -// : free : -// | | -// +---------------+ -// | | -// : nonarg locals : -// | | -// +---------------+ -// | | -// : arguments : -// | | <--- Llocals -// +---------------+ <--- Gargs -// | | - -address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter::MethodKind kind) { - // determine code generation flags - bool synchronized = false; - address entry_point = NULL; - - switch (kind) { - case Interpreter::zerolocals : break; - case Interpreter::zerolocals_synchronized: synchronized = true; break; - case Interpreter::native : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(false); break; - case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(true); break; - case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break; - case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break; - case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break; - - case Interpreter::java_lang_math_sin : break; - case Interpreter::java_lang_math_cos : break; - case Interpreter::java_lang_math_tan : break; - case Interpreter::java_lang_math_sqrt : break; - case Interpreter::java_lang_math_abs : break; - case Interpreter::java_lang_math_log : break; - case Interpreter::java_lang_math_log10 : break; - case Interpreter::java_lang_math_pow : break; - case Interpreter::java_lang_math_exp : break; - case Interpreter::java_lang_ref_reference_get - : entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break; - default: - fatal(err_msg("unexpected method kind: %d", kind)); - break; - } - - if (entry_point) return entry_point; - - return ((InterpreterGenerator*)this)->generate_normal_entry(synchronized); -} - - bool AbstractInterpreter::can_be_compiled(methodHandle m) { // No special entry points that preclude compilation return true; diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index c261900003b..99ec87803d5 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -6184,7 +6184,11 @@ instruct loadConP_no_oop_cheap(iRegP dst, immP_no_oop_cheap con) %{ ins_cost(DEFAULT_COST * 3/2); format %{ "SET $con,$dst\t! non-oop ptr" %} ins_encode %{ - __ set($con$$constant, $dst$$Register); + if (_opnds[1]->constant_reloc() == relocInfo::metadata_type) { + __ set_metadata_constant((Metadata*)$con$$constant, $dst$$Register); + } else { + __ set($con$$constant, $dst$$Register); + } %} ins_pipe(loadConP); %} diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index 1f8503161cc..93f87807482 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -456,6 +456,115 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rframe // Generate a fixed interpreter frame. This is identical setup for interpreted // methods and for native methods hence the shared code. + +//---------------------------------------------------------------------------------------------------- +// Stack frame layout +// +// When control flow reaches any of the entry types for the interpreter +// the following holds -> +// +// C2 Calling Conventions: +// +// The entry code below assumes that the following registers are set +// when coming in: +// G5_method: holds the Method* of the method to call +// Lesp: points to the TOS of the callers expression stack +// after having pushed all the parameters +// +// The entry code does the following to setup an interpreter frame +// pop parameters from the callers stack by adjusting Lesp +// set O0 to Lesp +// compute X = (max_locals - num_parameters) +// bump SP up by X to accomadate the extra locals +// compute X = max_expression_stack +// + vm_local_words +// + 16 words of register save area +// save frame doing a save sp, -X, sp growing towards lower addresses +// set Lbcp, Lmethod, LcpoolCache +// set Llocals to i0 +// set Lmonitors to FP - rounded_vm_local_words +// set Lesp to Lmonitors - 4 +// +// The frame has now been setup to do the rest of the entry code + +// Try this optimization: Most method entries could live in a +// "one size fits all" stack frame without all the dynamic size +// calculations. It might be profitable to do all this calculation +// statically and approximately for "small enough" methods. + +//----------------------------------------------------------------------------------------------- + +// C1 Calling conventions +// +// Upon method entry, the following registers are setup: +// +// g2 G2_thread: current thread +// g5 G5_method: method to activate +// g4 Gargs : pointer to last argument +// +// +// Stack: +// +// +---------------+ <--- sp +// | | +// : reg save area : +// | | +// +---------------+ <--- sp + 0x40 +// | | +// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) +// | | +// +---------------+ <--- sp + 0x5c +// | | +// : free : +// | | +// +---------------+ <--- Gargs +// | | +// : arguments : +// | | +// +---------------+ +// | | +// +// +// +// AFTER FRAME HAS BEEN SETUP for method interpretation the stack looks like: +// +// +---------------+ <--- sp +// | | +// : reg save area : +// | | +// +---------------+ <--- sp + 0x40 +// | | +// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) +// | | +// +---------------+ <--- sp + 0x5c +// | | +// : : +// | | <--- Lesp +// +---------------+ <--- Lmonitors (fp - 0x18) +// | VM locals | +// +---------------+ <--- fp +// | | +// : reg save area : +// | | +// +---------------+ <--- fp + 0x40 +// | | +// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) +// | | +// +---------------+ <--- fp + 0x5c +// | | +// : free : +// | | +// +---------------+ +// | | +// : nonarg locals : +// | | +// +---------------+ +// | | +// : arguments : +// | | <--- Llocals +// +---------------+ <--- Gargs +// | | + void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // // @@ -599,136 +708,6 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { } -// Empty method, generate a very fast return. - -address InterpreterGenerator::generate_empty_entry(void) { - - // A method that does nother 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()); - __ set(sync_state, G3_scratch); - __ cmp_and_br_short(G3_scratch, SafepointSynchronize::_not_synchronized, Assembler::notEqual, Assembler::pn, slow_path); - - // Code: _return - __ retl(); - __ delayed()->mov(O5_savedSP, SP); - - __ bind(slow_path); - (void) generate_normal_entry(false); - - return entry; - } - return NULL; -} - -// Call an accessor method (assuming it is resolved, otherwise drop into -// vanilla (slow path) entry - -// Generates code to elide accessor methods -// Uses G3_scratch and G1_scratch as scratch -address InterpreterGenerator::generate_accessor_entry(void) { - - // Code: _aload_0, _(i|a)getfield, _(i|a)return or any rewrites thereof; - // parameter size = 1 - // Note: We can only use this code if the getfield has been resolved - // and if we don't have a null-pointer exception => check for - // these conditions first and use slow path if necessary. - address entry = __ pc(); - Label slow_path; - - - // XXX: for compressed oops pointer loading and decoding doesn't fit in - // delay slot and damages G1 - if ( UseFastAccessorMethods && !UseCompressedOops ) { - // Check if we need to reach a safepoint and generate full interpreter - // frame if so. - AddressLiteral sync_state(SafepointSynchronize::address_of_state()); - __ load_contents(sync_state, G3_scratch); - __ cmp(G3_scratch, SafepointSynchronize::_not_synchronized); - __ cmp_and_br_short(G3_scratch, SafepointSynchronize::_not_synchronized, Assembler::notEqual, Assembler::pn, slow_path); - - // Check if local 0 != NULL - __ ld_ptr(Gargs, G0, Otos_i ); // get local 0 - // check if local 0 == NULL and go the slow path - __ br_null_short(Otos_i, Assembler::pn, slow_path); - - - // read first instruction word and extract bytecode @ 1 and index @ 2 - // get first 4 bytes of the bytecodes (big endian!) - __ ld_ptr(G5_method, Method::const_offset(), G1_scratch); - __ ld(G1_scratch, ConstMethod::codes_offset(), G1_scratch); - - // move index @ 2 far left then to the right most two bytes. - __ sll(G1_scratch, 2*BitsPerByte, G1_scratch); - __ srl(G1_scratch, 2*BitsPerByte - exact_log2(in_words( - ConstantPoolCacheEntry::size()) * BytesPerWord), G1_scratch); - - // get constant pool cache - __ ld_ptr(G5_method, Method::const_offset(), G3_scratch); - __ ld_ptr(G3_scratch, ConstMethod::constants_offset(), G3_scratch); - __ ld_ptr(G3_scratch, ConstantPool::cache_offset_in_bytes(), G3_scratch); - - // get specific constant pool cache entry - __ add(G3_scratch, G1_scratch, G3_scratch); - - // Check the constant Pool cache entry to see if it has been resolved. - // If not, need the slow path. - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - __ ld_ptr(G3_scratch, cp_base_offset + ConstantPoolCacheEntry::indices_offset(), G1_scratch); - __ srl(G1_scratch, 2*BitsPerByte, G1_scratch); - __ and3(G1_scratch, 0xFF, G1_scratch); - __ cmp_and_br_short(G1_scratch, Bytecodes::_getfield, Assembler::notEqual, Assembler::pn, slow_path); - - // Get the type and return field offset from the constant pool cache - __ ld_ptr(G3_scratch, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), G1_scratch); - __ ld_ptr(G3_scratch, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), G3_scratch); - - Label xreturn_path; - // Need to differentiate between igetfield, agetfield, bgetfield etc. - // because they are different sizes. - // Get the type from the constant pool cache - __ srl(G1_scratch, ConstantPoolCacheEntry::tos_state_shift, G1_scratch); - // Make sure we don't need to mask G1_scratch after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - __ cmp(G1_scratch, atos ); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->ld_ptr(Otos_i, G3_scratch, Otos_i); - __ cmp(G1_scratch, itos); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->ld(Otos_i, G3_scratch, Otos_i); - __ cmp(G1_scratch, stos); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->ldsh(Otos_i, G3_scratch, Otos_i); - __ cmp(G1_scratch, ctos); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->lduh(Otos_i, G3_scratch, Otos_i); -#ifdef ASSERT - __ cmp(G1_scratch, btos); - __ br(Assembler::equal, true, Assembler::pt, xreturn_path); - __ delayed()->ldsb(Otos_i, G3_scratch, Otos_i); - __ should_not_reach_here(); -#endif - __ ldsb(Otos_i, G3_scratch, Otos_i); - __ bind(xreturn_path); - - // _ireturn/_areturn - __ retl(); // return from leaf routine - __ delayed()->mov(O5_savedSP, SP); - - // Generate regular method entry - __ bind(slow_path); - (void) generate_normal_entry(false); - return entry; - } - return NULL; -} - // Method entry for java.lang.ref.Reference.get. address InterpreterGenerator::generate_Reference_get_entry(void) { #if INCLUDE_ALL_GCS @@ -806,7 +785,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_accessor_entry(); + return generate_jump_to_normal_entry(); } // @@ -1242,8 +1221,6 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // Generic method entry to (asm) interpreter -//------------------------------------------------------------------------------------------------------------------------ -// address InterpreterGenerator::generate_normal_entry(bool synchronized) { address entry = __ pc(); @@ -1410,123 +1387,6 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { return entry; } - -//---------------------------------------------------------------------------------------------------- -// Entry points & stack frame layout -// -// Here we generate the various kind of entries into the interpreter. -// The two main entry type are generic bytecode methods and native call method. -// These both come in synchronized and non-synchronized versions but the -// frame layout they create is very similar. The other method entry -// types are really just special purpose entries that are really entry -// and interpretation all in one. These are for trivial methods like -// accessor, empty, or special math methods. -// -// When control flow reaches any of the entry types for the interpreter -// the following holds -> -// -// C2 Calling Conventions: -// -// The entry code below assumes that the following registers are set -// when coming in: -// G5_method: holds the Method* of the method to call -// Lesp: points to the TOS of the callers expression stack -// after having pushed all the parameters -// -// The entry code does the following to setup an interpreter frame -// pop parameters from the callers stack by adjusting Lesp -// set O0 to Lesp -// compute X = (max_locals - num_parameters) -// bump SP up by X to accomadate the extra locals -// compute X = max_expression_stack -// + vm_local_words -// + 16 words of register save area -// save frame doing a save sp, -X, sp growing towards lower addresses -// set Lbcp, Lmethod, LcpoolCache -// set Llocals to i0 -// set Lmonitors to FP - rounded_vm_local_words -// set Lesp to Lmonitors - 4 -// -// The frame has now been setup to do the rest of the entry code - -// Try this optimization: Most method entries could live in a -// "one size fits all" stack frame without all the dynamic size -// calculations. It might be profitable to do all this calculation -// statically and approximately for "small enough" methods. - -//----------------------------------------------------------------------------------------------- - -// C1 Calling conventions -// -// Upon method entry, the following registers are setup: -// -// g2 G2_thread: current thread -// g5 G5_method: method to activate -// g4 Gargs : pointer to last argument -// -// -// Stack: -// -// +---------------+ <--- sp -// | | -// : reg save area : -// | | -// +---------------+ <--- sp + 0x40 -// | | -// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) -// | | -// +---------------+ <--- sp + 0x5c -// | | -// : free : -// | | -// +---------------+ <--- Gargs -// | | -// : arguments : -// | | -// +---------------+ -// | | -// -// -// -// AFTER FRAME HAS BEEN SETUP for method interpretation the stack looks like: -// -// +---------------+ <--- sp -// | | -// : reg save area : -// | | -// +---------------+ <--- sp + 0x40 -// | | -// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) -// | | -// +---------------+ <--- sp + 0x5c -// | | -// : : -// | | <--- Lesp -// +---------------+ <--- Lmonitors (fp - 0x18) -// | VM locals | -// +---------------+ <--- fp -// | | -// : reg save area : -// | | -// +---------------+ <--- fp + 0x40 -// | | -// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) -// | | -// +---------------+ <--- fp + 0x5c -// | | -// : free : -// | | -// +---------------+ -// | | -// : nonarg locals : -// | | -// +---------------+ -// | | -// : arguments : -// | | <--- Llocals -// +---------------+ <--- Gargs -// | | - 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 diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index 79bf7139a12..91a9f76af4c 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -26,6 +26,7 @@ #include "asm/macroAssembler.inline.hpp" #include "memory/resourceArea.hpp" #include "runtime/java.hpp" +#include "runtime/os.hpp" #include "runtime/stubCodeGenerator.hpp" #include "vm_version_sparc.hpp" @@ -249,7 +250,7 @@ void VM_Version::initialize() { (!has_hardware_fsmuld() ? ", no-fsmuld" : "")); // buf is started with ", " or is empty - _features_str = strdup(strlen(buf) > 2 ? buf + 2 : buf); + _features_str = os::strdup(strlen(buf) > 2 ? buf + 2 : buf); // There are three 64-bit SPARC families that do not overlap, e.g., // both is_ultra3() and is_sparc64() cannot be true at the same time. diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 64b8ce731a5..34219277523 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -3853,6 +3853,15 @@ void Assembler::vpbroadcastd(XMMRegister dst, XMMRegister src) { emit_int8((unsigned char)(0xC0 | encode)); } +// Carry-Less Multiplication Quadword +void Assembler::pclmulqdq(XMMRegister dst, XMMRegister src, int mask) { + assert(VM_Version::supports_clmul(), ""); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A); + emit_int8(0x44); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8((unsigned char)mask); +} + // Carry-Less Multiplication Quadword void Assembler::vpclmulqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int mask) { assert(VM_Version::supports_avx() && VM_Version::supports_clmul(), ""); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 12bc14e7195..8edf31cada8 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1837,6 +1837,7 @@ private: void vpbroadcastd(XMMRegister dst, XMMRegister src); // Carry-Less Multiplication Quadword + void pclmulqdq(XMMRegister dst, XMMRegister src, int mask); void vpclmulqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int mask); // AVX instruction which is used to clear upper 128 bits of YMM registers and diff --git a/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp b/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp index 2f9f1d47deb..9f81215b396 100644 --- a/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp +++ b/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, 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 @@ -27,21 +27,6 @@ protected: -#if 0 - address generate_asm_interpreter_entry(bool synchronized); - address generate_native_entry(bool synchronized); - address generate_abstract_entry(void); - address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_empty_entry(void); - address generate_accessor_entry(void); - address generate_Reference_get_entry(void); - void lock_method(void); - 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 - void generate_more_monitors(); void generate_deopt_handling(); address generate_interpreter_frame_manager(bool synchronized); // C++ interpreter only diff --git a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp index 9eb1a6ebf77..27f1b309727 100644 --- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp +++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -66,9 +66,6 @@ extern "C" void RecursiveInterpreterActivation(interpreterState istate ) #define __ _masm-> #define STATE(field_name) (Address(state, byte_offset_of(BytecodeInterpreter, field_name))) -Label fast_accessor_slow_entry_path; // fast accessor methods need to be able to jmp to unsynchronized - // c++ interpreter entry point this holds that entry point label. - // 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 @@ -660,7 +657,6 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { // generate_method_entry) so the guard should work for them too. // - // monitor entry size: see picture of stack set (generate_method_entry) and frame_i486.hpp const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; // total overhead size: entry_size + (saved rbp, thru expr stack bottom). @@ -794,156 +790,6 @@ void InterpreterGenerator::lock_method(void) { __ lock_object(monitor); } -// Call an accessor method (assuming it is resolved, otherwise drop into vanilla (slow path) entry - -address InterpreterGenerator::generate_accessor_entry(void) { - - // rbx: Method* - - // rsi/r13: senderSP must preserved for slow path, set SP to it on fast path - - Label xreturn_path; - - // do fastpath for resolved accessor methods - if (UseFastAccessorMethods) { - - address entry_point = __ pc(); - - Label slow_path; - // If we need a safepoint check, generate full interpreter entry. - ExternalAddress state(SafepointSynchronize::address_of_state()); - __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()), - SafepointSynchronize::_not_synchronized); - - __ jcc(Assembler::notEqual, slow_path); - // ASM/C++ Interpreter - // Code: _aload_0, _(i|a)getfield, _(i|a)return or any rewrites thereof; parameter size = 1 - // Note: We can only use this code if the getfield has been resolved - // and if we don't have a null-pointer exception => check for - // these conditions first and use slow path if necessary. - // rbx,: method - // rcx: receiver - __ movptr(rax, Address(rsp, wordSize)); - - // check if local 0 != NULL and read field - __ testptr(rax, rax); - __ jcc(Assembler::zero, slow_path); - - // read first instruction word and extract bytecode @ 1 and index @ 2 - __ movptr(rdx, Address(rbx, Method::const_offset())); - __ movptr(rdi, Address(rdx, ConstMethod::constants_offset())); - __ movl(rdx, Address(rdx, ConstMethod::codes_offset())); - // Shift codes right to get the index on the right. - // The bytecode fetched looks like <0xb4><0x2a> - __ shrl(rdx, 2*BitsPerByte); - __ shll(rdx, exact_log2(in_words(ConstantPoolCacheEntry::size()))); - __ movptr(rdi, Address(rdi, ConstantPool::cache_offset_in_bytes())); - - // rax,: local 0 - // rbx,: method - // rcx: receiver - do not destroy since it is needed for slow path! - // rcx: scratch - // rdx: constant pool cache index - // rdi: constant pool cache - // rsi/r13: sender sp - - // check if getfield has been resolved and read constant pool cache entry - // check the validity of the cache entry by testing whether _indices field - // contains Bytecode::_getfield in b1 byte. - assert(in_words(ConstantPoolCacheEntry::size()) == 4, "adjust shift below"); - __ movl(rcx, - Address(rdi, - rdx, - Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())); - __ shrl(rcx, 2*BitsPerByte); - __ andl(rcx, 0xFF); - __ cmpl(rcx, Bytecodes::_getfield); - __ jcc(Assembler::notEqual, slow_path); - - // Note: constant pool entry is not valid before bytecode is resolved - __ movptr(rcx, - Address(rdi, - rdx, - Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset())); - __ movl(rdx, - Address(rdi, - rdx, - Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())); - - Label notByte, notShort, notChar; - const Address field_address (rax, rcx, Address::times_1); - - // Need to differentiate between igetfield, agetfield, bgetfield etc. - // because they are different sizes. - // Use the type from the constant pool cache - __ shrl(rdx, ConstantPoolCacheEntry::tos_state_shift); - // Make sure we don't need to mask rdx after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); -#ifdef _LP64 - Label notObj; - __ cmpl(rdx, atos); - __ jcc(Assembler::notEqual, notObj); - // atos - __ movptr(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notObj); -#endif // _LP64 - __ cmpl(rdx, btos); - __ jcc(Assembler::notEqual, notByte); - __ load_signed_byte(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notByte); - __ cmpl(rdx, stos); - __ jcc(Assembler::notEqual, notShort); - __ load_signed_short(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notShort); - __ cmpl(rdx, ctos); - __ jcc(Assembler::notEqual, notChar); - __ load_unsigned_short(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notChar); -#ifdef ASSERT - Label okay; -#ifndef _LP64 - __ cmpl(rdx, atos); - __ jcc(Assembler::equal, okay); -#endif // _LP64 - __ cmpl(rdx, itos); - __ jcc(Assembler::equal, okay); - __ stop("what type is this?"); - __ bind(okay); -#endif // ASSERT - // All the rest are a 32 bit wordsize - __ movl(rax, field_address); - - __ bind(xreturn_path); - - // _ireturn/_areturn - __ pop(rdi); // get return address - __ mov(rsp, sender_sp_on_entry); // set sp to sender sp - __ jmp(rdi); - - // generate a vanilla interpreter entry as the slow path - __ bind(slow_path); - // We will enter c++ interpreter looking like it was - // called by the call_stub this will cause it to return - // a tosca result to the invoker which might have been - // the c++ interpreter itself. - - __ jmp(fast_accessor_slow_entry_path); - return entry_point; - - } else { - return NULL; - } - -} - address InterpreterGenerator::generate_Reference_get_entry(void) { #if INCLUDE_ALL_GCS if (UseG1GC) { @@ -961,7 +807,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_accessor_entry(); + return generate_jump_to_normal_entry(); } // @@ -1670,10 +1516,6 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { address entry_point = __ pc(); - // Fast accessor methods share this entry point. - // This works because frame manager is in the same codelet - if (UseFastAccessorMethods && !synchronized) __ bind(fast_accessor_slow_entry_path); - Label dispatch_entry_2; __ movptr(rcx, sender_sp_on_entry); __ movptr(state, (int32_t)NULL_WORD); // no current activation @@ -2212,40 +2054,6 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { return entry_point; } -address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter::MethodKind kind) { - // determine code generation flags - bool synchronized = false; - address entry_point = NULL; - - switch (kind) { - case Interpreter::zerolocals : break; - case Interpreter::zerolocals_synchronized: synchronized = true; break; - case Interpreter::native : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(false); break; - case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(true); break; - case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break; - case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break; - case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->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 : // fall thru - entry_point = ((InterpreterGenerator*)this)->generate_math_entry(kind); break; - case Interpreter::java_lang_ref_reference_get - : entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break; - default : ShouldNotReachHere(); break; - } - - if (entry_point) return entry_point; - - return ((InterpreterGenerator*)this)->generate_normal_entry(synchronized); - -} InterpreterGenerator::InterpreterGenerator(StubQueue* code) : CppInterpreterGenerator(code) { diff --git a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp new file mode 100644 index 00000000000..229803a80ff --- /dev/null +++ b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp @@ -0,0 +1,66 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterGenerator.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "interpreter/interp_masm.hpp" + +#define __ _masm-> + +// Jump into normal path for accessor and empty entry to jump to normal entry +// The "fast" optimization don't update compilation count therefore can disable inlining +// for these functions that should be inlined. +address InterpreterGenerator::generate_jump_to_normal_entry(void) { + address entry_point = __ pc(); + + assert(Interpreter::entry_for_kind(Interpreter::zerolocals) != NULL, "should already be generated"); + __ jump(RuntimeAddress(Interpreter::entry_for_kind(Interpreter::zerolocals))); + return entry_point; +} + +// Abstract method entry +// Attempt to execute abstract method. Throw exception +address InterpreterGenerator::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)); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + + return entry_point; +} diff --git a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp index 08f47708cdc..b802e9c405b 100644 --- a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp +++ b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -36,8 +36,9 @@ address generate_native_entry(bool synchronized); address generate_abstract_entry(void); address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_empty_entry(void); - address generate_accessor_entry(void); + address generate_jump_to_normal_entry(void); + address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } + address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } address generate_Reference_get_entry(); address generate_CRC32_update_entry(); address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp index abe354360ff..4a2903b3736 100644 --- a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp @@ -67,45 +67,6 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { } -// -// Various method entries (that c++ and asm interpreter agree upon) -//------------------------------------------------------------------------------------------------------------------------ -// -// - -// Empty method, generate a very fast return. - -address InterpreterGenerator::generate_empty_entry(void) { - - // rbx,: Method* - // rcx: receiver (unused) - // rsi: previous interpreter state (C++ interpreter) must preserve - // rsi: sender sp must set sp to this value on return - - if (!UseFastEmptyMethods) return NULL; - - address entry_point = __ pc(); - - // If we need a safepoint check, generate full interpreter entry. - Label slow_path; - ExternalAddress state(SafepointSynchronize::address_of_state()); - __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()), - SafepointSynchronize::_not_synchronized); - __ jcc(Assembler::notEqual, slow_path); - - // do nothing for empty methods (do not even increment invocation counter) - // Code: _return - // _return - // return w/o popping parameters - __ pop(rax); - __ mov(rsp, rsi); - __ jmp(rax); - - __ bind(slow_path); - (void) generate_normal_entry(false); - return entry_point; -} - address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { // rbx,: Method* @@ -216,36 +177,6 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin } -// Abstract method entry -// Attempt to execute abstract method. Throw exception -address InterpreterGenerator::generate_abstract_entry(void) { - - // rbx,: Method* - // rcx: receiver (unused) - // rsi: previous interpreter state (C++ interpreter) must preserve - - // rsi: sender SP - - 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)); - // the call_VM checks for exception, so we should never return here. - __ should_not_reach_here(); - - return entry_point; -} - - void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) { // This code is sort of the equivalent of C2IAdapter::setup_stack_frame back in diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp index 65ffc6d2e97..af4f7fac388 100644 --- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp @@ -301,66 +301,6 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin return entry_point; } - -// Abstract method entry -// Attempt to execute abstract method. Throw exception -address InterpreterGenerator::generate_abstract_entry(void) { - // rbx: Method* - // r13: sender SP - - 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)); - // the call_VM checks for exception, so we should never return here. - __ should_not_reach_here(); - - return entry_point; -} - - -// Empty method, generate a very fast return. - -address InterpreterGenerator::generate_empty_entry(void) { - // rbx: Method* - // r13: sender sp must set sp to this value on return - - if (!UseFastEmptyMethods) { - return NULL; - } - - address entry_point = __ pc(); - - // If we need a safepoint check, generate full interpreter entry. - Label slow_path; - __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()), - SafepointSynchronize::_not_synchronized); - __ jcc(Assembler::notEqual, slow_path); - - // do nothing for empty methods (do not even increment invocation counter) - // Code: _return - // _return - // return w/o popping parameters - __ pop(rax); - __ mov(rsp, r13); - __ jmp(rax); - - __ bind(slow_path); - (void) generate_normal_entry(false); - return entry_point; - -} - void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) { // This code is sort of the equivalent of C2IAdapter::setup_stack_frame back in diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 5b324124138..7216c198027 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -7316,17 +7316,34 @@ void MacroAssembler::update_byte_crc32(Register crc, Register val, Register tabl * Fold 128-bit data chunk */ void MacroAssembler::fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, int offset) { - vpclmulhdq(xtmp, xK, xcrc); // [123:64] - vpclmulldq(xcrc, xK, xcrc); // [63:0] - vpxor(xcrc, xcrc, Address(buf, offset), false /* vector256 */); - pxor(xcrc, xtmp); + if (UseAVX > 0) { + vpclmulhdq(xtmp, xK, xcrc); // [123:64] + vpclmulldq(xcrc, xK, xcrc); // [63:0] + vpxor(xcrc, xcrc, Address(buf, offset), false /* vector256 */); + pxor(xcrc, xtmp); + } else { + movdqa(xtmp, xcrc); + pclmulhdq(xtmp, xK); // [123:64] + pclmulldq(xcrc, xK); // [63:0] + pxor(xcrc, xtmp); + movdqu(xtmp, Address(buf, offset)); + pxor(xcrc, xtmp); + } } void MacroAssembler::fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, XMMRegister xbuf) { - vpclmulhdq(xtmp, xK, xcrc); - vpclmulldq(xcrc, xK, xcrc); - pxor(xcrc, xbuf); - pxor(xcrc, xtmp); + if (UseAVX > 0) { + vpclmulhdq(xtmp, xK, xcrc); + vpclmulldq(xcrc, xK, xcrc); + pxor(xcrc, xbuf); + pxor(xcrc, xtmp); + } else { + movdqa(xtmp, xcrc); + pclmulhdq(xtmp, xK); + pclmulldq(xcrc, xK); + pxor(xcrc, xbuf); + pxor(xcrc, xtmp); + } } /** @@ -7444,9 +7461,17 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Regi // Fold 128 bits in xmm1 down into 32 bits in crc register. BIND(L_fold_128b); movdqu(xmm0, ExternalAddress(StubRoutines::x86::crc_by128_masks_addr())); - vpclmulqdq(xmm2, xmm0, xmm1, 0x1); - vpand(xmm3, xmm0, xmm2, false /* vector256 */); - vpclmulqdq(xmm0, xmm0, xmm3, 0x1); + if (UseAVX > 0) { + vpclmulqdq(xmm2, xmm0, xmm1, 0x1); + vpand(xmm3, xmm0, xmm2, false /* vector256 */); + vpclmulqdq(xmm0, xmm0, xmm3, 0x1); + } else { + movdqa(xmm2, xmm0); + pclmulqdq(xmm2, xmm1, 0x1); + movdqa(xmm3, xmm0); + pand(xmm3, xmm2); + pclmulqdq(xmm0, xmm3, 0x1); + } psrldq(xmm1, 8); psrldq(xmm2, 4); pxor(xmm0, xmm1); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 3d8802632a4..3b3073e633a 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -966,6 +966,16 @@ public: void mulss(XMMRegister dst, Address src) { Assembler::mulss(dst, src); } void mulss(XMMRegister dst, AddressLiteral src); + // Carry-Less Multiplication Quadword + void pclmulldq(XMMRegister dst, XMMRegister src) { + // 0x00 - multiply lower 64 bits [0:63] + Assembler::pclmulqdq(dst, src, 0x00); + } + void pclmulhdq(XMMRegister dst, XMMRegister src) { + // 0x11 - multiply upper 64 bits [64:127] + Assembler::pclmulqdq(dst, src, 0x11); + } + void sqrtsd(XMMRegister dst, XMMRegister src) { Assembler::sqrtsd(dst, src); } void sqrtsd(XMMRegister dst, Address src) { Assembler::sqrtsd(dst, src); } void sqrtsd(XMMRegister dst, AddressLiteral src); diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp index 23dcbee036e..7a12d82e9af 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp @@ -38,7 +38,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 AbstractInterpreterGenerator::generate_method_entry. + // in InterpreterGenerator::generate_fixed_frame. // fixed size of an interpreter frame: int overhead = frame::sender_sp_offset - diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index e705dfbe0ce..93772f3df4c 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -468,10 +468,10 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { // 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. + // generate_fixed_frame) so the guard should work for them too. // - // monitor entry size: see picture of stack set (generate_method_entry) and frame_x86.hpp + // monitor entry size: see picture of stack in frame_x86.hpp const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; // total overhead size: entry_size + (saved rbp, thru expr stack bottom). @@ -633,145 +633,6 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ movptr(Address(rsp, 0), rsp); // set expression stack bottom } -// End of helpers - -// -// Various method entries -//------------------------------------------------------------------------------------------------------------------------ -// -// - -// Call an accessor method (assuming it is resolved, otherwise drop into vanilla (slow path) entry - -address InterpreterGenerator::generate_accessor_entry(void) { - - // rbx,: Method* - // rcx: receiver (preserve for slow entry into asm interpreter) - - // rsi: senderSP must preserved for slow path, set SP to it on fast path - - address entry_point = __ pc(); - Label xreturn_path; - - // do fastpath for resolved accessor methods - if (UseFastAccessorMethods) { - Label slow_path; - // If we need a safepoint check, generate full interpreter entry. - ExternalAddress state(SafepointSynchronize::address_of_state()); - __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()), - SafepointSynchronize::_not_synchronized); - - __ jcc(Assembler::notEqual, slow_path); - // ASM/C++ Interpreter - // Code: _aload_0, _(i|a)getfield, _(i|a)return or any rewrites thereof; parameter size = 1 - // Note: We can only use this code if the getfield has been resolved - // and if we don't have a null-pointer exception => check for - // these conditions first and use slow path if necessary. - // rbx,: method - // rcx: receiver - __ movptr(rax, Address(rsp, wordSize)); - - // check if local 0 != NULL and read field - __ testptr(rax, rax); - __ jcc(Assembler::zero, slow_path); - - // read first instruction word and extract bytecode @ 1 and index @ 2 - __ movptr(rdx, Address(rbx, Method::const_offset())); - __ movptr(rdi, Address(rdx, ConstMethod::constants_offset())); - __ movl(rdx, Address(rdx, ConstMethod::codes_offset())); - // Shift codes right to get the index on the right. - // The bytecode fetched looks like <0xb4><0x2a> - __ shrl(rdx, 2*BitsPerByte); - __ shll(rdx, exact_log2(in_words(ConstantPoolCacheEntry::size()))); - __ movptr(rdi, Address(rdi, ConstantPool::cache_offset_in_bytes())); - - // rax,: local 0 - // rbx,: method - // rcx: receiver - do not destroy since it is needed for slow path! - // rcx: scratch - // rdx: constant pool cache index - // rdi: constant pool cache - // rsi: sender sp - - // check if getfield has been resolved and read constant pool cache entry - // check the validity of the cache entry by testing whether _indices field - // contains Bytecode::_getfield in b1 byte. - assert(in_words(ConstantPoolCacheEntry::size()) == 4, "adjust shift below"); - __ movl(rcx, - Address(rdi, - rdx, - Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())); - __ shrl(rcx, 2*BitsPerByte); - __ andl(rcx, 0xFF); - __ cmpl(rcx, Bytecodes::_getfield); - __ jcc(Assembler::notEqual, slow_path); - - // Note: constant pool entry is not valid before bytecode is resolved - __ movptr(rcx, - Address(rdi, - rdx, - Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset())); - __ movl(rdx, - Address(rdi, - rdx, - Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())); - - Label notByte, notShort, notChar; - const Address field_address (rax, rcx, Address::times_1); - - // Need to differentiate between igetfield, agetfield, bgetfield etc. - // because they are different sizes. - // Use the type from the constant pool cache - __ shrl(rdx, ConstantPoolCacheEntry::tos_state_shift); - // Make sure we don't need to mask rdx after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - __ cmpl(rdx, btos); - __ jcc(Assembler::notEqual, notByte); - __ load_signed_byte(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notByte); - __ cmpl(rdx, stos); - __ jcc(Assembler::notEqual, notShort); - __ load_signed_short(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notShort); - __ cmpl(rdx, ctos); - __ jcc(Assembler::notEqual, notChar); - __ load_unsigned_short(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notChar); -#ifdef ASSERT - Label okay; - __ cmpl(rdx, atos); - __ jcc(Assembler::equal, okay); - __ cmpl(rdx, itos); - __ jcc(Assembler::equal, okay); - __ stop("what type is this?"); - __ bind(okay); -#endif // ASSERT - // All the rest are a 32 bit wordsize - // This is ok for now. Since fast accessors should be going away - __ movptr(rax, field_address); - - __ bind(xreturn_path); - - // _ireturn/_areturn - __ pop(rdi); // get return address - __ mov(rsp, rsi); // set sp to sender sp - __ jmp(rdi); - - // generate a vanilla interpreter entry as the slow path - __ bind(slow_path); - - (void) generate_normal_entry(false); - return entry_point; - } - return NULL; - -} // Method entry for java.lang.ref.Reference.get. address InterpreterGenerator::generate_Reference_get_entry(void) { @@ -862,7 +723,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_accessor_entry(); + return generate_jump_to_normal_entry(); } /** @@ -1557,100 +1418,6 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { return entry_point; } -//------------------------------------------------------------------------------------------------------------------------ -// Entry points -// -// Here we generate the various kind of entries into the interpreter. -// The two main entry type are generic bytecode methods and native call method. -// These both come in synchronized and non-synchronized versions but the -// frame layout they create is very similar. The other method entry -// types are really just special purpose entries that are really entry -// and interpretation all in one. These are for trivial methods like -// accessor, empty, or special math methods. -// -// When control flow reaches any of the entry types for the interpreter -// the following holds -> -// -// Arguments: -// -// rbx,: Method* -// rcx: receiver -// -// -// Stack layout immediately at entry -// -// [ return address ] <--- rsp -// [ parameter n ] -// ... -// [ parameter 1 ] -// [ expression stack ] (caller's java expression stack) - -// Assuming that we don't go to one of the trivial specialized -// entries the stack will look like below when we are ready to execute -// the first bytecode (or call the native routine). The register usage -// will be as the template based interpreter expects (see interpreter_x86.hpp). -// -// local variables follow incoming parameters immediately; i.e. -// the return address is moved to the end of the locals). -// -// [ monitor entry ] <--- rsp -// ... -// [ monitor entry ] -// [ expr. stack bottom ] -// [ saved rsi ] -// [ current rdi ] -// [ Method* ] -// [ saved rbp, ] <--- rbp, -// [ return address ] -// [ local variable m ] -// ... -// [ local variable 1 ] -// [ parameter n ] -// ... -// [ parameter 1 ] <--- rdi - -address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter::MethodKind kind) { - // determine code generation flags - bool synchronized = false; - address entry_point = NULL; - InterpreterGenerator* ig_this = (InterpreterGenerator*)this; - - switch (kind) { - case Interpreter::zerolocals : break; - case Interpreter::zerolocals_synchronized: synchronized = true; break; - case Interpreter::native : entry_point = ig_this->generate_native_entry(false); break; - case Interpreter::native_synchronized : entry_point = ig_this->generate_native_entry(true); break; - case Interpreter::empty : entry_point = ig_this->generate_empty_entry(); break; - case Interpreter::accessor : entry_point = ig_this->generate_accessor_entry(); break; - case Interpreter::abstract : entry_point = ig_this->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 = ig_this->generate_math_entry(kind); break; - case Interpreter::java_lang_ref_reference_get - : entry_point = ig_this->generate_Reference_get_entry(); break; - case Interpreter::java_util_zip_CRC32_update - : entry_point = ig_this->generate_CRC32_update_entry(); break; - case Interpreter::java_util_zip_CRC32_updateBytes - : // fall thru - case Interpreter::java_util_zip_CRC32_updateByteBuffer - : entry_point = ig_this->generate_CRC32_updateBytes_entry(kind); break; - default: - fatal(err_msg("unexpected method kind: %d", kind)); - break; - } - - if (entry_point) return entry_point; - - return ig_this->generate_normal_entry(synchronized); - -} // These should never be compiled since the interpreter will prefer // the compiled version to the intrinsic version. diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 9c81d6787a1..f3390c94ca9 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -400,7 +400,7 @@ void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { // page mechanism will work for that. // // NOTE: Since the additional locals are also always pushed (wasn't -// obvious in generate_method_entry) so the guard should work for them +// obvious in generate_fixed_frame) so the guard should work for them // too. // // Args: @@ -411,8 +411,7 @@ void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { // rax void InterpreterGenerator::generate_stack_overflow_check(void) { - // monitor entry size: see picture of stack set - // (generate_method_entry) and frame_amd64.hpp + // monitor entry size: see picture of stack in frame_x86.hpp const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; // total overhead size: entry_size + (saved rbp through expr stack @@ -600,153 +599,6 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // End of helpers -// Various method entries -//------------------------------------------------------------------------------------------------------------------------ -// -// - -// Call an accessor method (assuming it is resolved, otherwise drop -// into vanilla (slow path) entry -address InterpreterGenerator::generate_accessor_entry(void) { - // rbx: Method* - - // r13: senderSP must preserver for slow path, set SP to it on fast path - - address entry_point = __ pc(); - Label xreturn_path; - - // do fastpath for resolved accessor methods - if (UseFastAccessorMethods) { - // Code: _aload_0, _(i|a)getfield, _(i|a)return or any rewrites - // thereof; parameter size = 1 - // Note: We can only use this code if the getfield has been resolved - // and if we don't have a null-pointer exception => check for - // these conditions first and use slow path if necessary. - Label slow_path; - // If we need a safepoint check, generate full interpreter entry. - __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()), - SafepointSynchronize::_not_synchronized); - - __ jcc(Assembler::notEqual, slow_path); - // rbx: method - __ movptr(rax, Address(rsp, wordSize)); - - // check if local 0 != NULL and read field - __ testptr(rax, rax); - __ jcc(Assembler::zero, slow_path); - - // read first instruction word and extract bytecode @ 1 and index @ 2 - __ movptr(rdx, Address(rbx, Method::const_offset())); - __ movptr(rdi, Address(rdx, ConstMethod::constants_offset())); - __ movl(rdx, Address(rdx, ConstMethod::codes_offset())); - // Shift codes right to get the index on the right. - // The bytecode fetched looks like <0xb4><0x2a> - __ shrl(rdx, 2 * BitsPerByte); - __ shll(rdx, exact_log2(in_words(ConstantPoolCacheEntry::size()))); - __ movptr(rdi, Address(rdi, ConstantPool::cache_offset_in_bytes())); - - // rax: local 0 - // rbx: method - // rdx: constant pool cache index - // rdi: constant pool cache - - // check if getfield has been resolved and read constant pool cache entry - // check the validity of the cache entry by testing whether _indices field - // contains Bytecode::_getfield in b1 byte. - assert(in_words(ConstantPoolCacheEntry::size()) == 4, - "adjust shift below"); - __ movl(rcx, - Address(rdi, - rdx, - Address::times_8, - ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::indices_offset())); - __ shrl(rcx, 2 * BitsPerByte); - __ andl(rcx, 0xFF); - __ cmpl(rcx, Bytecodes::_getfield); - __ jcc(Assembler::notEqual, slow_path); - - // Note: constant pool entry is not valid before bytecode is resolved - __ movptr(rcx, - Address(rdi, - rdx, - Address::times_8, - ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::f2_offset())); - // edx: flags - __ movl(rdx, - Address(rdi, - rdx, - Address::times_8, - ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::flags_offset())); - - Label notObj, notInt, notByte, notShort; - const Address field_address(rax, rcx, Address::times_1); - - // Need to differentiate between igetfield, agetfield, bgetfield etc. - // because they are different sizes. - // Use the type from the constant pool cache - __ shrl(rdx, ConstantPoolCacheEntry::tos_state_shift); - // Make sure we don't need to mask edx after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - - __ cmpl(rdx, atos); - __ jcc(Assembler::notEqual, notObj); - // atos - __ load_heap_oop(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notObj); - __ cmpl(rdx, itos); - __ jcc(Assembler::notEqual, notInt); - // itos - __ movl(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notInt); - __ cmpl(rdx, btos); - __ jcc(Assembler::notEqual, notByte); - // btos - __ load_signed_byte(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notByte); - __ cmpl(rdx, stos); - __ jcc(Assembler::notEqual, notShort); - // stos - __ load_signed_short(rax, field_address); - __ jmp(xreturn_path); - - __ bind(notShort); -#ifdef ASSERT - Label okay; - __ cmpl(rdx, ctos); - __ jcc(Assembler::equal, okay); - __ stop("what type is this?"); - __ bind(okay); -#endif - // ctos - __ load_unsigned_short(rax, field_address); - - __ bind(xreturn_path); - - // _ireturn/_areturn - __ pop(rdi); - __ mov(rsp, r13); - __ jmp(rdi); - __ ret(0); - - // generate a vanilla interpreter entry as the slow path - __ bind(slow_path); - (void) generate_normal_entry(false); - } else { - (void) generate_normal_entry(false); - } - - return entry_point; -} - // Method entry for java.lang.ref.Reference.get. address InterpreterGenerator::generate_Reference_get_entry(void) { #if INCLUDE_ALL_GCS @@ -773,8 +625,6 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // and so we don't need to call the G1 pre-barrier. Thus we can use the // regular method entry code to generate the NPE. // - // This code is based on generate_accessor_enty. - // // rbx: Method* // r13: senderSP must preserve for slow path, set SP to it on fast path @@ -832,7 +682,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_accessor_entry(); + return generate_jump_to_normal_entry(); } /** @@ -1566,100 +1416,6 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { return entry_point; } -// Entry points -// -// Here we generate the various kind of entries into the interpreter. -// The two main entry type are generic bytecode methods and native -// call method. These both come in synchronized and non-synchronized -// versions but the frame layout they create is very similar. The -// other method entry types are really just special purpose entries -// that are really entry and interpretation all in one. These are for -// trivial methods like accessor, empty, or special math methods. -// -// When control flow reaches any of the entry types for the interpreter -// the following holds -> -// -// Arguments: -// -// rbx: Method* -// -// Stack layout immediately at entry -// -// [ return address ] <--- rsp -// [ parameter n ] -// ... -// [ parameter 1 ] -// [ expression stack ] (caller's java expression stack) - -// Assuming that we don't go to one of the trivial specialized entries -// the stack will look like below when we are ready to execute the -// first bytecode (or call the native routine). The register usage -// will be as the template based interpreter expects (see -// interpreter_amd64.hpp). -// -// local variables follow incoming parameters immediately; i.e. -// the return address is moved to the end of the locals). -// -// [ monitor entry ] <--- rsp -// ... -// [ monitor entry ] -// [ expr. stack bottom ] -// [ saved r13 ] -// [ current r14 ] -// [ Method* ] -// [ saved ebp ] <--- rbp -// [ return address ] -// [ local variable m ] -// ... -// [ local variable 1 ] -// [ parameter n ] -// ... -// [ parameter 1 ] <--- r14 - -address AbstractInterpreterGenerator::generate_method_entry( - AbstractInterpreter::MethodKind kind) { - // determine code generation flags - bool synchronized = false; - address entry_point = NULL; - InterpreterGenerator* ig_this = (InterpreterGenerator*)this; - - switch (kind) { - case Interpreter::zerolocals : break; - case Interpreter::zerolocals_synchronized: synchronized = true; break; - case Interpreter::native : entry_point = ig_this->generate_native_entry(false); break; - case Interpreter::native_synchronized : entry_point = ig_this->generate_native_entry(true); break; - case Interpreter::empty : entry_point = ig_this->generate_empty_entry(); break; - case Interpreter::accessor : entry_point = ig_this->generate_accessor_entry(); break; - case Interpreter::abstract : entry_point = ig_this->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 = ig_this->generate_math_entry(kind); break; - case Interpreter::java_lang_ref_reference_get - : entry_point = ig_this->generate_Reference_get_entry(); break; - case Interpreter::java_util_zip_CRC32_update - : entry_point = ig_this->generate_CRC32_update_entry(); break; - case Interpreter::java_util_zip_CRC32_updateBytes - : // fall thru - case Interpreter::java_util_zip_CRC32_updateByteBuffer - : entry_point = ig_this->generate_CRC32_updateBytes_entry(kind); break; - default: - fatal(err_msg("unexpected method kind: %d", kind)); - break; - } - - if (entry_point) { - return entry_point; - } - - return ig_this->generate_normal_entry(synchronized); -} // These should never be compiled since the interpreter will prefer // the compiled version to the intrinsic version. diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index 57a1545166a..5145d801298 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -27,6 +27,7 @@ #include "asm/macroAssembler.inline.hpp" #include "memory/resourceArea.hpp" #include "runtime/java.hpp" +#include "runtime/os.hpp" #include "runtime/stubCodeGenerator.hpp" #include "vm_version_x86.hpp" @@ -514,7 +515,7 @@ void VM_Version::get_processor_features() { (supports_tscinv() ? ", tscinv": ""), (supports_bmi1() ? ", bmi1" : ""), (supports_bmi2() ? ", bmi2" : "")); - _features_str = strdup(buf); + _features_str = 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 @@ -559,7 +560,7 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseCLMUL, false); } - if (UseCLMUL && (UseAVX > 0) && (UseSSE > 2)) { + if (UseCLMUL && (UseSSE > 2)) { if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { UseCRC32Intrinsics = true; } @@ -805,6 +806,21 @@ void VM_Version::get_processor_features() { } } } + if ((cpu_family() == 0x06) && + ((extended_cpu_model() == 0x36) || // Centerton + (extended_cpu_model() == 0x37) || // Silvermont + (extended_cpu_model() == 0x4D))) { +#ifdef COMPILER2 + if (FLAG_IS_DEFAULT(OptoScheduling)) { + OptoScheduling = true; + } +#endif + if (supports_sse4_2()) { // Silvermont + if (FLAG_IS_DEFAULT(UseUnalignedLoadStores)) { + UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus + } + } + } } // Use count leading zeros count instruction if available. @@ -892,23 +908,25 @@ void VM_Version::get_processor_features() { AllocatePrefetchDistance = allocate_prefetch_distance(); AllocatePrefetchStyle = allocate_prefetch_style(); - if( is_intel() && cpu_family() == 6 && supports_sse3() ) { - if( AllocatePrefetchStyle == 2 ) { // watermark prefetching on Core + if (is_intel() && cpu_family() == 6 && supports_sse3()) { + if (AllocatePrefetchStyle == 2) { // watermark prefetching on Core #ifdef _LP64 AllocatePrefetchDistance = 384; #else AllocatePrefetchDistance = 320; #endif } - if( supports_sse4_2() && supports_ht() ) { // Nehalem based cpus + if (supports_sse4_2() && supports_ht()) { // Nehalem based cpus AllocatePrefetchDistance = 192; AllocatePrefetchLines = 4; + } #ifdef COMPILER2 - if (AggressiveOpts && FLAG_IS_DEFAULT(UseFPUForSpilling)) { + if (supports_sse4_2()) { + if (FLAG_IS_DEFAULT(UseFPUForSpilling)) { FLAG_SET_DEFAULT(UseFPUForSpilling, true); } -#endif } +#endif } assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value"); diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index fe9115be9ec..068cc4f9ffe 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -731,7 +731,7 @@ InterpreterFrame *InterpreterFrame::build(Method* const method, TRAPS) { if (method->is_static()) object = method->constants()->pool_holder()->java_mirror(); else - object = (oop) locals[0]; + object = (oop) (void*)locals[0]; monitor->set_obj(object); } @@ -831,60 +831,6 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { return generate_entry((address) CppInterpreter::normal_entry); } -address AbstractInterpreterGenerator::generate_method_entry( - AbstractInterpreter::MethodKind kind) { - address entry_point = NULL; - - switch (kind) { - case Interpreter::zerolocals: - case Interpreter::zerolocals_synchronized: - break; - - case Interpreter::native: - entry_point = ((InterpreterGenerator*) this)->generate_native_entry(false); - break; - - case Interpreter::native_synchronized: - entry_point = ((InterpreterGenerator*) this)->generate_native_entry(false); - break; - - case Interpreter::empty: - entry_point = ((InterpreterGenerator*) this)->generate_empty_entry(); - break; - - case Interpreter::accessor: - entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry(); - break; - - case Interpreter::abstract: - entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry(); - break; - - case Interpreter::java_lang_math_sin: - case Interpreter::java_lang_math_cos: - case Interpreter::java_lang_math_tan: - case Interpreter::java_lang_math_abs: - case Interpreter::java_lang_math_log: - case Interpreter::java_lang_math_log10: - case Interpreter::java_lang_math_sqrt: - case Interpreter::java_lang_math_pow: - case Interpreter::java_lang_math_exp: - entry_point = ((InterpreterGenerator*) this)->generate_math_entry(kind); - break; - - case Interpreter::java_lang_ref_reference_get: - entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); - break; - - default: - ShouldNotReachHere(); - } - - if (entry_point == NULL) - entry_point = ((InterpreterGenerator*) this)->generate_normal_entry(false); - - return entry_point; -} InterpreterGenerator::InterpreterGenerator(StubQueue* code) : CppInterpreterGenerator(code) { diff --git a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp index 64e7f5fdf1f..0ea5bbc4f77 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp @@ -26,6 +26,8 @@ #ifndef CPU_ZERO_VM_FRAME_ZERO_INLINE_HPP #define CPU_ZERO_VM_FRAME_ZERO_INLINE_HPP +#include "code/codeCache.hpp" + // Constructors inline frame::frame() { diff --git a/hotspot/src/cpu/zero/vm/globals_zero.hpp b/hotspot/src/cpu/zero/vm/globals_zero.hpp index 0f88bba8537..7698a7a2480 100644 --- a/hotspot/src/cpu/zero/vm/globals_zero.hpp +++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -61,6 +61,12 @@ define_pd_global(uintx, CMSYoungGenPerWorker, 16*M); // default max size of CMS define_pd_global(uintx, TypeProfileLevel, 0); -#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) +#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ + product(bool, UseFastEmptyMethods, true, \ + "Use fast method entry code for empty methods") \ + \ + product(bool, UseFastAccessorMethods, true, \ + "Use fast method entry code for accessor methods") \ + \ #endif // CPU_ZERO_VM_GLOBALS_ZERO_HPP diff --git a/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp b/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp index eb170370630..68516b4daf9 100644 --- a/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp +++ b/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * 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. * @@ -39,4 +39,7 @@ 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; } #endif // CPU_ZERO_VM_INTERPRETERGENERATOR_ZERO_HPP diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index 70ca91a62ce..6d8c55bf541 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -58,6 +58,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/orderAccess.inline.hpp" +#include "runtime/os.hpp" #include "runtime/osThread.hpp" #include "runtime/perfMemory.hpp" #include "runtime/sharedRuntime.hpp" @@ -378,10 +379,10 @@ void os::Aix::query_multipage_support() { // default should be 4K. size_t data_page_size = SIZE_4K; { - void* p = ::malloc(SIZE_16M); + void* p = os::malloc(SIZE_16M, mtInternal); guarantee(p != NULL, "malloc failed"); data_page_size = os::Aix::query_pagesize(p); - ::free(p); + os::free(p); } // query default shm page size (LDR_CNTRL SHMPSIZE) diff --git a/hotspot/src/os/aix/vm/porting_aix.cpp b/hotspot/src/os/aix/vm/porting_aix.cpp index 5e6a78ddcc9..038693cfdf1 100644 --- a/hotspot/src/os/aix/vm/porting_aix.cpp +++ b/hotspot/src/os/aix/vm/porting_aix.cpp @@ -24,6 +24,8 @@ #include "asm/assembler.hpp" #include "memory/allocation.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/os.hpp" #include "loadlib_aix.hpp" #include "porting_aix.hpp" #include "utilities/debug.hpp" @@ -83,7 +85,7 @@ class fixed_strings { while (n) { node* p = n; n = n->next; - free(p->v); + os::free(p->v); delete p; } } @@ -95,7 +97,7 @@ class fixed_strings { } } node* p = new node; - p->v = strdup(s); + p->v = os::strdup_check_oom(s); p->next = first; first = p; return p->v; diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index b0756b8bc2b..51e9f866cf2 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -2439,23 +2439,25 @@ char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, } // The memory is committed - MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC); return addr; } bool os::release_memory_special(char* base, size_t bytes) { - MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); - // detaching the SHM segment will also delete it, see reserve_memory_special() - int rslt = shmdt(base); - if (rslt == 0) { - tkr.record((address)base, bytes); - return true; + if (MemTracker::tracking_level() > NMT_minimal) { + Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + // detaching the SHM segment will also delete it, see reserve_memory_special() + int rslt = shmdt(base); + if (rslt == 0) { + tkr.record((address)base, bytes); + return true; + } else { + return false; + } } else { - tkr.discard(); - return false; + return shmdt(base) == 0; } - } size_t os::large_page_size() { diff --git a/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp b/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp index e812a76f51b..2737fe38ce1 100644 --- a/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp +++ b/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp @@ -753,7 +753,7 @@ static char* mmap_create_shared(size_t size) { (void)::memset((void*) mapAddress, 0, size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size, CURRENT_PC, mtInternal); return mapAddress; } @@ -918,7 +918,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size, CURRENT_PC, mtInternal); *addr = mapAddress; *sizep = size; diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index ed12d800c5b..586f46a26b3 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -2246,7 +2246,7 @@ 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(); @@ -2256,6 +2256,7 @@ void os::print_siginfo(outputStream* st, void* siginfo) { " possible disk/network problem."); } } +#endif st->cr(); } @@ -3504,9 +3505,12 @@ char* os::Linux::reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t al assert(is_ptr_aligned(start, alignment), "Must be"); - // os::reserve_memory_special will record this memory area. - // Need to release it here to prevent overlapping reservations. - MemTracker::record_virtual_memory_release((address)start, bytes); + if (MemTracker::tracking_level() > NMT_minimal) { + // os::reserve_memory_special will record this memory area. + // Need to release it here to prevent overlapping reservations. + Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + tkr.record((address)start, bytes); + } char* end = start + bytes; @@ -3601,7 +3605,7 @@ char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, } // The memory is committed - MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC); } return addr; @@ -3617,24 +3621,30 @@ bool os::Linux::release_memory_special_huge_tlbfs(char* base, size_t bytes) { } bool os::release_memory_special(char* base, size_t bytes) { - assert(UseLargePages, "only for large pages"); - - MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); - bool res; + if (MemTracker::tracking_level() > NMT_minimal) { + Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + res = os::Linux::release_memory_special_impl(base, bytes); + if (res) { + tkr.record((address)base, bytes); + } + + } else { + res = os::Linux::release_memory_special_impl(base, bytes); + } + return res; +} + +bool os::Linux::release_memory_special_impl(char* base, size_t bytes) { + assert(UseLargePages, "only for large pages"); + bool res; + if (UseSHM) { res = os::Linux::release_memory_special_shm(base, bytes); } else { assert(UseHugeTLBFS, "must be"); res = os::Linux::release_memory_special_huge_tlbfs(base, bytes); } - - if (res) { - tkr.record((address)base, bytes); - } else { - tkr.discard(); - } - return res; } diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp index 1b62f3f35ea..cf9b71b4033 100644 --- a/hotspot/src/os/linux/vm/os_linux.hpp +++ b/hotspot/src/os/linux/vm/os_linux.hpp @@ -108,6 +108,7 @@ class Linux { static char* reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec); static char* reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec); + static bool release_memory_special_impl(char* base, size_t bytes); static bool release_memory_special_shm(char* base, size_t bytes); static bool release_memory_special_huge_tlbfs(char* base, size_t bytes); diff --git a/hotspot/src/os/linux/vm/perfMemory_linux.cpp b/hotspot/src/os/linux/vm/perfMemory_linux.cpp index 9708734295f..2eef5da69f9 100644 --- a/hotspot/src/os/linux/vm/perfMemory_linux.cpp +++ b/hotspot/src/os/linux/vm/perfMemory_linux.cpp @@ -753,7 +753,7 @@ static char* mmap_create_shared(size_t size) { (void)::memset((void*) mapAddress, 0, size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size, CURRENT_PC, mtInternal); return mapAddress; } @@ -924,7 +924,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size, CURRENT_PC, mtInternal); *addr = mapAddress; *sizep = size; diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index d17bc15cbae..66ad5d8a904 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -75,21 +75,41 @@ void os::check_or_create_dump(void* exceptionRecord, void* contextRecord, char* VMError::report_coredump_status(buffer, success); } -address os::get_caller_pc(int n) { +int os::get_native_stack(address* stack, int frames, int toSkip) { #ifdef _NMT_NOINLINE_ - n ++; + toSkip++; #endif + + int frame_idx = 0; + int num_of_frames; // number of frames captured frame fr = os::current_frame(); - while (n > 0 && fr.pc() && - !os::is_first_C_frame(&fr) && fr.sender_pc()) { - fr = os::get_sender_for_C_frame(&fr); - n --; + while (fr.pc() && frame_idx < frames) { + if (toSkip > 0) { + toSkip --; + } else { + stack[frame_idx ++] = fr.pc(); + } + if (fr.fp() == NULL || os::is_first_C_frame(&fr) + ||fr.sender_pc() == NULL || fr.cb() != NULL) break; + + if (fr.sender_pc() && !os::is_first_C_frame(&fr)) { + fr = os::get_sender_for_C_frame(&fr); + } else { + break; + } } - if (n == 0) { - return fr.pc(); - } else { - return NULL; + num_of_frames = frame_idx; + for (; frame_idx < frames; frame_idx ++) { + stack[frame_idx] = NULL; } + + return num_of_frames; +} + + +bool os::unsetenv(const char* name) { + assert(name != NULL, "Null pointer"); + return (::unsetenv(name) == 0); } int os::get_last_error() { diff --git a/hotspot/src/os/solaris/vm/attachListener_solaris.cpp b/hotspot/src/os/solaris/vm/attachListener_solaris.cpp index bee98a1a7fe..1426356dade 100644 --- a/hotspot/src/os/solaris/vm/attachListener_solaris.cpp +++ b/hotspot/src/os/solaris/vm/attachListener_solaris.cpp @@ -199,23 +199,29 @@ class ArgumentIterator : public StackObj { // Calls from the door function to check that the client credentials // match this process. Returns 0 if credentials okay, otherwise -1. static int check_credentials() { - door_cred_t cred_info; + ucred_t *cred_info = NULL; + int ret = -1; // deny by default // get client credentials - if (door_cred(&cred_info) == -1) { - return -1; // unable to get them + if (door_ucred(&cred_info) == -1) { + return -1; // unable to get them, deny } // get our euid/eguid (probably could cache these) uid_t euid = geteuid(); gid_t egid = getegid(); - // check that the effective uid/gid matches - discuss this with Jeff. - if (cred_info.dc_euid == euid && cred_info.dc_egid == egid) { - return 0; // okay - } else { - return -1; // denied + // get euid/egid from ucred_free + uid_t ucred_euid = ucred_geteuid(cred_info); + gid_t ucred_egid = ucred_getegid(cred_info); + + // check that the effective uid/gid matches + if (ucred_euid == euid && ucred_egid == egid) { + ret = 0; // allow } + + ucred_free(cred_info); + return ret; } diff --git a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp index 1fa30012d6b..2d279af0c2b 100644 --- a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp +++ b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp @@ -770,7 +770,8 @@ static char* mmap_create_shared(size_t size) { (void)::memset((void*) mapAddress, 0, size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, + size, CURRENT_PC, mtInternal); return mapAddress; } @@ -941,7 +942,8 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, + size, CURRENT_PC, mtInternal); *addr = mapAddress; *sizep = size; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index d312b975abc..73055a88039 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -138,9 +138,8 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) { // Workaround for issue when a custom launcher doesn't call // DestroyJavaVM and NMT is trying to track memory when free is // called from a static destructor - if (MemTracker::is_on()) { - MemTracker::shutdown(MemTracker::NMT_normal); - } + MemTracker::shutdown(); + break; default: break; @@ -163,6 +162,10 @@ bool os::getenv(const char* name, char* buffer, int len) { return result > 0 && result < len; } +bool os::unsetenv(const char* name) { + assert(name != NULL, "Null pointer"); + return (SetEnvironmentVariable(name, NULL) == TRUE); +} // No setuid programs under Windows. bool os::have_special_privileges() { @@ -319,15 +322,16 @@ extern "C" void breakpoint() { * So far, this method is only used by Native Memory Tracking, which is * only supported on Windows XP or later. */ -address os::get_caller_pc(int n) { +int os::get_native_stack(address* stack, int frames, int toSkip) { #ifdef _NMT_NOINLINE_ - n++; + toSkip ++; #endif - address pc; - if (os::Kernel32Dll::RtlCaptureStackBackTrace(n + 1, 1, (PVOID*)&pc, NULL) == 1) { - return pc; + int captured = Kernel32Dll::RtlCaptureStackBackTrace(toSkip + 1, frames, + (PVOID*)stack, NULL); + for (int index = captured; index < frames; index ++) { + stack[index] = NULL; } - return NULL; + return captured; } @@ -2901,7 +2905,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, PAGE_READWRITE); // If reservation failed, return NULL if (p_buf == NULL) return NULL; - MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, mtNone, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC); os::release_memory(p_buf, bytes + chunk_size); // we still need to round up to a page boundary (in case we are using large pages) @@ -2967,7 +2971,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, // need to create a dummy 'reserve' record to match // the release. MemTracker::record_virtual_memory_reserve((address)p_buf, - bytes_to_release, mtNone, CALLER_PC); + bytes_to_release, CALLER_PC); os::release_memory(p_buf, bytes_to_release); } #ifdef ASSERT @@ -2986,11 +2990,10 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, } // Although the memory is allocated individually, it is returned as one. // NMT records it as one block. - address pc = CALLER_PC; if ((flags & MEM_COMMIT) != 0) { - MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, mtNone, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC); } else { - MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, mtNone, pc); + MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC); } // made it this far, success @@ -3188,8 +3191,7 @@ char* os::reserve_memory_special(size_t bytes, size_t alignment, char* addr, boo DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; char * res = (char *)VirtualAlloc(addr, bytes, flag, prot); if (res != NULL) { - address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve_and_commit((address)res, bytes, mtNone, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)res, bytes, CALLER_PC); } return res; diff --git a/hotspot/src/os/windows/vm/perfMemory_windows.cpp b/hotspot/src/os/windows/vm/perfMemory_windows.cpp index 1bf27296520..e1b59253e82 100644 --- a/hotspot/src/os/windows/vm/perfMemory_windows.cpp +++ b/hotspot/src/os/windows/vm/perfMemory_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -29,6 +29,7 @@ #include "oops/oop.inline.hpp" #include "os_windows.inline.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/os.hpp" #include "runtime/perfMemory.hpp" #include "services/memTracker.hpp" #include "utilities/exceptions.hpp" @@ -1388,7 +1389,7 @@ static HANDLE create_sharedmem_resources(const char* dirname, const char* filena // the file has been successfully created and the file mapping // object has been created. sharedmem_fileHandle = fh; - sharedmem_fileName = strdup(filename); + sharedmem_fileName = os::strdup(filename); return fmh; } @@ -1498,7 +1499,8 @@ static char* mapping_create_shared(size_t size) { (void)memset(mapAddress, '\0', size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, + size, CURRENT_PC, mtInternal); return (char*) mapAddress; } @@ -1680,7 +1682,8 @@ static void open_file_mapping(const char* user, int vmid, } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size, + CURRENT_PC, mtInternal); *addrp = (char*)mapAddress; @@ -1834,10 +1837,14 @@ void PerfMemory::detach(char* addr, size_t bytes, TRAPS) { return; } - MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); - remove_file_mapping(addr); - // it does not go through os api, the operation has to record from here - tkr.record((address)addr, bytes); + if (MemTracker::tracking_level() > NMT_minimal) { + // it does not go through os api, the operation has to record from here + Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + remove_file_mapping(addr); + tkr.record((address)addr, bytes); + } else { + remove_file_mapping(addr); + } } char* PerfMemory::backing_store_filename() { diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp index 028e33f37d4..f30ad48669a 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp @@ -23,6 +23,8 @@ */ #include "precompiled.hpp" +#include "memory/allocation.hpp" +#include "memory/allocation.inline.hpp" #include "runtime/os.hpp" #include "vm_version_sparc.hpp" @@ -48,7 +50,7 @@ static void do_sysinfo(int si, const char* string, int* features, int mask) { // All SI defines used below must be supported. guarantee(bufsize != -1, "must be supported"); - char* buf = (char*) malloc(bufsize); + char* buf = (char*) os::malloc(bufsize, mtInternal); if (buf == NULL) return; @@ -60,133 +62,96 @@ static void do_sysinfo(int si, const char* string, int* features, int mask) { } } - free(buf); + os::free(buf); } int VM_Version::platform_features(int features) { - // getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are - // supported on Solaris 10 and later. - if (os::Solaris::supports_getisax()) { + assert(os::Solaris::supports_getisax(), "getisax() must be available"); - // Check 32-bit architecture. - do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); + // Check 32-bit architecture. + do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); - // Check 64-bit architecture. - do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m); + // Check 64-bit architecture. + do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m); - // Extract valid instruction set extensions. - uint_t avs[2]; - uint_t avn = os::Solaris::getisax(avs, 2); - assert(avn <= 2, "should return two or less av's"); - uint_t av = avs[0]; + // Extract valid instruction set extensions. + uint_t avs[2]; + uint_t avn = os::Solaris::getisax(avs, 2); + assert(avn <= 2, "should return two or less av's"); + uint_t av = avs[0]; #ifndef PRODUCT - if (PrintMiscellaneous && Verbose) { - tty->print("getisax(2) returned: " PTR32_FORMAT, av); - if (avn > 1) { - tty->print(", " PTR32_FORMAT, avs[1]); - } - tty->cr(); + if (PrintMiscellaneous && Verbose) { + tty->print("getisax(2) returned: " PTR32_FORMAT, av); + if (avn > 1) { + tty->print(", " PTR32_FORMAT, avs[1]); } + tty->cr(); + } #endif - if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; - if (av & AV_SPARC_DIV32) features |= hardware_div32_m; - if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; - if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m; - if (av & AV_SPARC_POPC) features |= hardware_popc_m; - if (av & AV_SPARC_VIS) features |= vis1_instructions_m; - if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; - if (avn > 1) { - uint_t av2 = avs[1]; + if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; + if (av & AV_SPARC_DIV32) features |= hardware_div32_m; + if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; + if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m; + if (av & AV_SPARC_POPC) features |= hardware_popc_m; + if (av & AV_SPARC_VIS) features |= vis1_instructions_m; + if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; + if (avn > 1) { + uint_t av2 = avs[1]; #ifndef AV2_SPARC_SPARC5 #define AV2_SPARC_SPARC5 0x00000008 /* The 29 new fp and sub instructions */ #endif - if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m; - } + if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m; + } - // Next values are not defined before Solaris 10 - // but Solaris 8 is used for jdk6 update builds. + // We only build on Solaris 10 and up, but some of the values below + // are not defined on all versions of Solaris 10, so we define them, + // if necessary. #ifndef AV_SPARC_ASI_BLK_INIT #define AV_SPARC_ASI_BLK_INIT 0x0080 /* ASI_BLK_INIT_xxx ASI */ #endif - if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m; + if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m; #ifndef AV_SPARC_FMAF #define AV_SPARC_FMAF 0x0100 /* Fused Multiply-Add */ #endif - if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m; + if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m; #ifndef AV_SPARC_FMAU -#define AV_SPARC_FMAU 0x0200 /* Unfused Multiply-Add */ +#define AV_SPARC_FMAU 0x0200 /* Unfused Multiply-Add */ #endif - if (av & AV_SPARC_FMAU) features |= fmau_instructions_m; + if (av & AV_SPARC_FMAU) features |= fmau_instructions_m; #ifndef AV_SPARC_VIS3 -#define AV_SPARC_VIS3 0x0400 /* VIS3 instruction set extensions */ +#define AV_SPARC_VIS3 0x0400 /* VIS3 instruction set extensions */ #endif - if (av & AV_SPARC_VIS3) features |= vis3_instructions_m; + if (av & AV_SPARC_VIS3) features |= vis3_instructions_m; #ifndef AV_SPARC_CBCOND #define AV_SPARC_CBCOND 0x10000000 /* compare and branch instrs supported */ #endif - if (av & AV_SPARC_CBCOND) features |= cbcond_instructions_m; + if (av & AV_SPARC_CBCOND) features |= cbcond_instructions_m; #ifndef AV_SPARC_AES #define AV_SPARC_AES 0x00020000 /* aes instrs supported */ #endif - if (av & AV_SPARC_AES) features |= aes_instructions_m; + if (av & AV_SPARC_AES) features |= aes_instructions_m; #ifndef AV_SPARC_SHA1 #define AV_SPARC_SHA1 0x00400000 /* sha1 instruction supported */ #endif - if (av & AV_SPARC_SHA1) features |= sha1_instruction_m; + if (av & AV_SPARC_SHA1) features |= sha1_instruction_m; #ifndef AV_SPARC_SHA256 #define AV_SPARC_SHA256 0x00800000 /* sha256 instruction supported */ #endif - if (av & AV_SPARC_SHA256) features |= sha256_instruction_m; + if (av & AV_SPARC_SHA256) features |= sha256_instruction_m; #ifndef AV_SPARC_SHA512 #define AV_SPARC_SHA512 0x01000000 /* sha512 instruction supported */ #endif - if (av & AV_SPARC_SHA512) features |= sha512_instruction_m; - - } else { - // getisax(2) failed, use the old legacy code. -#ifndef PRODUCT - if (PrintMiscellaneous && Verbose) - tty->print_cr("getisax(2) is not supported."); -#endif - - char tmp; - size_t bufsize = sysinfo(SI_ISALIST, &tmp, 1); - char* buf = (char*) malloc(bufsize); - - if (buf != NULL) { - if (sysinfo(SI_ISALIST, buf, bufsize) == bufsize) { - // Figure out what kind of sparc we have - char *sparc_string = strstr(buf, "sparc"); - if (sparc_string != NULL) { features |= v8_instructions_m; - if (sparc_string[5] == 'v') { - if (sparc_string[6] == '8') { - if (sparc_string[7] == '-') { features |= hardware_mul32_m; - features |= hardware_div32_m; - } else if (sparc_string[7] == 'p') features |= generic_v9_m; - else features |= generic_v8_m; - } else if (sparc_string[6] == '9') features |= generic_v9_m; - } - } - - // Check for visualization instructions - char *vis = strstr(buf, "vis"); - if (vis != NULL) { features |= vis1_instructions_m; - if (vis[3] == '2') features |= vis2_instructions_m; - } - } - free(buf); - } - } + if (av & AV_SPARC_SHA512) features |= sha512_instruction_m; // Determine the machine type. do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m); @@ -201,37 +166,18 @@ int VM_Version::platform_features(int features) { kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; for (int i = 0; i < ksp->ks_ndata; i++) { if (strcmp((const char*)&(knm[i].name),"implementation") == 0) { -#ifndef KSTAT_DATA_STRING -#define KSTAT_DATA_STRING 9 -#endif - if (knm[i].data_type == KSTAT_DATA_CHAR) { - // VM is running on Solaris 8 which does not have value.str. - implementation = &(knm[i].value.c[0]); - } else if (knm[i].data_type == KSTAT_DATA_STRING) { - // VM is running on Solaris 10. -#ifndef KSTAT_NAMED_STR_PTR - // Solaris 8 was used to build VM, define the structure it misses. - struct str_t { - union { - char *ptr; /* NULL-term string */ - char __pad[8]; /* 64-bit padding */ - } addr; - uint32_t len; /* # bytes for strlen + '\0' */ - }; -#define KSTAT_NAMED_STR_PTR(knptr) (( (str_t*)&((knptr)->value) )->addr.ptr) -#endif - implementation = KSTAT_NAMED_STR_PTR(&knm[i]); - } + implementation = KSTAT_NAMED_STR_PTR(&knm[i]); #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("cpu_info.implementation: %s", implementation); } #endif // Convert to UPPER case before compare. - char* impl = strdup(implementation); + char* impl = os::strdup_check_oom(implementation); for (int i = 0; impl[i] != 0; i++) impl[i] = (char)toupper((uint)impl[i]); + if (strstr(impl, "SPARC64") != NULL) { features |= sparc64_family_m; } else if (strstr(impl, "SPARC-M") != NULL) { @@ -246,13 +192,15 @@ int VM_Version::platform_features(int features) { if (strstr(impl, "SPARC") == NULL) { #ifndef PRODUCT // kstat on Solaris 8 virtual machines (branded zones) - // returns "(unsupported)" implementation. - warning("kstat cpu_info implementation = '%s', should contain SPARC", impl); + // returns "(unsupported)" implementation. Solaris 8 is not + // supported anymore, but include this check to be on the + // safe side. + warning("kstat cpu_info implementation = '%s', assume generic SPARC", impl); #endif implementation = "SPARC"; } } - free((void*)impl); + os::free((void*)impl); break; } } // for( diff --git a/hotspot/src/share/vm/adlc/output_c.cpp b/hotspot/src/share/vm/adlc/output_c.cpp index 6169c8f62b7..68e92380cf2 100644 --- a/hotspot/src/share/vm/adlc/output_c.cpp +++ b/hotspot/src/share/vm/adlc/output_c.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -997,7 +997,7 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { int nopcnt = 0; for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != NULL; nopcnt++ ); - fprintf(fp_cpp, "void Bundle::initialize_nops(MachNode * nop_list[%d], Compile *C) {\n", nopcnt); + fprintf(fp_cpp, "void Bundle::initialize_nops(MachNode * nop_list[%d]) {\n", nopcnt); int i = 0; for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != NULL; i++ ) { fprintf(fp_cpp, " nop_list[%d] = (MachNode *) new %sNode();\n", i, nop); @@ -1369,7 +1369,7 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch fprintf(fp, " ra_->add_reference(root, inst%d);\n", inst_num); fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%d));\n", inst_num); fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%d), ra_->get_reg_first(inst%d));\n", inst_num, inst_num); - fprintf(fp, " root->_opnds[0] = inst%d->_opnds[0]->clone(C); // result\n", inst_num); + fprintf(fp, " root->_opnds[0] = inst%d->_opnds[0]->clone(); // result\n", inst_num); fprintf(fp, " // ----- Done with initial setup -----\n"); } else { if( (op_form == NULL) || (op_form->is_base_constant(globals) == Form::none) ) { @@ -1382,7 +1382,7 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch } else { fprintf(fp, " // no ideal edge for constants after matching\n"); } - fprintf(fp, " root->_opnds[%d] = inst%d->_opnds[%d]->clone(C);\n", + fprintf(fp, " root->_opnds[%d] = inst%d->_opnds[%d]->clone();\n", opnds_index, inst_num, inst_op_num ); } ++opnds_index; @@ -1402,7 +1402,7 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch // Define the Peephole method for an instruction node void ArchDesc::definePeephole(FILE *fp, InstructForm *node) { // Generate Peephole function header - fprintf(fp, "MachNode *%sNode::peephole( Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile* C ) {\n", node->_ident); + fprintf(fp, "MachNode *%sNode::peephole(Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted) {\n", node->_ident); fprintf(fp, " bool matches = true;\n"); // Identify the maximum instruction position, @@ -1593,7 +1593,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { } const char *resultOper = new_inst->reduce_result(); - fprintf(fp," n%d->set_opnd_array(0, state->MachOperGenerator( %s, C ));\n", + fprintf(fp," n%d->set_opnd_array(0, state->MachOperGenerator(%s));\n", cnt, machOperEnum(resultOper)); // get the formal operand NameList @@ -1634,7 +1634,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { // If there is no use of the created operand, just skip it if (new_pos != NameList::Not_in_list) { //Copy the operand from the original made above - fprintf(fp," n%d->set_opnd_array(%d, op%d->clone(C)); // %s\n", + fprintf(fp," n%d->set_opnd_array(%d, op%d->clone()); // %s\n", cnt, new_pos, exp_pos-node->num_opnds(), opid); // Check for who defines this operand & add edge if needed fprintf(fp," if(tmp%d != NULL)\n", exp_pos); @@ -1662,7 +1662,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { new_pos = new_inst->operand_position(parameter,Component::USE); if (new_pos != -1) { // Copy the operand from the ExpandNode to the new node - fprintf(fp," n%d->set_opnd_array(%d, opnd_array(%d)->clone(C)); // %s\n", + fprintf(fp," n%d->set_opnd_array(%d, opnd_array(%d)->clone()); // %s\n", cnt, new_pos, exp_pos, opid); // For each operand add appropriate input edges by looking at tmp's fprintf(fp," if(tmp%d == this) {\n", exp_pos); @@ -1729,14 +1729,14 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { declared_def = true; } if (op && op->_interface && op->_interface->is_RegInterface()) { - fprintf(fp," def = new MachTempNode(state->MachOperGenerator( %s, C ));\n", + fprintf(fp," def = new MachTempNode(state->MachOperGenerator(%s));\n", machOperEnum(op->_ident)); fprintf(fp," add_req(def);\n"); // The operand for TEMP is already constructed during // this mach node construction, see buildMachNode(). // // int idx = node->operand_position_format(comp->_name); - // fprintf(fp," set_opnd_array(%d, state->MachOperGenerator( %s, C ));\n", + // fprintf(fp," set_opnd_array(%d, state->MachOperGenerator(%s));\n", // idx, machOperEnum(op->_ident)); } else { assert(false, "can't have temps which aren't registers"); @@ -1802,7 +1802,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { uint j = node->unique_opnds_idx(i); // unique_opnds_idx(i) is unique if unique_opnds_idx(j) is not unique. if( j != node->unique_opnds_idx(j) ) { - fprintf(fp," set_opnd_array(%d, opnd_array(%d)->clone(C)); // %s\n", + fprintf(fp," set_opnd_array(%d, opnd_array(%d)->clone()); // %s\n", new_num_opnds, i, comp->_name); // delete not unique edges here fprintf(fp," for(unsigned i = 0; i < num%d; i++) {\n", i); @@ -2839,12 +2839,12 @@ static void defineIn_RegMask(FILE *fp, FormDict &globals, OperandForm &oper) { // generate code to create a clone for a class derived from MachOper // -// (0) MachOper *MachOperXOper::clone(Compile* C) const { +// (0) MachOper *MachOperXOper::clone() const { // (1) return new MachXOper( _ccode, _c0, _c1, ..., _cn); // (2) } // static void defineClone(FILE *fp, FormDict &globalNames, OperandForm &oper) { - fprintf(fp,"MachOper *%sOper::clone(Compile* C) const {\n", oper._ident); + fprintf(fp,"MachOper *%sOper::clone() const {\n", oper._ident); // Check for constants that need to be copied over const int num_consts = oper.num_consts(globalNames); const bool is_ideal_bool = oper.is_ideal_bool(); @@ -3043,7 +3043,7 @@ void ArchDesc::define_oper_interface(FILE *fp, OperandForm &oper, FormDict &glob static void define_fill_new_machnode(bool used, FILE *fp_cpp) { fprintf(fp_cpp, "\n"); fprintf(fp_cpp, "// Copy _idx, inputs and operands to new node\n"); - fprintf(fp_cpp, "void MachNode::fill_new_machnode( MachNode* node, Compile* C) const {\n"); + fprintf(fp_cpp, "void MachNode::fill_new_machnode(MachNode* node) const {\n"); if( !used ) { fprintf(fp_cpp, " // This architecture does not have cisc or short branch instructions\n"); fprintf(fp_cpp, " ShouldNotCallThis();\n"); @@ -3064,7 +3064,7 @@ static void define_fill_new_machnode(bool used, FILE *fp_cpp) { fprintf(fp_cpp, " MachOper **to = node->_opnds;\n"); fprintf(fp_cpp, " for( int i = 0; i < nopnds; i++ ) {\n"); fprintf(fp_cpp, " if( i != cisc_operand() ) \n"); - fprintf(fp_cpp, " to[i] = _opnds[i]->clone(C);\n"); + fprintf(fp_cpp, " to[i] = _opnds[i]->clone();\n"); fprintf(fp_cpp, " }\n"); fprintf(fp_cpp, "}\n"); } @@ -3105,7 +3105,7 @@ void ArchDesc::defineClasses(FILE *fp) { if ( strcmp(oper->_ident,"label") == 0 ) { defineIn_RegMask(_CPP_MISC_file._fp, _globalNames, *oper); - fprintf(fp,"MachOper *%sOper::clone(Compile* C) const {\n", oper->_ident); + fprintf(fp,"MachOper *%sOper::clone() const {\n", oper->_ident); fprintf(fp," return new %sOper(_label, _block_num);\n", oper->_ident); fprintf(fp,"}\n"); @@ -3124,7 +3124,7 @@ void ArchDesc::defineClasses(FILE *fp) { if ( strcmp(oper->_ident,"method") == 0 ) { defineIn_RegMask(_CPP_MISC_file._fp, _globalNames, *oper); - fprintf(fp,"MachOper *%sOper::clone(Compile* C) const {\n", oper->_ident); + fprintf(fp,"MachOper *%sOper::clone() const {\n", oper->_ident); fprintf(fp," return new %sOper(_method);\n", oper->_ident); fprintf(fp,"}\n"); @@ -3845,7 +3845,7 @@ void ArchDesc::buildMachOperGenerator(FILE *fp_cpp) { "// that invokes 'new' on the corresponding class constructor.\n"); fprintf(fp_cpp, "\n"); fprintf(fp_cpp, "MachOper *State::MachOperGenerator"); - fprintf(fp_cpp, "(int opcode, Compile* C)"); + fprintf(fp_cpp, "(int opcode)"); fprintf(fp_cpp, "{\n"); fprintf(fp_cpp, "\n"); fprintf(fp_cpp, " switch(opcode) {\n"); @@ -3921,7 +3921,7 @@ void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *inden int index = clist.operand_position(comp->_name, comp->_usedef, inst); const char *opcode = machOperEnum(comp->_type); fprintf(fp_cpp, "%s node->set_opnd_array(%d, ", indent, index); - fprintf(fp_cpp, "MachOperGenerator(%s, C));\n", opcode); + fprintf(fp_cpp, "MachOperGenerator(%s));\n", opcode); } } else if ( inst->is_chain_of_constant(_globalNames, opType) ) { @@ -3978,7 +3978,7 @@ void InstructForm::declare_cisc_version(ArchDesc &AD, FILE *fp_hpp) { InstructForm *inst_cisc = cisc_spill_alternate(); if (inst_cisc != NULL) { fprintf(fp_hpp, " virtual int cisc_operand() const { return %d; }\n", cisc_spill_operand()); - fprintf(fp_hpp, " virtual MachNode *cisc_version(int offset, Compile* C);\n"); + fprintf(fp_hpp, " virtual MachNode *cisc_version(int offset);\n"); fprintf(fp_hpp, " virtual void use_cisc_RegMask();\n"); fprintf(fp_hpp, " virtual const RegMask *cisc_RegMask() const { return _cisc_RegMask; }\n"); } @@ -4008,7 +4008,7 @@ bool InstructForm::define_cisc_version(ArchDesc &AD, FILE *fp_cpp) { // Construct CISC version of this instruction fprintf(fp_cpp, "\n"); fprintf(fp_cpp, "// Build CISC version of this instruction\n"); - fprintf(fp_cpp, "MachNode *%sNode::cisc_version( int offset, Compile* C ) {\n", this->_ident); + fprintf(fp_cpp, "MachNode *%sNode::cisc_version(int offset) {\n", this->_ident); // Create the MachNode object fprintf(fp_cpp, " %sNode *node = new %sNode();\n", name, name); // Fill in the bottom_type where requested @@ -4023,7 +4023,7 @@ bool InstructForm::define_cisc_version(ArchDesc &AD, FILE *fp_cpp) { fprintf(fp_cpp, "\n"); fprintf(fp_cpp, " // Copy _idx, inputs and operands to new node\n"); - fprintf(fp_cpp, " fill_new_machnode(node, C);\n"); + fprintf(fp_cpp, " fill_new_machnode(node);\n"); // Construct operand to access [stack_pointer + offset] fprintf(fp_cpp, " // Construct operand to access [stack_pointer + offset]\n"); fprintf(fp_cpp, " node->set_opnd_array(cisc_operand(), new %sOper(offset));\n", cisc_oper_name); @@ -4042,7 +4042,7 @@ bool InstructForm::define_cisc_version(ArchDesc &AD, FILE *fp_cpp) { // Build prototypes for short branch methods void InstructForm::declare_short_branch_methods(FILE *fp_hpp) { if (has_short_branch_form()) { - fprintf(fp_hpp, " virtual MachNode *short_branch_version(Compile* C);\n"); + fprintf(fp_hpp, " virtual MachNode *short_branch_version();\n"); } } @@ -4055,7 +4055,7 @@ bool InstructForm::define_short_branch_methods(ArchDesc &AD, FILE *fp_cpp) { // Construct short_branch_version() method. fprintf(fp_cpp, "// Build short branch version of this instruction\n"); - fprintf(fp_cpp, "MachNode *%sNode::short_branch_version(Compile* C) {\n", this->_ident); + fprintf(fp_cpp, "MachNode *%sNode::short_branch_version() {\n", this->_ident); // Create the MachNode object fprintf(fp_cpp, " %sNode *node = new %sNode();\n", name, name); if( is_ideal_if() ) { @@ -4071,7 +4071,7 @@ bool InstructForm::define_short_branch_methods(ArchDesc &AD, FILE *fp_cpp) { // Short branch version must use same node index for access // through allocator's tables fprintf(fp_cpp, " // Copy _idx, inputs and operands to new node\n"); - fprintf(fp_cpp, " fill_new_machnode(node, C);\n"); + fprintf(fp_cpp, " fill_new_machnode(node);\n"); // Return result and exit scope fprintf(fp_cpp, " return node;\n"); @@ -4097,7 +4097,7 @@ void ArchDesc::buildMachNodeGenerator(FILE *fp_cpp) { "// that invokes 'new' on the corresponding class constructor.\n"); fprintf(fp_cpp, "\n"); fprintf(fp_cpp, "MachNode *State::MachNodeGenerator"); - fprintf(fp_cpp, "(int opcode, Compile* C)"); + fprintf(fp_cpp, "(int opcode)"); fprintf(fp_cpp, "{\n"); fprintf(fp_cpp, " switch(opcode) {\n"); diff --git a/hotspot/src/share/vm/adlc/output_h.cpp b/hotspot/src/share/vm/adlc/output_h.cpp index 7e020fb1726..c204af9f13b 100644 --- a/hotspot/src/share/vm/adlc/output_h.cpp +++ b/hotspot/src/share/vm/adlc/output_h.cpp @@ -1119,7 +1119,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " _nop_count = %d\n", _pipeline->_nopcnt); fprintf(fp_hpp, " };\n\n"); - fprintf(fp_hpp, " static void initialize_nops(MachNode *nop_list[%d], Compile* C);\n\n", + fprintf(fp_hpp, " static void initialize_nops(MachNode *nop_list[%d]);\n\n", _pipeline->_nopcnt); fprintf(fp_hpp, "#ifndef PRODUCT\n"); fprintf(fp_hpp, " void dump(outputStream *st = tty) const;\n"); @@ -1240,7 +1240,7 @@ void ArchDesc::declareClasses(FILE *fp) { constant_type, _globalNames); // Clone function - fprintf(fp," virtual MachOper *clone(Compile* C) const;\n"); + fprintf(fp," virtual MachOper *clone() const;\n"); // Support setting a spill offset into a constant operand. // We only support setting an 'int' offset, while in the @@ -1718,7 +1718,7 @@ void ArchDesc::declareClasses(FILE *fp) { // If there is an explicit peephole rule, build it if ( instr->peepholes() != NULL ) { - fprintf(fp," virtual MachNode *peephole(Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile *C);\n"); + fprintf(fp," virtual MachNode *peephole(Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted);\n"); } // Output the declaration for number of relocation entries @@ -1863,7 +1863,7 @@ void ArchDesc::declareClasses(FILE *fp) { } if ( instr->num_post_match_opnds() != 0 || instr->is_chain_of_constant(_globalNames) ) { - fprintf(fp," friend MachNode *State::MachNodeGenerator(int opcode, Compile* C);\n"); + fprintf(fp," friend MachNode *State::MachNodeGenerator(int opcode);\n"); } if ( instr->rematerialize(_globalNames, get_registers()) ) { fprintf(fp," // Rematerialize %s\n", instr->_ident); @@ -2071,8 +2071,8 @@ void ArchDesc::defineStateClass(FILE *fp) { fprintf(fp," DEBUG_ONLY( ~State(void); ) // Destructor\n"); fprintf(fp,"\n"); fprintf(fp," // Methods created by ADLC and invoked by Reduce\n"); - fprintf(fp," MachOper *MachOperGenerator( int opcode, Compile* C );\n"); - fprintf(fp," MachNode *MachNodeGenerator( int opcode, Compile* C );\n"); + fprintf(fp," MachOper *MachOperGenerator(int opcode);\n"); + fprintf(fp," MachNode *MachNodeGenerator(int opcode);\n"); fprintf(fp,"\n"); fprintf(fp," // Assign a state to a node, definition of method produced by ADLC\n"); fprintf(fp," bool DFA( int opcode, const Node *ideal );\n"); diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index 9c4bc206158..085330a6444 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -269,7 +269,7 @@ address CodeBuffer::decode_begin() { GrowableArray* CodeBuffer::create_patch_overflow() { if (_overflow_arena == NULL) { - _overflow_arena = new (mtCode) Arena(); + _overflow_arena = new (mtCode) Arena(mtCode); } return new (_overflow_arena) GrowableArray(_overflow_arena, 8, 0, 0); } diff --git a/hotspot/src/share/vm/c1/c1_Compiler.cpp b/hotspot/src/share/vm/c1/c1_Compiler.cpp index f673b236f19..b547c1d3554 100644 --- a/hotspot/src/share/vm/c1/c1_Compiler.cpp +++ b/hotspot/src/share/vm/c1/c1_Compiler.cpp @@ -48,7 +48,7 @@ Compiler::Compiler() : AbstractCompiler(c1) { void Compiler::init_c1_runtime() { BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); - Arena* arena = new (mtCompiler) Arena(); + Arena* arena = new (mtCompiler) Arena(mtCompiler); Runtime1::initialize(buffer_blob); FrameMap::initialize(); // initialize data structures diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp index 48b560840e3..f2753cbff9d 100644 --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp @@ -30,6 +30,7 @@ #include "c1/c1_MacroAssembler.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciInstance.hpp" +#include "runtime/os.hpp" void LIR_Assembler::patching_epilog(PatchingStub* patch, LIR_PatchCode patch_code, Register obj, CodeEmitInfo* info) { // we must have enough patching space so that call can be inserted @@ -848,7 +849,7 @@ void LIR_Assembler::verify_oop_map(CodeEmitInfo* info) { stringStream st; st.print("bad oop %s at %d", r->as_Register()->name(), _masm->offset()); #ifdef SPARC - _masm->_verify_oop(r->as_Register(), strdup(st.as_string()), __FILE__, __LINE__); + _masm->_verify_oop(r->as_Register(), os::strdup(st.as_string(), mtCompiler), __FILE__, __LINE__); #else _masm->verify_oop(r->as_Register()); #endif diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index afed1de995f..833b357d2e4 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -1613,25 +1613,22 @@ void LinearScan::allocate_registers() { Interval* precolored_cpu_intervals, *not_precolored_cpu_intervals; Interval* precolored_fpu_intervals, *not_precolored_fpu_intervals; - create_unhandled_lists(&precolored_cpu_intervals, ¬_precolored_cpu_intervals, is_precolored_cpu_interval, is_virtual_cpu_interval); - if (has_fpu_registers()) { - create_unhandled_lists(&precolored_fpu_intervals, ¬_precolored_fpu_intervals, is_precolored_fpu_interval, is_virtual_fpu_interval); -#ifdef ASSERT - } else { - // fpu register allocation is omitted because no virtual fpu registers are present - // just check this again... - create_unhandled_lists(&precolored_fpu_intervals, ¬_precolored_fpu_intervals, is_precolored_fpu_interval, is_virtual_fpu_interval); - assert(not_precolored_fpu_intervals == Interval::end(), "missed an uncolored fpu interval"); -#endif - } - // allocate cpu registers + create_unhandled_lists(&precolored_cpu_intervals, ¬_precolored_cpu_intervals, + is_precolored_cpu_interval, is_virtual_cpu_interval); + + // allocate fpu registers + create_unhandled_lists(&precolored_fpu_intervals, ¬_precolored_fpu_intervals, + is_precolored_fpu_interval, is_virtual_fpu_interval); + + // the fpu interval allocation cannot be moved down below with the fpu section as + // the cpu_lsw.walk() changes interval positions. + LinearScanWalker cpu_lsw(this, precolored_cpu_intervals, not_precolored_cpu_intervals); cpu_lsw.walk(); cpu_lsw.finish_allocation(); if (has_fpu_registers()) { - // allocate fpu registers LinearScanWalker fpu_lsw(this, precolored_fpu_intervals, not_precolored_fpu_intervals); fpu_lsw.walk(); fpu_lsw.finish_allocation(); diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index b8dd1bbfb83..d480a70838e 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -546,13 +546,18 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // normal bytecode execution. thread->clear_exception_oop_and_pc(); + Handle original_exception(thread, exception()); + continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false); // If an exception was thrown during exception dispatch, the exception oop may have changed thread->set_exception_oop(exception()); thread->set_exception_pc(pc); // the exception cache is used only by non-implicit exceptions - if (continuation != NULL) { + // Update the exception cache only when there didn't happen + // another exception during the computation of the compiled + // exception handler. + if (continuation != NULL && original_exception() == exception()) { nm->add_handler_for_exception_and_pc(exception, pc, continuation); } } diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 310b4c2a407..5353a61964d 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -86,7 +86,8 @@ static bool firstEnv = true; // ------------------------------------------------------------------ // ciEnv::ciEnv -ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter) { +ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter) + : _ciEnv_arena(mtCompiler) { VM_ENTRY_MARK; // Set up ciEnv::current immediately, for the sake of ciObjectFactory, etc. @@ -144,7 +145,7 @@ ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter) { _jvmti_can_pop_frame = false; } -ciEnv::ciEnv(Arena* arena) { +ciEnv::ciEnv(Arena* arena) : _ciEnv_arena(mtCompiler) { ASSERT_IN_VM; // Set up ciEnv::current immediately, for the sake of ciObjectFactory, etc. diff --git a/hotspot/src/share/vm/ci/ciObjectFactory.cpp b/hotspot/src/share/vm/ci/ciObjectFactory.cpp index 6bacf2b2f1f..aaa607ff135 100644 --- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp +++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -112,7 +112,7 @@ void ciObjectFactory::initialize() { // This Arena is long lived and exists in the resource mark of the // compiler thread that initializes the initial ciObjectFactory which // creates the shared ciObjects that all later ciObjectFactories use. - Arena* arena = new (mtCompiler) Arena(); + Arena* arena = new (mtCompiler) Arena(mtCompiler); ciEnv initial(arena); ciEnv* env = ciEnv::current(); env->_factory->init_shared_objects(); diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index c6de3e2e4f7..8b3ef37d590 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -31,6 +31,9 @@ #include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" +#if INCLUDE_CDS +#include "classfile/systemDictionaryShared.hpp" +#endif #include "classfile/verificationType.hpp" #include "classfile/verifier.hpp" #include "classfile/vmSymbols.hpp" @@ -60,6 +63,7 @@ #include "services/threadService.hpp" #include "utilities/array.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" // We generally try to create the oops directly when parsing, rather than // allocating temporary data structures and copying the bytes twice. A @@ -3786,7 +3790,15 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, instanceKlassHandle nullHandle; // Figure out whether we can skip format checking (matching classic VM behavior) - _need_verify = Verifier::should_verify_for(class_loader(), verify); + if (DumpSharedSpaces) { + // verify == true means it's a 'remote' class (i.e., non-boot class) + // Verification decision is based on BytecodeVerificationRemote flag + // for those classes. + _need_verify = (verify) ? BytecodeVerificationRemote : + BytecodeVerificationLocal; + } else { + _need_verify = Verifier::should_verify_for(class_loader(), verify); + } // Set the verify flag in stream cfs->set_verify(_need_verify); @@ -3805,6 +3817,18 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, u2 minor_version = cfs->get_u2_fast(); u2 major_version = cfs->get_u2_fast(); + if (DumpSharedSpaces && major_version < JAVA_1_5_VERSION) { + ResourceMark rm; + warning("Pre JDK 1.5 class not supported by CDS: %u.%u %s", + major_version, minor_version, name->as_C_string()); + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_UnsupportedClassVersionError(), + "Unsupported major.minor version for dump time %u.%u", + major_version, + minor_version); + } + // Check version numbers - we check this even with verifier off if (!is_supported_version(major_version, minor_version)) { if (name == NULL) { @@ -3912,6 +3936,18 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, if (cfs->source() != NULL) tty->print(" from %s", cfs->source()); tty->print_cr("]"); } +#if INCLUDE_CDS + if (DumpLoadedClassList != NULL && cfs->source() != NULL && classlist_file->is_open()) { + // Only dump the classes that can be stored into CDS archive + if (SystemDictionaryShared::is_sharing_possible(loader_data)) { + if (name != NULL) { + ResourceMark rm(THREAD); + classlist_file->print_cr("%s", name->as_C_string()); + classlist_file->flush(); + } + } + } +#endif u2 super_class_index = cfs->get_u2_fast(); instanceKlassHandle super_klass = parse_super_class(super_class_index, diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 1664411337f..19aec02c26f 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -26,8 +26,13 @@ #include "classfile/classFileParser.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.hpp" +#if INCLUDE_CDS +#include "classfile/sharedPathsMiscInfo.hpp" +#include "classfile/sharedClassUtil.hpp" +#endif #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" @@ -35,6 +40,7 @@ #include "interpreter/bytecodeStream.hpp" #include "interpreter/oopMapCache.hpp" #include "memory/allocation.inline.hpp" +#include "memory/filemap.hpp" #include "memory/generation.hpp" #include "memory/oopFactory.hpp" #include "memory/universe.inline.hpp" @@ -114,8 +120,12 @@ PerfCounter* ClassLoader::_load_instance_class_failCounter = NULL; ClassPathEntry* ClassLoader::_first_entry = NULL; ClassPathEntry* ClassLoader::_last_entry = NULL; +int ClassLoader::_num_entries = 0; PackageHashtable* ClassLoader::_package_hash_table = NULL; +#if INCLUDE_CDS +SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL; +#endif // helper routines bool string_starts_with(const char* str, const char* str_to_find) { size_t str_len = strlen(str); @@ -194,6 +204,14 @@ ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) { // check if file exists struct stat st; if (os::stat(path, &st) == 0) { +#if INCLUDE_CDS + if (DumpSharedSpaces) { + // We have already check in ClassLoader::check_shared_classpath() that the directory is empty, so + // we should never find a file underneath it -- unless user has added a new file while we are running + // the dump, in which case let's quit! + ShouldNotReachHere(); + } +#endif // found file, open it int file_handle = os::open(path, 0, 0); if (file_handle != -1) { @@ -228,13 +246,13 @@ ClassPathZipEntry::~ClassPathZipEntry() { FREE_C_HEAP_ARRAY(char, _zip_name, mtClass); } -ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) { - // enable call to C land +u1* ClassPathZipEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) { + // enable call to C land JavaThread* thread = JavaThread::current(); ThreadToNativeFromVM ttn(thread); // check whether zip archive contains name - jint filesize, name_len; - jzentry* entry = (*FindEntry)(_zip, name, &filesize, &name_len); + jint name_len; + jzentry* entry = (*FindEntry)(_zip, name, filesize, &name_len); if (entry == NULL) return NULL; u1* buffer; char name_buf[128]; @@ -245,19 +263,33 @@ ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) { filename = NEW_RESOURCE_ARRAY(char, name_len + 1); } - // file found, get pointer to class in mmaped jar file. + // file found, get pointer to the entry in mmapped jar file. if (ReadMappedEntry == NULL || !(*ReadMappedEntry)(_zip, entry, &buffer, filename)) { - // mmaped access not available, perhaps due to compression, + // mmapped access not available, perhaps due to compression, // read contents into resource array - buffer = NEW_RESOURCE_ARRAY(u1, filesize); + int size = (*filesize) + ((nul_terminate) ? 1 : 0); + buffer = NEW_RESOURCE_ARRAY(u1, size); if (!(*ReadEntry)(_zip, entry, buffer, filename)) return NULL; } + + // return result + if (nul_terminate) { + buffer[*filesize] = 0; + } + return buffer; +} + +ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) { + jint filesize; + u1* buffer = open_entry(name, &filesize, false, CHECK_NULL); + if (buffer == NULL) { + return NULL; + } if (UsePerfData) { ClassLoader::perf_sys_classfile_bytes_read()->inc(filesize); } - // return result - return new ClassFileStream(buffer, filesize, _zip_name); // Resource allocated + return new ClassFileStream(buffer, filesize, _zip_name); // Resource allocated } // invoke function for each entry in the zip file @@ -272,12 +304,17 @@ void ClassPathZipEntry::contents_do(void f(const char* name, void* context), voi } } -LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st) : ClassPathEntry() { - _path = strdup(path); +LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st, bool throw_exception) : ClassPathEntry() { + _path = os::strdup_check_oom(path); _st = *st; _meta_index = NULL; _resolved_entry = NULL; _has_error = false; + _throw_exception = throw_exception; +} + +LazyClassPathEntry::~LazyClassPathEntry() { + os::free(_path); } bool LazyClassPathEntry::is_jar_file() { @@ -289,7 +326,11 @@ ClassPathEntry* LazyClassPathEntry::resolve_entry(TRAPS) { return (ClassPathEntry*) _resolved_entry; } ClassPathEntry* new_entry = NULL; - new_entry = ClassLoader::create_class_path_entry(_path, &_st, false, CHECK_NULL); + new_entry = ClassLoader::create_class_path_entry(_path, &_st, false, _throw_exception, CHECK_NULL); + if (!_throw_exception && new_entry == NULL) { + assert(!HAS_PENDING_EXCEPTION, "must be"); + return NULL; + } { ThreadCritical tc; if (_resolved_entry == NULL) { @@ -323,6 +364,23 @@ bool LazyClassPathEntry::is_lazy() { return true; } +u1* LazyClassPathEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) { + if (_has_error) { + return NULL; + } + ClassPathEntry* cpe = resolve_entry(THREAD); + if (cpe == NULL) { + _has_error = true; + return NULL; + } else if (cpe->is_jar_file()) { + return ((ClassPathZipEntry*)cpe)->open_entry(name, filesize, nul_terminate,THREAD); + } else { + ShouldNotReachHere(); + *filesize = 0; + return NULL; + } +} + static void print_meta_index(LazyClassPathEntry* entry, GrowableArray& meta_packages) { tty->print("[Meta index for %s=", entry->name()); @@ -333,15 +391,62 @@ static void print_meta_index(LazyClassPathEntry* entry, tty->print_cr("]"); } +#if INCLUDE_CDS +void ClassLoader::exit_with_path_failure(const char* error, const char* message) { + assert(DumpSharedSpaces, "only called at dump time"); + tty->print_cr("Hint: enable -XX:+TraceClassPaths to diagnose the failure"); + vm_exit_during_initialization(error, message); +} +#endif -void ClassLoader::setup_meta_index() { +void ClassLoader::trace_class_path(const char* msg, const char* name) { + if (!TraceClassPaths) { + return; + } + + if (msg) { + tty->print("%s", msg); + } + if (name) { + if (strlen(name) < 256) { + tty->print("%s", name); + } else { + // For very long paths, we need to print each character separately, + // as print_cr() has a length limit + while (name[0] != '\0') { + tty->print("%c", name[0]); + name++; + } + } + } + if (msg && msg[0] == '[') { + tty->print_cr("]"); + } else { + tty->cr(); + } +} + +void ClassLoader::setup_bootstrap_meta_index() { // Set up meta index which allows us to open boot jars lazily if // class data sharing is enabled + const char* meta_index_path = Arguments::get_meta_index_path(); + const char* meta_index_dir = Arguments::get_meta_index_dir(); + setup_meta_index(meta_index_path, meta_index_dir, 0); +} + +void ClassLoader::setup_meta_index(const char* meta_index_path, const char* meta_index_dir, int start_index) { const char* known_version = "% VERSION 2"; - char* meta_index_path = Arguments::get_meta_index_path(); - char* meta_index_dir = Arguments::get_meta_index_dir(); FILE* file = fopen(meta_index_path, "r"); int line_no = 0; +#if INCLUDE_CDS + if (DumpSharedSpaces) { + if (file != NULL) { + _shared_paths_misc_info->add_required_file(meta_index_path); + } else { + _shared_paths_misc_info->add_nonexist_path(meta_index_path); + } + } +#endif if (file != NULL) { ResourceMark rm; LazyClassPathEntry* cur_entry = NULL; @@ -376,7 +481,7 @@ void ClassLoader::setup_meta_index() { // Hand off current packages to current lazy entry (if any) if ((cur_entry != NULL) && (boot_class_path_packages.length() > 0)) { - if (TraceClassLoading && Verbose) { + if ((TraceClassLoading || TraceClassPaths) && Verbose) { print_meta_index(cur_entry, boot_class_path_packages); } MetaIndex* index = new MetaIndex(boot_class_path_packages.adr_at(0), @@ -387,8 +492,10 @@ void ClassLoader::setup_meta_index() { boot_class_path_packages.clear(); // Find lazy entry corresponding to this jar file - for (ClassPathEntry* entry = _first_entry; entry != NULL; entry = entry->next()) { - if (entry->is_lazy() && + int count = 0; + for (ClassPathEntry* entry = _first_entry; entry != NULL; entry = entry->next(), count++) { + if (count >= start_index && + entry->is_lazy() && string_starts_with(entry->name(), meta_index_dir) && string_ends_with(entry->name(), &package_name[2])) { cur_entry = (LazyClassPathEntry*) entry; @@ -416,7 +523,7 @@ void ClassLoader::setup_meta_index() { default: { if (!skipCurrentJar && cur_entry != NULL) { - char* new_name = strdup(package_name); + char* new_name = os::strdup_check_oom(package_name); boot_class_path_packages.append(new_name); } } @@ -425,7 +532,7 @@ void ClassLoader::setup_meta_index() { // Hand off current packages to current lazy entry (if any) if ((cur_entry != NULL) && (boot_class_path_packages.length() > 0)) { - if (TraceClassLoading && Verbose) { + if ((TraceClassLoading || TraceClassPaths) && Verbose) { print_meta_index(cur_entry, boot_class_path_packages); } MetaIndex* index = new MetaIndex(boot_class_path_packages.adr_at(0), @@ -436,36 +543,88 @@ void ClassLoader::setup_meta_index() { } } -void ClassLoader::setup_bootstrap_search_path() { - assert(_first_entry == NULL, "should not setup bootstrap class search path twice"); - char* sys_class_path = os::strdup(Arguments::get_sysclasspath()); - if (TraceClassLoading && Verbose) { - tty->print_cr("[Bootstrap loader class path=%s]", sys_class_path); +#if INCLUDE_CDS +void ClassLoader::check_shared_classpath(const char *path) { + if (strcmp(path, "") == 0) { + exit_with_path_failure("Cannot have empty path in archived classpaths", NULL); } - int len = (int)strlen(sys_class_path); + struct stat st; + if (os::stat(path, &st) == 0) { + if ((st.st_mode & S_IFREG) != S_IFREG) { // is directory + if (!os::dir_is_empty(path)) { + tty->print_cr("Error: non-empty directory '%s'", path); + exit_with_path_failure("CDS allows only empty directories in archived classpaths", NULL); + } + } + } +} +#endif + +void ClassLoader::setup_bootstrap_search_path() { + assert(_first_entry == NULL, "should not setup bootstrap class search path twice"); + char* sys_class_path = os::strdup_check_oom(Arguments::get_sysclasspath()); + if (!PrintSharedArchiveAndExit) { + trace_class_path("[Bootstrap loader class path=", sys_class_path); + } +#if INCLUDE_CDS + if (DumpSharedSpaces) { + _shared_paths_misc_info->add_boot_classpath(Arguments::get_sysclasspath()); + } +#endif + setup_search_path(sys_class_path); + os::free(sys_class_path); +} + +#if INCLUDE_CDS +int ClassLoader::get_shared_paths_misc_info_size() { + return _shared_paths_misc_info->get_used_bytes(); +} + +void* ClassLoader::get_shared_paths_misc_info() { + return _shared_paths_misc_info->buffer(); +} + +bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) { + SharedPathsMiscInfo* checker = SharedClassUtil::allocate_shared_paths_misc_info((char*)buf, size); + bool result = checker->check(); + delete checker; + return result; +} +#endif + +void ClassLoader::setup_search_path(char *class_path) { + int offset = 0; + int len = (int)strlen(class_path); int end = 0; // Iterate over class path entries for (int start = 0; start < len; start = end) { - while (sys_class_path[end] && sys_class_path[end] != os::path_separator()[0]) { + while (class_path[end] && class_path[end] != os::path_separator()[0]) { end++; } - char* path = NEW_C_HEAP_ARRAY(char, end-start+1, mtClass); - strncpy(path, &sys_class_path[start], end-start); - path[end-start] = '\0'; + EXCEPTION_MARK; + ResourceMark rm(THREAD); + char* path = NEW_RESOURCE_ARRAY(char, end - start + 1); + strncpy(path, &class_path[start], end - start); + path[end - start] = '\0'; update_class_path_entry_list(path, false); - FREE_C_HEAP_ARRAY(char, path, mtClass); - while (sys_class_path[end] == os::path_separator()[0]) { +#if INCLUDE_CDS + if (DumpSharedSpaces) { + check_shared_classpath(path); + } +#endif + while (class_path[end] == os::path_separator()[0]) { end++; } } } -ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct stat* st, bool lazy, TRAPS) { +ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct stat* st, + bool lazy, bool throw_exception, TRAPS) { JavaThread* thread = JavaThread::current(); if (lazy) { - return new LazyClassPathEntry(path, st); + return new LazyClassPathEntry(path, st, throw_exception); } ClassPathEntry* new_entry = NULL; if ((st->st_mode & S_IFREG) == S_IFREG) { @@ -474,7 +633,11 @@ ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct st char canonical_path[JVM_MAXPATHLEN]; if (!get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { // This matches the classic VM - THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL); + if (throw_exception) { + THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL); + } else { + return NULL; + } } char* error_msg = NULL; jzfile* zip; @@ -486,7 +649,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct st } if (zip != NULL && error_msg == NULL) { new_entry = new ClassPathZipEntry(zip, path); - if (TraceClassLoading) { + if (TraceClassLoading || TraceClassPaths) { tty->print_cr("[Opened %s]", path); } } else { @@ -500,12 +663,16 @@ ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct st msg = NEW_RESOURCE_ARRAY(char, len); ; jio_snprintf(msg, len - 1, "error in opening JAR file <%s> %s", error_msg, path); } - THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL); + if (throw_exception) { + THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL); + } else { + return NULL; + } } } else { // Directory new_entry = new ClassPathDirEntry(path); - if (TraceClassLoading) { + if (TraceClassLoading || TraceClassPaths) { tty->print_cr("[Path %s]", path); } } @@ -566,23 +733,37 @@ void ClassLoader::add_to_list(ClassPathEntry *new_entry) { _last_entry = new_entry; } } + _num_entries ++; } -void ClassLoader::update_class_path_entry_list(char *path, - bool check_for_duplicates) { +// Returns true IFF the file/dir exists and the entry was successfully created. +bool ClassLoader::update_class_path_entry_list(char *path, + bool check_for_duplicates, + bool throw_exception) { struct stat st; if (os::stat(path, &st) == 0) { // File or directory found ClassPathEntry* new_entry = NULL; Thread* THREAD = Thread::current(); - new_entry = create_class_path_entry(path, &st, LazyBootClassLoader, CHECK); + new_entry = create_class_path_entry(path, &st, LazyBootClassLoader, throw_exception, CHECK_(false)); + if (new_entry == NULL) { + return false; + } // The kernel VM adds dynamically to the end of the classloader path and // doesn't reorder the bootclasspath which would break java.lang.Package // (see PackageInfo). // Add new entry to linked list if (!check_for_duplicates || !contains_entry(new_entry)) { - add_to_list(new_entry); + ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry); } + return true; + } else { +#if INCLUDE_CDS + if (DumpSharedSpaces) { + _shared_paths_misc_info->add_nonexist_path(path); + } + return false; +#endif } } @@ -734,10 +915,10 @@ public: assert(n == number_of_entries(), "just checking"); } - void copy_table(char** top, char* end, PackageHashtable* table); + CDS_ONLY(void copy_table(char** top, char* end, PackageHashtable* table);) }; - +#if INCLUDE_CDS void PackageHashtable::copy_table(char** top, char* end, PackageHashtable* table) { // Copy (relocate) the table to the shared space. @@ -745,33 +926,30 @@ void PackageHashtable::copy_table(char** top, char* end, // Calculate the space needed for the package name strings. int i; - int n = 0; - for (i = 0; i < table_size(); ++i) { - for (PackageInfo* pp = table->bucket(i); - pp != NULL; - pp = pp->next()) { - n += (int)(strlen(pp->pkgname()) + 1); - } - } - if (*top + n + sizeof(intptr_t) >= end) { - report_out_of_shared_space(SharedMiscData); - } - - // Copy the table data (the strings) to the shared space. - n = align_size_up(n, sizeof(HeapWord)); - *(intptr_t*)(*top) = n; - *top += sizeof(intptr_t); + intptr_t* tableSize = (intptr_t*)(*top); + *top += sizeof(intptr_t); // For table size + char* tableStart = *top; for (i = 0; i < table_size(); ++i) { for (PackageInfo* pp = table->bucket(i); pp != NULL; pp = pp->next()) { int n1 = (int)(strlen(pp->pkgname()) + 1); + if (*top + n1 >= end) { + report_out_of_shared_space(SharedMiscData); + } pp->set_pkgname((char*)memcpy(*top, pp->pkgname(), n1)); *top += n1; } } *top = (char*)align_size_up((intptr_t)*top, sizeof(HeapWord)); + if (*top >= end) { + report_out_of_shared_space(SharedMiscData); + } + + // Write table size + intptr_t len = *top - (char*)tableStart; + *tableSize = len; } @@ -782,7 +960,7 @@ void ClassLoader::copy_package_info_buckets(char** top, char* end) { void ClassLoader::copy_package_info_table(char** top, char* end) { _package_hash_table->copy_table(top, end, _package_hash_table); } - +#endif PackageInfo* ClassLoader::lookup_package(const char *pkgname) { const char *cp = strrchr(pkgname, '/'); @@ -875,7 +1053,8 @@ objArrayOop ClassLoader::get_system_packages(TRAPS) { instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) { ResourceMark rm(THREAD); - EventMark m("loading class %s", h_name->as_C_string()); + const char* class_name = h_name->as_C_string(); + EventMark m("loading class %s", class_name); ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion); stringStream st; @@ -883,18 +1062,24 @@ instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) { // st.print("%s.class", h_name->as_utf8()); st.print_raw(h_name->as_utf8()); st.print_raw(".class"); - char* name = st.as_string(); + const char* file_name = st.as_string(); + ClassLoaderExt::Context context(class_name, file_name, THREAD); // Lookup stream for parsing .class file ClassFileStream* stream = NULL; int classpath_index = 0; + ClassPathEntry* e = NULL; + instanceKlassHandle h; { PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_LOAD); - ClassPathEntry* e = _first_entry; + e = _first_entry; while (e != NULL) { - stream = e->open_stream(name, CHECK_NULL); + stream = e->open_stream(file_name, CHECK_NULL); + if (!context.check(stream, classpath_index)) { + return h; // NULL + } if (stream != NULL) { break; } @@ -903,9 +1088,7 @@ instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) { } } - instanceKlassHandle h; if (stream != NULL) { - // class file found, parse it ClassFileParser parser(stream); ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); @@ -915,12 +1098,19 @@ instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) { loader_data, protection_domain, parsed_name, - false, - CHECK_(h)); - - // add to package table - if (add_package(name, classpath_index, THREAD)) { - h = result; + context.should_verify(classpath_index), + THREAD); + if (HAS_PENDING_EXCEPTION) { + ResourceMark rm; + if (DumpSharedSpaces) { + tty->print_cr("Preload Error: Failed to load %s", class_name); + } + return h; + } + h = context.record_result(classpath_index, e, result, THREAD); + } else { + if (DumpSharedSpaces) { + tty->print_cr("Preload Error: Cannot find %s", class_name); } } @@ -1015,14 +1205,27 @@ void ClassLoader::initialize() { // lookup zip library entry points load_zip_library(); +#if INCLUDE_CDS // initialize search path + if (DumpSharedSpaces) { + _shared_paths_misc_info = SharedClassUtil::allocate_shared_paths_misc_info(); + } +#endif setup_bootstrap_search_path(); if (LazyBootClassLoader) { // set up meta index which makes boot classpath initialization lazier - setup_meta_index(); + setup_bootstrap_meta_index(); } } +#if INCLUDE_CDS +void ClassLoader::initialize_shared_path() { + if (DumpSharedSpaces) { + ClassLoaderExt::setup_search_paths(); + _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check() + } +} +#endif jlong ClassLoader::classloader_time_ms() { return UsePerfData ? diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp index 2cfcde6387e..bd1fe24b6e2 100644 --- a/hotspot/src/share/vm/classfile/classLoader.hpp +++ b/hotspot/src/share/vm/classfile/classLoader.hpp @@ -107,6 +107,7 @@ class ClassPathZipEntry: public ClassPathEntry { const char* name() { return _zip_name; } ClassPathZipEntry(jzfile* zip, const char* zip_name); ~ClassPathZipEntry(); + u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS); ClassFileStream* open_stream(const char* name, TRAPS); void contents_do(void f(const char* name, void* context), void* context); // Debugging @@ -122,12 +123,16 @@ class LazyClassPathEntry: public ClassPathEntry { struct stat _st; MetaIndex* _meta_index; bool _has_error; + bool _throw_exception; volatile ClassPathEntry* _resolved_entry; ClassPathEntry* resolve_entry(TRAPS); public: bool is_jar_file(); const char* name() { return _path; } - LazyClassPathEntry(char* path, const struct stat* st); + LazyClassPathEntry(char* path, const struct stat* st, bool throw_exception); + virtual ~LazyClassPathEntry(); + u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS); + ClassFileStream* open_stream(const char* name, TRAPS); void set_meta_index(MetaIndex* meta_index) { _meta_index = meta_index; } virtual bool is_lazy(); @@ -138,6 +143,7 @@ class LazyClassPathEntry: public ClassPathEntry { class PackageHashtable; class PackageInfo; +class SharedPathsMiscInfo; template class HashtableBucket; class ClassLoader: AllStatic { @@ -145,7 +151,7 @@ class ClassLoader: AllStatic { enum SomeConstants { package_hash_table_size = 31 // Number of buckets }; - private: + protected: friend class LazyClassPathEntry; // Performance counters @@ -187,10 +193,15 @@ class ClassLoader: AllStatic { static ClassPathEntry* _first_entry; // Last entry in linked list of ClassPathEntry instances static ClassPathEntry* _last_entry; + static int _num_entries; + // Hash table used to keep track of loaded packages static PackageHashtable* _package_hash_table; static const char* _shared_archive; + // Info used by CDS + CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;) + // Hash function static unsigned int hash(const char *s, int n); // Returns the package file name corresponding to the specified package @@ -201,19 +212,23 @@ class ClassLoader: AllStatic { static bool add_package(const char *pkgname, int classpath_index, TRAPS); // Initialization - static void setup_meta_index(); + static void setup_bootstrap_meta_index(); + static void setup_meta_index(const char* meta_index_path, const char* meta_index_dir, + int start_index); static void setup_bootstrap_search_path(); + static void setup_search_path(char *class_path); + static void load_zip_library(); static ClassPathEntry* create_class_path_entry(char *path, const struct stat* st, - bool lazy, TRAPS); + bool lazy, bool throw_exception, TRAPS); // Canonicalizes path names, so strcmp will work properly. This is mainly // to avoid confusing the zip library static bool get_canonical_path(char* orig, char* out, int len); public: - // Used by the kernel jvm. - static void update_class_path_entry_list(char *path, - bool check_for_duplicates); + static bool update_class_path_entry_list(char *path, + bool check_for_duplicates, + bool throw_exception=true); static void print_bootclasspath(); // Timing @@ -296,6 +311,7 @@ class ClassLoader: AllStatic { // Initialization static void initialize(); + CDS_ONLY(static void initialize_shared_path();) static void create_package_info_table(); static void create_package_info_table(HashtableBucket *t, int length, int number_of_entries); @@ -310,10 +326,21 @@ class ClassLoader: AllStatic { return e; } +#if INCLUDE_CDS // Sharing dump and restore static void copy_package_info_buckets(char** top, char* end); static void copy_package_info_table(char** top, char* end); + static void check_shared_classpath(const char *path); + static void finalize_shared_paths_misc_info(); + static int get_shared_paths_misc_info_size(); + static void* get_shared_paths_misc_info(); + static bool check_shared_paths_misc_info(void* info, int size); + static void exit_with_path_failure(const char* error, const char* message); +#endif + + static void trace_class_path(const char* msg, const char* name = NULL); + // VM monitoring and management support static jlong classloader_time_ms(); static jlong class_method_total_size(); @@ -337,7 +364,7 @@ class ClassLoader: AllStatic { // Force compilation of all methods in all classes in bootstrap class path (stress test) #ifndef PRODUCT - private: + protected: static int _compile_the_world_class_counter; static int _compile_the_world_method_counter; public: diff --git a/hotspot/src/share/vm/classfile/classLoaderExt.hpp b/hotspot/src/share/vm/classfile/classLoaderExt.hpp new file mode 100644 index 00000000000..ed3eda08e9a --- /dev/null +++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp @@ -0,0 +1,69 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP +#define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP + +#include "classfile/classLoader.hpp" + +class ClassLoaderExt: public ClassLoader { // AllStatic +public: + + class Context { + const char* _file_name; + public: + Context(const char* class_name, const char* file_name, TRAPS) { + _file_name = file_name; + } + + bool check(ClassFileStream* stream, const int classpath_index) { + return true; + } + + bool should_verify(int classpath_index) { + return false; + } + + instanceKlassHandle record_result(const int classpath_index, + ClassPathEntry* e, instanceKlassHandle result, TRAPS) { + if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) { + if (DumpSharedSpaces) { + result->set_shared_classpath_index(classpath_index); + } + return result; + } else { + return instanceKlassHandle(); // NULL + } + } + }; + + + static void add_class_path_entry(char* path, bool check_for_duplicates, + ClassPathEntry* new_entry) { + ClassLoader::add_to_list(new_entry); + } + static void setup_search_paths() {} +}; + +#endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP diff --git a/hotspot/src/share/vm/classfile/dictionary.cpp b/hotspot/src/share/vm/classfile/dictionary.cpp index dcb295687aa..37381afbd65 100644 --- a/hotspot/src/share/vm/classfile/dictionary.cpp +++ b/hotspot/src/share/vm/classfile/dictionary.cpp @@ -130,15 +130,13 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, oop protection_dom } -bool Dictionary::do_unloading() { +void Dictionary::do_unloading() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - bool class_was_unloaded = false; - int index = 0; // Defined here for portability! Do not move // Remove unloadable entries and classes from system dictionary // The placeholder array has been handled in always_strong_oops_do. DictionaryEntry* probe = NULL; - for (index = 0; index < table_size(); index++) { + for (int index = 0; index < table_size(); index++) { for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) { probe = *p; Klass* e = probe->klass(); @@ -158,16 +156,8 @@ bool Dictionary::do_unloading() { // Do we need to delete this system dictionary entry? if (loader_data->is_unloading()) { // If the loader is not live this entry should always be - // removed (will never be looked up again). Note that this is - // not the same as unloading the referred class. - if (k_def_class_loader_data == loader_data) { - // This is the defining entry, so the referred class is about - // to be unloaded. - class_was_unloaded = true; - } - // Also remove this system dictionary entry. + // removed (will never be looked up again). purge_entry = true; - } else { // The loader in this entry is alive. If the klass is dead, // (determined by checking the defining class loader) @@ -196,7 +186,6 @@ bool Dictionary::do_unloading() { p = probe->next_addr(); } } - return class_was_unloaded; } void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) { @@ -220,6 +209,29 @@ void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) { _pd_cache_table->roots_oops_do(strong, weak); } +void Dictionary::remove_classes_in_error_state() { + assert(DumpSharedSpaces, "supported only when dumping"); + DictionaryEntry* probe = NULL; + for (int index = 0; index < table_size(); index++) { + for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) { + probe = *p; + InstanceKlass* ik = InstanceKlass::cast(probe->klass()); + if (ik->is_in_error_state()) { // purge this entry + *p = probe->next(); + if (probe == _current_class_entry) { + _current_class_entry = NULL; + } + free_entry(probe); + ResourceMark rm; + tty->print_cr("Removed error class: %s", ik->external_name()); + continue; + } + + p = probe->next_addr(); + } + } +} + void Dictionary::always_strong_oops_do(OopClosure* blk) { // Follow all system classes and temporary placeholders in dictionary; only // protection domain oops contain references into the heap. In a first @@ -693,16 +705,17 @@ void SymbolPropertyTable::methods_do(void f(Method*)) { // ---------------------------------------------------------------------------- -#ifndef PRODUCT -void Dictionary::print() { +void Dictionary::print(bool details) { ResourceMark rm; HandleMark hm; - tty->print_cr("Java system dictionary (table_size=%d, classes=%d)", - table_size(), number_of_entries()); - tty->print_cr("^ indicates that initiating loader is different from " - "defining loader"); + if (details) { + tty->print_cr("Java system dictionary (table_size=%d, classes=%d)", + table_size(), number_of_entries()); + tty->print_cr("^ indicates that initiating loader is different from " + "defining loader"); + } for (int index = 0; index < table_size(); index++) { for (DictionaryEntry* probe = bucket(index); @@ -713,21 +726,28 @@ void Dictionary::print() { ClassLoaderData* loader_data = probe->loader_data(); bool is_defining_class = (loader_data == InstanceKlass::cast(e)->class_loader_data()); - tty->print("%s%s", is_defining_class ? " " : "^", + tty->print("%s%s", ((!details) || is_defining_class) ? " " : "^", e->external_name()); + if (details) { tty->print(", loader "); - loader_data->print_value(); + if (loader_data != NULL) { + loader_data->print_value(); + } else { + tty->print("NULL"); + } + } tty->cr(); } } - tty->cr(); - _pd_cache_table->print(); + + if (details) { + tty->cr(); + _pd_cache_table->print(); + } tty->cr(); } -#endif - void Dictionary::verify() { guarantee(number_of_entries() >= 0, "Verify of system dictionary failed"); diff --git a/hotspot/src/share/vm/classfile/dictionary.hpp b/hotspot/src/share/vm/classfile/dictionary.hpp index 042772f45cc..180f07e9e01 100644 --- a/hotspot/src/share/vm/classfile/dictionary.hpp +++ b/hotspot/src/share/vm/classfile/dictionary.hpp @@ -100,6 +100,7 @@ public: void methods_do(void f(Method*)); void unlink(BoolObjectClosure* is_alive); + void remove_classes_in_error_state(); // Classes loaded by the bootstrap loader are always strongly reachable. // If we're not doing class unloading, all classes are strongly reachable. @@ -108,9 +109,8 @@ public: return (loader_data->is_the_null_class_loader_data() || !ClassUnloading); } - // Unload (that is, break root links to) all unmarked classes and - // loaders. Returns "true" iff something was unloaded. - bool do_unloading(); + // Unload (that is, break root links to) all unmarked classes and loaders. + void do_unloading(); // Protection domains Klass* find(int index, unsigned int hash, Symbol* name, @@ -127,9 +127,7 @@ public: ProtectionDomainCacheEntry* cache_get(oop protection_domain); -#ifndef PRODUCT - void print(); -#endif + void print(bool details = true); void verify(); }; diff --git a/hotspot/src/share/vm/classfile/sharedClassUtil.hpp b/hotspot/src/share/vm/classfile/sharedClassUtil.hpp new file mode 100644 index 00000000000..13be2b1b5de --- /dev/null +++ b/hotspot/src/share/vm/classfile/sharedClassUtil.hpp @@ -0,0 +1,69 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_CLASSFILE_SHAREDCLASSUTIL_HPP +#define SHARE_VM_CLASSFILE_SHAREDCLASSUTIL_HPP + +#include "classfile/sharedPathsMiscInfo.hpp" +#include "memory/filemap.hpp" + +class SharedClassUtil : AllStatic { +public: + + static SharedPathsMiscInfo* allocate_shared_paths_misc_info() { + return new SharedPathsMiscInfo(); + } + + static SharedPathsMiscInfo* allocate_shared_paths_misc_info(char* buf, int size) { + return new SharedPathsMiscInfo(buf, size); + } + + static FileMapInfo::FileMapHeader* allocate_file_map_header() { + return new FileMapInfo::FileMapHeader(); + } + + static size_t file_map_header_size() { + return sizeof(FileMapInfo::FileMapHeader); + } + + static size_t shared_class_path_entry_size() { + return sizeof(SharedClassPathEntry); + } + + static void update_shared_classpath(ClassPathEntry *cpe, + SharedClassPathEntry* ent, + time_t timestamp, + long filesize, TRAPS) { + ent->_timestamp = timestamp; + ent->_filesize = filesize; + } + + static void initialize(TRAPS) {} + + inline static bool is_shared_boot_class(Klass* klass) { + return (klass->_shared_class_path_index >= 0); + } +}; + +#endif // SHARE_VM_CLASSFILE_SHAREDCLASSUTIL_HPP diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp new file mode 100644 index 00000000000..c988abdf9da --- /dev/null +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp @@ -0,0 +1,154 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "classfile/classLoader.hpp" +#include "classfile/classLoaderData.inline.hpp" +#include "classfile/sharedPathsMiscInfo.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/metaspaceShared.hpp" +#include "runtime/arguments.hpp" + +void SharedPathsMiscInfo::add_path(const char* path, int type) { + if (TraceClassPaths) { + tty->print("[type=%s] ", type_name(type)); + trace_class_path("[Add misc shared path ", path); + } + write(path, strlen(path) + 1); + write_jint(jint(type)); +} + +void SharedPathsMiscInfo::ensure_size(size_t needed_bytes) { + assert(_allocated, "cannot modify buffer during validation."); + int used = get_used_bytes(); + int target = used + int(needed_bytes); + if (target > _buf_size) { + _buf_size = _buf_size * 2 + (int)needed_bytes; + _buf_start = REALLOC_C_HEAP_ARRAY(char, _buf_start, _buf_size, mtClass); + _cur_ptr = _buf_start + used; + _end_ptr = _buf_start + _buf_size; + } +} + +void SharedPathsMiscInfo::write(const void* ptr, size_t size) { + ensure_size(size); + memcpy(_cur_ptr, ptr, size); + _cur_ptr += size; +} + +bool SharedPathsMiscInfo::read(void* ptr, size_t size) { + if (_cur_ptr + size <= _end_ptr) { + memcpy(ptr, _cur_ptr, size); + _cur_ptr += size; + return true; + } + return false; +} + +bool SharedPathsMiscInfo::fail(const char* msg, const char* name) { + ClassLoader::trace_class_path(msg, name); + MetaspaceShared::set_archive_loading_failed(); + return false; +} + +bool SharedPathsMiscInfo::check() { + // The whole buffer must be 0 terminated so that we can use strlen and strcmp + // without fear. + _end_ptr -= sizeof(jint); + if (_cur_ptr >= _end_ptr) { + return fail("Truncated archive file header"); + } + if (*_end_ptr != 0) { + return fail("Corrupted archive file header"); + } + + while (_cur_ptr < _end_ptr) { + jint type; + const char* path = _cur_ptr; + _cur_ptr += strlen(path) + 1; + if (!read_jint(&type)) { + return fail("Corrupted archive file header"); + } + if (TraceClassPaths) { + tty->print("[type=%s ", type_name(type)); + print_path(tty, type, path); + tty->print_cr("]"); + } + if (!check(type, path)) { + if (!PrintSharedArchiveAndExit) { + return false; + } + } else { + trace_class_path("[ok"); + } + } + + return true; +} + +bool SharedPathsMiscInfo::check(jint type, const char* path) { + switch (type) { + case BOOT: + if (strcmp(path, Arguments::get_sysclasspath()) != 0) { + return fail("[BOOT classpath mismatch, actual: -Dsun.boot.class.path=", Arguments::get_sysclasspath()); + } + break; + case NON_EXIST: // fall-through + case REQUIRED: + { + struct stat st; + if (os::stat(path, &st) != 0) { + // The file does not actually exist + if (type == REQUIRED) { + // but we require it to exist -> fail + return fail("Required file doesn't exist"); + } + } else { + // The file actually exists + if (type == NON_EXIST) { + // But we want it to not exist -> fail + return fail("File must not exist"); + } + time_t timestamp; + long filesize; + + if (!read_time(×tamp) || !read_long(&filesize)) { + return fail("Corrupted archive file header"); + } + if (timestamp != st.st_mtime) { + return fail("Timestamp mismatch"); + } + if (filesize != st.st_size) { + return fail("File size mismatch"); + } + } + } + break; + + default: + return fail("Corrupted archive file header"); + } + + return true; +} diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp new file mode 100644 index 00000000000..78b09256218 --- /dev/null +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp @@ -0,0 +1,187 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_CLASSFILE_SHAREDPATHSMISCINFO_HPP +#define SHARE_VM_CLASSFILE_SHAREDPATHSMISCINFO_HPP + +#include "runtime/os.hpp" + +// During dumping time, when processing class paths, we build up the dump-time +// classpath. The JAR files that exist are stored in the list ClassLoader::_first_entry. +// However, we need to store other "misc" information for run-time checking, such as +// +// + The values of Arguments::get_sysclasspath() used during dumping. +// +// + The meta-index file(s) used during dumping (incl modification time and size) +// +// + The class path elements specified during dumping but did not exist -- +// these elements must also be specified at run time, and they also must not +// exist at run time. +// +// These misc items are stored in a linear buffer in SharedPathsMiscInfo. +// The storage format is stream oriented to minimize its size. +// +// When writing the information to the archive file, SharedPathsMiscInfo is stored in +// the archive file header. At run-time, this information is used only during initialization +// (accessed using read() instead of mmap()), and is deallocated afterwards to save space. +// +// The SharedPathsMiscInfo class is used for both creating the the information (during +// dumping time) and validation (at run time). Different constructors are used in the +// two situations. See below. + +class SharedPathsMiscInfo : public CHeapObj { +protected: + char* _buf_start; + char* _cur_ptr; + char* _end_ptr; + int _buf_size; + bool _allocated; // was _buf_start allocated by me? + void ensure_size(size_t needed_bytes); + void add_path(const char* path, int type); + + void write(const void* ptr, size_t size); + bool read(void* ptr, size_t size); + + static void trace_class_path(const char* msg, const char* name = NULL) { + ClassLoader::trace_class_path(msg, name); + } +protected: + static bool fail(const char* msg, const char* name = NULL); + virtual bool check(jint type, const char* path); + +public: + enum { + INITIAL_BUF_SIZE = 128 + }; + // This constructor is used when creating the misc information (during dump) + SharedPathsMiscInfo() { + _buf_size = INITIAL_BUF_SIZE; + _cur_ptr = _buf_start = NEW_C_HEAP_ARRAY(char, _buf_size, mtClass); + _allocated = true; + } + // This constructor is used when validating the misc info (during run time) + SharedPathsMiscInfo(char *buff, int size) { + _cur_ptr = _buf_start = buff; + _end_ptr = _buf_start + size; + _buf_size = size; + _allocated = false; + } + ~SharedPathsMiscInfo() { + if (_allocated) { + FREE_C_HEAP_ARRAY(char, _buf_start, mtClass); + } + } + int get_used_bytes() { + return _cur_ptr - _buf_start; + } + void* buffer() { + return _buf_start; + } + + // writing -- + + // The path must not exist at run-time + void add_nonexist_path(const char* path) { + add_path(path, NON_EXIST); + } + + // The path must exist and have required size and modification time + void add_required_file(const char* path) { + add_path(path, REQUIRED); + + struct stat st; + if (os::stat(path, &st) != 0) { + assert(0, "sanity"); + ClassLoader::exit_with_path_failure("failed to os::stat(%s)", path); // should not happen + } + write_time(st.st_mtime); + write_long(st.st_size); + } + + // The path must exist, and must contain exactly files/dirs + void add_boot_classpath(const char* path) { + add_path(path, BOOT); + } + int write_jint(jint num) { + write(&num, sizeof(num)); + return 0; + } + void write_time(time_t t) { + write(&t, sizeof(t)); + } + void write_long(long l) { + write(&l, sizeof(l)); + } + + bool dump_to_file(int fd) { + int n = get_used_bytes(); + return (os::write(fd, _buf_start, n) == (size_t)n); + } + + // reading -- + + enum { + BOOT = 1, + NON_EXIST = 2, + REQUIRED = 3 + }; + + virtual const char* type_name(int type) { + switch (type) { + case BOOT: return "BOOT"; + case NON_EXIST: return "NON_EXIST"; + case REQUIRED: return "REQUIRED"; + default: ShouldNotReachHere(); return "?"; + } + } + + virtual void print_path(outputStream* out, int type, const char* path) { + switch (type) { + case BOOT: + out->print("Expecting -Dsun.boot.class.path=%s", path); + break; + case NON_EXIST: + out->print("Expecting that %s does not exist", path); + break; + case REQUIRED: + out->print("Expecting that file %s must exist and not altered", path); + break; + default: + ShouldNotReachHere(); + } + } + + bool check(); + bool read_jint(jint *ptr) { + return read(ptr, sizeof(jint)); + } + bool read_long(long *ptr) { + return read(ptr, sizeof(long)); + } + bool read_time(time_t *ptr) { + return read(ptr, sizeof(time_t)); + } +}; + +#endif // SHARE_VM_CLASSFILE_SHAREDPATHSMISCINFO_HPP diff --git a/hotspot/src/share/vm/classfile/stackMapFrame.cpp b/hotspot/src/share/vm/classfile/stackMapFrame.cpp index c3f69463c48..9cb1d307a52 100644 --- a/hotspot/src/share/vm/classfile/stackMapFrame.cpp +++ b/hotspot/src/share/vm/classfile/stackMapFrame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -54,21 +54,6 @@ StackMapFrame* StackMapFrame::frame_in_exception_handler(u1 flags) { return frame; } -bool StackMapFrame::has_new_object() const { - int32_t i; - for (i = 0; i < _max_locals; i++) { - if (_locals[i].is_uninitialized()) { - return true; - } - } - for (i = 0; i < _stack_size; i++) { - if (_stack[i].is_uninitialized()) { - return true; - } - } - return false; -} - void StackMapFrame::initialize_object( VerificationType old_object, VerificationType new_object) { int32_t i; diff --git a/hotspot/src/share/vm/classfile/stackMapFrame.hpp b/hotspot/src/share/vm/classfile/stackMapFrame.hpp index 237accec0d4..53582c1673c 100644 --- a/hotspot/src/share/vm/classfile/stackMapFrame.hpp +++ b/hotspot/src/share/vm/classfile/stackMapFrame.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -154,10 +154,6 @@ class StackMapFrame : public ResourceObj { VerificationType set_locals_from_arg( const methodHandle m, VerificationType thisKlass, TRAPS); - // Search local variable type array and stack type array. - // Return true if an uninitialized object is found. - bool has_new_object() const; - // Search local variable type array and stack type array. // Set every element with type of old_object to new_object. void initialize_object( diff --git a/hotspot/src/share/vm/classfile/stackMapTable.cpp b/hotspot/src/share/vm/classfile/stackMapTable.cpp index feb5ae250d2..f74adbe3172 100644 --- a/hotspot/src/share/vm/classfile/stackMapTable.cpp +++ b/hotspot/src/share/vm/classfile/stackMapTable.cpp @@ -70,24 +70,26 @@ int StackMapTable::get_index_from_offset(int32_t offset) const { bool StackMapTable::match_stackmap( StackMapFrame* frame, int32_t target, - bool match, bool update, ErrorContext* ctx, TRAPS) const { + bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const { int index = get_index_from_offset(target); - return match_stackmap(frame, target, index, match, update, ctx, THREAD); + return match_stackmap(frame, target, index, match, update, handler, ctx, THREAD); } // Match and/or update current_frame to the frame in stackmap table with // specified offset and frame index. Return true if the two frames match. +// handler is true if the frame in stackmap_table is for an exception handler. // -// The values of match and update are: _match__update_ +// The values of match and update are: _match__update__handler // -// checking a branch target/exception handler: true false +// checking a branch target: true false false +// checking an exception handler: true false true // linear bytecode verification following an -// unconditional branch: false true +// unconditional branch: false true false // linear bytecode verification not following an -// unconditional branch: true true +// unconditional branch: true true false bool StackMapTable::match_stackmap( StackMapFrame* frame, int32_t target, int32_t frame_index, - bool match, bool update, ErrorContext* ctx, TRAPS) const { + bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const { if (frame_index < 0 || frame_index >= _frame_count) { *ctx = ErrorContext::missing_stackmap(frame->offset()); frame->verifier()->verify_error( @@ -98,11 +100,9 @@ bool StackMapTable::match_stackmap( StackMapFrame *stackmap_frame = _frame_array[frame_index]; bool result = true; if (match) { - // when checking handler target, match == true && update == false - bool is_exception_handler = !update; // Has direct control flow from last instruction, need to match the two // frames. - result = frame->is_assignable_to(stackmap_frame, is_exception_handler, + result = frame->is_assignable_to(stackmap_frame, handler, ctx, CHECK_VERIFY_(frame->verifier(), result)); } if (update) { @@ -126,24 +126,10 @@ void StackMapTable::check_jump_target( StackMapFrame* frame, int32_t target, TRAPS) const { ErrorContext ctx; bool match = match_stackmap( - frame, target, true, false, &ctx, CHECK_VERIFY(frame->verifier())); + frame, target, true, false, false, &ctx, CHECK_VERIFY(frame->verifier())); if (!match || (target < 0 || target >= _code_length)) { frame->verifier()->verify_error(ctx, "Inconsistent stackmap frames at branch target %d", target); - return; - } - // check if uninitialized objects exist on backward branches - check_new_object(frame, target, CHECK_VERIFY(frame->verifier())); - frame->verifier()->update_furthest_jump(target); -} - -void StackMapTable::check_new_object( - const StackMapFrame* frame, int32_t target, TRAPS) const { - if (frame->offset() > target && frame->has_new_object()) { - frame->verifier()->verify_error( - ErrorContext::bad_code(frame->offset()), - "Uninitialized object exists on backward branch %d", target); - return; } } diff --git a/hotspot/src/share/vm/classfile/stackMapTable.hpp b/hotspot/src/share/vm/classfile/stackMapTable.hpp index 385aef3a7e6..590adda5f67 100644 --- a/hotspot/src/share/vm/classfile/stackMapTable.hpp +++ b/hotspot/src/share/vm/classfile/stackMapTable.hpp @@ -60,12 +60,12 @@ class StackMapTable : public StackObj { // specified offset. Return true if the two frames match. bool match_stackmap( StackMapFrame* current_frame, int32_t offset, - bool match, bool update, ErrorContext* ctx, TRAPS) const; + bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const; // Match and/or update current_frame to the frame in stackmap table with // specified offset and frame index. Return true if the two frames match. bool match_stackmap( StackMapFrame* current_frame, int32_t offset, int32_t frame_index, - bool match, bool update, ErrorContext* ctx, TRAPS) const; + bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const; // Check jump instructions. Make sure there are no uninitialized // instances on backward branch. @@ -76,10 +76,6 @@ class StackMapTable : public StackObj { // Returns the frame array index where the frame with offset is stored. int get_index_from_offset(int32_t offset) const; - // Make sure that there's no uninitialized object exist on backward branch. - void check_new_object( - const StackMapFrame* frame, int32_t target, TRAPS) const; - void print_on(outputStream* str) const; }; diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index 00761e478ad..d688235f1f5 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -70,9 +70,9 @@ Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS void SymbolTable::initialize_symbols(int arena_alloc_size) { // Initialize the arena for global symbols, size passed in depends on CDS. if (arena_alloc_size == 0) { - _arena = new (mtSymbol) Arena(); + _arena = new (mtSymbol) Arena(mtSymbol); } else { - _arena = new (mtSymbol) Arena(arena_alloc_size); + _arena = new (mtSymbol) Arena(mtSymbol, arena_alloc_size); } } diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 3b058b5a625..e794d93a778 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -31,10 +31,15 @@ #include "classfile/resolutionErrors.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" +#if INCLUDE_CDS +#include "classfile/sharedClassUtil.hpp" +#include "classfile/systemDictionaryShared.hpp" +#endif #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/interpreter.hpp" +#include "memory/filemap.hpp" #include "memory/gcLocker.hpp" #include "memory/oopFactory.hpp" #include "oops/instanceKlass.hpp" @@ -110,6 +115,8 @@ void SystemDictionary::compute_java_system_loader(TRAPS) { CHECK); _java_system_loader = (oop)result.get_jobject(); + + CDS_ONLY(SystemDictionaryShared::initialize(CHECK);) } @@ -974,6 +981,7 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name, // Create a new CLD for anonymous class, that uses the same class loader // as the host_klass guarantee(host_klass->class_loader() == class_loader(), "should be the same"); + guarantee(!DumpSharedSpaces, "must not create anonymous classes when dumping"); loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL); loader_data->record_dependency(host_klass(), CHECK_NULL); } else { @@ -1134,7 +1142,7 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name, return k(); } - +#if INCLUDE_CDS void SystemDictionary::set_shared_dictionary(HashtableBucket* t, int length, int number_of_entries) { assert(length == _nof_buckets * sizeof(HashtableBucket), @@ -1167,15 +1175,21 @@ Klass* SystemDictionary::find_shared_class(Symbol* class_name) { instanceKlassHandle SystemDictionary::load_shared_class( Symbol* class_name, Handle class_loader, TRAPS) { instanceKlassHandle ik (THREAD, find_shared_class(class_name)); - return load_shared_class(ik, class_loader, THREAD); + // Make sure we only return the boot class for the NULL classloader. + if (ik.not_null() && + SharedClassUtil::is_shared_boot_class(ik()) && class_loader.is_null()) { + Handle protection_domain; + return load_shared_class(ik, class_loader, protection_domain, THREAD); + } + return instanceKlassHandle(); } -instanceKlassHandle SystemDictionary::load_shared_class( - instanceKlassHandle ik, Handle class_loader, TRAPS) { - assert(class_loader.is_null(), "non-null classloader for shared class?"); +instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, + Handle class_loader, + Handle protection_domain, TRAPS) { if (ik.not_null()) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle - Symbol* class_name = ik->name(); + Symbol* class_name = ik->name(); // Found the class, now load the superclass and interfaces. If they // are shared, add them to the main system dictionary and reset @@ -1184,7 +1198,7 @@ instanceKlassHandle SystemDictionary::load_shared_class( if (ik->super() != NULL) { Symbol* cn = ik->super()->name(); resolve_super_or_fail(class_name, cn, - class_loader, Handle(), true, CHECK_(nh)); + class_loader, protection_domain, true, CHECK_(nh)); } Array* interfaces = ik->local_interfaces(); @@ -1197,7 +1211,7 @@ instanceKlassHandle SystemDictionary::load_shared_class( // reinitialized yet (they will be once the interface classes // are loaded) Symbol* name = k->name(); - resolve_super_or_fail(class_name, name, class_loader, Handle(), false, CHECK_(nh)); + resolve_super_or_fail(class_name, name, class_loader, protection_domain, false, CHECK_(nh)); } // Adjust methods to recover missing data. They need addresses for @@ -1206,30 +1220,47 @@ instanceKlassHandle SystemDictionary::load_shared_class( // Updating methods must be done under a lock so multiple // threads don't update these in parallel - // Shared classes are all currently loaded by the bootstrap - // classloader, so this will never cause a deadlock on - // a custom class loader lock. + // + // Shared classes are all currently loaded by either the bootstrap or + // internal parallel class loaders, so this will never cause a deadlock + // on a custom class loader lock. + ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); { Handle lockObject = compute_loader_lock_object(class_loader, THREAD); check_loader_lock_contention(lockObject, THREAD); ObjectLocker ol(lockObject, THREAD, true); - ik->restore_unshareable_info(CHECK_(nh)); + ik->restore_unshareable_info(loader_data, protection_domain, CHECK_(nh)); } if (TraceClassLoading) { ResourceMark rm; tty->print("[Loaded %s", ik->external_name()); tty->print(" from shared objects file"); + if (class_loader.not_null()) { + tty->print(" by %s", loader_data->loader_name()); + } tty->print_cr("]"); } + +#if INCLUDE_CDS + if (DumpLoadedClassList != NULL && classlist_file->is_open()) { + // Only dump the classes that can be stored into CDS archive + if (SystemDictionaryShared::is_sharing_possible(loader_data)) { + ResourceMark rm(THREAD); + classlist_file->print_cr("%s", ik->name()->as_C_string()); + classlist_file->flush(); + } + } +#endif + // notify a class loaded from shared object ClassLoadingService::notify_class_loaded(InstanceKlass::cast(ik()), true /* shared class */); } return ik; } - +#endif instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle @@ -1239,8 +1270,10 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Ha // shared spaces. instanceKlassHandle k; { +#if INCLUDE_CDS PerfTraceTime vmtimer(ClassLoader::perf_shared_classload_time()); k = load_shared_class(class_name, class_loader, THREAD); +#endif } if (k.is_null()) { @@ -1599,7 +1632,6 @@ void SystemDictionary::add_to_hierarchy(instanceKlassHandle k, TRAPS) { Universe::flush_dependents_on(k); } - // ---------------------------------------------------------------------------- // GC support @@ -1661,10 +1693,9 @@ public: // Note: anonymous classes are not in the SD. bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) { // First, mark for unload all ClassLoaderData referencing a dead class loader. - bool has_dead_loaders = ClassLoaderDataGraph::do_unloading(is_alive); - bool unloading_occurred = false; - if (has_dead_loaders) { - unloading_occurred = dictionary()->do_unloading(); + bool unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive); + if (unloading_occurred) { + dictionary()->do_unloading(); constraints()->purge_loader_constraints(); resolution_errors()->purge_resolution_errors(); } @@ -1682,6 +1713,7 @@ bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) { void SystemDictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) { strong->do_oop(&_java_system_loader); strong->do_oop(&_system_loader_lock_obj); + CDS_ONLY(SystemDictionaryShared::roots_oops_do(strong);) // Adjust dictionary dictionary()->roots_oops_do(strong, weak); @@ -1693,6 +1725,7 @@ void SystemDictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) { void SystemDictionary::oops_do(OopClosure* f) { f->do_oop(&_java_system_loader); f->do_oop(&_system_loader_lock_obj); + CDS_ONLY(SystemDictionaryShared::oops_do(f);) // Adjust dictionary dictionary()->oops_do(f); @@ -1754,6 +1787,10 @@ void SystemDictionary::methods_do(void f(Method*)) { invoke_method_table()->methods_do(f); } +void SystemDictionary::remove_classes_in_error_state() { + dictionary()->remove_classes_in_error_state(); +} + // ---------------------------------------------------------------------------- // Lazily load klasses @@ -2563,10 +2600,12 @@ int SystemDictionary::number_of_classes() { // ---------------------------------------------------------------------------- -#ifndef PRODUCT +void SystemDictionary::print_shared(bool details) { + shared_dictionary()->print(details); +} -void SystemDictionary::print() { - dictionary()->print(); +void SystemDictionary::print(bool details) { + dictionary()->print(details); // Placeholders GCMutexLocker mu(SystemDictionary_lock); @@ -2576,7 +2615,6 @@ void SystemDictionary::print() { constraints()->print(); } -#endif void SystemDictionary::verify() { guarantee(dictionary() != NULL, "Verify of system dictionary failed"); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index f46f67bd9b5..33ecc83480b 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -111,6 +111,7 @@ class Ticks; do_klass(SecurityManager_klass, java_lang_SecurityManager, Pre ) \ do_klass(ProtectionDomain_klass, java_security_ProtectionDomain, Pre ) \ do_klass(AccessControlContext_klass, java_security_AccessControlContext, Pre ) \ + do_klass(SecureClassLoader_klass, java_security_SecureClassLoader, Pre ) \ do_klass(ClassNotFoundException_klass, java_lang_ClassNotFoundException, Pre ) \ do_klass(NoClassDefFoundError_klass, java_lang_NoClassDefFoundError, Pre ) \ do_klass(LinkageError_klass, java_lang_LinkageError, Pre ) \ @@ -166,6 +167,15 @@ class Ticks; do_klass(StringBuilder_klass, java_lang_StringBuilder, Pre ) \ do_klass(misc_Unsafe_klass, sun_misc_Unsafe, Pre ) \ \ + /* support for CDS */ \ + do_klass(ByteArrayInputStream_klass, java_io_ByteArrayInputStream, Pre ) \ + do_klass(File_klass, java_io_File, Pre ) \ + do_klass(URLClassLoader_klass, java_net_URLClassLoader, Pre ) \ + do_klass(URL_klass, java_net_URL, Pre ) \ + do_klass(Jar_Manifest_klass, java_util_jar_Manifest, Pre ) \ + do_klass(sun_misc_Launcher_klass, sun_misc_Launcher, Pre ) \ + do_klass(CodeSource_klass, java_security_CodeSource, Pre ) \ + \ /* It's NULL in non-1.4 JDKs. */ \ do_klass(StackTraceElement_klass, java_lang_StackTraceElement, Opt ) \ /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ @@ -221,7 +231,7 @@ class SystemDictionary : AllStatic { static Klass* resolve_or_fail(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, TRAPS); // Convenient call for null loader and protection domain. static Klass* resolve_or_fail(Symbol* class_name, bool throw_error, TRAPS); -private: +protected: // handle error translation for resolve_or_null results static Klass* handle_resolution_exception(Symbol* class_name, bool throw_error, KlassHandle klass_h, TRAPS); @@ -326,6 +336,9 @@ public: // loaders. Returns "true" iff something was unloaded. static bool do_unloading(BoolObjectClosure* is_alive); + // Used by DumpSharedSpaces only to remove classes that failed verification + static void remove_classes_in_error_state(); + static int calculate_systemdictionary_size(int loadedclasses); // Applies "f->do_oop" to all root oops in the system dictionary. @@ -335,7 +348,7 @@ public: // System loader lock static oop system_loader_lock() { return _system_loader_lock_obj; } -private: +protected: // Extended Redefine classes support (tbi) static void preloaded_classes_do(KlassClosure* f); static void lazily_loaded_classes_do(KlassClosure* f); @@ -348,7 +361,8 @@ public: static void set_shared_dictionary(HashtableBucket* t, int length, int number_of_entries); // Printing - static void print() PRODUCT_RETURN; + static void print(bool details = true); + static void print_shared(bool details = true); static void print_class_statistics() PRODUCT_RETURN; static void print_method_statistics() PRODUCT_RETURN; @@ -424,7 +438,7 @@ public: static void load_abstract_ownable_synchronizer_klass(TRAPS); -private: +protected: // Tells whether ClassLoader.loadClassInternal is present static bool has_loadClassInternal() { return _has_loadClassInternal; } @@ -452,7 +466,7 @@ public: // Register a new class loader static ClassLoaderData* register_loader(Handle class_loader, TRAPS); -private: +protected: // Mirrors for primitive classes (created eagerly) static oop check_mirror(oop m) { assert(m != NULL, "mirror not initialized"); @@ -523,7 +537,7 @@ public: static Symbol* find_resolution_error(constantPoolHandle pool, int which, Symbol** message); - private: + protected: enum Constants { _loader_constraint_size = 107, // number of entries in constraint table @@ -574,7 +588,7 @@ public: friend class CounterDecay; static Klass* try_get_next_class(); -private: +protected: static void validate_protection_domain(instanceKlassHandle klass, Handle class_loader, Handle protection_domain, TRAPS); @@ -601,10 +615,10 @@ private: static instanceKlassHandle find_or_define_instance_class(Symbol* class_name, Handle class_loader, instanceKlassHandle k, TRAPS); - static instanceKlassHandle load_shared_class(Symbol* class_name, - Handle class_loader, TRAPS); static instanceKlassHandle load_shared_class(instanceKlassHandle ik, - Handle class_loader, TRAPS); + Handle class_loader, + Handle protection_domain, + TRAPS); static instanceKlassHandle load_instance_class(Symbol* class_name, Handle class_loader, TRAPS); static Handle compute_loader_lock_object(Handle class_loader, TRAPS); static void check_loader_lock_contention(Handle loader_lock, TRAPS); @@ -612,9 +626,12 @@ private: static bool is_parallelDefine(Handle class_loader); public: + static instanceKlassHandle load_shared_class(Symbol* class_name, + Handle class_loader, + TRAPS); static bool is_ext_class_loader(Handle class_loader); -private: +protected: static Klass* find_shared_class(Symbol* class_name); // Setup link to hierarchy diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp new file mode 100644 index 00000000000..bc688798ce8 --- /dev/null +++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp @@ -0,0 +1,47 @@ +/* + * 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. + * + */ + + +#ifndef SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP +#define SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP + +#include "classfile/systemDictionary.hpp" + +class SystemDictionaryShared: public SystemDictionary { +public: + static void initialize(TRAPS) {} + static instanceKlassHandle find_or_load_shared_class(Symbol* class_name, + Handle class_loader, + TRAPS) { + return instanceKlassHandle(); + } + static void roots_oops_do(OopClosure* blk) {} + static void oops_do(OopClosure* f) {} + static bool is_sharing_possible(ClassLoaderData* loader_data) { + oop class_loader = loader_data->class_loader(); + return (class_loader == NULL); + } +}; + +#endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp index 6fc9ed239af..89d9d8b5323 100644 --- a/hotspot/src/share/vm/classfile/verifier.cpp +++ b/hotspot/src/share/vm/classfile/verifier.cpp @@ -620,8 +620,6 @@ void ClassVerifier::verify_method(methodHandle m, TRAPS) { // flow from current instruction to the next // instruction in sequence - set_furthest_jump(0); - Bytecodes::Code opcode; while (!bcs.is_last_bytecode()) { // Check for recursive re-verification before each bytecode. @@ -1780,7 +1778,7 @@ u2 ClassVerifier::verify_stackmap_table(u2 stackmap_index, u2 bci, // If matched, current_frame will be updated by this method. bool matches = stackmap_table->match_stackmap( current_frame, this_offset, stackmap_index, - !no_control_flow, true, &ctx, CHECK_VERIFY_(this, 0)); + !no_control_flow, true, false, &ctx, CHECK_VERIFY_(this, 0)); if (!matches) { // report type error verify_error(ctx, "Instruction type does not match stack map"); @@ -1827,7 +1825,7 @@ void ClassVerifier::verify_exception_handler_targets(u2 bci, bool this_uninit, S } ErrorContext ctx; bool matches = stackmap_table->match_stackmap( - new_frame, handler_pc, true, false, &ctx, CHECK_VERIFY(this)); + new_frame, handler_pc, true, false, true, &ctx, CHECK_VERIFY(this)); if (!matches) { verify_error(ctx, "Stack map does not match the one at " "exception handler %d", handler_pc); @@ -2219,6 +2217,181 @@ void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, } } +// Look at the method's handlers. If the bci is in the handler's try block +// then check if the handler_pc is already on the stack. If not, push it. +void ClassVerifier::push_handlers(ExceptionTable* exhandlers, + GrowableArray* handler_stack, + u4 bci) { + int exlength = exhandlers->length(); + for(int x = 0; x < exlength; x++) { + if (bci >= exhandlers->start_pc(x) && bci < exhandlers->end_pc(x)) { + handler_stack->append_if_missing(exhandlers->handler_pc(x)); + } + } +} + +// Return TRUE if all code paths starting with start_bc_offset end in +// bytecode athrow or loop. +bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) { + ResourceMark rm; + // Create bytecode stream. + RawBytecodeStream bcs(method()); + u4 code_length = method()->code_size(); + bcs.set_start(start_bc_offset); + u4 target; + // Create stack for storing bytecode start offsets for if* and *switch. + GrowableArray* bci_stack = new GrowableArray(30); + // Create stack for handlers for try blocks containing this handler. + GrowableArray* handler_stack = new GrowableArray(30); + // Create list of visited branch opcodes (goto* and if*). + GrowableArray* visited_branches = new GrowableArray(30); + ExceptionTable exhandlers(_method()); + + while (true) { + if (bcs.is_last_bytecode()) { + // if no more starting offsets to parse or if at the end of the + // method then return false. + if ((bci_stack->is_empty()) || ((u4)bcs.end_bci() == code_length)) + return false; + // Pop a bytecode starting offset and scan from there. + bcs.set_start(bci_stack->pop()); + } + Bytecodes::Code opcode = bcs.raw_next(); + u4 bci = bcs.bci(); + + // If the bytecode is in a TRY block, push its handlers so they + // will get parsed. + push_handlers(&exhandlers, handler_stack, bci); + + switch (opcode) { + case Bytecodes::_if_icmpeq: + case Bytecodes::_if_icmpne: + case Bytecodes::_if_icmplt: + case Bytecodes::_if_icmpge: + case Bytecodes::_if_icmpgt: + case Bytecodes::_if_icmple: + case Bytecodes::_ifeq: + case Bytecodes::_ifne: + case Bytecodes::_iflt: + case Bytecodes::_ifge: + case Bytecodes::_ifgt: + case Bytecodes::_ifle: + case Bytecodes::_if_acmpeq: + case Bytecodes::_if_acmpne: + case Bytecodes::_ifnull: + case Bytecodes::_ifnonnull: + target = bcs.dest(); + if (visited_branches->contains(bci)) { + if (bci_stack->is_empty()) return true; + // Pop a bytecode starting offset and scan from there. + bcs.set_start(bci_stack->pop()); + } else { + if (target > bci) { // forward branch + if (target >= code_length) return false; + // Push the branch target onto the stack. + bci_stack->push(target); + // then, scan bytecodes starting with next. + bcs.set_start(bcs.next_bci()); + } else { // backward branch + // Push bytecode offset following backward branch onto the stack. + bci_stack->push(bcs.next_bci()); + // Check bytecodes starting with branch target. + bcs.set_start(target); + } + // Record target so we don't branch here again. + visited_branches->append(bci); + } + break; + + case Bytecodes::_goto: + case Bytecodes::_goto_w: + target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w()); + if (visited_branches->contains(bci)) { + if (bci_stack->is_empty()) return true; + // Been here before, pop new starting offset from stack. + bcs.set_start(bci_stack->pop()); + } else { + if (target >= code_length) return false; + // Continue scanning from the target onward. + bcs.set_start(target); + // Record target so we don't branch here again. + visited_branches->append(bci); + } + break; + + // Check that all switch alternatives end in 'athrow' bytecodes. Since it + // is difficult to determine where each switch alternative ends, parse + // each switch alternative until either hit a 'return', 'athrow', or reach + // the end of the method's bytecodes. This is gross but should be okay + // because: + // 1. tableswitch and lookupswitch byte codes in handlers for ctor explicit + // constructor invocations should be rare. + // 2. if each switch alternative ends in an athrow then the parsing should be + // short. If there is no athrow then it is bogus code, anyway. + case Bytecodes::_lookupswitch: + case Bytecodes::_tableswitch: + { + address aligned_bcp = (address) round_to((intptr_t)(bcs.bcp() + 1), jintSize); + u4 default_offset = Bytes::get_Java_u4(aligned_bcp) + bci; + int keys, delta; + if (opcode == Bytecodes::_tableswitch) { + jint low = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize); + jint high = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize); + // This is invalid, but let the regular bytecode verifier + // report this because the user will get a better error message. + if (low > high) return true; + keys = high - low + 1; + delta = 1; + } else { + keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize); + delta = 2; + } + // Invalid, let the regular bytecode verifier deal with it. + if (keys < 0) return true; + + // Push the offset of the next bytecode onto the stack. + bci_stack->push(bcs.next_bci()); + + // Push the switch alternatives onto the stack. + for (int i = 0; i < keys; i++) { + u4 target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize); + if (target > code_length) return false; + bci_stack->push(target); + } + + // Start bytecode parsing for the switch at the default alternative. + if (default_offset > code_length) return false; + bcs.set_start(default_offset); + break; + } + + case Bytecodes::_return: + return false; + + case Bytecodes::_athrow: + { + if (bci_stack->is_empty()) { + if (handler_stack->is_empty()) { + return true; + } else { + // Parse the catch handlers for try blocks containing athrow. + bcs.set_start(handler_stack->pop()); + } + } else { + // Pop a bytecode offset and starting scanning from there. + bcs.set_start(bci_stack->pop()); + } + } + break; + + default: + ; + } // end switch + } // end while loop + + return false; +} + void ClassVerifier::verify_invoke_init( RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type, StackMapFrame* current_frame, u4 code_length, bool *this_uninit, @@ -2238,25 +2411,26 @@ void ClassVerifier::verify_invoke_init( return; } - // Make sure that this call is not jumped over. - if (bci < furthest_jump()) { - verify_error(ErrorContext::bad_code(bci), - "Bad method call from inside of a branch"); - return; - } - - // Make sure that this call is not done from within a TRY block because - // that can result in returning an incomplete object. Simply checking - // (bci >= start_pc) also ensures that this call is not done after a TRY - // block. That is also illegal because this call must be the first Java - // statement in the constructor. + // Check if this call is done from inside of a TRY block. If so, make + // sure that all catch clause paths end in a throw. Otherwise, this + // can result in returning an incomplete object. ExceptionTable exhandlers(_method()); int exlength = exhandlers.length(); for(int i = 0; i < exlength; i++) { - if (bci >= exhandlers.start_pc(i)) { - verify_error(ErrorContext::bad_code(bci), - "Bad method call from after the start of a try block"); - return; + u2 start_pc = exhandlers.start_pc(i); + u2 end_pc = exhandlers.end_pc(i); + + if (bci >= start_pc && bci < end_pc) { + if (!ends_in_athrow(exhandlers.handler_pc(i))) { + verify_error(ErrorContext::bad_code(bci), + "Bad method call from after the start of a try block"); + return; + } else if (VerboseVerification) { + ResourceMark rm; + tty->print_cr( + "Survived call to ends_in_athrow(): %s", + current_class()->name()->as_C_string()); + } } } diff --git a/hotspot/src/share/vm/classfile/verifier.hpp b/hotspot/src/share/vm/classfile/verifier.hpp index 6eecd4b2d4c..4c8b5895a21 100644 --- a/hotspot/src/share/vm/classfile/verifier.hpp +++ b/hotspot/src/share/vm/classfile/verifier.hpp @@ -30,6 +30,7 @@ #include "oops/klass.hpp" #include "oops/method.hpp" #include "runtime/handles.hpp" +#include "utilities/growableArray.hpp" #include "utilities/exceptions.hpp" // The verifier class @@ -258,9 +259,6 @@ class ClassVerifier : public StackObj { ErrorContext _error_context; // contains information about an error - // Used to detect illegal jumps over calls to super() nd this() in ctors. - int32_t _furthest_jump; - void verify_method(methodHandle method, TRAPS); char* generate_code_data(methodHandle m, u4 code_length, TRAPS); void verify_exception_handler_table(u4 code_length, char* code_data, @@ -306,6 +304,16 @@ class ClassVerifier : public StackObj { StackMapFrame* current_frame, u4 code_length, bool* this_uninit, constantPoolHandle cp, TRAPS); + // Used by ends_in_athrow() to push all handlers that contain bci onto + // the handler_stack, if the handler is not already on the stack. + void push_handlers(ExceptionTable* exhandlers, + GrowableArray* handler_stack, + u4 bci); + + // Returns true if all paths starting with start_bc_offset end in athrow + // bytecode or loop. + bool ends_in_athrow(u4 start_bc_offset); + void verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, bool* this_uninit, VerificationType return_type, @@ -407,19 +415,6 @@ class ClassVerifier : public StackObj { TypeOrigin ref_ctx(const char* str, TRAPS); - // Keep track of the furthest branch done in a method to make sure that - // there are no branches over calls to super() or this() from inside of - // a constructor. - int32_t furthest_jump() { return _furthest_jump; } - - void set_furthest_jump(int32_t target) { - _furthest_jump = target; - } - - void update_furthest_jump(int32_t target) { - if (target > _furthest_jump) _furthest_jump = target; - } - }; inline int ClassVerifier::change_sig_to_verificationType( diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index db09171dbe6..50fe81e8d24 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -91,11 +91,17 @@ template(java_lang_CharSequence, "java/lang/CharSequence") \ template(java_lang_SecurityManager, "java/lang/SecurityManager") \ template(java_security_AccessControlContext, "java/security/AccessControlContext") \ + template(java_security_CodeSource, "java/security/CodeSource") \ template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \ + template(java_security_SecureClassLoader, "java/security/SecureClassLoader") \ + template(java_net_URLClassLoader, "java/net/URLClassLoader") \ + template(java_net_URL, "java/net/URL") \ + template(java_util_jar_Manifest, "java/util/jar/Manifest") \ template(impliesCreateAccessControlContext_name, "impliesCreateAccessControlContext") \ template(java_io_OutputStream, "java/io/OutputStream") \ template(java_io_Reader, "java/io/Reader") \ template(java_io_BufferedReader, "java/io/BufferedReader") \ + template(java_io_File, "java/io/File") \ template(java_io_FileInputStream, "java/io/FileInputStream") \ template(java_io_ByteArrayInputStream, "java/io/ByteArrayInputStream") \ template(java_io_Serializable, "java/io/Serializable") \ @@ -106,6 +112,7 @@ template(java_util_Hashtable, "java/util/Hashtable") \ template(java_lang_Compiler, "java/lang/Compiler") \ template(sun_misc_Signal, "sun/misc/Signal") \ + template(sun_misc_Launcher, "sun/misc/Launcher") \ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \ @@ -396,6 +403,14 @@ template(signers_name, "signers_name") \ template(loader_data_name, "loader_data") \ template(dependencies_name, "dependencies") \ + template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \ + template(getFileURL_name, "getFileURL") \ + template(getFileURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \ + template(definePackageInternal_name, "definePackageInternal") \ + template(definePackageInternal_signature, "(Ljava/lang/String;Ljava/util/jar/Manifest;Ljava/net/URL;)V") \ + template(getProtectionDomain_name, "getProtectionDomain") \ + template(getProtectionDomain_signature, "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \ + template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp index 0f50425bcdd..9761d8d98b3 100644 --- a/hotspot/src/share/vm/code/dependencies.cpp +++ b/hotspot/src/share/vm/code/dependencies.cpp @@ -407,56 +407,66 @@ void Dependencies::check_valid_dependency_type(DepType dept) { // for the sake of the compiler log, print out current dependencies: void Dependencies::log_all_dependencies() { if (log() == NULL) return; - ciBaseObject* args[max_arg_count]; + ResourceMark rm; for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; - if (deps->length() == 0) continue; + int deplen = deps->length(); + if (deplen == 0) { + continue; + } int stride = dep_args(dept); + GrowableArray* ciargs = new GrowableArray(stride); for (int i = 0; i < deps->length(); i += stride) { for (int j = 0; j < stride; j++) { // flush out the identities before printing - args[j] = deps->at(i+j); + ciargs->push(deps->at(i+j)); } - write_dependency_to(log(), dept, stride, args); + write_dependency_to(log(), dept, ciargs); + ciargs->clear(); } + guarantee(deplen == deps->length(), "deps array cannot grow inside nested ResoureMark scope"); } } void Dependencies::write_dependency_to(CompileLog* log, DepType dept, - int nargs, DepArgument args[], + GrowableArray* args, Klass* witness) { if (log == NULL) { return; } + ResourceMark rm; ciEnv* env = ciEnv::current(); - ciBaseObject* ciargs[max_arg_count]; - assert(nargs <= max_arg_count, "oob"); - for (int j = 0; j < nargs; j++) { - if (args[j].is_oop()) { - ciargs[j] = env->get_object(args[j].oop_value()); + GrowableArray* ciargs = new GrowableArray(args->length()); + for (GrowableArrayIterator it = args->begin(); it != args->end(); ++it) { + DepArgument arg = *it; + if (arg.is_oop()) { + ciargs->push(env->get_object(arg.oop_value())); } else { - ciargs[j] = env->get_metadata(args[j].metadata_value()); + ciargs->push(env->get_metadata(arg.metadata_value())); } } - Dependencies::write_dependency_to(log, dept, nargs, ciargs, witness); + int argslen = ciargs->length(); + Dependencies::write_dependency_to(log, dept, ciargs, witness); + guarantee(argslen == ciargs->length(), "ciargs array cannot grow inside nested ResoureMark scope"); } void Dependencies::write_dependency_to(CompileLog* log, DepType dept, - int nargs, ciBaseObject* args[], + GrowableArray* args, Klass* witness) { - if (log == NULL) return; - assert(nargs <= max_arg_count, "oob"); - int argids[max_arg_count]; - int ctxkj = dep_context_arg(dept); // -1 if no context arg - int j; - for (j = 0; j < nargs; j++) { - if (args[j]->is_object()) { - argids[j] = log->identify(args[j]->as_object()); + if (log == NULL) { + return; + } + ResourceMark rm; + GrowableArray* argids = new GrowableArray(args->length()); + for (GrowableArrayIterator it = args->begin(); it != args->end(); ++it) { + ciBaseObject* obj = *it; + if (obj->is_object()) { + argids->push(log->identify(obj->as_object())); } else { - argids[j] = log->identify(args[j]->as_metadata()); + argids->push(log->identify(obj->as_metadata())); } } if (witness != NULL) { @@ -465,16 +475,17 @@ void Dependencies::write_dependency_to(CompileLog* log, log->begin_elem("dependency"); } log->print(" type='%s'", dep_name(dept)); - if (ctxkj >= 0) { - log->print(" ctxk='%d'", argids[ctxkj]); + const int ctxkj = dep_context_arg(dept); // -1 if no context arg + if (ctxkj >= 0 && ctxkj < argids->length()) { + log->print(" ctxk='%d'", argids->at(ctxkj)); } // write remaining arguments, if any. - for (j = 0; j < nargs; j++) { + for (int j = 0; j < argids->length(); j++) { if (j == ctxkj) continue; // already logged if (j == 1) { - log->print( " x='%d'", argids[j]); + log->print( " x='%d'", argids->at(j)); } else { - log->print(" x%d='%d'", j, argids[j]); + log->print(" x%d='%d'", j, argids->at(j)); } } if (witness != NULL) { @@ -486,9 +497,12 @@ void Dependencies::write_dependency_to(CompileLog* log, void Dependencies::write_dependency_to(xmlStream* xtty, DepType dept, - int nargs, DepArgument args[], + GrowableArray* args, Klass* witness) { - if (xtty == NULL) return; + if (xtty == NULL) { + return; + } + ResourceMark rm; ttyLocker ttyl; int ctxkj = dep_context_arg(dept); // -1 if no context arg if (witness != NULL) { @@ -498,23 +512,24 @@ void Dependencies::write_dependency_to(xmlStream* xtty, } xtty->print(" type='%s'", dep_name(dept)); if (ctxkj >= 0) { - xtty->object("ctxk", args[ctxkj].metadata_value()); + xtty->object("ctxk", args->at(ctxkj).metadata_value()); } // write remaining arguments, if any. - for (int j = 0; j < nargs; j++) { + for (int j = 0; j < args->length(); j++) { if (j == ctxkj) continue; // already logged + DepArgument arg = args->at(j); if (j == 1) { - if (args[j].is_oop()) { - xtty->object("x", args[j].oop_value()); + if (arg.is_oop()) { + xtty->object("x", arg.oop_value()); } else { - xtty->object("x", args[j].metadata_value()); + xtty->object("x", arg.metadata_value()); } } else { char xn[10]; sprintf(xn, "x%d", j); - if (args[j].is_oop()) { - xtty->object(xn, args[j].oop_value()); + if (arg.is_oop()) { + xtty->object(xn, arg.oop_value()); } else { - xtty->object(xn, args[j].metadata_value()); + xtty->object(xn, arg.metadata_value()); } } } @@ -525,7 +540,7 @@ void Dependencies::write_dependency_to(xmlStream* xtty, xtty->end_elem(); } -void Dependencies::print_dependency(DepType dept, int nargs, DepArgument args[], +void Dependencies::print_dependency(DepType dept, GrowableArray* args, Klass* witness) { ResourceMark rm; ttyLocker ttyl; // keep the following output all in one block @@ -534,8 +549,8 @@ void Dependencies::print_dependency(DepType dept, int nargs, DepArgument args[], dep_name(dept)); // print arguments int ctxkj = dep_context_arg(dept); // -1 if no context arg - for (int j = 0; j < nargs; j++) { - DepArgument arg = args[j]; + for (int j = 0; j < args->length(); j++) { + DepArgument arg = args->at(j); bool put_star = false; if (arg.is_null()) continue; const char* what; @@ -571,31 +586,33 @@ void Dependencies::print_dependency(DepType dept, int nargs, DepArgument args[], void Dependencies::DepStream::log_dependency(Klass* witness) { if (_deps == NULL && xtty == NULL) return; // fast cutout for runtime ResourceMark rm; - int nargs = argument_count(); - DepArgument args[max_arg_count]; + const int nargs = argument_count(); + GrowableArray* args = new GrowableArray(nargs); for (int j = 0; j < nargs; j++) { if (type() == call_site_target_value) { - args[j] = argument_oop(j); + args->push(argument_oop(j)); } else { - args[j] = argument(j); + args->push(argument(j)); } } + int argslen = args->length(); if (_deps != NULL && _deps->log() != NULL) { - Dependencies::write_dependency_to(_deps->log(), - type(), nargs, args, witness); + Dependencies::write_dependency_to(_deps->log(), type(), args, witness); } else { - Dependencies::write_dependency_to(xtty, - type(), nargs, args, witness); + Dependencies::write_dependency_to(xtty, type(), args, witness); } + guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope"); } void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose) { + ResourceMark rm; int nargs = argument_count(); - DepArgument args[max_arg_count]; + GrowableArray* args = new GrowableArray(nargs); for (int j = 0; j < nargs; j++) { - args[j] = argument(j); + args->push(argument(j)); } - Dependencies::print_dependency(type(), nargs, args, witness); + int argslen = args->length(); + Dependencies::print_dependency(type(), args, witness); if (verbose) { if (_code != NULL) { tty->print(" code: "); @@ -603,6 +620,7 @@ void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose) { tty->cr(); } } + guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope"); } diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp index 3501b57fd51..ff4ff328f8d 100644 --- a/hotspot/src/share/vm/code/dependencies.hpp +++ b/hotspot/src/share/vm/code/dependencies.hpp @@ -369,20 +369,36 @@ class Dependencies: public ResourceObj { void copy_to(nmethod* nm); void log_all_dependencies(); - void log_dependency(DepType dept, int nargs, ciBaseObject* args[]) { - write_dependency_to(log(), dept, nargs, args); + + void log_dependency(DepType dept, GrowableArray* args) { + ResourceMark rm; + int argslen = args->length(); + write_dependency_to(log(), dept, args); + guarantee(argslen == args->length(), + "args array cannot grow inside nested ResoureMark scope"); } + void log_dependency(DepType dept, ciBaseObject* x0, ciBaseObject* x1 = NULL, ciBaseObject* x2 = NULL) { - if (log() == NULL) return; - ciBaseObject* args[max_arg_count]; - args[0] = x0; - args[1] = x1; - args[2] = x2; - assert(2 < max_arg_count, ""); - log_dependency(dept, dep_args(dept), args); + if (log() == NULL) { + return; + } + ResourceMark rm; + GrowableArray* ciargs = + new GrowableArray(dep_args(dept)); + assert (x0 != NULL, "no log x0"); + ciargs->push(x0); + + if (x1 != NULL) { + ciargs->push(x1); + } + if (x2 != NULL) { + ciargs->push(x2); + } + assert(ciargs->length() == dep_args(dept), ""); + log_dependency(dept, ciargs); } class DepArgument : public ResourceObj { @@ -405,20 +421,8 @@ class Dependencies: public ResourceObj { Metadata* metadata_value() const { assert(!_is_oop && _valid, "must be"); return (Metadata*) _value; } }; - static void write_dependency_to(CompileLog* log, - DepType dept, - int nargs, ciBaseObject* args[], - Klass* witness = NULL); - static void write_dependency_to(CompileLog* log, - DepType dept, - int nargs, DepArgument args[], - Klass* witness = NULL); - static void write_dependency_to(xmlStream* xtty, - DepType dept, - int nargs, DepArgument args[], - Klass* witness = NULL); static void print_dependency(DepType dept, - int nargs, DepArgument args[], + GrowableArray* args, Klass* witness = NULL); private: @@ -427,6 +431,18 @@ class Dependencies: public ResourceObj { static Klass* ctxk_encoded_as_null(DepType dept, Metadata* x); + static void write_dependency_to(CompileLog* log, + DepType dept, + GrowableArray* args, + Klass* witness = NULL); + static void write_dependency_to(CompileLog* log, + DepType dept, + GrowableArray* args, + Klass* witness = NULL); + static void write_dependency_to(xmlStream* xtty, + DepType dept, + GrowableArray* args, + Klass* witness = NULL); public: // Use this to iterate over an nmethod's dependency set. // Works on new and old dependency sets. diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp index b646158af28..7cf3be645f2 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp @@ -33,6 +33,7 @@ #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" +#include "runtime/os.hpp" class MethodMatcher : public CHeapObj { public: @@ -175,7 +176,11 @@ class MethodOptionMatcher: public MethodMatcher { Symbol* method_name, Mode method_mode, Symbol* signature, const char * opt, MethodMatcher* next): MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next) { - option = opt; + option = os::strdup_check_oom(opt); + } + + virtual ~MethodOptionMatcher() { + os::free((void*)option); } bool match(methodHandle method, const char* opt) { @@ -498,7 +503,7 @@ void CompilerOracle::parse_from_line(char* line) { tty->print("CompilerOracle: %s ", command_names[command]); match->print(); } - match = add_option_string(c_name, c_match, m_name, m_match, signature, strdup(option)); + match = add_option_string(c_name, c_match, m_name, m_match, signature, option); line += bytes_read; } } else { diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp index c2df7a29512..aed729017c0 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -52,7 +52,8 @@ void ConcurrentMarkSweepPolicy::initialize_alignments() { } void ConcurrentMarkSweepPolicy::initialize_generations() { - _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, 0, AllocFailStrategy::RETURN_NULL); + _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, + CURRENT_PC, AllocFailStrategy::RETURN_NULL); if (_generations == NULL) vm_exit_during_initialization("Unable to allocate gen spec"); diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index 2164628a77f..460692b5cea 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -2734,10 +2734,12 @@ void CFLS_LAB::retire(int tid) { } } -void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, AdaptiveFreeList* fl) { - assert(fl->count() == 0, "Precondition."); - assert(word_sz < CompactibleFreeListSpace::IndexSetSize, - "Precondition"); +// Used by par_get_chunk_of_blocks() for the chunks from the +// indexed_free_lists. Looks for a chunk with size that is a multiple +// of "word_sz" and if found, splits it into "word_sz" chunks and add +// to the free list "fl". "n" is the maximum number of chunks to +// be added to "fl". +bool CompactibleFreeListSpace:: par_get_chunk_of_blocks_IFL(size_t word_sz, size_t n, AdaptiveFreeList* fl) { // We'll try all multiples of word_sz in the indexed set, starting with // word_sz itself and, if CMSSplitIndexedFreeListBlocks, try larger multiples, @@ -2818,11 +2820,15 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n Mutex::_no_safepoint_check_flag); ssize_t births = _indexedFreeList[word_sz].split_births() + num; _indexedFreeList[word_sz].set_split_births(births); - return; + return true; } } + return found; } - // Otherwise, we'll split a block from the dictionary. +} + +FreeChunk* CompactibleFreeListSpace::get_n_way_chunk_to_split(size_t word_sz, size_t n) { + FreeChunk* fc = NULL; FreeChunk* rem_fc = NULL; size_t rem; @@ -2833,16 +2839,12 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n fc = dictionary()->get_chunk(MAX2(n * word_sz, _dictionary->min_size()), FreeBlockDictionary::atLeast); if (fc != NULL) { - _bt.allocated((HeapWord*)fc, fc->size(), true /* reducing */); // update _unallocated_blk - dictionary()->dict_census_update(fc->size(), - true /*split*/, - false /*birth*/); break; } else { n--; } } - if (fc == NULL) return; + if (fc == NULL) return NULL; // Otherwise, split up that block. assert((ssize_t)n >= 1, "Control point invariant"); assert(fc->is_free(), "Error: should be a free block"); @@ -2864,10 +2866,14 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n // dictionary and return, leaving "fl" empty. if (n == 0) { returnChunkToDictionary(fc); - assert(fl->count() == 0, "We never allocated any blocks"); - return; + return NULL; } + _bt.allocated((HeapWord*)fc, fc->size(), true /* reducing */); // update _unallocated_blk + dictionary()->dict_census_update(fc->size(), + true /*split*/, + false /*birth*/); + // First return the remainder, if any. // Note that we hold the lock until we decide if we're going to give // back the remainder to the dictionary, since a concurrent allocation @@ -2900,7 +2906,24 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n _indexedFreeList[rem].return_chunk_at_head(rem_fc); smallSplitBirth(rem); } - assert((ssize_t)n > 0 && fc != NULL, "Consistency"); + assert(n * word_sz == fc->size(), + err_msg("Chunk size " SIZE_FORMAT " is not exactly splittable by " + SIZE_FORMAT " sized chunks of size " SIZE_FORMAT, + fc->size(), n, word_sz)); + return fc; +} + +void CompactibleFreeListSpace:: par_get_chunk_of_blocks_dictionary(size_t word_sz, size_t targetted_number_of_chunks, AdaptiveFreeList* fl) { + + FreeChunk* fc = get_n_way_chunk_to_split(word_sz, targetted_number_of_chunks); + + if (fc == NULL) { + return; + } + + size_t n = fc->size() / word_sz; + + assert((ssize_t)n > 0, "Consistency"); // Now do the splitting up. // Must do this in reverse order, so that anybody attempting to // access the main chunk sees it as a single free block until we @@ -2948,6 +2971,20 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n assert(fl->tail()->next() == NULL, "List invariant."); } +void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, AdaptiveFreeList* fl) { + assert(fl->count() == 0, "Precondition."); + assert(word_sz < CompactibleFreeListSpace::IndexSetSize, + "Precondition"); + + if (par_get_chunk_of_blocks_IFL(word_sz, n, fl)) { + // Got it + return; + } + + // Otherwise, we'll split a block from the dictionary. + par_get_chunk_of_blocks_dictionary(word_sz, n, fl); +} + // Set up the space's par_seq_tasks structure for work claiming // for parallel rescan. See CMSParRemarkTask where this is currently used. // XXX Need to suitably abstract and generalize this and the next diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index ba2ff9c55ff..4b10e6fb2bc 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -172,6 +172,20 @@ class CompactibleFreeListSpace: public CompactibleSpace { // list of size "word_sz", and must now be decremented. void par_get_chunk_of_blocks(size_t word_sz, size_t n, AdaptiveFreeList* fl); + // Used by par_get_chunk_of_blocks() for the chunks from the + // indexed_free_lists. + bool par_get_chunk_of_blocks_IFL(size_t word_sz, size_t n, AdaptiveFreeList* fl); + + // Used by par_get_chunk_of_blocks_dictionary() to get a chunk + // evenly splittable into "n" "word_sz" chunks. Returns that + // evenly splittable chunk. May split a larger chunk to get the + // evenly splittable chunk. + FreeChunk* get_n_way_chunk_to_split(size_t word_sz, size_t n); + + // Used by par_get_chunk_of_blocks() for the chunks from the + // dictionary. + void par_get_chunk_of_blocks_dictionary(size_t word_sz, size_t n, AdaptiveFreeList* fl); + // Allocation helper functions // Allocate using a strategy that takes from the indexed free lists // first. This allocation strategy assumes a companion sweeping diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 7dbc7f1d503..a530038b662 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -5987,6 +5987,8 @@ public: }; void CMSRefProcTaskProxy::work(uint worker_id) { + ResourceMark rm; + HandleMark hm; assert(_collector->_span.equals(_span), "Inconsistency in _span"); CMSParKeepAliveClosure par_keep_alive(_collector, _span, _mark_bit_map, diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp index 90e0aedd084..f01f77ce1fa 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp @@ -81,8 +81,8 @@ void ConcurrentG1Refine::reset_threshold_step() { } } -void ConcurrentG1Refine::init() { - _hot_card_cache.initialize(); +void ConcurrentG1Refine::init(G1RegionToSpaceMapper* card_counts_storage) { + _hot_card_cache.initialize(card_counts_storage); } void ConcurrentG1Refine::stop() { diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp index f466e0de339..7f77163818c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp @@ -34,6 +34,7 @@ class ConcurrentG1RefineThread; class G1CollectedHeap; class G1HotCardCache; +class G1RegionToSpaceMapper; class G1RemSet; class DirtyCardQueue; @@ -74,7 +75,7 @@ class ConcurrentG1Refine: public CHeapObj { ConcurrentG1Refine(G1CollectedHeap* g1h, CardTableEntryClosure* refine_closure); ~ConcurrentG1Refine(); - void init(); // Accomplish some initialization that has to wait. + void init(G1RegionToSpaceMapper* card_counts_storage); void stop(); void reinitialize_threads(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 3b9c0aa1906..b8755eb0dc5 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -36,6 +36,7 @@ #include "gc_implementation/g1/heapRegion.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" +#include "gc_implementation/g1/heapRegionSet.inline.hpp" #include "gc_implementation/shared/vmGCOperations.hpp" #include "gc_implementation/shared/gcTimer.hpp" #include "gc_implementation/shared/gcTrace.hpp" @@ -99,12 +100,12 @@ int CMBitMapRO::heapWordDiffToOffsetDiff(size_t diff) const { } #ifndef PRODUCT -bool CMBitMapRO::covers(ReservedSpace heap_rs) const { +bool CMBitMapRO::covers(MemRegion heap_rs) const { // assert(_bm.map() == _virtual_space.low(), "map inconsistency"); assert(((size_t)_bm.size() * ((size_t)1 << _shifter)) == _bmWordSize, "size inconsistency"); - return _bmStartWord == (HeapWord*)(heap_rs.base()) && - _bmWordSize == heap_rs.size()>>LogHeapWordSize; + return _bmStartWord == (HeapWord*)(heap_rs.start()) && + _bmWordSize == heap_rs.word_size(); } #endif @@ -112,33 +113,73 @@ void CMBitMapRO::print_on_error(outputStream* st, const char* prefix) const { _bm.print_on_error(st, prefix); } -bool CMBitMap::allocate(ReservedSpace heap_rs) { - _bmStartWord = (HeapWord*)(heap_rs.base()); - _bmWordSize = heap_rs.size()/HeapWordSize; // heap_rs.size() is in bytes - ReservedSpace brs(ReservedSpace::allocation_align_size_up( - (_bmWordSize >> (_shifter + LogBitsPerByte)) + 1)); - if (!brs.is_reserved()) { - warning("ConcurrentMark marking bit map allocation failure"); - return false; - } - MemTracker::record_virtual_memory_type((address)brs.base(), mtGC); - // For now we'll just commit all of the bit map up front. - // Later on we'll try to be more parsimonious with swap. - if (!_virtual_space.initialize(brs, brs.size())) { - warning("ConcurrentMark marking bit map backing store failure"); - return false; - } - assert(_virtual_space.committed_size() == brs.size(), - "didn't reserve backing store for all of concurrent marking bit map?"); - _bm.set_map((BitMap::bm_word_t*)_virtual_space.low()); - assert(_virtual_space.committed_size() << (_shifter + LogBitsPerByte) >= - _bmWordSize, "inconsistency in bit map sizing"); - _bm.set_size(_bmWordSize >> _shifter); - return true; +size_t CMBitMap::compute_size(size_t heap_size) { + return heap_size / mark_distance(); } +size_t CMBitMap::mark_distance() { + return MinObjAlignmentInBytes * BitsPerByte; +} + +void CMBitMap::initialize(MemRegion heap, G1RegionToSpaceMapper* storage) { + _bmStartWord = heap.start(); + _bmWordSize = heap.word_size(); + + _bm.set_map((BitMap::bm_word_t*) storage->reserved().start()); + _bm.set_size(_bmWordSize >> _shifter); + + storage->set_mapping_changed_listener(&_listener); +} + +void CMBitMapMappingChangedListener::on_commit(uint start_region, size_t num_regions) { + // We need to clear the bitmap on commit, removing any existing information. + MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_region), num_regions * HeapRegion::GrainWords); + _bm->clearRange(mr); +} + +// Closure used for clearing the given mark bitmap. +class ClearBitmapHRClosure : public HeapRegionClosure { + private: + ConcurrentMark* _cm; + CMBitMap* _bitmap; + bool _may_yield; // The closure may yield during iteration. If yielded, abort the iteration. + public: + ClearBitmapHRClosure(ConcurrentMark* cm, CMBitMap* bitmap, bool may_yield) : HeapRegionClosure(), _cm(cm), _bitmap(bitmap), _may_yield(may_yield) { + assert(!may_yield || cm != NULL, "CM must be non-NULL if this closure is expected to yield."); + } + + virtual bool doHeapRegion(HeapRegion* r) { + size_t const chunk_size_in_words = M / HeapWordSize; + + HeapWord* cur = r->bottom(); + HeapWord* const end = r->end(); + + while (cur < end) { + MemRegion mr(cur, MIN2(cur + chunk_size_in_words, end)); + _bitmap->clearRange(mr); + + cur += chunk_size_in_words; + + // Abort iteration if after yielding the marking has been aborted. + if (_may_yield && _cm->do_yield_check() && _cm->has_aborted()) { + return true; + } + // Repeat the asserts from before the start of the closure. We will do them + // as asserts here to minimize their overhead on the product. However, we + // will have them as guarantees at the beginning / end of the bitmap + // clearing to get some checking in the product. + assert(!_may_yield || _cm->cmThread()->during_cycle(), "invariant"); + assert(!_may_yield || !G1CollectedHeap::heap()->mark_in_progress(), "invariant"); + } + + return false; + } +}; + void CMBitMap::clearAll() { - _bm.clear(); + ClearBitmapHRClosure cl(NULL, this, false /* may_yield */); + G1CollectedHeap::heap()->heap_region_iterate(&cl); + guarantee(cl.complete(), "Must have completed iteration."); return; } @@ -483,10 +524,10 @@ uint ConcurrentMark::scale_parallel_threads(uint n_par_threads) { return MAX2((n_par_threads + 2) / 4, 1U); } -ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) : +ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage) : _g1h(g1h), - _markBitMap1(log2_intptr(MinObjAlignment)), - _markBitMap2(log2_intptr(MinObjAlignment)), + _markBitMap1(), + _markBitMap2(), _parallel_marking_threads(0), _max_parallel_marking_threads(0), _sleep_factor(0.0), @@ -495,7 +536,7 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) : _cleanup_task_overhead(1.0), _cleanup_list("Cleanup List"), _region_bm((BitMap::idx_t)(g1h->max_regions()), false /* in_resource_area*/), - _card_bm((heap_rs.size() + CardTableModRefBS::card_size - 1) >> + _card_bm((g1h->reserved_region().byte_size() + CardTableModRefBS::card_size - 1) >> CardTableModRefBS::card_shift, false /* in_resource_area*/), @@ -545,14 +586,8 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) : "heap end = " PTR_FORMAT, p2i(_heap_start), p2i(_heap_end)); } - if (!_markBitMap1.allocate(heap_rs)) { - warning("Failed to allocate first CM bit map"); - return; - } - if (!_markBitMap2.allocate(heap_rs)) { - warning("Failed to allocate second CM bit map"); - return; - } + _markBitMap1.initialize(g1h->reserved_region(), prev_bitmap_storage); + _markBitMap2.initialize(g1h->reserved_region(), next_bitmap_storage); // Create & start a ConcurrentMark thread. _cmThread = new ConcurrentMarkThread(this); @@ -563,8 +598,8 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) : } assert(CGC_lock != NULL, "Where's the CGC_lock?"); - assert(_markBitMap1.covers(heap_rs), "_markBitMap1 inconsistency"); - assert(_markBitMap2.covers(heap_rs), "_markBitMap2 inconsistency"); + assert(_markBitMap1.covers(g1h->reserved_region()), "_markBitMap1 inconsistency"); + assert(_markBitMap2.covers(g1h->reserved_region()), "_markBitMap2 inconsistency"); SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set(); satb_qs.set_buffer_size(G1SATBBufferSize); @@ -724,38 +759,17 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) : clear_all_count_data(); // so that the call below can read a sensible value - _heap_start = (HeapWord*) heap_rs.base(); + _heap_start = g1h->reserved_region().start(); set_non_marking_state(); _completed_initialization = true; } -void ConcurrentMark::update_g1_committed(bool force) { - // If concurrent marking is not in progress, then we do not need to - // update _heap_end. - if (!concurrent_marking_in_progress() && !force) return; - - MemRegion committed = _g1h->g1_committed(); - assert(committed.start() == _heap_start, "start shouldn't change"); - HeapWord* new_end = committed.end(); - if (new_end > _heap_end) { - // The heap has been expanded. - - _heap_end = new_end; - } - // Notice that the heap can also shrink. However, this only happens - // during a Full GC (at least currently) and the entire marking - // phase will bail out and the task will not be restarted. So, let's - // do nothing. -} - void ConcurrentMark::reset() { // Starting values for these two. This should be called in a STW - // phase. CM will be notified of any future g1_committed expansions - // will be at the end of evacuation pauses, when tasks are - // inactive. - MemRegion committed = _g1h->g1_committed(); - _heap_start = committed.start(); - _heap_end = committed.end(); + // phase. + MemRegion reserved = _g1h->g1_reserved(); + _heap_start = reserved.start(); + _heap_end = reserved.end(); // Separated the asserts so that we know which one fires. assert(_heap_start != NULL, "heap bounds should look ok"); @@ -827,7 +841,6 @@ void ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurren assert(out_of_regions(), err_msg("only way to get here: _finger: "PTR_FORMAT", _heap_end: "PTR_FORMAT, p2i(_finger), p2i(_heap_end))); - update_g1_committed(true); } } @@ -846,7 +859,6 @@ ConcurrentMark::~ConcurrentMark() { void ConcurrentMark::clearNextBitmap() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1CollectorPolicy* g1p = g1h->g1_policy(); // Make sure that the concurrent mark thread looks to still be in // the current cycle. @@ -858,41 +870,36 @@ void ConcurrentMark::clearNextBitmap() { // is the case. guarantee(!g1h->mark_in_progress(), "invariant"); - // clear the mark bitmap (no grey objects to start with). - // We need to do this in chunks and offer to yield in between - // each chunk. - HeapWord* start = _nextMarkBitMap->startWord(); - HeapWord* end = _nextMarkBitMap->endWord(); - HeapWord* cur = start; - size_t chunkSize = M; - while (cur < end) { - HeapWord* next = cur + chunkSize; - if (next > end) { - next = end; - } - MemRegion mr(cur,next); - _nextMarkBitMap->clearRange(mr); - cur = next; - do_yield_check(); + ClearBitmapHRClosure cl(this, _nextMarkBitMap, true /* may_yield */); + g1h->heap_region_iterate(&cl); - // Repeat the asserts from above. We'll do them as asserts here to - // minimize their overhead on the product. However, we'll have - // them as guarantees at the beginning / end of the bitmap - // clearing to get some checking in the product. - assert(cmThread()->during_cycle(), "invariant"); - assert(!g1h->mark_in_progress(), "invariant"); + // Clear the liveness counting data. If the marking has been aborted, the abort() + // call already did that. + if (cl.complete()) { + clear_all_count_data(); } - // Clear the liveness counting data - clear_all_count_data(); - // Repeat the asserts from above. guarantee(cmThread()->during_cycle(), "invariant"); guarantee(!g1h->mark_in_progress(), "invariant"); } +class CheckBitmapClearHRClosure : public HeapRegionClosure { + CMBitMap* _bitmap; + bool _error; + public: + CheckBitmapClearHRClosure(CMBitMap* bitmap) : _bitmap(bitmap) { + } + + virtual bool doHeapRegion(HeapRegion* r) { + return _bitmap->getNextMarkedWordAddress(r->bottom(), r->end()) != r->end(); + } +}; + bool ConcurrentMark::nextMarkBitmapIsClear() { - return _nextMarkBitMap->getNextMarkedWordAddress(_heap_start, _heap_end) == _heap_end; + CheckBitmapClearHRClosure cl(_nextMarkBitMap); + _g1h->heap_region_iterate(&cl); + return cl.complete(); } class NoteStartOfMarkHRClosure: public HeapRegionClosure { @@ -2167,7 +2174,9 @@ void ConcurrentMark::cleanup() { g1h->increment_total_collections(); // Clean out dead classes and update Metaspace sizes. - ClassLoaderDataGraph::purge(); + if (ClassUnloadingWithConcurrentMark) { + ClassLoaderDataGraph::purge(); + } MetaspaceGC::compute_new_size(); // We reclaimed old regions so we should calculate the sizes to make @@ -2191,10 +2200,10 @@ void ConcurrentMark::completeCleanup() { _cleanup_list.length()); } - // Noone else should be accessing the _cleanup_list at this point, - // so it's not necessary to take any locks + // No one else should be accessing the _cleanup_list at this point, + // so it is not necessary to take any locks while (!_cleanup_list.is_empty()) { - HeapRegion* hr = _cleanup_list.remove_head(); + HeapRegion* hr = _cleanup_list.remove_region(true /* from_head */); assert(hr != NULL, "Got NULL from a non-empty list"); hr->par_clear(); tmp_free_list.add_ordered(hr); @@ -2403,6 +2412,8 @@ public: } virtual void work(uint worker_id) { + ResourceMark rm; + HandleMark hm; CMTask* task = _cm->task(worker_id); G1CMIsAliveClosure g1_is_alive(_g1h); G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, task, false /* is_serial */); @@ -2595,24 +2606,27 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { assert(_markStack.isEmpty(), "Marking should have completed"); // Unload Klasses, String, Symbols, Code Cache, etc. - - G1RemarkGCTraceTime trace("Unloading", G1Log::finer()); - - bool purged_classes; - { - G1RemarkGCTraceTime trace("System Dictionary Unloading", G1Log::finest()); - purged_classes = SystemDictionary::do_unloading(&g1_is_alive); - } + G1RemarkGCTraceTime trace("Unloading", G1Log::finer()); - { - G1RemarkGCTraceTime trace("Parallel Unloading", G1Log::finest()); - weakRefsWorkParallelPart(&g1_is_alive, purged_classes); - } + if (ClassUnloadingWithConcurrentMark) { + bool purged_classes; - if (G1StringDedup::is_enabled()) { - G1RemarkGCTraceTime trace("String Deduplication Unlink", G1Log::finest()); - G1StringDedup::unlink(&g1_is_alive); + { + G1RemarkGCTraceTime trace("System Dictionary Unloading", G1Log::finest()); + purged_classes = SystemDictionary::do_unloading(&g1_is_alive); + } + + { + G1RemarkGCTraceTime trace("Parallel Unloading", G1Log::finest()); + weakRefsWorkParallelPart(&g1_is_alive, purged_classes); + } + } + + if (G1StringDedup::is_enabled()) { + G1RemarkGCTraceTime trace("String Deduplication Unlink", G1Log::finest()); + G1StringDedup::unlink(&g1_is_alive); + } } } @@ -2973,22 +2987,25 @@ ConcurrentMark::claim_region(uint worker_id) { // claim_region() and a humongous object allocation might force us // to do a bit of unnecessary work (due to some unnecessary bitmap // iterations) but it should not introduce and correctness issues. - HeapRegion* curr_region = _g1h->heap_region_containing_raw(finger); - HeapWord* bottom = curr_region->bottom(); - HeapWord* end = curr_region->end(); - HeapWord* limit = curr_region->next_top_at_mark_start(); + HeapRegion* curr_region = _g1h->heap_region_containing_raw(finger); - if (verbose_low()) { - gclog_or_tty->print_cr("[%u] curr_region = "PTR_FORMAT" " - "["PTR_FORMAT", "PTR_FORMAT"), " - "limit = "PTR_FORMAT, - worker_id, p2i(curr_region), p2i(bottom), p2i(end), p2i(limit)); - } + // Above heap_region_containing_raw may return NULL as we always scan claim + // until the end of the heap. In this case, just jump to the next region. + HeapWord* end = curr_region != NULL ? curr_region->end() : finger + HeapRegion::GrainWords; // Is the gap between reading the finger and doing the CAS too long? HeapWord* res = (HeapWord*) Atomic::cmpxchg_ptr(end, &_finger, finger); - if (res == finger) { + if (res == finger && curr_region != NULL) { // we succeeded + HeapWord* bottom = curr_region->bottom(); + HeapWord* limit = curr_region->next_top_at_mark_start(); + + if (verbose_low()) { + gclog_or_tty->print_cr("[%u] curr_region = "PTR_FORMAT" " + "["PTR_FORMAT", "PTR_FORMAT"), " + "limit = "PTR_FORMAT, + worker_id, p2i(curr_region), p2i(bottom), p2i(end), p2i(limit)); + } // notice that _finger == end cannot be guaranteed here since, // someone else might have moved the finger even further @@ -3019,10 +3036,17 @@ ConcurrentMark::claim_region(uint worker_id) { } else { assert(_finger > finger, "the finger should have moved forward"); if (verbose_low()) { - gclog_or_tty->print_cr("[%u] somebody else moved the finger, " - "global finger = "PTR_FORMAT", " - "our finger = "PTR_FORMAT, - worker_id, p2i(_finger), p2i(finger)); + if (curr_region == NULL) { + gclog_or_tty->print_cr("[%u] found uncommitted region, moving finger, " + "global finger = "PTR_FORMAT", " + "our finger = "PTR_FORMAT, + worker_id, p2i(_finger), p2i(finger)); + } else { + gclog_or_tty->print_cr("[%u] somebody else moved the finger, " + "global finger = "PTR_FORMAT", " + "our finger = "PTR_FORMAT, + worker_id, p2i(_finger), p2i(finger)); + } } // read it again @@ -3137,8 +3161,10 @@ void ConcurrentMark::verify_no_cset_oops(bool verify_stacks, // happens, heap_region_containing() will return the bottom of the // corresponding starts humongous region and the check below will // not hold any more. + // Since we always iterate over all regions, we might get a NULL HeapRegion + // here. HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger); - guarantee(global_finger == global_hr->bottom(), + guarantee(global_hr == NULL || global_finger == global_hr->bottom(), err_msg("global finger: "PTR_FORMAT" region: "HR_FORMAT, p2i(global_finger), HR_FORMAT_PARAMS(global_hr))); } @@ -3151,7 +3177,7 @@ void ConcurrentMark::verify_no_cset_oops(bool verify_stacks, if (task_finger != NULL && task_finger < _heap_end) { // See above note on the global finger verification. HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger); - guarantee(task_finger == task_hr->bottom() || + guarantee(task_hr == NULL || task_finger == task_hr->bottom() || !task_hr->in_collection_set(), err_msg("task finger: "PTR_FORMAT" region: "HR_FORMAT, p2i(task_finger), HR_FORMAT_PARAMS(task_hr))); @@ -4667,7 +4693,6 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name) _hum_prev_live_bytes(0), _hum_next_live_bytes(0), _total_remset_bytes(0), _total_strong_code_roots_bytes(0) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - MemRegion g1_committed = g1h->g1_committed(); MemRegion g1_reserved = g1h->g1_reserved(); double now = os::elapsedTime(); @@ -4675,10 +4700,8 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name) _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("committed") G1PPRL_SUM_ADDR_FORMAT("reserved") G1PPRL_SUM_BYTE_FORMAT("region-size"), - p2i(g1_committed.start()), p2i(g1_committed.end()), p2i(g1_reserved.start()), p2i(g1_reserved.end()), HeapRegion::GrainBytes); _out->print_cr(G1PPRL_LINE_PREFIX); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index a564855277b..e44ddb5b0ab 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -27,10 +27,12 @@ #include "classfile/javaClasses.hpp" #include "gc_implementation/g1/heapRegionSet.hpp" +#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "gc_implementation/shared/gcId.hpp" #include "utilities/taskqueue.hpp" class G1CollectedHeap; +class CMBitMap; class CMTask; typedef GenericTaskQueue CMTaskQueue; typedef GenericTaskQueueSet CMTaskQueueSet; @@ -57,7 +59,6 @@ class CMBitMapRO VALUE_OBJ_CLASS_SPEC { HeapWord* _bmStartWord; // base address of range covered by map size_t _bmWordSize; // map size (in #HeapWords covered) const int _shifter; // map to char or bit - VirtualSpace _virtual_space; // underlying the bit map BitMap _bm; // the bit map itself public: @@ -115,42 +116,41 @@ class CMBitMapRO VALUE_OBJ_CLASS_SPEC { void print_on_error(outputStream* st, const char* prefix) const; // debugging - NOT_PRODUCT(bool covers(ReservedSpace rs) const;) + NOT_PRODUCT(bool covers(MemRegion rs) const;) +}; + +class CMBitMapMappingChangedListener : public G1MappingChangedListener { + private: + CMBitMap* _bm; + public: + CMBitMapMappingChangedListener() : _bm(NULL) {} + + void set_bitmap(CMBitMap* bm) { _bm = bm; } + + virtual void on_commit(uint start_idx, size_t num_regions); }; class CMBitMap : public CMBitMapRO { + private: + CMBitMapMappingChangedListener _listener; public: - // constructor - CMBitMap(int shifter) : - CMBitMapRO(shifter) {} + static size_t compute_size(size_t heap_size); + // Returns the amount of bytes on the heap between two marks in the bitmap. + static size_t mark_distance(); - // Allocates the back store for the marking bitmap - bool allocate(ReservedSpace heap_rs); + CMBitMap() : CMBitMapRO(LogMinObjAlignment), _listener() { _listener.set_bitmap(this); } + + // Initializes the underlying BitMap to cover the given area. + void initialize(MemRegion heap, G1RegionToSpaceMapper* storage); + + // Write marks. + inline void mark(HeapWord* addr); + inline void clear(HeapWord* addr); + inline bool parMark(HeapWord* addr); + inline bool parClear(HeapWord* addr); - // write marks - void mark(HeapWord* addr) { - assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize), - "outside underlying space?"); - _bm.set_bit(heapWordToOffset(addr)); - } - void clear(HeapWord* addr) { - assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize), - "outside underlying space?"); - _bm.clear_bit(heapWordToOffset(addr)); - } - bool parMark(HeapWord* addr) { - assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize), - "outside underlying space?"); - return _bm.par_set_bit(heapWordToOffset(addr)); - } - bool parClear(HeapWord* addr) { - assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize), - "outside underlying space?"); - return _bm.par_clear_bit(heapWordToOffset(addr)); - } void markRange(MemRegion mr); - void clearAll(); void clearRange(MemRegion mr); // Starting at the bit corresponding to "addr" (inclusive), find the next @@ -161,6 +161,9 @@ class CMBitMap : public CMBitMapRO { // the run. If there is no "1" bit at or after "addr", return an empty // MemRegion. MemRegion getAndClearMarkedRegion(HeapWord* addr, HeapWord* end_addr); + + // Clear the whole mark bitmap. + void clearAll(); }; // Represents a marking stack used by ConcurrentMarking in the G1 collector. @@ -680,7 +683,7 @@ public: return _task_queues->steal(worker_id, hash_seed, obj); } - ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs); + ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage); ~ConcurrentMark(); ConcurrentMarkThread* cmThread() { return _cmThread; } @@ -736,7 +739,8 @@ public: // Clear the next marking bitmap (will be called concurrently). void clearNextBitmap(); - // Return whether the next mark bitmap has no marks set. + // Return whether the next mark bitmap has no marks set. To be used for assertions + // only. Will not yield to pause requests. bool nextMarkBitmapIsClear(); // These two do the work that needs to be done before and after the @@ -794,12 +798,6 @@ public: bool verify_thread_buffers, bool verify_fingers) PRODUCT_RETURN; - // It is called at the end of an evacuation pause during marking so - // that CM is notified of where the new end of the heap is. It - // doesn't do anything if concurrent_marking_in_progress() is false, - // unless the force parameter is true. - void update_g1_committed(bool force = false); - bool isMarked(oop p) const { assert(p != NULL && p->is_oop(), "expected an oop"); HeapWord* addr = (HeapWord*)p; diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp index 12ba5683ed8..27ddac5a622 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp @@ -268,6 +268,36 @@ inline bool CMBitMapRO::iterate(BitMapClosure* cl) { return iterate(cl, mr); } +#define check_mark(addr) \ + assert(_bmStartWord <= (addr) && (addr) < (_bmStartWord + _bmWordSize), \ + "outside underlying space?"); \ + assert(G1CollectedHeap::heap()->is_in_exact(addr), \ + err_msg("Trying to access not available bitmap "PTR_FORMAT \ + " corresponding to "PTR_FORMAT" (%u)", \ + p2i(this), p2i(addr), G1CollectedHeap::heap()->addr_to_region(addr))); + +inline void CMBitMap::mark(HeapWord* addr) { + check_mark(addr); + _bm.set_bit(heapWordToOffset(addr)); +} + +inline void CMBitMap::clear(HeapWord* addr) { + check_mark(addr); + _bm.clear_bit(heapWordToOffset(addr)); +} + +inline bool CMBitMap::parMark(HeapWord* addr) { + check_mark(addr); + return _bm.par_set_bit(heapWordToOffset(addr)); +} + +inline bool CMBitMap::parClear(HeapWord* addr) { + check_mark(addr); + return _bm.par_clear_bit(heapWordToOffset(addr)); +} + +#undef check_mark + inline void CMTask::push(oop obj) { HeapWord* objAddr = (HeapWord*) obj; assert(_g1h->is_in_g1_reserved(objAddr), "invariant"); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp index 050490dbbef..50cc9be07ea 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp @@ -173,7 +173,7 @@ public: // Should be called when we want to release the active region which // is returned after it's been retired. - HeapRegion* release(); + virtual HeapRegion* release(); #if G1_ALLOC_REGION_TRACING void trace(const char* str, size_t word_size = 0, HeapWord* result = NULL); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp index c7d4ff3431a..1eae8b9d3f8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp @@ -32,64 +32,37 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +void G1BlockOffsetSharedArrayMappingChangedListener::on_commit(uint start_idx, size_t num_regions) { + // Nothing to do. The BOT is hard-wired to be part of the HeapRegion, and we cannot + // retrieve it here since this would cause firing of several asserts. The code + // executed after commit of a region already needs to do some re-initialization of + // the HeapRegion, so we combine that. +} + ////////////////////////////////////////////////////////////////////// // G1BlockOffsetSharedArray ////////////////////////////////////////////////////////////////////// -G1BlockOffsetSharedArray::G1BlockOffsetSharedArray(MemRegion reserved, - size_t init_word_size) : - _reserved(reserved), _end(NULL) -{ - size_t size = compute_size(reserved.word_size()); - ReservedSpace rs(ReservedSpace::allocation_align_size_up(size)); - if (!rs.is_reserved()) { - vm_exit_during_initialization("Could not reserve enough space for heap offset array"); - } - if (!_vs.initialize(rs, 0)) { - vm_exit_during_initialization("Could not reserve enough space for heap offset array"); - } +G1BlockOffsetSharedArray::G1BlockOffsetSharedArray(MemRegion heap, G1RegionToSpaceMapper* storage) : + _reserved(), _end(NULL), _listener(), _offset_array(NULL) { - MemTracker::record_virtual_memory_type((address)rs.base(), mtGC); + _reserved = heap; + _end = NULL; + + MemRegion bot_reserved = storage->reserved(); + + _offset_array = (u_char*)bot_reserved.start(); + _end = _reserved.end(); + + storage->set_mapping_changed_listener(&_listener); - _offset_array = (u_char*)_vs.low_boundary(); - resize(init_word_size); if (TraceBlockOffsetTable) { gclog_or_tty->print_cr("G1BlockOffsetSharedArray::G1BlockOffsetSharedArray: "); gclog_or_tty->print_cr(" " " rs.base(): " INTPTR_FORMAT " rs.size(): " INTPTR_FORMAT " rs end(): " INTPTR_FORMAT, - rs.base(), rs.size(), rs.base() + rs.size()); - gclog_or_tty->print_cr(" " - " _vs.low_boundary(): " INTPTR_FORMAT - " _vs.high_boundary(): " INTPTR_FORMAT, - _vs.low_boundary(), - _vs.high_boundary()); - } -} - -void G1BlockOffsetSharedArray::resize(size_t new_word_size) { - assert(new_word_size <= _reserved.word_size(), "Resize larger than reserved"); - size_t new_size = compute_size(new_word_size); - size_t old_size = _vs.committed_size(); - size_t delta; - char* high = _vs.high(); - _end = _reserved.start() + new_word_size; - if (new_size > old_size) { - delta = ReservedSpace::page_align_size_up(new_size - old_size); - assert(delta > 0, "just checking"); - if (!_vs.expand_by(delta)) { - // Do better than this for Merlin - vm_exit_out_of_memory(delta, OOM_MMAP_ERROR, "offset table expansion"); - } - assert(_vs.high() == high + delta, "invalid expansion"); - // Initialization of the contents is left to the - // G1BlockOffsetArray that uses it. - } else { - delta = ReservedSpace::page_align_size_down(old_size - new_size); - if (delta == 0) return; - _vs.shrink_by(delta); - assert(_vs.high() == high - delta, "invalid expansion"); + bot_reserved.start(), bot_reserved.byte_size(), bot_reserved.end()); } } @@ -100,18 +73,7 @@ bool G1BlockOffsetSharedArray::is_card_boundary(HeapWord* p) const { } void G1BlockOffsetSharedArray::set_offset_array(HeapWord* left, HeapWord* right, u_char offset) { - check_index(index_for(right - 1), "right address out of range"); - assert(left < right, "Heap addresses out of order"); - size_t num_cards = pointer_delta(right, left) >> LogN_words; - if (UseMemSetInBOT) { - memset(&_offset_array[index_for(left)], offset, num_cards); - } else { - size_t i = index_for(left); - const size_t end = i + num_cards; - for (; i < end; i++) { - _offset_array[i] = offset; - } - } + set_offset_array(index_for(left), index_for(right -1), offset); } ////////////////////////////////////////////////////////////////////// @@ -650,6 +612,25 @@ G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array, _next_offset_index = 0; } +HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold_raw() { + assert(!Universe::heap()->is_in_reserved(_array->_offset_array), + "just checking"); + _next_offset_index = _array->index_for_raw(_bottom); + _next_offset_index++; + _next_offset_threshold = + _array->address_for_index_raw(_next_offset_index); + return _next_offset_threshold; +} + +void G1BlockOffsetArrayContigSpace::zero_bottom_entry_raw() { + assert(!Universe::heap()->is_in_reserved(_array->_offset_array), + "just checking"); + size_t bottom_index = _array->index_for_raw(_bottom); + assert(_array->address_for_index_raw(bottom_index) == _bottom, + "Precondition of call"); + _array->set_offset_array_raw(bottom_index, 0); +} + HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold() { assert(!Universe::heap()->is_in_reserved(_array->_offset_array), "just checking"); @@ -674,8 +655,7 @@ G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* new_top) { assert(new_top <= _end, "_end should have already been updated"); // The first BOT entry should have offset 0. - zero_bottom_entry(); - initialize_threshold(); + reset_bot(); alloc_block(_bottom, new_top); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp index 5395899f143..70bc41390a3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1BLOCKOFFSETTABLE_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_G1BLOCKOFFSETTABLE_HPP +#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "memory/memRegion.hpp" #include "runtime/virtualspace.hpp" #include "utilities/globalDefinitions.hpp" @@ -106,6 +107,11 @@ public: inline HeapWord* block_start_const(const void* addr) const; }; +class G1BlockOffsetSharedArrayMappingChangedListener : public G1MappingChangedListener { + public: + virtual void on_commit(uint start_idx, size_t num_regions); +}; + // This implementation of "G1BlockOffsetTable" divides the covered region // into "N"-word subregions (where "N" = 2^"LogN". An array with an entry // for each such subregion indicates how far back one must go to find the @@ -125,6 +131,7 @@ class G1BlockOffsetSharedArray: public CHeapObj { friend class VMStructs; private: + G1BlockOffsetSharedArrayMappingChangedListener _listener; // The reserved region covered by the shared array. MemRegion _reserved; @@ -133,16 +140,8 @@ private: // Array for keeping offsets for retrieving object start fast given an // address. - VirtualSpace _vs; u_char* _offset_array; // byte array keeping backwards offsets - void check_index(size_t index, const char* msg) const { - assert(index < _vs.committed_size(), - err_msg("%s - " - "index: " SIZE_FORMAT ", _vs.committed_size: " SIZE_FORMAT, - msg, index, _vs.committed_size())); - } - void check_offset(size_t offset, const char* msg) const { assert(offset <= N_words, err_msg("%s - " @@ -152,63 +151,33 @@ private: // Bounds checking accessors: // For performance these have to devolve to array accesses in product builds. - u_char offset_array(size_t index) const { - check_index(index, "index out of range"); - return _offset_array[index]; - } + inline u_char offset_array(size_t index) const; void set_offset_array(HeapWord* left, HeapWord* right, u_char offset); - void set_offset_array(size_t index, u_char offset) { - check_index(index, "index out of range"); - check_offset(offset, "offset too large"); + void set_offset_array_raw(size_t index, u_char offset) { _offset_array[index] = offset; } - void set_offset_array(size_t index, HeapWord* high, HeapWord* low) { - check_index(index, "index out of range"); - assert(high >= low, "addresses out of order"); - check_offset(pointer_delta(high, low), "offset too large"); - _offset_array[index] = (u_char) pointer_delta(high, low); - } + inline void set_offset_array(size_t index, u_char offset); - void set_offset_array(size_t left, size_t right, u_char offset) { - check_index(right, "right index out of range"); - assert(left <= right, "indexes out of order"); - size_t num_cards = right - left + 1; - if (UseMemSetInBOT) { - memset(&_offset_array[left], offset, num_cards); - } else { - size_t i = left; - const size_t end = i + num_cards; - for (; i < end; i++) { - _offset_array[i] = offset; - } - } - } + inline void set_offset_array(size_t index, HeapWord* high, HeapWord* low); - void check_offset_array(size_t index, HeapWord* high, HeapWord* low) const { - check_index(index, "index out of range"); - assert(high >= low, "addresses out of order"); - check_offset(pointer_delta(high, low), "offset too large"); - assert(_offset_array[index] == pointer_delta(high, low), "Wrong offset"); - } + inline void set_offset_array(size_t left, size_t right, u_char offset); + + inline void check_offset_array(size_t index, HeapWord* high, HeapWord* low) const; bool is_card_boundary(HeapWord* p) const; +public: + // Return the number of slots needed for an offset array // that covers mem_region_words words. - // We always add an extra slot because if an object - // ends on a card boundary we put a 0 in the next - // offset array slot, so we want that slot always - // to be reserved. - - size_t compute_size(size_t mem_region_words) { - size_t number_of_slots = (mem_region_words / N_words) + 1; - return ReservedSpace::page_align_size_up(number_of_slots); + static size_t compute_size(size_t mem_region_words) { + size_t number_of_slots = (mem_region_words / N_words); + return ReservedSpace::allocation_align_size_up(number_of_slots); } -public: enum SomePublicConstants { LogN = 9, LogN_words = LogN - LogHeapWordSize, @@ -222,25 +191,21 @@ public: // least "init_word_size".) The contents of the initial table are // undefined; it is the responsibility of the constituent // G1BlockOffsetTable(s) to initialize cards. - G1BlockOffsetSharedArray(MemRegion reserved, size_t init_word_size); - - // Notes a change in the committed size of the region covered by the - // table. The "new_word_size" may not be larger than the size of the - // reserved region this table covers. - void resize(size_t new_word_size); + G1BlockOffsetSharedArray(MemRegion heap, G1RegionToSpaceMapper* storage); void set_bottom(HeapWord* new_bottom); - // Updates all the BlockOffsetArray's sharing this shared array to - // reflect the current "top"'s of their spaces. - void update_offset_arrays(); - // Return the appropriate index into "_offset_array" for "p". inline size_t index_for(const void* p) const; + inline size_t index_for_raw(const void* p) const; // Return the address indicating the start of the region corresponding to // "index" in "_offset_array". inline HeapWord* address_for_index(size_t index) const; + // Variant of address_for_index that does not check the index for validity. + inline HeapWord* address_for_index_raw(size_t index) const { + return _reserved.start() + (index << LogN_words); + } }; // And here is the G1BlockOffsetTable subtype that uses the array. @@ -480,6 +445,14 @@ class G1BlockOffsetArrayContigSpace: public G1BlockOffsetArray { blk_start, blk_end); } + // Variant of zero_bottom_entry that does not check for availability of the + // memory first. + void zero_bottom_entry_raw(); + // Variant of initialize_threshold that does not check for availability of the + // memory first. + HeapWord* initialize_threshold_raw(); + // Zero out the entry for _bottom (offset will be zero). + void zero_bottom_entry(); public: G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array, MemRegion mr); @@ -487,8 +460,10 @@ class G1BlockOffsetArrayContigSpace: public G1BlockOffsetArray { // bottom of the covered region. HeapWord* initialize_threshold(); - // Zero out the entry for _bottom (offset will be zero). - void zero_bottom_entry(); + void reset_bot() { + zero_bottom_entry_raw(); + initialize_threshold_raw(); + } // Return the next threshold, the point at which the table should be // updated. diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp index 4cf0a06cd74..cd4ebd2d05f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp @@ -47,14 +47,69 @@ G1BlockOffsetTable::block_start_const(const void* addr) const { } } +#define check_index(index, msg) \ + assert((index) < (_reserved.word_size() >> LogN_words), \ + err_msg("%s - index: "SIZE_FORMAT", _vs.committed_size: "SIZE_FORMAT, \ + msg, (index), (_reserved.word_size() >> LogN_words))); \ + assert(G1CollectedHeap::heap()->is_in_exact(address_for_index_raw(index)), \ + err_msg("Index "SIZE_FORMAT" corresponding to "PTR_FORMAT \ + " (%u) is not in committed area.", \ + (index), \ + p2i(address_for_index_raw(index)), \ + G1CollectedHeap::heap()->addr_to_region(address_for_index_raw(index)))); + +u_char G1BlockOffsetSharedArray::offset_array(size_t index) const { + check_index(index, "index out of range"); + return _offset_array[index]; +} + +void G1BlockOffsetSharedArray::set_offset_array(size_t index, u_char offset) { + check_index(index, "index out of range"); + set_offset_array_raw(index, offset); +} + +void G1BlockOffsetSharedArray::set_offset_array(size_t index, HeapWord* high, HeapWord* low) { + check_index(index, "index out of range"); + assert(high >= low, "addresses out of order"); + size_t offset = pointer_delta(high, low); + check_offset(offset, "offset too large"); + set_offset_array(index, (u_char)offset); +} + +void G1BlockOffsetSharedArray::set_offset_array(size_t left, size_t right, u_char offset) { + check_index(right, "right index out of range"); + assert(left <= right, "indexes out of order"); + size_t num_cards = right - left + 1; + if (UseMemSetInBOT) { + memset(&_offset_array[left], offset, num_cards); + } else { + size_t i = left; + const size_t end = i + num_cards; + for (; i < end; i++) { + _offset_array[i] = offset; + } + } +} + +void G1BlockOffsetSharedArray::check_offset_array(size_t index, HeapWord* high, HeapWord* low) const { + check_index(index, "index out of range"); + assert(high >= low, "addresses out of order"); + check_offset(pointer_delta(high, low), "offset too large"); + assert(_offset_array[index] == pointer_delta(high, low), "Wrong offset"); +} + +// Variant of index_for that does not check the index for validity. +inline size_t G1BlockOffsetSharedArray::index_for_raw(const void* p) const { + return pointer_delta((char*)p, _reserved.start(), sizeof(char)) >> LogN; +} + inline size_t G1BlockOffsetSharedArray::index_for(const void* p) const { char* pc = (char*)p; assert(pc >= (char*)_reserved.start() && pc < (char*)_reserved.end(), err_msg("p (" PTR_FORMAT ") not in reserved [" PTR_FORMAT ", " PTR_FORMAT ")", p2i(p), p2i(_reserved.start()), p2i(_reserved.end()))); - size_t delta = pointer_delta(pc, _reserved.start(), sizeof(char)); - size_t result = delta >> LogN; + size_t result = index_for_raw(p); check_index(result, "bad index from address"); return result; } @@ -62,7 +117,7 @@ inline size_t G1BlockOffsetSharedArray::index_for(const void* p) const { inline HeapWord* G1BlockOffsetSharedArray::address_for_index(size_t index) const { check_index(index, "index out of range"); - HeapWord* result = _reserved.start() + (index << LogN_words); + HeapWord* result = address_for_index_raw(index); assert(result >= _reserved.start() && result < _reserved.end(), err_msg("bad address from index result " PTR_FORMAT " _reserved.start() " PTR_FORMAT " _reserved.end() " @@ -71,6 +126,8 @@ G1BlockOffsetSharedArray::address_for_index(size_t index) const { return result; } +#undef check_index + inline size_t G1BlockOffsetArray::block_size(const HeapWord* p) const { return gsp()->block_size(p); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.cpp index 9fff9604ff2..f9fd47cfb64 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.cpp @@ -33,31 +33,26 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +void G1CardCountsMappingChangedListener::on_commit(uint start_idx, size_t num_regions) { + MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * HeapRegion::GrainWords); + _counts->clear_range(mr); +} + void G1CardCounts::clear_range(size_t from_card_num, size_t to_card_num) { if (has_count_table()) { - assert(from_card_num >= 0 && from_card_num < _committed_max_card_num, - err_msg("from card num out of range: "SIZE_FORMAT, from_card_num)); assert(from_card_num < to_card_num, err_msg("Wrong order? from: " SIZE_FORMAT ", to: "SIZE_FORMAT, from_card_num, to_card_num)); - assert(to_card_num <= _committed_max_card_num, - err_msg("to card num out of range: " - "to: "SIZE_FORMAT ", " - "max: "SIZE_FORMAT, - to_card_num, _committed_max_card_num)); - - to_card_num = MIN2(_committed_max_card_num, to_card_num); - Copy::fill_to_bytes(&_card_counts[from_card_num], (to_card_num - from_card_num)); } } G1CardCounts::G1CardCounts(G1CollectedHeap *g1h): - _g1h(g1h), _card_counts(NULL), - _reserved_max_card_num(0), _committed_max_card_num(0), - _committed_size(0) {} + _listener(), _g1h(g1h), _card_counts(NULL), _reserved_max_card_num(0) { + _listener.set_cardcounts(this); +} -void G1CardCounts::initialize() { +void G1CardCounts::initialize(G1RegionToSpaceMapper* mapper) { assert(_g1h->max_capacity() > 0, "initialization order"); assert(_g1h->capacity() == 0, "initialization order"); @@ -70,70 +65,9 @@ void G1CardCounts::initialize() { _ct_bs = _g1h->g1_barrier_set(); _ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start()); - // Allocate/Reserve the counts table - size_t reserved_bytes = _g1h->max_capacity(); - _reserved_max_card_num = reserved_bytes >> CardTableModRefBS::card_shift; - - size_t reserved_size = _reserved_max_card_num * sizeof(jbyte); - ReservedSpace rs(ReservedSpace::allocation_align_size_up(reserved_size)); - if (!rs.is_reserved()) { - warning("Could not reserve enough space for the card counts table"); - guarantee(!has_reserved_count_table(), "should be NULL"); - return; - } - - MemTracker::record_virtual_memory_type((address)rs.base(), mtGC); - - _card_counts_storage.initialize(rs, 0); - _card_counts = (jubyte*) _card_counts_storage.low(); - } -} - -void G1CardCounts::resize(size_t heap_capacity) { - // Expand the card counts table to handle a heap with the given capacity. - - if (!has_reserved_count_table()) { - // Don't expand if we failed to reserve the card counts table. - return; - } - - assert(_committed_size == - ReservedSpace::allocation_align_size_up(_committed_size), - err_msg("Unaligned? committed_size: " SIZE_FORMAT, _committed_size)); - - // Verify that the committed space for the card counts matches our - // committed max card num. Note for some allocation alignments, the - // amount of space actually committed for the counts table will be able - // to span more cards than the number spanned by the maximum heap. - size_t prev_committed_size = _committed_size; - size_t prev_committed_card_num = committed_to_card_num(prev_committed_size); - - assert(prev_committed_card_num == _committed_max_card_num, - err_msg("Card mismatch: " - "prev: " SIZE_FORMAT ", " - "committed: "SIZE_FORMAT", " - "reserved: "SIZE_FORMAT, - prev_committed_card_num, _committed_max_card_num, _reserved_max_card_num)); - - size_t new_size = (heap_capacity >> CardTableModRefBS::card_shift) * sizeof(jbyte); - size_t new_committed_size = ReservedSpace::allocation_align_size_up(new_size); - size_t new_committed_card_num = committed_to_card_num(new_committed_size); - - if (_committed_max_card_num < new_committed_card_num) { - // we need to expand the backing store for the card counts - size_t expand_size = new_committed_size - prev_committed_size; - - if (!_card_counts_storage.expand_by(expand_size)) { - warning("Card counts table backing store commit failure"); - return; - } - assert(_card_counts_storage.committed_size() == new_committed_size, - "expansion commit failure"); - - _committed_size = new_committed_size; - _committed_max_card_num = new_committed_card_num; - - clear_range(prev_committed_card_num, _committed_max_card_num); + _card_counts = (jubyte*) mapper->reserved().start(); + _reserved_max_card_num = mapper->reserved().byte_size(); + mapper->set_mapping_changed_listener(&_listener); } } @@ -149,12 +83,13 @@ uint G1CardCounts::add_card_count(jbyte* card_ptr) { uint count = 0; if (has_count_table()) { size_t card_num = ptr_2_card_num(card_ptr); - if (card_num < _committed_max_card_num) { - count = (uint) _card_counts[card_num]; - if (count < G1ConcRSHotCardLimit) { - _card_counts[card_num] = - (jubyte)(MIN2((uintx)(_card_counts[card_num] + 1), G1ConcRSHotCardLimit)); - } + assert(card_num < _reserved_max_card_num, + err_msg("Card "SIZE_FORMAT" outside of card counts table (max size "SIZE_FORMAT")", + card_num, _reserved_max_card_num)); + count = (uint) _card_counts[card_num]; + if (count < G1ConcRSHotCardLimit) { + _card_counts[card_num] = + (jubyte)(MIN2((uintx)(_card_counts[card_num] + 1), G1ConcRSHotCardLimit)); } } return count; @@ -165,31 +100,23 @@ bool G1CardCounts::is_hot(uint count) { } void G1CardCounts::clear_region(HeapRegion* hr) { - assert(!hr->isHumongous(), "Should have been cleared"); + MemRegion mr(hr->bottom(), hr->end()); + clear_range(mr); +} + +void G1CardCounts::clear_range(MemRegion mr) { if (has_count_table()) { - HeapWord* bottom = hr->bottom(); - - // We use the last address in hr as hr could be the - // last region in the heap. In which case trying to find - // the card for hr->end() will be an OOB access to the - // card table. - HeapWord* last = hr->end() - 1; - assert(_g1h->g1_committed().contains(last), - err_msg("last not in committed: " - "last: " PTR_FORMAT ", " - "committed: [" PTR_FORMAT ", " PTR_FORMAT ")", - last, - _g1h->g1_committed().start(), - _g1h->g1_committed().end())); - - const jbyte* from_card_ptr = _ct_bs->byte_for_const(bottom); - const jbyte* last_card_ptr = _ct_bs->byte_for_const(last); + const jbyte* from_card_ptr = _ct_bs->byte_for_const(mr.start()); + // We use the last address in the range as the range could represent the + // last region in the heap. In which case trying to find the card will be an + // OOB access to the card table. + const jbyte* last_card_ptr = _ct_bs->byte_for_const(mr.last()); #ifdef ASSERT HeapWord* start_addr = _ct_bs->addr_for(from_card_ptr); - assert(start_addr == hr->bottom(), "alignment"); + assert(start_addr == mr.start(), "MemRegion start must be aligned to a card."); HeapWord* last_addr = _ct_bs->addr_for(last_card_ptr); - assert((last_addr + CardTableModRefBS::card_size_in_words) == hr->end(), "alignment"); + assert((last_addr + CardTableModRefBS::card_size_in_words) == mr.end(), "MemRegion end must be aligned to a card."); #endif // ASSERT // Clear the counts for the (exclusive) card range. @@ -199,14 +126,22 @@ void G1CardCounts::clear_region(HeapRegion* hr) { } } +class G1CardCountsClearClosure : public HeapRegionClosure { + private: + G1CardCounts* _card_counts; + public: + G1CardCountsClearClosure(G1CardCounts* card_counts) : + HeapRegionClosure(), _card_counts(card_counts) { } + + + virtual bool doHeapRegion(HeapRegion* r) { + _card_counts->clear_region(r); + return false; + } +}; + void G1CardCounts::clear_all() { assert(SafepointSynchronize::is_at_safepoint(), "don't call this otherwise"); - clear_range((size_t)0, _committed_max_card_num); + G1CardCountsClearClosure cl(this); + _g1h->heap_region_iterate(&cl); } - -G1CardCounts::~G1CardCounts() { - if (has_reserved_count_table()) { - _card_counts_storage.release(); - } -} - diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp index ef08479f60a..4252cba0937 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp @@ -25,14 +25,26 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1CARDCOUNTS_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_G1CARDCOUNTS_HPP +#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "memory/allocation.hpp" #include "runtime/virtualspace.hpp" #include "utilities/globalDefinitions.hpp" class CardTableModRefBS; +class G1CardCounts; class G1CollectedHeap; +class G1RegionToSpaceMapper; class HeapRegion; +class G1CardCountsMappingChangedListener : public G1MappingChangedListener { + private: + G1CardCounts* _counts; + public: + void set_cardcounts(G1CardCounts* counts) { _counts = counts; } + + virtual void on_commit(uint start_idx, size_t num_regions); +}; + // Table to track the number of times a card has been refined. Once // a card has been refined a certain number of times, it is // considered 'hot' and its refinement is delayed by inserting the @@ -41,6 +53,8 @@ class HeapRegion; // is 'drained' during the next evacuation pause. class G1CardCounts: public CHeapObj { + G1CardCountsMappingChangedListener _listener; + G1CollectedHeap* _g1h; // The table of counts @@ -49,27 +63,18 @@ class G1CardCounts: public CHeapObj { // Max capacity of the reserved space for the counts table size_t _reserved_max_card_num; - // Max capacity of the committed space for the counts table - size_t _committed_max_card_num; - - // Size of committed space for the counts table - size_t _committed_size; - // CardTable bottom. const jbyte* _ct_bot; // Barrier set CardTableModRefBS* _ct_bs; - // The virtual memory backing the counts table - VirtualSpace _card_counts_storage; - // Returns true if the card counts table has been reserved. bool has_reserved_count_table() { return _card_counts != NULL; } // Returns true if the card counts table has been reserved and committed. bool has_count_table() { - return has_reserved_count_table() && _committed_max_card_num > 0; + return has_reserved_count_table(); } size_t ptr_2_card_num(const jbyte* card_ptr) { @@ -79,37 +84,24 @@ class G1CardCounts: public CHeapObj { "_ct_bot: " PTR_FORMAT, p2i(card_ptr), p2i(_ct_bot))); size_t card_num = pointer_delta(card_ptr, _ct_bot, sizeof(jbyte)); - assert(card_num >= 0 && card_num < _committed_max_card_num, + assert(card_num >= 0 && card_num < _reserved_max_card_num, err_msg("card pointer out of range: " PTR_FORMAT, p2i(card_ptr))); return card_num; } jbyte* card_num_2_ptr(size_t card_num) { - assert(card_num >= 0 && card_num < _committed_max_card_num, + assert(card_num >= 0 && card_num < _reserved_max_card_num, err_msg("card num out of range: "SIZE_FORMAT, card_num)); return (jbyte*) (_ct_bot + card_num); } - // Helper routine. - // Returns the number of cards that can be counted by the given committed - // table size, with a maximum of the number of cards spanned by the max - // capacity of the heap. - size_t committed_to_card_num(size_t committed_size) { - return MIN2(_reserved_max_card_num, committed_size / sizeof(jbyte)); - } - // Clear the counts table for the given (exclusive) index range. void clear_range(size_t from_card_num, size_t to_card_num); public: G1CardCounts(G1CollectedHeap* g1h); - ~G1CardCounts(); - void initialize(); - - // Resize the committed space for the card counts table in - // response to a resize of the committed space for the heap. - void resize(size_t heap_capacity); + void initialize(G1RegionToSpaceMapper* mapper); // Increments the refinement count for the given card. // Returns the pre-increment count value. @@ -122,8 +114,10 @@ class G1CardCounts: public CHeapObj { // Clears the card counts for the cards spanned by the region void clear_region(HeapRegion* hr); + // Clears the card counts for the cards spanned by the MemRegion + void clear_range(MemRegion mr); + // Clear the entire card counts table during GC. - // Updates the policy stats with the duration. void clear_all(); }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index db56c33b91a..da2f34fdd62 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -45,12 +45,13 @@ #include "gc_implementation/g1/g1MarkSweep.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1ParScanThreadState.inline.hpp" +#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "gc_implementation/g1/g1RemSet.inline.hpp" #include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/g1/g1YCTypes.hpp" #include "gc_implementation/g1/heapRegion.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" -#include "gc_implementation/g1/heapRegionSeq.inline.hpp" +#include "gc_implementation/g1/heapRegionSet.inline.hpp" #include "gc_implementation/g1/vm_operations_g1.hpp" #include "gc_implementation/shared/gcHeapSummary.hpp" #include "gc_implementation/shared/gcTimer.hpp" @@ -381,6 +382,14 @@ void YoungList::print() { gclog_or_tty->cr(); } +void G1RegionMappingChangedListener::reset_from_card_cache(uint start_idx, size_t num_regions) { + OtherRegionsTable::invalidate(start_idx, num_regions); +} + +void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_regions) { + reset_from_card_cache(start_idx, num_regions); +} + void G1CollectedHeap::push_dirty_cards_region(HeapRegion* hr) { // Claim the right to put the region on the dirty cards region list @@ -523,9 +532,9 @@ G1CollectedHeap::new_region_try_secondary_free_list(bool is_old) { // again to allocate from it. append_secondary_free_list(); - assert(!_free_list.is_empty(), "if the secondary_free_list was not " + assert(_hrs.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 = _free_list.remove_region(is_old); + HeapRegion* res = _hrs.allocate_free_region(is_old); if (G1ConcRegionFreeingVerbose) { gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " "allocated "HR_FORMAT" from secondary_free_list", @@ -566,7 +575,7 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool is_old, bool do_e } } - res = _free_list.remove_region(is_old); + res = _hrs.allocate_free_region(is_old); if (res == NULL) { if (G1ConcRegionFreeingVerbose) { @@ -591,8 +600,8 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool is_old, bool do_e // Given that expand() succeeded in expanding the heap, and we // always expand the heap by an amount aligned to the heap // region size, the free list should in theory not be empty. - // In either case remove_region() will check for NULL. - res = _free_list.remove_region(is_old); + // In either case allocate_free_region() will check for NULL. + res = _hrs.allocate_free_region(is_old); } else { _expand_heap_after_alloc_failure = false; } @@ -600,55 +609,11 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool is_old, bool do_e return res; } -uint G1CollectedHeap::humongous_obj_allocate_find_first(uint num_regions, - size_t word_size) { - assert(isHumongous(word_size), "word_size should be humongous"); - assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition"); - - uint first = G1_NULL_HRS_INDEX; - if (num_regions == 1) { - // Only one region to allocate, no need to go through the slower - // path. The caller will attempt the expansion if this fails, so - // let's not try to expand here too. - HeapRegion* hr = new_region(word_size, true /* is_old */, false /* do_expand */); - if (hr != NULL) { - first = hr->hrs_index(); - } else { - first = G1_NULL_HRS_INDEX; - } - } else { - // We can't allocate humongous regions while cleanupComplete() is - // running, since some of the regions we find to be empty might not - // yet be added to the free list and it is not straightforward to - // know which list they are on so that we can remove them. Note - // that we only need to do this if we need to allocate more than - // one region to satisfy the current humongous allocation - // request. If we are only allocating one region we use the common - // region allocation code (see above). - wait_while_free_regions_coming(); - append_secondary_free_list_if_not_empty_with_lock(); - - if (free_regions() >= num_regions) { - first = _hrs.find_contiguous(num_regions); - if (first != G1_NULL_HRS_INDEX) { - for (uint i = first; i < first + num_regions; ++i) { - HeapRegion* hr = region_at(i); - assert(hr->is_empty(), "sanity"); - assert(is_on_master_free_list(hr), "sanity"); - hr->set_pending_removal(true); - } - _free_list.remove_all_pending(num_regions); - } - } - } - return first; -} - HeapWord* G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first, uint num_regions, size_t word_size) { - assert(first != G1_NULL_HRS_INDEX, "pre-condition"); + assert(first != G1_NO_HRS_INDEX, "pre-condition"); assert(isHumongous(word_size), "word_size should be humongous"); assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition"); @@ -786,42 +751,70 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) { verify_region_sets_optional(); - size_t word_size_rounded = round_to(word_size, HeapRegion::GrainWords); - uint num_regions = (uint) (word_size_rounded / HeapRegion::GrainWords); - uint x_num = expansion_regions(); - uint fs = _hrs.free_suffix(); - uint first = humongous_obj_allocate_find_first(num_regions, word_size); - if (first == G1_NULL_HRS_INDEX) { - // The only thing we can do now is attempt expansion. - if (fs + x_num >= num_regions) { - // If the number of regions we're trying to allocate for this - // object is at most the number of regions in the free suffix, - // then the call to humongous_obj_allocate_find_first() above - // should have succeeded and we wouldn't be here. - // - // We should only be trying to expand when the free suffix is - // not sufficient for the object _and_ we have some expansion - // room available. - assert(num_regions > fs, "earlier allocation should have succeeded"); + uint first = G1_NO_HRS_INDEX; + uint obj_regions = (uint)(align_size_up_(word_size, HeapRegion::GrainWords) / HeapRegion::GrainWords); + if (obj_regions == 1) { + // Only one region to allocate, try to use a fast path by directly allocating + // from the free lists. Do not try to expand here, we will potentially do that + // later. + HeapRegion* hr = new_region(word_size, true /* is_old */, false /* do_expand */); + if (hr != NULL) { + first = hr->hrs_index(); + } + } else { + // We can't allocate humongous regions spanning more than one region while + // cleanupComplete() is running, since some of the regions we find to be + // empty might not yet be added to the free list. It is not straightforward + // to know in which list they are on so that we can remove them. We only + // need to do this if we need to allocate more than one region to satisfy the + // current humongous allocation request. If we are only allocating one region + // we use the one-region region allocation code (see above), that already + // potentially waits for regions from the secondary free list. + wait_while_free_regions_coming(); + append_secondary_free_list_if_not_empty_with_lock(); + + // Policy: Try only empty regions (i.e. already committed first). Maybe we + // are lucky enough to find some. + first = _hrs.find_contiguous_only_empty(obj_regions); + if (first != G1_NO_HRS_INDEX) { + _hrs.allocate_free_regions_starting_at(first, obj_regions); + } + } + + if (first == G1_NO_HRS_INDEX) { + // Policy: We could not find enough regions for the humongous object in the + // free list. Look through the heap to find a mix of free and uncommitted regions. + // If so, try expansion. + first = _hrs.find_contiguous_empty_or_unavailable(obj_regions); + if (first != G1_NO_HRS_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); - if (expand((num_regions - fs) * HeapRegion::GrainBytes)) { - // Even though the heap was expanded, it might not have - // reached the desired size. So, we cannot assume that the - // allocation will succeed. - first = humongous_obj_allocate_find_first(num_regions, word_size); + + _hrs.expand_at(first, obj_regions); + g1_policy()->record_new_heap_size(num_regions()); + +#ifdef ASSERT + for (uint i = first; i < first + obj_regions; ++i) { + HeapRegion* hr = region_at(i); + assert(hr->is_empty(), "sanity"); + assert(is_on_master_free_list(hr), "sanity"); } +#endif + _hrs.allocate_free_regions_starting_at(first, obj_regions); + } else { + // Policy: Potentially trigger a defragmentation GC. } } HeapWord* result = NULL; - if (first != G1_NULL_HRS_INDEX) { - result = - humongous_obj_allocate_initialize_regions(first, num_regions, word_size); + if (first != G1_NO_HRS_INDEX) { + result = humongous_obj_allocate_initialize_regions(first, obj_regions, word_size); assert(result != NULL, "it should always return a valid result"); // A successful humongous object allocation changes the used space @@ -1384,7 +1377,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, G1MarkSweep::invoke_at_safepoint(ref_processor_stw(), do_clear_all_soft_refs); } - assert(free_regions() == 0, "we should not have added any free regions"); + assert(num_free_regions() == 0, "we should not have added any free regions"); rebuild_region_sets(false /* free_list_only */); // Enqueue any discovered reference objects that have @@ -1749,21 +1742,6 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size) { return NULL; } -void G1CollectedHeap::update_committed_space(HeapWord* old_end, - HeapWord* new_end) { - assert(old_end != new_end, "don't call this otherwise"); - assert((HeapWord*) _g1_storage.high() == new_end, "invariant"); - - // Update the committed mem region. - _g1_committed.set_end(new_end); - // Tell the card table about the update. - Universe::heap()->barrier_set()->resize_covered_region(_g1_committed); - // Tell the BOT about the update. - _bot_shared->resize(_g1_committed.word_size()); - // Tell the hot card cache about the update - _cg1r->hot_card_cache()->resize_card_counts(capacity()); -} - bool G1CollectedHeap::expand(size_t expand_bytes) { size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); aligned_expand_bytes = align_size_up(aligned_expand_bytes, @@ -1774,55 +1752,22 @@ bool G1CollectedHeap::expand(size_t expand_bytes) { ergo_format_byte("attempted expansion amount"), expand_bytes, aligned_expand_bytes); - if (_g1_storage.uncommitted_size() == 0) { + if (is_maximal_no_gc()) { ergo_verbose0(ErgoHeapSizing, "did not expand the heap", ergo_format_reason("heap already fully expanded")); return false; } - // First commit the memory. - HeapWord* old_end = (HeapWord*) _g1_storage.high(); - bool successful = _g1_storage.expand_by(aligned_expand_bytes); - if (successful) { - // Then propagate this update to the necessary data structures. - HeapWord* new_end = (HeapWord*) _g1_storage.high(); - update_committed_space(old_end, new_end); + uint regions_to_expand = (uint)(aligned_expand_bytes / HeapRegion::GrainBytes); + assert(regions_to_expand > 0, "Must expand by at least one region"); - FreeRegionList expansion_list("Local Expansion List"); - MemRegion mr = _hrs.expand_by(old_end, new_end, &expansion_list); - assert(mr.start() == old_end, "post-condition"); - // mr might be a smaller region than what was requested if - // expand_by() was unable to allocate the HeapRegion instances - assert(mr.end() <= new_end, "post-condition"); + uint expanded_by = _hrs.expand_by(regions_to_expand); - size_t actual_expand_bytes = mr.byte_size(); + if (expanded_by > 0) { + size_t actual_expand_bytes = expanded_by * HeapRegion::GrainBytes; assert(actual_expand_bytes <= aligned_expand_bytes, "post-condition"); - assert(actual_expand_bytes == expansion_list.total_capacity_bytes(), - "post-condition"); - if (actual_expand_bytes < aligned_expand_bytes) { - // We could not expand _hrs to the desired size. In this case we - // need to shrink the committed space accordingly. - assert(mr.end() < new_end, "invariant"); - - size_t diff_bytes = aligned_expand_bytes - actual_expand_bytes; - // First uncommit the memory. - _g1_storage.shrink_by(diff_bytes); - // Then propagate this update to the necessary data structures. - update_committed_space(new_end, mr.end()); - } - _free_list.add_as_tail(&expansion_list); - - if (_hr_printer.is_active()) { - HeapWord* curr = mr.start(); - while (curr < mr.end()) { - HeapWord* curr_end = curr + HeapRegion::GrainWords; - _hr_printer.commit(curr, curr_end); - curr = curr_end; - } - assert(curr == mr.end(), "post-condition"); - } - g1_policy()->record_new_heap_size(n_regions()); + g1_policy()->record_new_heap_size(num_regions()); } else { ergo_verbose0(ErgoHeapSizing, "did not expand the heap", @@ -1830,12 +1775,12 @@ bool G1CollectedHeap::expand(size_t expand_bytes) { // The expansion of the virtual storage space was unsuccessful. // Let's see if it was because we ran out of swap. if (G1ExitOnExpansionFailure && - _g1_storage.uncommitted_size() >= aligned_expand_bytes) { + _hrs.available() >= regions_to_expand) { // We had head room... vm_exit_out_of_memory(aligned_expand_bytes, OOM_MMAP_ERROR, "G1 heap expansion"); } } - return successful; + return regions_to_expand > 0; } void G1CollectedHeap::shrink_helper(size_t shrink_bytes) { @@ -1846,7 +1791,6 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) { uint num_regions_to_remove = (uint)(shrink_bytes / HeapRegion::GrainBytes); uint num_regions_removed = _hrs.shrink_by(num_regions_to_remove); - HeapWord* old_end = (HeapWord*) _g1_storage.high(); size_t shrunk_bytes = num_regions_removed * HeapRegion::GrainBytes; ergo_verbose3(ErgoHeapSizing, @@ -1856,22 +1800,7 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) { ergo_format_byte("attempted shrinking amount"), shrink_bytes, aligned_shrink_bytes, shrunk_bytes); if (num_regions_removed > 0) { - _g1_storage.shrink_by(shrunk_bytes); - HeapWord* new_end = (HeapWord*) _g1_storage.high(); - - if (_hr_printer.is_active()) { - HeapWord* curr = old_end; - while (curr > new_end) { - HeapWord* curr_end = curr; - curr -= HeapRegion::GrainWords; - _hr_printer.uncommit(curr, curr_end); - } - } - - _expansion_regions += num_regions_removed; - update_committed_space(old_end, new_end); - HeapRegionRemSet::shrink_heap(n_regions()); - g1_policy()->record_new_heap_size(n_regions()); + g1_policy()->record_new_heap_size(num_regions()); } else { ergo_verbose0(ErgoHeapSizing, "did not shrink the heap", @@ -1922,10 +1851,11 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _g1mm(NULL), _refine_cte_cl(NULL), _full_collection(false), - _free_list("Master Free List", new MasterFreeRegionListMtSafeChecker()), _secondary_free_list("Secondary Free List", new SecondaryFreeRegionListMtSafeChecker()), _old_set("Old Set", false /* humongous */, new OldRegionSetMtSafeChecker()), _humongous_set("Master Humongous Set", true /* humongous */, new HumongousRegionSetMtSafeChecker()), + _humongous_is_live(), + _has_humongous_reclaim_candidates(false), _free_regions_coming(false), _young_list(new YoungList(this)), _gc_time_stamp(0), @@ -2034,8 +1964,6 @@ jint G1CollectedHeap::initialize() { _reserved.set_start((HeapWord*)heap_rs.base()); _reserved.set_end((HeapWord*)(heap_rs.base() + heap_rs.size())); - _expansion_regions = (uint) (max_byte_size / HeapRegion::GrainBytes); - // Create the gen rem set (and barrier set) for the entire reserved region. _rem_set = collector_policy()->create_rem_set(_reserved, 2); set_barrier_set(rem_set()->bs()); @@ -2049,20 +1977,65 @@ jint G1CollectedHeap::initialize() { // Carve out the G1 part of the heap. - ReservedSpace g1_rs = heap_rs.first_part(max_byte_size); - _g1_reserved = MemRegion((HeapWord*)g1_rs.base(), - g1_rs.size()/HeapWordSize); + ReservedSpace g1_rs = heap_rs.first_part(max_byte_size); + G1RegionToSpaceMapper* heap_storage = + G1RegionToSpaceMapper::create_mapper(g1_rs, + UseLargePages ? os::large_page_size() : os::vm_page_size(), + HeapRegion::GrainBytes, + 1, + mtJavaHeap); + heap_storage->set_mapping_changed_listener(&_listener); - _g1_storage.initialize(g1_rs, 0); - _g1_committed = MemRegion((HeapWord*)_g1_storage.low(), (size_t) 0); - _hrs.initialize((HeapWord*) _g1_reserved.start(), - (HeapWord*) _g1_reserved.end()); - assert(_hrs.max_length() == _expansion_regions, - err_msg("max length: %u expansion regions: %u", - _hrs.max_length(), _expansion_regions)); + // Reserve space for the block offset table. We do not support automatic uncommit + // for the card table at this time. BOT only. + ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize)); + G1RegionToSpaceMapper* bot_storage = + G1RegionToSpaceMapper::create_mapper(bot_rs, + os::vm_page_size(), + HeapRegion::GrainBytes, + G1BlockOffsetSharedArray::N_bytes, + mtGC); - // Do later initialization work for concurrent refinement. - _cg1r->init(); + ReservedSpace cardtable_rs(G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize)); + G1RegionToSpaceMapper* cardtable_storage = + G1RegionToSpaceMapper::create_mapper(cardtable_rs, + os::vm_page_size(), + HeapRegion::GrainBytes, + G1BlockOffsetSharedArray::N_bytes, + mtGC); + + // Reserve space for the card counts table. + ReservedSpace card_counts_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize)); + G1RegionToSpaceMapper* card_counts_storage = + G1RegionToSpaceMapper::create_mapper(card_counts_rs, + os::vm_page_size(), + HeapRegion::GrainBytes, + G1BlockOffsetSharedArray::N_bytes, + mtGC); + + // Reserve space for prev and next bitmap. + size_t bitmap_size = CMBitMap::compute_size(g1_rs.size()); + + ReservedSpace prev_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size)); + G1RegionToSpaceMapper* prev_bitmap_storage = + G1RegionToSpaceMapper::create_mapper(prev_bitmap_rs, + os::vm_page_size(), + HeapRegion::GrainBytes, + CMBitMap::mark_distance(), + mtGC); + + ReservedSpace next_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size)); + G1RegionToSpaceMapper* next_bitmap_storage = + G1RegionToSpaceMapper::create_mapper(next_bitmap_rs, + os::vm_page_size(), + HeapRegion::GrainBytes, + CMBitMap::mark_distance(), + mtGC); + + _hrs.initialize(heap_storage, prev_bitmap_storage, next_bitmap_storage, bot_storage, cardtable_storage, card_counts_storage); + g1_barrier_set()->initialize(cardtable_storage); + // Do later initialization work for concurrent refinement. + _cg1r->init(card_counts_storage); // 6843694 - ensure that the maximum region index can fit // in the remembered set structures. @@ -2076,16 +2049,16 @@ jint G1CollectedHeap::initialize() { FreeRegionList::set_unrealistically_long_length(max_regions() + 1); - _bot_shared = new G1BlockOffsetSharedArray(_reserved, - heap_word_size(init_byte_size)); + _bot_shared = new G1BlockOffsetSharedArray(_reserved, bot_storage); _g1h = this; - _in_cset_fast_test.initialize(_g1_reserved.start(), _g1_reserved.end(), HeapRegion::GrainBytes); + _in_cset_fast_test.initialize(_hrs.reserved().start(), _hrs.reserved().end(), HeapRegion::GrainBytes); + _humongous_is_live.initialize(_hrs.reserved().start(), _hrs.reserved().end(), HeapRegion::GrainBytes); // Create the ConcurrentMark data structure and thread. // (Must do this late, so that "max_regions" is defined.) - _cm = new ConcurrentMark(this, heap_rs); + _cm = new ConcurrentMark(this, prev_bitmap_storage, next_bitmap_storage); if (_cm == NULL || !_cm->completed_initialization()) { vm_shutdown_during_initialization("Could not create/initialize ConcurrentMark"); return JNI_ENOMEM; @@ -2140,12 +2113,10 @@ jint G1CollectedHeap::initialize() { // counts and that mechanism. SpecializationStats::clear(); - // Here we allocate the dummy full region that is required by the - // G1AllocRegion class. If we don't pass an address in the reserved - // space here, lots of asserts fire. + // Here we allocate the dummy HeapRegion that is required by the + // G1AllocRegion class. + HeapRegion* dummy_region = _hrs.get_dummy_region(); - HeapRegion* dummy_region = new_heap_region(0 /* index of bottom region */, - _g1_reserved.start()); // We'll re-use the same region whether the alloc region will // require BOT updates or not and, if it doesn't, then a non-young // region will complain that it cannot support allocations without @@ -2177,6 +2148,11 @@ void G1CollectedHeap::stop() { } } +void G1CollectedHeap::clear_humongous_is_live_table() { + guarantee(G1ReclaimDeadHumongousObjectsAtYoungGC, "Should only be called if true"); + _humongous_is_live.clear(); +} + size_t G1CollectedHeap::conservative_max_heap_alignment() { return HeapRegion::max_region_size(); } @@ -2256,7 +2232,7 @@ void G1CollectedHeap::ref_processing_init() { } size_t G1CollectedHeap::capacity() const { - return _g1_committed.byte_size(); + return _hrs.length() * HeapRegion::GrainBytes; } void G1CollectedHeap::reset_gc_time_stamps(HeapRegion* hr) { @@ -2540,7 +2516,7 @@ void G1CollectedHeap::collect(GCCause::Cause cause) { } } } else { - if (cause == GCCause::_gc_locker + if (cause == GCCause::_gc_locker || cause == GCCause::_wb_young_gc DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) { // Schedule a standard evacuation pause. We're setting word_size @@ -2561,8 +2537,8 @@ void G1CollectedHeap::collect(GCCause::Cause cause) { } bool G1CollectedHeap::is_in(const void* p) const { - if (_g1_committed.contains(p)) { - // Given that we know that p is in the committed space, + if (_hrs.reserved().contains(p)) { + // Given that we know that p is in the reserved space, // heap_region_containing_raw() should successfully // return the containing region. HeapRegion* hr = heap_region_containing_raw(p); @@ -2572,17 +2548,26 @@ bool G1CollectedHeap::is_in(const void* p) const { } } +#ifdef ASSERT +bool G1CollectedHeap::is_in_exact(const void* p) const { + bool contains = reserved_region().contains(p); + bool available = _hrs.is_available(addr_to_region((HeapWord*)p)); + if (contains && available) { + return true; + } else { + return false; + } +} +#endif + // Iteration functions. -// Iterates an OopClosure over all ref-containing fields of objects -// within a HeapRegion. +// Applies an ExtendedOopClosure onto all references of objects within a HeapRegion. class IterateOopClosureRegionClosure: public HeapRegionClosure { - MemRegion _mr; ExtendedOopClosure* _cl; public: - IterateOopClosureRegionClosure(MemRegion mr, ExtendedOopClosure* cl) - : _mr(mr), _cl(cl) {} + IterateOopClosureRegionClosure(ExtendedOopClosure* cl) : _cl(cl) {} bool doHeapRegion(HeapRegion* r) { if (!r->continuesHumongous()) { r->oop_iterate(_cl); @@ -2592,12 +2577,7 @@ public: }; void G1CollectedHeap::oop_iterate(ExtendedOopClosure* cl) { - IterateOopClosureRegionClosure blk(_g1_committed, cl); - heap_region_iterate(&blk); -} - -void G1CollectedHeap::oop_iterate(MemRegion mr, ExtendedOopClosure* cl) { - IterateOopClosureRegionClosure blk(mr, cl); + IterateOopClosureRegionClosure blk(cl); heap_region_iterate(&blk); } @@ -2644,83 +2624,9 @@ void G1CollectedHeap::heap_region_iterate(HeapRegionClosure* cl) const { void G1CollectedHeap::heap_region_par_iterate_chunked(HeapRegionClosure* cl, uint worker_id, - uint no_of_par_workers, - jint claim_value) { - const uint regions = n_regions(); - const uint max_workers = (G1CollectedHeap::use_parallel_gc_threads() ? - no_of_par_workers : - 1); - assert(UseDynamicNumberOfGCThreads || - no_of_par_workers == workers()->total_workers(), - "Non dynamic should use fixed number of workers"); - // try to spread out the starting points of the workers - const HeapRegion* start_hr = - start_region_for_worker(worker_id, no_of_par_workers); - const uint start_index = start_hr->hrs_index(); - - // each worker will actually look at all regions - for (uint count = 0; count < regions; ++count) { - const uint index = (start_index + count) % regions; - assert(0 <= index && index < regions, "sanity"); - HeapRegion* r = region_at(index); - // we'll ignore "continues humongous" regions (we'll process them - // when we come across their corresponding "start humongous" - // region) and regions already claimed - if (r->claim_value() == claim_value || r->continuesHumongous()) { - continue; - } - // OK, try to claim it - if (r->claimHeapRegion(claim_value)) { - // success! - assert(!r->continuesHumongous(), "sanity"); - if (r->startsHumongous()) { - // If the region is "starts humongous" we'll iterate over its - // "continues humongous" first; in fact we'll do them - // first. The order is important. In on case, calling the - // closure on the "starts humongous" region might de-allocate - // and clear all its "continues humongous" regions and, as a - // result, we might end up processing them twice. So, we'll do - // them first (notice: most closures will ignore them anyway) and - // then we'll do the "starts humongous" region. - for (uint ch_index = index + 1; ch_index < regions; ++ch_index) { - HeapRegion* chr = region_at(ch_index); - - // if the region has already been claimed or it's not - // "continues humongous" we're done - if (chr->claim_value() == claim_value || - !chr->continuesHumongous()) { - break; - } - - // No one should have claimed it directly. We can given - // that we claimed its "starts humongous" region. - assert(chr->claim_value() != claim_value, "sanity"); - assert(chr->humongous_start_region() == r, "sanity"); - - if (chr->claimHeapRegion(claim_value)) { - // we should always be able to claim it; no one else should - // be trying to claim this region - - bool res2 = cl->doHeapRegion(chr); - assert(!res2, "Should not abort"); - - // Right now, this holds (i.e., no closure that actually - // does something with "continues humongous" regions - // clears them). We might have to weaken it in the future, - // but let's leave these two asserts here for extra safety. - assert(chr->continuesHumongous(), "should still be the case"); - assert(chr->humongous_start_region() == r, "sanity"); - } else { - guarantee(false, "we should not reach here"); - } - } - } - - assert(!r->continuesHumongous(), "sanity"); - bool res = cl->doHeapRegion(r); - assert(!res, "Should not abort"); - } - } + uint num_workers, + jint claim_value) const { + _hrs.par_iterate(cl, worker_id, num_workers, claim_value); } class ResetClaimValuesClosure: public HeapRegionClosure { @@ -2898,17 +2804,6 @@ HeapRegion* G1CollectedHeap::start_cset_region_for_worker(uint worker_i) { return result; } -HeapRegion* G1CollectedHeap::start_region_for_worker(uint worker_i, - uint no_of_par_workers) { - uint worker_num = - G1CollectedHeap::use_parallel_gc_threads() ? no_of_par_workers : 1U; - assert(UseDynamicNumberOfGCThreads || - no_of_par_workers == workers()->total_workers(), - "Non dynamic should use fixed number of workers"); - const uint start_index = n_regions() * worker_i / worker_num; - return region_at(start_index); -} - void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) { HeapRegion* r = g1_policy()->collection_set(); while (r != NULL) { @@ -2951,15 +2846,11 @@ void G1CollectedHeap::collection_set_iterate_from(HeapRegion* r, } HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const { - // We're not using an iterator given that it will wrap around when - // it reaches the last region and this is not what we want here. - for (uint index = from->hrs_index() + 1; index < n_regions(); index++) { - HeapRegion* hr = region_at(index); - if (!hr->isHumongous()) { - return hr; - } + HeapRegion* result = _hrs.next_region_in_heap(from); + while (result != NULL && result->isHumongous()) { + result = _hrs.next_region_in_heap(result); } - return NULL; + return result; } Space* G1CollectedHeap::space_containing(const void* addr) const { @@ -3017,7 +2908,7 @@ size_t G1CollectedHeap::unsafe_max_tlab_alloc(Thread* ignored) const { } size_t G1CollectedHeap::max_capacity() const { - return _g1_reserved.byte_size(); + return _hrs.reserved().byte_size(); } jlong G1CollectedHeap::millis_since_last_gc() { @@ -3546,9 +3437,9 @@ void G1CollectedHeap::print_on(outputStream* st) const { st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", capacity()/K, used_unlocked()/K); st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")", - _g1_storage.low_boundary(), - _g1_storage.high(), - _g1_storage.high_boundary()); + _hrs.reserved().start(), + _hrs.reserved().start() + _hrs.length() + HeapRegion::GrainWords, + _hrs.reserved().end()); st->cr(); st->print(" region size " SIZE_FORMAT "K, ", HeapRegion::GrainBytes / K); uint young_regions = _young_list->length(); @@ -3771,6 +3662,61 @@ size_t G1CollectedHeap::cards_scanned() { return g1_rem_set()->cardsScanned(); } +bool G1CollectedHeap::humongous_region_is_always_live(uint index) { + HeapRegion* region = region_at(index); + assert(region->startsHumongous(), "Must start a humongous object"); + return oop(region->bottom())->is_objArray() || !region->rem_set()->is_empty(); +} + +class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure { + private: + size_t _total_humongous; + size_t _candidate_humongous; + public: + RegisterHumongousWithInCSetFastTestClosure() : _total_humongous(0), _candidate_humongous(0) { + } + + virtual bool doHeapRegion(HeapRegion* r) { + if (!r->startsHumongous()) { + return false; + } + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + + uint region_idx = r->hrs_index(); + bool is_candidate = !g1h->humongous_region_is_always_live(region_idx); + // Is_candidate already filters out humongous regions with some remembered set. + // This will not lead to humongous object that we mistakenly keep alive because + // during young collection the remembered sets will only be added to. + if (is_candidate) { + g1h->register_humongous_region_with_in_cset_fast_test(region_idx); + _candidate_humongous++; + } + _total_humongous++; + + return false; + } + + size_t total_humongous() const { return _total_humongous; } + size_t candidate_humongous() const { return _candidate_humongous; } +}; + +void G1CollectedHeap::register_humongous_regions_with_in_cset_fast_test() { + if (!G1ReclaimDeadHumongousObjectsAtYoungGC) { + g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0, 0); + return; + } + + RegisterHumongousWithInCSetFastTestClosure cl; + heap_region_iterate(&cl); + g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(cl.total_humongous(), + cl.candidate_humongous()); + _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0; + + if (_has_humongous_reclaim_candidates) { + clear_humongous_is_live_table(); + } +} + void G1CollectedHeap::setup_surviving_young_words() { assert(_surviving_young_words == NULL, "pre-condition"); @@ -4058,6 +4004,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { g1_policy()->finalize_cset(target_pause_time_ms, evacuation_info); + register_humongous_regions_with_in_cset_fast_test(); + _cm->note_start_of_gc(); // We should not verify the per-thread SATB buffers given that // we have not filtered them yet (we'll do so during the @@ -4108,6 +4056,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { true /* verify_fingers */); free_collection_set(g1_policy()->collection_set(), evacuation_info); + + eagerly_reclaim_humongous_regions(); + g1_policy()->clear_collection_set(); cleanup_surviving_young_words(); @@ -4179,10 +4130,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // No need for an ergo verbose message here, // expansion_amount() does this when it returns a value > 0. if (!expand(expand_bytes)) { - // We failed to expand the heap so let's verify that - // committed/uncommitted amount match the backing store - assert(capacity() == _g1_storage.committed_size(), "committed size mismatch"); - assert(max_capacity() == _g1_storage.reserved_size(), "reserved size mismatch"); + // We failed to expand the heap. Cannot do anything about it. } } } @@ -4242,10 +4190,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // RETIRE events are generated before the end GC event. _hr_printer.end_gc(false /* full */, (size_t) total_collections()); - if (mark_in_progress()) { - concurrent_mark()->update_g1_committed(); - } - #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); #endif @@ -4608,7 +4552,9 @@ void G1ParCopyClosure::do_oop_work(T* p) { assert(_worker_id == _par_scan_state->queue_num(), "sanity"); - if (_g1->in_cset_fast_test(obj)) { + G1CollectedHeap::in_cset_state_t state = _g1->in_cset_state(obj); + + if (state == G1CollectedHeap::InCSet) { oop forwardee; if (obj->is_forwarded()) { forwardee = obj->forwardee(); @@ -4627,6 +4573,9 @@ void G1ParCopyClosure::do_oop_work(T* p) { do_klass_barrier(p, forwardee); } } else { + if (state == G1CollectedHeap::IsHumongous) { + _g1->set_humongous_is_live(obj); + } // 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) { @@ -4719,11 +4668,6 @@ protected: Mutex _stats_lock; Mutex* stats_lock() { return &_stats_lock; } - size_t getNCards() { - return (_g1h->capacity() + G1BlockOffsetSharedArray::N_bytes - 1) - / G1BlockOffsetSharedArray::N_bytes; - } - public: G1ParTask(G1CollectedHeap* g1h, RefToScanQueueSet *task_queues) : AbstractGangTask("G1 collection"), @@ -4847,10 +4791,15 @@ public: if (_g1h->g1_policy()->during_initial_mark_pause()) { // We also need to mark copied objects. strong_root_cl = &scan_mark_root_cl; - weak_root_cl = &scan_mark_weak_root_cl; strong_cld_cl = &scan_mark_cld_cl; - weak_cld_cl = &scan_mark_weak_cld_cl; strong_code_cl = &scan_mark_code_cl; + if (ClassUnloadingWithConcurrentMark) { + weak_root_cl = &scan_mark_weak_root_cl; + weak_cld_cl = &scan_mark_weak_cld_cl; + } else { + weak_root_cl = &scan_mark_root_cl; + weak_cld_cl = &scan_mark_cld_cl; + } } else { strong_root_cl = &scan_only_root_cl; weak_root_cl = &scan_only_root_cl; @@ -4921,6 +4870,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots, double closure_app_time_sec = 0.0; bool during_im = _g1h->g1_policy()->during_initial_mark_pause(); + bool trace_metadata = during_im && ClassUnloadingWithConcurrentMark; BufferingOopClosure buf_scan_non_heap_roots(scan_non_heap_roots); BufferingOopClosure buf_scan_non_heap_weak_roots(scan_non_heap_weak_roots); @@ -4930,8 +4880,8 @@ g1_process_roots(OopClosure* scan_non_heap_roots, &buf_scan_non_heap_roots, &buf_scan_non_heap_weak_roots, scan_strong_clds, - // Initial Mark handles the weak CLDs separately. - (during_im ? NULL : scan_weak_clds), + // Unloading Initial Marks handle the weak CLDs separately. + (trace_metadata ? NULL : scan_weak_clds), scan_strong_code); // Now the CM ref_processor roots. @@ -4943,7 +4893,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots, ref_processor_cm()->weak_oops_do(&buf_scan_non_heap_roots); } - if (during_im) { + if (trace_metadata) { // Barrier to make sure all workers passed // the strong CLD and strong nmethods phases. active_strong_roots_scope()->wait_until_all_workers_done_with_threads(n_par_threads()); @@ -5450,12 +5400,21 @@ class G1KeepAliveClosure: public OopClosure { public: G1KeepAliveClosure(G1CollectedHeap* g1) : _g1(g1) {} void do_oop(narrowOop* p) { guarantee(false, "Not needed"); } - void do_oop( oop* p) { + void do_oop(oop* p) { oop obj = *p; - if (_g1->obj_in_cs(obj)) { + G1CollectedHeap::in_cset_state_t cset_state = _g1->in_cset_state(obj); + if (obj == NULL || cset_state == G1CollectedHeap::InNeither) { + return; + } + if (cset_state == G1CollectedHeap::InCSet) { assert( obj->is_forwarded(), "invariant" ); *p = obj->forwardee(); + } else { + assert(!obj->is_forwarded(), "invariant" ); + assert(cset_state == G1CollectedHeap::IsHumongous, + err_msg("Only allowed InCSet state is IsHumongous, but is %d", cset_state)); + _g1->set_humongous_is_live(obj); } } }; @@ -5485,7 +5444,7 @@ public: template void do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); - if (_g1h->obj_in_cs(obj)) { + if (_g1h->is_in_cset_or_humongous(obj)) { // If the referent object has been forwarded (either copied // to a new location or to itself in the event of an // evacuation failure) then we need to update the reference @@ -5510,10 +5469,10 @@ public: assert(!Metaspace::contains((const void*)p), err_msg("Unexpectedly found a pointer from metadata: " PTR_FORMAT, p)); - _copy_non_heap_obj_cl->do_oop(p); - } + _copy_non_heap_obj_cl->do_oop(p); } } + } }; // Serial drain queue closure. Called as the 'complete_gc' @@ -6065,6 +6024,7 @@ void G1CollectedHeap::free_region(HeapRegion* hr, bool locked) { assert(!hr->isHumongous(), "this is only for non-humongous regions"); assert(!hr->is_empty(), "the region should not be empty"); + assert(_hrs.is_available(hr->hrs_index()), "region should be committed"); assert(free_list != NULL, "pre-condition"); if (G1VerifyBitmaps) { @@ -6119,7 +6079,7 @@ void G1CollectedHeap::prepend_to_freelist(FreeRegionList* list) { assert(list != NULL, "list can't be null"); if (!list->is_empty()) { MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag); - _free_list.add_ordered(list); + _hrs.insert_list_into_free_list(list); } } @@ -6435,6 +6395,154 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e policy->phase_times()->record_non_young_free_cset_time_ms(non_young_time_ms); } +class G1FreeHumongousRegionClosure : public HeapRegionClosure { + private: + FreeRegionList* _free_region_list; + HeapRegionSet* _proxy_set; + HeapRegionSetCount _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) { + } + + virtual bool doHeapRegion(HeapRegion* r) { + if (!r->startsHumongous()) { + return false; + } + + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + + oop obj = (oop)r->bottom(); + CMBitMap* next_bitmap = g1h->concurrent_mark()->nextMarkBitMap(); + + // The following checks whether the humongous object is live are sufficient. + // The main additional check (in addition to having a reference from the roots + // or the young gen) is whether the humongous object has a remembered set entry. + // + // A humongous object cannot be live if there is no remembered set for it + // because: + // - there can be no references from within humongous starts regions referencing + // the object because we never allocate other objects into them. + // (I.e. there are no intra-region references that may be missed by the + // remembered set) + // - as soon there is a remembered set entry to the humongous starts region + // (i.e. it has "escaped" to an old object) this remembered set entry will stay + // until the end of a concurrent mark. + // + // It is not required to check whether the object has been found dead by marking + // or not, in fact it would prevent reclamation within a concurrent cycle, as + // all objects allocated during that time are considered live. + // SATB marking is even more conservative than the remembered set. + // So if at this point in the collection there is no remembered set entry, + // nobody has a reference to it. + // At the start of collection we flush all refinement logs, and remembered sets + // are completely up-to-date wrt to references to the humongous object. + // + // Other implementation considerations: + // - never consider object arrays: while they are a valid target, they have not + // been observed to be used as temporary objects. + // - they would also pose considerable effort for cleaning up the the remembered + // sets. + // While this cleanup is not strictly necessary to be done (or done instantly), + // given that their occurrence is very low, this saves us this additional + // complexity. + uint region_idx = r->hrs_index(); + if (g1h->humongous_is_live(region_idx) || + g1h->humongous_region_is_always_live(region_idx)) { + + if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) { + gclog_or_tty->print_cr("Live humongous %d region %d with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", + r->isHumongous(), + region_idx, + r->rem_set()->occupied(), + r->rem_set()->strong_code_roots_list_length(), + next_bitmap->isMarked(r->bottom()), + g1h->humongous_is_live(region_idx), + obj->is_objArray() + ); + } + + return false; + } + + guarantee(!obj->is_objArray(), + err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.", + r->bottom())); + + if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) { + gclog_or_tty->print_cr("Reclaim humongous region %d start "PTR_FORMAT" region %d length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", + r->isHumongous(), + r->bottom(), + region_idx, + r->region_num(), + r->rem_set()->occupied(), + r->rem_set()->strong_code_roots_list_length(), + next_bitmap->isMarked(r->bottom()), + g1h->humongous_is_live(region_idx), + obj->is_objArray() + ); + } + // Need to clear mark bit of the humongous object if already set. + if (next_bitmap->isMarked(r->bottom())) { + next_bitmap->clear(r->bottom()); + } + _freed_bytes += r->used(); + r->set_containing_set(NULL); + _humongous_regions_removed.increment(1u, r->capacity()); + g1h->free_humongous_region(r, _free_region_list, false); + + return false; + } + + HeapRegionSetCount& 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 (!G1ReclaimDeadHumongousObjectsAtYoungGC || !_has_humongous_reclaim_candidates) { + g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms(0.0, 0); + return; + } + + double start_time = os::elapsedTime(); + + FreeRegionList local_cleanup_list("Local Humongous Cleanup List"); + + G1FreeHumongousRegionClosure cl(&local_cleanup_list); + heap_region_iterate(&cl); + + HeapRegionSetCount empty_set; + remove_from_old_sets(empty_set, cl.humongous_free_count()); + + G1HRPrinter* hr_printer = _g1h->hr_printer(); + if (hr_printer->is_active()) { + FreeRegionListIterator iter(&local_cleanup_list); + while (iter.more_available()) { + HeapRegion* hr = iter.get_next(); + hr_printer->cleanup(hr); + } + } + + prepend_to_freelist(&local_cleanup_list); + 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()); +} + // This routine is similar to the above but does not record // any policy statistics or update free lists; we are abandoning // the current incremental collection set in preparation of a @@ -6579,22 +6687,22 @@ void G1CollectedHeap::tear_down_region_sets(bool free_list_only) { // this is that during a full GC string deduplication needs to know if // a collected region was young or old when the full GC was initiated. } - _free_list.remove_all(); + _hrs.remove_all_free_regions(); } class RebuildRegionSetsClosure : public HeapRegionClosure { private: bool _free_list_only; HeapRegionSet* _old_set; - FreeRegionList* _free_list; + HeapRegionSeq* _hrs; size_t _total_used; public: RebuildRegionSetsClosure(bool free_list_only, - HeapRegionSet* old_set, FreeRegionList* free_list) : + HeapRegionSet* old_set, HeapRegionSeq* hrs) : _free_list_only(free_list_only), - _old_set(old_set), _free_list(free_list), _total_used(0) { - assert(_free_list->is_empty(), "pre-condition"); + _old_set(old_set), _hrs(hrs), _total_used(0) { + assert(_hrs->num_free_regions() == 0, "pre-condition"); if (!free_list_only) { assert(_old_set->is_empty(), "pre-condition"); } @@ -6607,7 +6715,7 @@ public: if (r->is_empty()) { // Add free regions to the free list - _free_list->add_as_tail(r); + _hrs->insert_into_free_list(r); } else if (!_free_list_only) { assert(!r->is_young(), "we should not come across young regions"); @@ -6635,7 +6743,7 @@ void G1CollectedHeap::rebuild_region_sets(bool free_list_only) { _young_list->empty_list(); } - RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_free_list); + RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_hrs); heap_region_iterate(&cl); if (!free_list_only) { @@ -6790,13 +6898,42 @@ void OldGCAllocRegion::retire_region(HeapRegion* alloc_region, _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, GCAllocForTenured); } + +HeapRegion* OldGCAllocRegion::release() { + HeapRegion* cur = get(); + if (cur != NULL) { + // Determine how far we are from the next card boundary. If it is smaller than + // the minimum object size we can allocate into, expand into the next card. + HeapWord* top = cur->top(); + HeapWord* aligned_top = (HeapWord*)align_ptr_up(top, G1BlockOffsetSharedArray::N_bytes); + + size_t to_allocate_words = pointer_delta(aligned_top, top, HeapWordSize); + + if (to_allocate_words != 0) { + // We are not at a card boundary. Fill up, possibly into the next, taking the + // end of the region and the minimum object size into account. + to_allocate_words = MIN2(pointer_delta(cur->end(), cur->top(), HeapWordSize), + MAX2(to_allocate_words, G1CollectedHeap::min_fill_size())); + + // Skip allocation if there is not enough space to allocate even the smallest + // possible object. In this case this region will not be retained, so the + // original problem cannot occur. + if (to_allocate_words >= G1CollectedHeap::min_fill_size()) { + HeapWord* dummy = attempt_allocation(to_allocate_words, true /* bot_updates */); + CollectedHeap::fill_with_object(dummy, to_allocate_words); + } + } + } + return G1AllocRegion::release(); +} + // Heap region set verification class VerifyRegionListsClosure : public HeapRegionClosure { private: HeapRegionSet* _old_set; HeapRegionSet* _humongous_set; - FreeRegionList* _free_list; + HeapRegionSeq* _hrs; public: HeapRegionSetCount _old_count; @@ -6805,8 +6942,8 @@ public: VerifyRegionListsClosure(HeapRegionSet* old_set, HeapRegionSet* humongous_set, - FreeRegionList* free_list) : - _old_set(old_set), _humongous_set(humongous_set), _free_list(free_list), + HeapRegionSeq* hrs) : + _old_set(old_set), _humongous_set(humongous_set), _hrs(hrs), _old_count(), _humongous_count(), _free_count(){ } bool doHeapRegion(HeapRegion* hr) { @@ -6820,7 +6957,7 @@ public: assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->hrs_index())); _humongous_count.increment(1u, hr->capacity()); } else if (hr->is_empty()) { - assert(hr->containing_set() == _free_list, err_msg("Heap region %u is empty but not on the free list.", hr->hrs_index())); + assert(_hrs->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrs_index())); _free_count.increment(1u, hr->capacity()); } else { assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrs_index())); @@ -6829,7 +6966,7 @@ public: return false; } - void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, FreeRegionList* free_list) { + void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionSeq* free_list) { guarantee(old_set->length() == _old_count.length(), err_msg("Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count.length())); guarantee(old_set->total_capacity_bytes() == _old_count.capacity(), err_msg("Old set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, old_set->total_capacity_bytes(), _old_count.capacity())); @@ -6838,26 +6975,17 @@ public: guarantee(humongous_set->total_capacity_bytes() == _humongous_count.capacity(), err_msg("Hum set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, humongous_set->total_capacity_bytes(), _humongous_count.capacity())); - guarantee(free_list->length() == _free_count.length(), err_msg("Free list count mismatch. Expected %u, actual %u.", free_list->length(), _free_count.length())); + guarantee(free_list->num_free_regions() == _free_count.length(), err_msg("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(), err_msg("Free list capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, free_list->total_capacity_bytes(), _free_count.capacity())); } }; -HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index, - HeapWord* bottom) { - HeapWord* end = bottom + HeapRegion::GrainWords; - MemRegion mr(bottom, end); - assert(_g1_reserved.contains(mr), "invariant"); - // This might return NULL if the allocation fails - return new HeapRegion(hrs_index, _bot_shared, mr); -} - void G1CollectedHeap::verify_region_sets() { assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); // First, check the explicit lists. - _free_list.verify_list(); + _hrs.verify(); { // Given that a concurrent operation might be adding regions to // the secondary free list we have to take the lock before @@ -6888,9 +7016,9 @@ void G1CollectedHeap::verify_region_sets() { // Finally, make sure that the region accounting in the lists is // consistent with what we see in the heap. - VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_free_list); + VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_hrs); heap_region_iterate(&cl); - cl.verify_counts(&_old_set, &_humongous_set, &_free_list); + cl.verify_counts(&_old_set, &_humongous_set, &_hrs); } // Optimized nmethod scanning diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 9f51eafa1ed..34667c1162c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -183,6 +183,13 @@ protected: public: OldGCAllocRegion() : G1AllocRegion("Old GC Alloc Region", true /* bot_updates */) { } + + // This specialization of release() makes sure that the last card that has been + // allocated into has been completely filled by a dummy object. + // This avoids races when remembered set scanning wants to update the BOT of the + // last card in the retained old gc alloc region, and allocation threads + // allocating into that card at the same time. + virtual HeapRegion* release(); }; // The G1 STW is alive closure. @@ -197,18 +204,15 @@ public: bool do_object_b(oop p); }; -// Instances of this class are used for quick tests on whether a reference points -// into the collection set. Each of the array's elements denotes whether the -// corresponding region is in the collection set. -class G1FastCSetBiasedMappedArray : public G1BiasedMappedArray { - protected: - bool default_value() const { return false; } - public: - void clear() { G1BiasedMappedArray::clear(); } -}; - class RefineCardTableEntryClosure; +class G1RegionMappingChangedListener : public G1MappingChangedListener { + private: + void reset_from_card_cache(uint start_idx, size_t num_regions); + public: + virtual void on_commit(uint start_idx, size_t num_regions); +}; + class G1CollectedHeap : public SharedHeap { friend class VM_CollectForMetadataAllocation; friend class VM_G1CollectForAllocation; @@ -237,6 +241,7 @@ class G1CollectedHeap : public SharedHeap { friend class EvacPopObjClosure; friend class G1ParCleanupCTTask; + friend class G1FreeHumongousRegionClosure; // Other related classes. friend class G1MarkSweep; @@ -246,19 +251,9 @@ private: static size_t _humongous_object_threshold_in_words; - // Storage for the G1 heap. - VirtualSpace _g1_storage; - MemRegion _g1_reserved; - - // The part of _g1_storage that is currently committed. - MemRegion _g1_committed; - - // The master free list. It will satisfy all new region allocations. - FreeRegionList _free_list; - // The secondary free list which contains regions that have been - // freed up during the cleanup process. This will be appended to the - // master free list when appropriate. + // freed up during the cleanup process. This will be appended to + // the master free list when appropriate. FreeRegionList _secondary_free_list; // It keeps track of the old regions. @@ -267,6 +262,9 @@ private: // It keeps track of the humongous regions. HeapRegionSet _humongous_set; + void clear_humongous_is_live_table(); + void eagerly_reclaim_humongous_regions(); + // The number of regions we could create by expansion. uint _expansion_regions; @@ -289,6 +287,9 @@ private: // after heap shrinking (free_list_only == true). void rebuild_region_sets(bool free_list_only); + // Callback for region mapping changed events. + G1RegionMappingChangedListener _listener; + // The sequence of all heap regions in the heap. HeapRegionSeq _hrs; @@ -367,10 +368,25 @@ private: // than the current allocation region. size_t _summary_bytes_used; - // This array is used for a quick test on whether a reference points into - // the collection set or not. Each of the array's elements denotes whether the - // corresponding region is in the collection set or not. - G1FastCSetBiasedMappedArray _in_cset_fast_test; + // Records whether the region at the given index is kept live by roots or + // references from the young generation. + class HumongousIsLiveBiasedMappedArray : public G1BiasedMappedArray { + protected: + bool default_value() const { return false; } + public: + void clear() { G1BiasedMappedArray::clear(); } + void set_live(uint region) { + set_by_index(region, true); + } + bool is_live(uint region) { + return get_by_index(region); + } + }; + + HumongousIsLiveBiasedMappedArray _humongous_is_live; + // Stores whether during humongous object registration we found candidate regions. + // If not, we can skip a few steps. + bool _has_humongous_reclaim_candidates; volatile unsigned _gc_time_stamp; @@ -504,14 +520,6 @@ protected: // humongous object, set is_old to true. If not, to false. HeapRegion* new_region(size_t word_size, bool is_old, bool do_expand); - // Attempt to satisfy a humongous allocation request of the given - // size by finding a contiguous set of free regions of num_regions - // length and remove them from the master free list. Return the - // index of the first region or G1_NULL_HRS_INDEX if the search - // was unsuccessful. - uint humongous_obj_allocate_find_first(uint num_regions, - size_t word_size); - // Initialize a contiguous set of free regions of length num_regions // and starting at index first so that they appear as a single // humongous region. @@ -690,10 +698,24 @@ public: virtual void gc_prologue(bool full); virtual void gc_epilogue(bool full); + inline void set_humongous_is_live(oop obj); + + bool humongous_is_live(uint region) { + return _humongous_is_live.is_live(region); + } + + // Returns whether the given region (which must be a humongous (start) region) + // is to be considered conservatively live regardless of any other conditions. + bool humongous_region_is_always_live(uint index); + // Register the given region to be part of the collection set. + inline void register_humongous_region_with_in_cset_fast_test(uint index); + // Register regions with humongous objects (actually on the start region) in + // the in_cset_fast_test table. + void register_humongous_regions_with_in_cset_fast_test(); // We register a region with the fast "in collection set" test. We // simply set to true the array slot corresponding to this region. void register_region_with_in_cset_fast_test(HeapRegion* r) { - _in_cset_fast_test.set_by_index(r->hrs_index(), true); + _in_cset_fast_test.set_in_cset(r->hrs_index()); } // This is a fast test on whether a reference points into the @@ -839,11 +861,6 @@ protected: CodeBlobClosure* scan_strong_code, uint worker_i); - // Notifies all the necessary spaces that the committed space has - // been updated (either expanded or shrunk). It should be called - // after _g1_storage is updated. - void update_committed_space(HeapWord* old_end, HeapWord* new_end); - // The concurrent marker (and the thread it runs in.) ConcurrentMark* _cm; ConcurrentMarkThread* _cmThread; @@ -1154,27 +1171,20 @@ public: // But G1CollectedHeap doesn't yet support this. virtual bool is_maximal_no_gc() const { - return _g1_storage.uncommitted_size() == 0; + return _hrs.available() == 0; } - // The total number of regions in the heap. - uint n_regions() const { return _hrs.length(); } + // The current number of regions in the heap. + uint num_regions() const { return _hrs.length(); } // The max number of regions in the heap. uint max_regions() const { return _hrs.max_length(); } // The number of regions that are completely free. - uint free_regions() const { return _free_list.length(); } + uint num_free_regions() const { return _hrs.num_free_regions(); } // The number of regions that are not completely free. - uint used_regions() const { return n_regions() - free_regions(); } - - // The number of regions available for "regular" expansion. - uint expansion_regions() const { return _expansion_regions; } - - // Factory method for HeapRegion instances. It will return NULL if - // the allocation fails. - HeapRegion* new_heap_region(uint hrs_index, HeapWord* bottom); + uint num_used_regions() const { return num_regions() - num_free_regions(); } void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN; void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN; @@ -1223,7 +1233,7 @@ public: #ifdef ASSERT bool is_on_master_free_list(HeapRegion* hr) { - return hr->containing_set() == &_free_list; + return _hrs.is_free(hr); } #endif // ASSERT @@ -1235,7 +1245,7 @@ public: } void append_secondary_free_list() { - _free_list.add_ordered(&_secondary_free_list); + _hrs.insert_list_into_free_list(&_secondary_free_list); } void append_secondary_free_list_if_not_empty_with_lock() { @@ -1281,33 +1291,84 @@ public: // Returns "TRUE" iff "p" points into the committed areas of the heap. virtual bool is_in(const void* p) const; +#ifdef ASSERT + // Returns whether p is in one of the available areas of the heap. Slow but + // extensive version. + bool is_in_exact(const void* p) const; +#endif // Return "TRUE" iff the given object address is within the collection - // set. + // set. Slow implementation. inline bool obj_in_cs(oop obj); + inline bool is_in_cset(oop obj); + + inline bool is_in_cset_or_humongous(const oop obj); + + enum in_cset_state_t { + InNeither, // neither in collection set nor humongous + InCSet, // region is in collection set only + IsHumongous // region is a humongous start region + }; + private: + // Instances of this class are used for quick tests on whether a reference points + // into the collection set or is a humongous object (points into a humongous + // object). + // Each of the array's elements denotes whether the corresponding region is in + // the collection set or a humongous region. + // We use this to quickly reclaim humongous objects: by making a humongous region + // succeed this test, we sort-of add it to the collection set. During the reference + // iteration closures, when we see a humongous region, we simply mark it as + // referenced, i.e. live. + class G1FastCSetBiasedMappedArray : public G1BiasedMappedArray { + protected: + char default_value() const { return G1CollectedHeap::InNeither; } + public: + void set_humongous(uintptr_t index) { + assert(get_by_index(index) != InCSet, "Should not overwrite InCSet values"); + set_by_index(index, G1CollectedHeap::IsHumongous); + } + + void clear_humongous(uintptr_t index) { + set_by_index(index, G1CollectedHeap::InNeither); + } + + void set_in_cset(uintptr_t index) { + assert(get_by_index(index) != G1CollectedHeap::IsHumongous, "Should not overwrite IsHumongous value"); + set_by_index(index, G1CollectedHeap::InCSet); + } + + bool is_in_cset_or_humongous(HeapWord* addr) const { return get_by_address(addr) != G1CollectedHeap::InNeither; } + bool is_in_cset(HeapWord* addr) const { return get_by_address(addr) == G1CollectedHeap::InCSet; } + G1CollectedHeap::in_cset_state_t at(HeapWord* addr) const { return (G1CollectedHeap::in_cset_state_t)get_by_address(addr); } + void clear() { G1BiasedMappedArray::clear(); } + }; + + // This array is used for a quick test on whether a reference points into + // the collection set or not. Each of the array's elements denotes whether the + // corresponding region is in the collection set or not. + G1FastCSetBiasedMappedArray _in_cset_fast_test; + + public: + + inline in_cset_state_t in_cset_state(const oop obj); + // Return "TRUE" iff the given object address is in the reserved // region of g1. bool is_in_g1_reserved(const void* p) const { - return _g1_reserved.contains(p); + return _hrs.reserved().contains(p); } // Returns a MemRegion that corresponds to the space that has been // reserved for the heap - MemRegion g1_reserved() { - return _g1_reserved; - } - - // Returns a MemRegion that corresponds to the space that has been - // committed in the heap - MemRegion g1_committed() { - return _g1_committed; + MemRegion g1_reserved() const { + return _hrs.reserved(); } virtual bool is_in_closed_subset(const void* p) const; - G1SATBCardTableModRefBS* g1_barrier_set() { - return (G1SATBCardTableModRefBS*) barrier_set(); + G1SATBCardTableLoggingModRefBS* g1_barrier_set() { + return (G1SATBCardTableLoggingModRefBS*) barrier_set(); } // This resets the card table to all zeros. It is used after @@ -1320,9 +1381,6 @@ public: // "cl.do_oop" on each. virtual void oop_iterate(ExtendedOopClosure* cl); - // Same as above, restricted to a memory region. - void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); - // Iterate over all objects, calling "cl.do_object" on each. virtual void object_iterate(ObjectClosure* cl); @@ -1340,6 +1398,12 @@ public: // Return the region with the given index. It assumes the index is valid. inline HeapRegion* region_at(uint index) const; + // Calculate the region index of the given address. Given address must be + // within the heap. + inline uint addr_to_region(HeapWord* addr) const; + + inline HeapWord* bottom_addr_for_region(uint index) const; + // Divide the heap region sequence into "chunks" of some size (the number // of regions divided by the number of parallel threads times some // overpartition factor, currently 4). Assumes that this will be called @@ -1353,10 +1417,10 @@ public: // setting the claim value of the second and subsequent regions of the // chunk.) For now requires that "doHeapRegion" always returns "false", // i.e., that a closure never attempt to abort a traversal. - void heap_region_par_iterate_chunked(HeapRegionClosure* blk, - uint worker, - uint no_of_par_workers, - jint claim_value); + void heap_region_par_iterate_chunked(HeapRegionClosure* cl, + uint worker_id, + uint num_workers, + jint claim_value) const; // It resets all the region claim values to the default. void reset_heap_region_claim_values(); @@ -1381,11 +1445,6 @@ public: // starting region for iterating over the current collection set. HeapRegion* start_cset_region_for_worker(uint worker_i); - // This is a convenience method that is used by the - // HeapRegionIterator classes to calculate the starting region for - // each worker so that they do not all start from the same region. - HeapRegion* start_region_for_worker(uint worker_i, uint no_of_par_workers); - // Iterate over the regions (if any) in the current collection set. void collection_set_iterate(HeapRegionClosure* blk); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp index 7d5e530c497..f0efb2eb191 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp @@ -40,19 +40,28 @@ // Return the region with the given index. It assumes the index is valid. inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrs.at(index); } +inline uint G1CollectedHeap::addr_to_region(HeapWord* addr) const { + assert(is_in_reserved(addr), + err_msg("Cannot calculate region index for address "PTR_FORMAT" that is outside of the heap ["PTR_FORMAT", "PTR_FORMAT")", + p2i(addr), p2i(_reserved.start()), p2i(_reserved.end()))); + return (uint)(pointer_delta(addr, _reserved.start(), sizeof(uint8_t)) >> HeapRegion::LogOfHRGrainBytes); +} + +inline HeapWord* G1CollectedHeap::bottom_addr_for_region(uint index) const { + return _hrs.reserved().start() + index * HeapRegion::GrainWords; +} + template -inline HeapRegion* -G1CollectedHeap::heap_region_containing_raw(const T addr) const { +inline HeapRegion* G1CollectedHeap::heap_region_containing_raw(const T addr) const { assert(addr != NULL, "invariant"); - assert(_g1_reserved.contains((const void*) addr), + assert(is_in_g1_reserved((const void*) addr), err_msg("Address "PTR_FORMAT" is outside of the heap ranging from ["PTR_FORMAT" to "PTR_FORMAT")", - p2i((void*)addr), p2i(_g1_reserved.start()), p2i(_g1_reserved.end()))); + p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end()))); return _hrs.addr_to_region((HeapWord*) addr); } template -inline HeapRegion* -G1CollectedHeap::heap_region_containing(const T addr) const { +inline HeapRegion* G1CollectedHeap::heap_region_containing(const T addr) const { HeapRegion* hr = heap_region_containing_raw(addr); if (hr->continuesHumongous()) { return hr->humongous_start_region(); @@ -82,10 +91,9 @@ inline bool G1CollectedHeap::obj_in_cs(oop obj) { return r != NULL && r->in_collection_set(); } -inline HeapWord* -G1CollectedHeap::attempt_allocation(size_t word_size, - unsigned int* gc_count_before_ret, - int* gclocker_retry_count_ret) { +inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size, + unsigned int* gc_count_before_ret, + int* gclocker_retry_count_ret) { assert_heap_not_locked_and_not_at_safepoint(); assert(!isHumongous(word_size), "attempt_allocation() should not " "be called for humongous allocation requests"); @@ -172,12 +180,11 @@ inline bool G1CollectedHeap::isMarkedNext(oop obj) const { return _cm->nextMarkBitMap()->isMarked((HeapWord *)obj); } - // This is a fast test on whether a reference points into the // collection set or not. Assume that the reference // points into the heap. -inline bool G1CollectedHeap::in_cset_fast_test(oop obj) { - bool ret = _in_cset_fast_test.get_by_address((HeapWord*)obj); +inline bool G1CollectedHeap::is_in_cset(oop obj) { + bool ret = _in_cset_fast_test.is_in_cset((HeapWord*)obj); // let's make sure the result is consistent with what the slower // test returns assert( ret || !obj_in_cs(obj), "sanity"); @@ -185,6 +192,18 @@ inline bool G1CollectedHeap::in_cset_fast_test(oop obj) { return ret; } +bool G1CollectedHeap::is_in_cset_or_humongous(const oop obj) { + return _in_cset_fast_test.is_in_cset_or_humongous((HeapWord*)obj); +} + +G1CollectedHeap::in_cset_state_t G1CollectedHeap::in_cset_state(const oop obj) { + return _in_cset_fast_test.at((HeapWord*)obj); +} + +void G1CollectedHeap::register_humongous_region_with_in_cset_fast_test(uint index) { + _in_cset_fast_test.set_humongous(index); +} + #ifndef PRODUCT // Support for G1EvacuationFailureALot @@ -234,8 +253,7 @@ G1CollectedHeap::set_evacuation_failure_alot_for_current_gc() { } } -inline bool -G1CollectedHeap::evacuation_should_fail() { +inline bool G1CollectedHeap::evacuation_should_fail() { if (!G1EvacuationFailureALot || !_evacuation_failure_alot_for_current_gc) { return false; } @@ -288,4 +306,22 @@ inline bool G1CollectedHeap::is_obj_ill(const oop obj) const { return is_obj_ill(obj, heap_region_containing(obj)); } +inline void G1CollectedHeap::set_humongous_is_live(oop obj) { + uint region = addr_to_region((HeapWord*)obj); + // We not only set the "live" flag in the humongous_is_live table, but also + // reset the entry in the _in_cset_fast_test table so that subsequent references + // to the same humongous object do not go into the slow path again. + // This is racy, as multiple threads may at the same time enter here, but this + // is benign. + // During collection we only ever set the "live" flag, and only ever clear the + // entry in the in_cset_fast_table. + // We only ever evaluate the contents of these tables (in the VM thread) after + // having synchronized the worker threads with the VM thread, or in the same + // thread (i.e. within the VM thread). + if (!_humongous_is_live.is_live(region)) { + _humongous_is_live.set_live(region); + _in_cset_fast_test.clear_humongous(region); + } +} + #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTEDHEAP_INLINE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index eba482046fd..931c4e3d25e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -456,7 +456,7 @@ void G1CollectorPolicy::init() { } else { _young_list_fixed_length = _young_gen_sizer->min_desired_young_length(); } - _free_regions_at_end_of_collection = _g1->free_regions(); + _free_regions_at_end_of_collection = _g1->num_free_regions(); update_young_list_target_length(); // We may immediately start allocating regions and placing them on the @@ -829,7 +829,7 @@ void G1CollectorPolicy::record_full_collection_end() { record_survivor_regions(0, NULL, NULL); - _free_regions_at_end_of_collection = _g1->free_regions(); + _free_regions_at_end_of_collection = _g1->num_free_regions(); // Reset survivors SurvRateGroup. _survivor_surv_rate_group->reset(); update_young_list_target_length(); @@ -1181,7 +1181,7 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, Evacua _in_marking_window = new_in_marking_window; _in_marking_window_im = new_in_marking_window_im; - _free_regions_at_end_of_collection = _g1->free_regions(); + _free_regions_at_end_of_collection = _g1->num_free_regions(); update_young_list_target_length(); // Note that _mmu_tracker->max_gc_time() returns the time in seconds. @@ -1203,7 +1203,7 @@ void G1CollectorPolicy::record_heap_size_info_at_start(bool full) { _survivor_used_bytes_before_gc = young_list->survivor_used_bytes(); _heap_capacity_bytes_before_gc = _g1->capacity(); _heap_used_bytes_before_gc = _g1->used(); - _cur_collection_pause_used_regions_at_start = _g1->used_regions(); + _cur_collection_pause_used_regions_at_start = _g1->num_used_regions(); _eden_capacity_bytes_before_gc = (_young_list_target_length * HeapRegion::GrainBytes) - _survivor_used_bytes_before_gc; @@ -1618,7 +1618,7 @@ void G1CollectorPolicy::record_concurrent_mark_cleanup_end(int no_of_gc_threads) { _collectionSetChooser->clear(); - uint region_num = _g1->n_regions(); + uint region_num = _g1->num_regions(); if (G1CollectedHeap::use_parallel_gc_threads()) { const uint OverpartitionFactor = 4; uint WorkUnit; @@ -1639,7 +1639,7 @@ G1CollectorPolicy::record_concurrent_mark_cleanup_end(int no_of_gc_threads) { MAX2(region_num / (uint) (ParallelGCThreads * OverpartitionFactor), MinWorkUnit); } - _collectionSetChooser->prepare_for_par_region_addition(_g1->n_regions(), + _collectionSetChooser->prepare_for_par_region_addition(_g1->num_regions(), WorkUnit); ParKnownGarbageTask parKnownGarbageTask(_collectionSetChooser, (int) WorkUnit); @@ -1936,7 +1936,7 @@ uint G1CollectorPolicy::calc_max_old_cset_length() { // of them are available. G1CollectedHeap* g1h = G1CollectedHeap::heap(); - const size_t region_num = g1h->n_regions(); + const size_t region_num = g1h->num_regions(); const size_t perc = (size_t) G1OldCSetRegionThresholdPercent; size_t result = region_num * perc / 100; // emulate ceiling diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index 49232d60728..4e3fde8b862 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -237,8 +237,10 @@ void G1GCPhaseTimes::note_gc_end() { _last_gc_worker_times_ms.verify(); _last_gc_worker_other_times_ms.verify(); - _last_redirty_logged_cards_time_ms.verify(); - _last_redirty_logged_cards_processed_cards.verify(); + if (G1DeferredRSUpdate) { + _last_redirty_logged_cards_time_ms.verify(); + _last_redirty_logged_cards_processed_cards.verify(); + } } void G1GCPhaseTimes::note_string_dedup_fixup_start() { @@ -255,6 +257,10 @@ 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); } @@ -357,6 +363,14 @@ void G1GCPhaseTimes::print(double pause_time_sec) { _last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards"); } } + if (G1ReclaimDeadHumongousObjectsAtYoungGC) { + print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_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(3, "Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed); + } + } print_stats(2, "Free CSet", (_recorded_young_free_cset_time_ms + _recorded_non_young_free_cset_time_ms)); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp index 12a3a7dd21b..4237c972a55 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp @@ -157,11 +157,17 @@ class G1GCPhaseTimes : public CHeapObj { double _recorded_young_free_cset_time_ms; double _recorded_non_young_free_cset_time_ms; + double _cur_fast_reclaim_humongous_time_ms; + size_t _cur_fast_reclaim_humongous_total; + size_t _cur_fast_reclaim_humongous_candidates; + size_t _cur_fast_reclaim_humongous_reclaimed; + double _cur_verify_before_time_ms; 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); public: @@ -282,6 +288,16 @@ class G1GCPhaseTimes : public CHeapObj { _recorded_non_young_free_cset_time_ms = time_ms; } + void record_fast_reclaim_humongous_stats(size_t total, size_t candidates) { + _cur_fast_reclaim_humongous_total = total; + _cur_fast_reclaim_humongous_candidates = candidates; + } + + void record_fast_reclaim_humongous_time_ms(double value, size_t reclaimed) { + _cur_fast_reclaim_humongous_time_ms = value; + _cur_fast_reclaim_humongous_reclaimed = reclaimed; + } + void record_young_cset_choice_time_ms(double time_ms) { _recorded_young_cset_choice_time_ms = time_ms; } @@ -348,6 +364,10 @@ class G1GCPhaseTimes : public CHeapObj { return _recorded_non_young_free_cset_time_ms; } + double fast_reclaim_humongous_time_ms() { + return _cur_fast_reclaim_humongous_time_ms; + } + double average_last_update_rs_time() { return _last_update_rs_times_ms.average(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp index a75ba66e06f..79655933da7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp @@ -33,7 +33,7 @@ G1HotCardCache::G1HotCardCache(G1CollectedHeap *g1h): _g1h(g1h), _hot_cache(NULL), _use_cache(false), _card_counts(g1h) {} -void G1HotCardCache::initialize() { +void G1HotCardCache::initialize(G1RegionToSpaceMapper* card_counts_storage) { if (default_use_cache()) { _use_cache = true; @@ -49,7 +49,7 @@ void G1HotCardCache::initialize() { _hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / (int)n_workers); _hot_cache_par_claimed_idx = 0; - _card_counts.initialize(); + _card_counts.initialize(card_counts_storage); } } @@ -135,11 +135,8 @@ void G1HotCardCache::drain(uint worker_i, // above, are discarded prior to re-enabling the cache near the end of the GC. } -void G1HotCardCache::resize_card_counts(size_t heap_capacity) { - _card_counts.resize(heap_capacity); -} - void G1HotCardCache::reset_card_counts(HeapRegion* hr) { + assert(!hr->isHumongous(), "Should have been cleared"); _card_counts.clear_region(hr); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp index 5dc929c25e2..becd6832769 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp @@ -78,7 +78,7 @@ class G1HotCardCache: public CHeapObj { G1HotCardCache(G1CollectedHeap* g1h); ~G1HotCardCache(); - void initialize(); + void initialize(G1RegionToSpaceMapper* card_counts_storage); bool use_cache() { return _use_cache; } @@ -115,9 +115,6 @@ class G1HotCardCache: public CHeapObj { bool hot_cache_is_empty() { return _n_hot == 0; } - // Resizes the card counts table to match the given capacity - void resize_card_counts(size_t heap_capacity); - // Zeros the values in the card counts table for entire committed heap void reset_card_counts(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp index 2db5b9bfa1a..ecdb19440fa 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp @@ -44,7 +44,7 @@ template inline void FilterIntoCSClosure::do_oop_nv(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop) && - _g1->obj_in_cs(oopDesc::decode_heap_oop_not_null(heap_oop))) { + _g1->is_in_cset_or_humongous(oopDesc::decode_heap_oop_not_null(heap_oop))) { _oc->do_oop(p); } } @@ -67,7 +67,8 @@ inline void G1ParScanClosure::do_oop_nv(T* p) { if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - if (_g1->in_cset_fast_test(obj)) { + G1CollectedHeap::in_cset_state_t state = _g1->in_cset_state(obj); + if (state == G1CollectedHeap::InCSet) { // We're not going to even bother checking whether the object is // already forwarded or not, as this usually causes an immediate // stall. We'll try to prefetch the object (for write, given that @@ -86,6 +87,9 @@ inline void G1ParScanClosure::do_oop_nv(T* p) { _par_scan_state->push_on_queue(p); } else { + if (state == G1CollectedHeap::IsHumongous) { + _g1->set_humongous_is_live(obj); + } _par_scan_state->update_rs(_from, p, _worker_id); } } @@ -97,12 +101,14 @@ 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->in_cset_fast_test(obj)) { + if (_g1->is_in_cset_or_humongous(obj)) { 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 { + assert(!_g1->obj_in_cs(obj), "checking"); } } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp new file mode 100644 index 00000000000..1b294edffed --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp @@ -0,0 +1,167 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/g1/g1PageBasedVirtualSpace.hpp" +#include "oops/markOop.hpp" +#include "oops/oop.inline.hpp" +#include "services/memTracker.hpp" +#ifdef TARGET_OS_FAMILY_linux +# include "os_linux.inline.hpp" +#endif +#ifdef TARGET_OS_FAMILY_solaris +# include "os_solaris.inline.hpp" +#endif +#ifdef TARGET_OS_FAMILY_windows +# include "os_windows.inline.hpp" +#endif +#ifdef TARGET_OS_FAMILY_aix +# include "os_aix.inline.hpp" +#endif +#ifdef TARGET_OS_FAMILY_bsd +# include "os_bsd.inline.hpp" +#endif +#include "utilities/bitMap.inline.hpp" + +G1PageBasedVirtualSpace::G1PageBasedVirtualSpace() : _low_boundary(NULL), + _high_boundary(NULL), _committed(), _page_size(0), _special(false), _executable(false) { +} + +bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t page_size) { + if (!rs.is_reserved()) { + return false; // Allocation failed. + } + assert(_low_boundary == NULL, "VirtualSpace already initialized"); + assert(page_size > 0, "Granularity must be non-zero."); + + _low_boundary = rs.base(); + _high_boundary = _low_boundary + rs.size(); + + _special = rs.special(); + _executable = rs.executable(); + + _page_size = page_size; + + assert(_committed.size() == 0, "virtual space initialized more than once"); + uintx size_in_bits = rs.size() / page_size; + _committed.resize(size_in_bits, /* in_resource_area */ false); + + return true; +} + + +G1PageBasedVirtualSpace::~G1PageBasedVirtualSpace() { + release(); +} + +void G1PageBasedVirtualSpace::release() { + // This does not release memory it never reserved. + // Caller must release via rs.release(); + _low_boundary = NULL; + _high_boundary = NULL; + _special = false; + _executable = false; + _page_size = 0; + _committed.resize(0, false); +} + +size_t G1PageBasedVirtualSpace::committed_size() const { + return _committed.count_one_bits() * _page_size; +} + +size_t G1PageBasedVirtualSpace::reserved_size() const { + return pointer_delta(_high_boundary, _low_boundary, sizeof(char)); +} + +size_t G1PageBasedVirtualSpace::uncommitted_size() const { + return reserved_size() - committed_size(); +} + +uintptr_t G1PageBasedVirtualSpace::addr_to_page_index(char* addr) const { + return (addr - _low_boundary) / _page_size; +} + +bool G1PageBasedVirtualSpace::is_area_committed(uintptr_t start, size_t size_in_pages) const { + uintptr_t end = start + size_in_pages; + return _committed.get_next_zero_offset(start, end) >= end; +} + +bool G1PageBasedVirtualSpace::is_area_uncommitted(uintptr_t start, size_t size_in_pages) const { + uintptr_t end = start + size_in_pages; + return _committed.get_next_one_offset(start, end) >= end; +} + +char* G1PageBasedVirtualSpace::page_start(uintptr_t index) { + return _low_boundary + index * _page_size; +} + +size_t G1PageBasedVirtualSpace::byte_size_for_pages(size_t num) { + return num * _page_size; +} + +MemRegion G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) { + // We need to make sure to commit all pages covered by the given area. + guarantee(is_area_uncommitted(start, size_in_pages), "Specified area is not uncommitted"); + + if (!_special) { + os::commit_memory_or_exit(page_start(start), byte_size_for_pages(size_in_pages), _executable, + err_msg("Failed to commit pages from "SIZE_FORMAT" of length "SIZE_FORMAT, start, size_in_pages)); + } + _committed.set_range(start, start + size_in_pages); + + MemRegion result((HeapWord*)page_start(start), byte_size_for_pages(size_in_pages) / HeapWordSize); + return result; +} + +MemRegion G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) { + guarantee(is_area_committed(start, size_in_pages), "checking"); + + if (!_special) { + os::uncommit_memory(page_start(start), byte_size_for_pages(size_in_pages)); + } + + _committed.clear_range(start, start + size_in_pages); + + MemRegion result((HeapWord*)page_start(start), byte_size_for_pages(size_in_pages) / HeapWordSize); + return result; +} + +bool G1PageBasedVirtualSpace::contains(const void* p) const { + return _low_boundary <= (const char*) p && (const char*) p < _high_boundary; +} + +#ifndef PRODUCT +void G1PageBasedVirtualSpace::print_on(outputStream* out) { + out->print ("Virtual space:"); + if (special()) out->print(" (pinned in memory)"); + out->cr(); + out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); + out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); + out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", p2i(_low_boundary), p2i(_high_boundary)); +} + +void G1PageBasedVirtualSpace::print() { + print_on(tty); +} +#endif diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp new file mode 100644 index 00000000000..972a69b2e8f --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp @@ -0,0 +1,111 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1PAGEBASEDVIRTUALSPACE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1PAGEBASEDVIRTUALSPACE_HPP + +#include "memory/allocation.hpp" +#include "memory/memRegion.hpp" +#include "runtime/virtualspace.hpp" +#include "utilities/bitMap.hpp" + +// Virtual space management helper for a virtual space with an OS page allocation +// granularity. +// (De-)Allocation requests are always OS page aligned by passing a page index +// and multiples of pages. +// The implementation gives an error when trying to commit or uncommit pages that +// have already been committed or uncommitted. +class G1PageBasedVirtualSpace VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + private: + // Reserved area addresses. + char* _low_boundary; + char* _high_boundary; + + // The commit/uncommit granularity in bytes. + size_t _page_size; + + // Bitmap used for verification of commit/uncommit operations. + BitMap _committed; + + // Indicates that the entire space has been committed and pinned in memory, + // os::commit_memory() or os::uncommit_memory() have no function. + bool _special; + + // Indicates whether the committed space should be executable. + bool _executable; + + // Returns the index of the page which contains the given address. + uintptr_t addr_to_page_index(char* addr) const; + // Returns the address of the given page index. + char* page_start(uintptr_t index); + // Returns the byte size of the given number of pages. + size_t byte_size_for_pages(size_t num); + + // Returns true if the entire area is backed by committed memory. + bool is_area_committed(uintptr_t start, size_t size_in_pages) const; + // Returns true if the entire area is not backed by committed memory. + bool is_area_uncommitted(uintptr_t start, size_t size_in_pages) const; + + public: + + // Commit the given area of pages starting at start being size_in_pages large. + MemRegion commit(uintptr_t start, size_t size_in_pages); + + // Uncommit the given area of pages starting at start being size_in_pages large. + MemRegion uncommit(uintptr_t start, size_t size_in_pages); + + bool special() const { return _special; } + + // Initialization + G1PageBasedVirtualSpace(); + bool initialize_with_granularity(ReservedSpace rs, size_t page_size); + + // Destruction + ~G1PageBasedVirtualSpace(); + + // Amount of reserved memory. + size_t reserved_size() const; + // Memory used in this virtual space. + size_t committed_size() const; + // Memory left to use/expand in this virtual space. + size_t uncommitted_size() const; + + bool contains(const void* p) const; + + MemRegion reserved() { + MemRegion x((HeapWord*)_low_boundary, reserved_size() / HeapWordSize); + return x; + } + + void release(); + + void check_for_contiguity() PRODUCT_RETURN; + + // Debugging + void print_on(outputStream* out) PRODUCT_RETURN; + void print(); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1PAGEBASEDVIRTUALSPACE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp index 89e3e813b98..bf5824f1ed2 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp @@ -288,7 +288,12 @@ void G1ParScanThreadState::undo_allocation(GCAllocPurpose purpose, HeapWord* obj } HeapWord* G1ParScanThreadState::allocate(GCAllocPurpose purpose, size_t word_sz) { - HeapWord* obj = alloc_buffer(purpose)->allocate(word_sz); + HeapWord* obj = NULL; + if (purpose == GCAllocForSurvived) { + obj = alloc_buffer(GCAllocForSurvived)->allocate_aligned(word_sz, SurvivorAlignmentInBytes); + } else { + obj = alloc_buffer(GCAllocForTenured)->allocate(word_sz); + } if (obj != NULL) { return obj; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp index fc2fbe3ff45..75517fb3f9d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp @@ -52,15 +52,20 @@ template void G1ParScanThreadState::do_oop_evac(T* p, HeapRegion* from // set, due to (benign) races in the claim mechanism during RSet scanning more // than one thread might claim the same card. So the same card may be // processed multiple times. So redo this check. - if (_g1h->in_cset_fast_test(obj)) { + G1CollectedHeap::in_cset_state_t in_cset_state = _g1h->in_cset_state(obj); + if (in_cset_state == G1CollectedHeap::InCSet) { oop forwardee; if (obj->is_forwarded()) { forwardee = obj->forwardee(); } else { forwardee = copy_to_survivor_space(obj); } - assert(forwardee != NULL, "forwardee should not be NULL"); oopDesc::encode_store_heap_oop(p, forwardee); + } else if (in_cset_state == G1CollectedHeap::IsHumongous) { + _g1h->set_humongous_is_live(obj); + } else { + assert(in_cset_state == G1CollectedHeap::InNeither, + err_msg("In_cset_state must be InNeither here, but is %d", in_cset_state)); } assert(obj != NULL, "Must be"); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp new file mode 100644 index 00000000000..da0976ca99b --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2001, 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 "gc_implementation/g1/g1BiasedArray.hpp" +#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/virtualspace.hpp" +#include "services/memTracker.hpp" +#include "utilities/bitMap.inline.hpp" + +G1RegionToSpaceMapper::G1RegionToSpaceMapper(ReservedSpace rs, + size_t commit_granularity, + size_t region_granularity, + MemoryType type) : + _storage(), + _commit_granularity(commit_granularity), + _region_granularity(region_granularity), + _listener(NULL), + _commit_map() { + guarantee(is_power_of_2(commit_granularity), "must be"); + guarantee(is_power_of_2(region_granularity), "must be"); + _storage.initialize_with_granularity(rs, commit_granularity); + + MemTracker::record_virtual_memory_type((address)rs.base(), type); +} + +// G1RegionToSpaceMapper implementation where the region granularity is larger than +// or the same as the commit granularity. +// Basically, the space corresponding to one region region spans several OS pages. +class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper { + private: + size_t _pages_per_region; + + public: + G1RegionsLargerThanCommitSizeMapper(ReservedSpace rs, + size_t os_commit_granularity, + size_t alloc_granularity, + size_t commit_factor, + MemoryType type) : + G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type), + _pages_per_region(alloc_granularity / (os_commit_granularity * commit_factor)) { + + guarantee(alloc_granularity >= os_commit_granularity, "allocation granularity smaller than commit granularity"); + _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false); + } + + virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { + _storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region); + _commit_map.set_range(start_idx, start_idx + num_regions); + fire_on_commit(start_idx, num_regions); + } + + virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { + _storage.uncommit(start_idx * _pages_per_region, num_regions * _pages_per_region); + _commit_map.clear_range(start_idx, start_idx + num_regions); + } +}; + +// G1RegionToSpaceMapper implementation where the region granularity is smaller +// than the commit granularity. +// Basically, the contents of one OS page span several regions. +class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { + private: + class CommitRefcountArray : public G1BiasedMappedArray { + protected: + virtual uint default_value() const { return 0; } + }; + + size_t _regions_per_page; + + CommitRefcountArray _refcounts; + + uintptr_t region_idx_to_page_idx(uint region) const { + return region / _regions_per_page; + } + + public: + G1RegionsSmallerThanCommitSizeMapper(ReservedSpace rs, + size_t os_commit_granularity, + size_t alloc_granularity, + size_t commit_factor, + MemoryType type) : + G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type), + _regions_per_page((os_commit_granularity * commit_factor) / alloc_granularity), _refcounts() { + + guarantee((os_commit_granularity * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); + _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + rs.size()), os_commit_granularity); + _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false); + } + + virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { + for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) { + assert(!_commit_map.at(i), err_msg("Trying to commit storage at region "INTPTR_FORMAT" that is already committed", i)); + uintptr_t idx = region_idx_to_page_idx(i); + uint old_refcount = _refcounts.get_by_index(idx); + if (old_refcount == 0) { + _storage.commit(idx, 1); + } + _refcounts.set_by_index(idx, old_refcount + 1); + _commit_map.set_bit(i); + fire_on_commit(i, 1); + } + } + + virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { + for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) { + assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region "INTPTR_FORMAT" that is not committed", i)); + uintptr_t idx = region_idx_to_page_idx(i); + uint old_refcount = _refcounts.get_by_index(idx); + assert(old_refcount > 0, "must be"); + if (old_refcount == 1) { + _storage.uncommit(idx, 1); + } + _refcounts.set_by_index(idx, old_refcount - 1); + _commit_map.clear_bit(i); + } + } +}; + +void G1RegionToSpaceMapper::fire_on_commit(uint start_idx, size_t num_regions) { + if (_listener != NULL) { + _listener->on_commit(start_idx, num_regions); + } +} + +G1RegionToSpaceMapper* G1RegionToSpaceMapper::create_mapper(ReservedSpace rs, + size_t os_commit_granularity, + size_t region_granularity, + size_t commit_factor, + MemoryType type) { + + if (region_granularity >= (os_commit_granularity * commit_factor)) { + return new G1RegionsLargerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type); + } else { + return new G1RegionsSmallerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type); + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp new file mode 100644 index 00000000000..5f614b7a866 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp @@ -0,0 +1,83 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1REGIONTOSPACEMAPPER_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1REGIONTOSPACEMAPPER_HPP + +#include "gc_implementation/g1/g1PageBasedVirtualSpace.hpp" +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" + +class G1MappingChangedListener VALUE_OBJ_CLASS_SPEC { + public: + // Fired after commit of the memory, i.e. the memory this listener is registered + // for can be accessed. + virtual void on_commit(uint start_idx, size_t num_regions) = 0; +}; + +// Maps region based commit/uncommit requests to the underlying page sized virtual +// space. +class G1RegionToSpaceMapper : public CHeapObj { + private: + G1MappingChangedListener* _listener; + protected: + // Backing storage. + G1PageBasedVirtualSpace _storage; + size_t _commit_granularity; + size_t _region_granularity; + // Mapping management + BitMap _commit_map; + + G1RegionToSpaceMapper(ReservedSpace rs, size_t commit_granularity, size_t region_granularity, MemoryType type); + + void fire_on_commit(uint start_idx, size_t num_regions); + public: + MemRegion reserved() { return _storage.reserved(); } + + void set_mapping_changed_listener(G1MappingChangedListener* listener) { _listener = listener; } + + virtual ~G1RegionToSpaceMapper() { + _commit_map.resize(0, /* in_resource_area */ false); + } + + bool is_committed(uintptr_t idx) const { + return _commit_map.at(idx); + } + + virtual void commit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0; + virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0; + + // Creates an appropriate G1RegionToSpaceMapper for the given parameters. + // The byte_translation_factor defines how many bytes in a region correspond to + // a single byte in the data structure this mapper is for. + // Eg. in the card table, this value corresponds to the size a single card + // table entry corresponds to. + static G1RegionToSpaceMapper* create_mapper(ReservedSpace rs, + size_t os_commit_granularity, + size_t region_granularity, + size_t byte_translation_factor, + MemoryType type); +}; + +#endif /* SHARE_VM_GC_IMPLEMENTATION_G1_G1REGIONTOSPACEMAPPER_HPP */ diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 69b17c56702..c8e30f1d3b8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -349,23 +349,8 @@ void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, assert((ParallelGCThreads > 0) || worker_i == 0, "invariant"); - // The two flags below were introduced temporarily to serialize - // the updating and scanning of remembered sets. There are some - // race conditions when these two operations are done in parallel - // and they are causing failures. When we resolve said race - // conditions, we'll revert back to parallel remembered set - // updating and scanning. See CRs 6677707 and 6677708. - if (G1UseParallelRSetUpdating || (worker_i == 0)) { - updateRS(&into_cset_dcq, worker_i); - } else { - _g1p->phase_times()->record_update_rs_processed_buffers(worker_i, 0); - _g1p->phase_times()->record_update_rs_time(worker_i, 0.0); - } - if (G1UseParallelRSetScanning || (worker_i == 0)) { - scanRS(oc, code_root_cl, worker_i); - } else { - _g1p->phase_times()->record_scan_rs_time(worker_i, 0.0); - } + updateRS(&into_cset_dcq, worker_i); + scanRS(oc, code_root_cl, worker_i); // We now clear the cached values of _cset_rs_update_cl for this worker _cset_rs_update_cl[worker_i] = NULL; @@ -555,6 +540,12 @@ G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h, bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i, bool check_for_refs_into_cset) { + assert(_g1->is_in_exact(_ct_bs->addr_for(card_ptr)), + err_msg("Card at "PTR_FORMAT" index "SIZE_FORMAT" representing heap at "PTR_FORMAT" (%u) must be in committed heap", + p2i(card_ptr), + _ct_bs->index_for(_ct_bs->addr_for(card_ptr)), + _ct_bs->addr_for(card_ptr), + _g1->addr_to_region(_ct_bs->addr_for(card_ptr)))); // If the card is no longer dirty, nothing to do. if (*card_ptr != CardTableModRefBS::dirty_card_val()) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp index bcabcdd9bfa..2156577ea92 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "gc_implementation/g1/satbQueue.hpp" @@ -38,7 +39,6 @@ G1SATBCardTableModRefBS::G1SATBCardTableModRefBS(MemRegion whole_heap, _kind = G1SATBCT; } - void G1SATBCardTableModRefBS::enqueue(oop pre_val) { // Nulls should have been already filtered. assert(pre_val->is_oop(true), "Error"); @@ -125,13 +125,52 @@ void G1SATBCardTableModRefBS::verify_g1_young_region(MemRegion mr) { } #endif +void G1SATBCardTableLoggingModRefBSChangedListener::on_commit(uint start_idx, size_t num_regions) { + MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * HeapRegion::GrainWords); + _card_table->clear(mr); +} + G1SATBCardTableLoggingModRefBS:: G1SATBCardTableLoggingModRefBS(MemRegion whole_heap, int max_covered_regions) : G1SATBCardTableModRefBS(whole_heap, max_covered_regions), - _dcqs(JavaThread::dirty_card_queue_set()) + _dcqs(JavaThread::dirty_card_queue_set()), + _listener() { _kind = G1SATBCTLogging; + _listener.set_card_table(this); +} + +void G1SATBCardTableLoggingModRefBS::initialize(G1RegionToSpaceMapper* mapper) { + mapper->set_mapping_changed_listener(&_listener); + + _byte_map_size = mapper->reserved().byte_size(); + + _guard_index = cards_required(_whole_heap.word_size()) - 1; + _last_valid_index = _guard_index - 1; + + HeapWord* low_bound = _whole_heap.start(); + HeapWord* high_bound = _whole_heap.end(); + + _cur_covered_regions = 1; + _covered[0] = _whole_heap; + + _byte_map = (jbyte*) mapper->reserved().start(); + byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift); + 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)); + } } void diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp index 3e612605c02..f02c28c227b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1SATBCARDTABLEMODREFBS_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_G1SATBCARDTABLEMODREFBS_HPP +#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "memory/cardTableModRefBS.hpp" #include "memory/memRegion.hpp" #include "oops/oop.inline.hpp" @@ -33,6 +34,7 @@ #if INCLUDE_ALL_GCS class DirtyCardQueueSet; +class G1SATBCardTableLoggingModRefBS; // This barrier is specialized to use a logging barrier to support // snapshot-at-the-beginning marking. @@ -126,18 +128,40 @@ public: jbyte val = _byte_map[card_index]; return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); } +}; +class G1SATBCardTableLoggingModRefBSChangedListener : public G1MappingChangedListener { + private: + G1SATBCardTableLoggingModRefBS* _card_table; + public: + G1SATBCardTableLoggingModRefBSChangedListener() : _card_table(NULL) { } + + void set_card_table(G1SATBCardTableLoggingModRefBS* card_table) { _card_table = card_table; } + + virtual void on_commit(uint start_idx, size_t num_regions); }; // Adds card-table logging to the post-barrier. // Usual invariant: all dirty cards are logged in the DirtyCardQueueSet. class G1SATBCardTableLoggingModRefBS: public G1SATBCardTableModRefBS { + friend class G1SATBCardTableLoggingModRefBSChangedListener; private: + G1SATBCardTableLoggingModRefBSChangedListener _listener; DirtyCardQueueSet& _dcqs; public: + static size_t compute_size(size_t mem_region_size_in_words) { + size_t number_of_slots = (mem_region_size_in_words / card_size_in_words); + return ReservedSpace::allocation_align_size_up(number_of_slots); + } + G1SATBCardTableLoggingModRefBS(MemRegion whole_heap, int max_covered_regions); + virtual void initialize() { } + virtual void initialize(G1RegionToSpaceMapper* mapper); + + virtual void resize_covered_region(MemRegion new_region) { ShouldNotReachHere(); } + bool is_a(BarrierSet::Name bsn) { return bsn == BarrierSet::G1SATBCTLogging || G1SATBCardTableModRefBS::is_a(bsn); @@ -154,8 +178,6 @@ class G1SATBCardTableLoggingModRefBS: public G1SATBCardTableModRefBS { void write_region_work(MemRegion mr) { invalidate(mr); } void write_ref_array_work(MemRegion mr) { invalidate(mr); } - - }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index f50eaa1001e..17ae309240d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -220,14 +220,6 @@ product(uintx, G1HeapRegionSize, 0, \ "Size of the G1 regions.") \ \ - experimental(bool, G1UseParallelRSetUpdating, true, \ - "Enables the parallelization of remembered set updating " \ - "during evacuation pauses") \ - \ - experimental(bool, G1UseParallelRSetScanning, true, \ - "Enables the parallelization of remembered set scanning " \ - "during evacuation pauses") \ - \ product(uintx, G1ConcRefinementThreads, 0, \ "If non-0 is the number of parallel rem set update threads, " \ "otherwise the value is determined ergonomically.") \ @@ -289,6 +281,13 @@ "The amount of code root chunks that should be kept at most " \ "as percentage of already allocated.") \ \ + experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true, \ + "Try to reclaim dead large objects at every young GC.") \ + \ + experimental(bool, G1TraceReclaimDeadHumongousObjectsAtYoungGC, 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.") \ diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 524f2f315fb..ea10843e3ed 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -345,11 +345,6 @@ HeapWord* HeapRegion::next_block_start_careful(HeapWord* addr) { return low; } -#ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away -#pragma warning( disable:4355 ) // 'this' : used in base member initializer list -#endif // _MSC_VER - - HeapRegion::HeapRegion(uint hrs_index, G1BlockOffsetSharedArray* sharedOffsetArray, MemRegion mr) : @@ -361,7 +356,7 @@ HeapRegion::HeapRegion(uint hrs_index, _claimed(InitialClaimValue), _evacuation_failed(false), _prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0), _young_type(NotYoung), _next_young_region(NULL), - _next_dirty_cards_region(NULL), _next(NULL), _prev(NULL), _pending_removal(false), + _next_dirty_cards_region(NULL), _next(NULL), _prev(NULL), #ifdef ASSERT _containing_set(NULL), #endif // ASSERT @@ -370,14 +365,20 @@ HeapRegion::HeapRegion(uint hrs_index, _predicted_bytes_to_copy(0) { _rem_set = new HeapRegionRemSet(sharedOffsetArray, this); + assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant."); + + initialize(mr); +} + +void HeapRegion::initialize(MemRegion mr, bool clear_space, bool mangle_space) { + assert(_rem_set->is_empty(), "Remembered set must be empty"); + + G1OffsetTableContigSpace::initialize(mr, clear_space, mangle_space); + _orig_end = mr.end(); - // Note that initialize() will set the start of the unmarked area of the - // region. hr_clear(false /*par*/, false /*clear_space*/); set_top(bottom()); record_top_and_timestamp(); - - assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant."); } CompactibleSpace* HeapRegion::next_compaction_space() const { @@ -905,7 +906,7 @@ void HeapRegion::verify(VerifyOption vo, } // If it returns false, verify_for_object() will output the - // appropriate messasge. + // appropriate message. if (do_bot_verify && !g1->is_obj_dead(obj, this) && !_offsets.verify_for_object(p, obj_size)) { @@ -1036,8 +1037,7 @@ void G1OffsetTableContigSpace::clear(bool mangle_space) { set_top(bottom()); set_saved_mark_word(bottom()); CompactibleSpace::clear(mangle_space); - _offsets.zero_bottom_entry(); - _offsets.initialize_threshold(); + reset_bot(); } void G1OffsetTableContigSpace::set_bottom(HeapWord* new_bottom) { @@ -1127,9 +1127,11 @@ G1OffsetTableContigSpace(G1BlockOffsetSharedArray* sharedOffsetArray, _gc_time_stamp(0) { _offsets.set_space(this); - // false ==> we'll do the clearing if there's clearing to be done. - CompactibleSpace::initialize(mr, false, SpaceDecorator::Mangle); - _top = bottom(); - _offsets.zero_bottom_entry(); - _offsets.initialize_threshold(); } + +void G1OffsetTableContigSpace::initialize(MemRegion mr, bool clear_space, bool mangle_space) { + CompactibleSpace::initialize(mr, clear_space, mangle_space); + _top = bottom(); + reset_bot(); +} + diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index 42c9eac5431..7f6485b316c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -62,7 +62,7 @@ class nmethod; p2i((_hr_)->bottom()), p2i((_hr_)->top()), p2i((_hr_)->end()) // sentinel value for hrs_index -#define G1_NULL_HRS_INDEX ((uint) -1) +#define G1_NO_HRS_INDEX ((uint) -1) // A dirty card to oop closure for heap regions. It // knows how to get the G1 heap and how to use the bitmap @@ -146,6 +146,9 @@ class G1OffsetTableContigSpace: public CompactibleSpace { HeapWord* top() const { return _top; } protected: + // Reset the G1OffsetTableContigSpace. + virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space); + HeapWord** top_addr() { return &_top; } // Allocation helpers (return NULL if full). inline HeapWord* allocate_impl(size_t word_size, HeapWord* end_value); @@ -200,8 +203,7 @@ class G1OffsetTableContigSpace: public CompactibleSpace { virtual void print() const; void reset_bot() { - _offsets.zero_bottom_entry(); - _offsets.initialize_threshold(); + _offsets.reset_bot(); } void update_bot_for_object(HeapWord* start, size_t word_size) { @@ -264,7 +266,6 @@ class HeapRegion: public G1OffsetTableContigSpace { #ifdef ASSERT HeapRegionSetBase* _containing_set; #endif // ASSERT - bool _pending_removal; // For parallel heapRegion traversal. jint _claimed; @@ -333,6 +334,12 @@ class HeapRegion: public G1OffsetTableContigSpace { G1BlockOffsetSharedArray* sharedOffsetArray, MemRegion mr); + // Initializing the HeapRegion not only resets the data structure, but also + // resets the BOT for that heap region. + // The default values for clear_space means that we will do the clearing if + // there's clearing to be done ourselves. We also always mangle the space. + virtual void initialize(MemRegion mr, bool clear_space = false, bool mangle_space = SpaceDecorator::Mangle); + static int LogOfHRGrainBytes; static int LogOfHRGrainWords; @@ -553,26 +560,6 @@ class HeapRegion: public G1OffsetTableContigSpace { // to provide a dummy version of it. #endif // ASSERT - // If we want to remove regions from a list in bulk we can simply tag - // them with the pending_removal tag and call the - // remove_all_pending() method on the list. - - bool pending_removal() { return _pending_removal; } - - void set_pending_removal(bool pending_removal) { - if (pending_removal) { - assert(!_pending_removal && containing_set() != NULL, - "can only set pending removal to true if it's false and " - "the region belongs to a region set"); - } else { - assert( _pending_removal && containing_set() == NULL, - "can only set pending removal to false if it's true and " - "the region does not belong to a region set"); - } - - _pending_removal = pending_removal; - } - HeapRegion* get_next_young_region() { return _next_young_region; } void set_next_young_region(HeapRegion* hr) { _next_young_region = hr; diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.inline.hpp index ebe4c067b9d..62ae230f1a3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.inline.hpp @@ -94,26 +94,37 @@ G1OffsetTableContigSpace::block_start_const(const void* p) const { inline bool HeapRegion::block_is_obj(const HeapWord* p) const { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - return !g1h->is_obj_dead(oop(p), this); + if (ClassUnloadingWithConcurrentMark) { + return !g1h->is_obj_dead(oop(p), this); + } + return p < top(); } inline size_t HeapRegion::block_size(const HeapWord *addr) const { + if (addr == top()) { + return pointer_delta(end(), addr); + } + + if (block_is_obj(addr)) { + return oop(addr)->size(); + } + + assert(ClassUnloadingWithConcurrentMark, + err_msg("All blocks should be objects if G1 Class Unloading isn't used. " + "HR: ["PTR_FORMAT", "PTR_FORMAT", "PTR_FORMAT") " + "addr: " PTR_FORMAT, + p2i(bottom()), p2i(top()), p2i(end()), p2i(addr))); + // Old regions' dead objects may have dead classes // We need to find the next live object in some other // manner than getting the oop size G1CollectedHeap* g1h = G1CollectedHeap::heap(); - if (g1h->is_obj_dead(oop(addr), this)) { - HeapWord* next = g1h->concurrent_mark()->prevMarkBitMap()-> - getNextMarkedWordAddress(addr, prev_top_at_mark_start()); + HeapWord* next = g1h->concurrent_mark()->prevMarkBitMap()-> + getNextMarkedWordAddress(addr, prev_top_at_mark_start()); - assert(next > addr, "must get the next live object"); - - return pointer_delta(next, addr); - } else if (addr == top()) { - return pointer_delta(end(), addr); - } - return oop(addr)->size(); + assert(next > addr, "must get the next live object"); + return pointer_delta(next, addr); } inline HeapWord* HeapRegion::par_allocate_no_bot_updates(size_t word_size) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index df65940100d..21d70c33572 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -289,7 +289,7 @@ OtherRegionsTable::OtherRegionsTable(HeapRegion* hr, Mutex* m) : } _fine_grain_regions = NEW_C_HEAP_ARRAY3(PerRegionTablePtr, _max_fine_entries, - mtGC, 0, AllocFailStrategy::RETURN_NULL); + mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL); if (_fine_grain_regions == NULL) { vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries, OOM_MALLOC_ERROR, @@ -373,17 +373,17 @@ void FromCardCache::initialize(uint n_par_rs, uint max_num_regions) { _max_regions, &_static_mem_size); - for (uint i = 0; i < n_par_rs; i++) { - for (uint j = 0; j < _max_regions; j++) { - set(i, j, InvalidCard); - } - } + invalidate(0, _max_regions); } -void FromCardCache::shrink(uint new_num_regions) { +void FromCardCache::invalidate(uint start_idx, size_t new_num_regions) { + guarantee((size_t)start_idx + new_num_regions <= max_uintx, + err_msg("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++) { - assert(new_num_regions <= _max_regions, "Must be within max."); - for (uint j = new_num_regions; j < _max_regions; j++) { + 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); } } @@ -407,12 +407,12 @@ void FromCardCache::clear(uint region_idx) { } } -void OtherRegionsTable::init_from_card_cache(uint max_regions) { +void OtherRegionsTable::initialize(uint max_regions) { FromCardCache::initialize(HeapRegionRemSet::num_par_rem_sets(), max_regions); } -void OtherRegionsTable::shrink_from_card_cache(uint new_num_regions) { - FromCardCache::shrink(new_num_regions); +void OtherRegionsTable::invalidate(uint start_idx, size_t num_regions) { + FromCardCache::invalidate(start_idx, num_regions); } void OtherRegionsTable::print_from_card_cache() { @@ -695,6 +695,9 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs, clear_fcc(); } +bool OtherRegionsTable::is_empty() const { + return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL; +} size_t OtherRegionsTable::occupied() const { size_t sum = occ_fine(); @@ -838,7 +841,7 @@ HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr) : _bosa(bosa), _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrs_index()), true), - _code_roots(), _other_regions(hr, &_m) { + _code_roots(), _other_regions(hr, &_m), _iter_state(Unclaimed), _iter_claimed(0) { reset_for_par_iteration(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index 64a02ead2ea..70eae9bdf2b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -84,7 +84,7 @@ class FromCardCache : public AllStatic { static void initialize(uint n_par_rs, uint max_num_regions); - static void shrink(uint new_num_regions); + static void invalidate(uint start_idx, size_t num_regions); static void print(outputStream* out = gclog_or_tty) PRODUCT_RETURN; @@ -185,6 +185,9 @@ public: // objects. void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm); + // Returns whether this remembered set (and all sub-sets) contain no entries. + bool is_empty() const; + size_t occupied() const; size_t occ_fine() const; size_t occ_coarse() const; @@ -210,11 +213,11 @@ public: // Declare the heap size (in # of regions) to the OtherRegionsTable. // (Uses it to initialize from_card_cache). - static void init_from_card_cache(uint max_regions); + static void initialize(uint max_regions); - // Declares that only regions i s.t. 0 <= i < new_n_regs are in use. - // Make sure any entries for higher regions are invalid. - static void shrink_from_card_cache(uint new_num_regions); + // Declares that regions between start_idx <= i < start_idx + num_regions are + // not in use. Make sure that any entries for these regions are invalid. + static void invalidate(uint start_idx, size_t num_regions); static void print_from_card_cache(); }; @@ -269,6 +272,10 @@ public: return _other_regions.hr(); } + bool is_empty() const { + return (strong_code_roots_list_length() == 0) && _other_regions.is_empty(); + } + size_t occupied() { MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); return occupied_locked(); @@ -371,7 +378,7 @@ public: void strong_code_roots_do(CodeBlobClosure* blk) const; // Returns the number of elements in the strong code roots list - size_t strong_code_roots_list_length() { + size_t strong_code_roots_list_length() const { return _code_roots.length(); } @@ -393,12 +400,11 @@ public: // 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) { - OtherRegionsTable::init_from_card_cache(max_regions); + OtherRegionsTable::initialize(max_regions); } - // Declares that only regions i s.t. 0 <= i < new_n_regs are in use. - static void shrink_heap(uint new_n_regs) { - OtherRegionsTable::shrink_from_card_cache(new_n_regs); + static void invalidate(uint start_idx, uint num_regions) { + OtherRegionsTable::invalidate(start_idx, num_regions); } #ifndef PRODUCT diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp index 04f48e60550..418d01a228b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp @@ -25,236 +25,426 @@ #include "precompiled.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" -#include "gc_implementation/g1/heapRegionSet.hpp" +#include "gc_implementation/g1/heapRegionSet.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/concurrentG1Refine.hpp" #include "memory/allocation.hpp" -// Private +void HeapRegionSeq::initialize(G1RegionToSpaceMapper* heap_storage, + G1RegionToSpaceMapper* prev_bitmap, + G1RegionToSpaceMapper* next_bitmap, + G1RegionToSpaceMapper* bot, + G1RegionToSpaceMapper* cardtable, + G1RegionToSpaceMapper* card_counts) { + _allocated_heapregions_length = 0; -uint HeapRegionSeq::find_contiguous_from(uint from, uint num) { - uint len = length(); - assert(num > 1, "use this only for sequences of length 2 or greater"); - assert(from <= len, - err_msg("from: %u should be valid and <= than %u", from, len)); + _heap_mapper = heap_storage; - uint curr = from; - uint first = G1_NULL_HRS_INDEX; - uint num_so_far = 0; - while (curr < len && num_so_far < num) { - if (at(curr)->is_empty()) { - if (first == G1_NULL_HRS_INDEX) { - first = curr; - num_so_far = 1; - } else { - num_so_far += 1; - } - } else { - first = G1_NULL_HRS_INDEX; - num_so_far = 0; + _prev_bitmap_mapper = prev_bitmap; + _next_bitmap_mapper = next_bitmap; + + _bot_mapper = bot; + _cardtable_mapper = cardtable; + + _card_counts_mapper = card_counts; + + MemRegion reserved = heap_storage->reserved(); + _regions.initialize(reserved.start(), reserved.end(), HeapRegion::GrainBytes); + + _available_map.resize(_regions.length(), false); + _available_map.clear(); +} + +bool HeapRegionSeq::is_available(uint region) const { + return _available_map.at(region); +} + +#ifdef ASSERT +bool HeapRegionSeq::is_free(HeapRegion* hr) const { + return _free_list.contains(hr); +} +#endif + +HeapRegion* HeapRegionSeq::new_heap_region(uint hrs_index) { + HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(hrs_index); + MemRegion mr(bottom, bottom + HeapRegion::GrainWords); + assert(reserved().contains(mr), "invariant"); + return new HeapRegion(hrs_index, G1CollectedHeap::heap()->bot_shared(), mr); +} + +void HeapRegionSeq::commit_regions(uint index, size_t num_regions) { + guarantee(num_regions > 0, "Must commit more than zero regions"); + guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions"); + + _num_committed += (uint)num_regions; + + _heap_mapper->commit_regions(index, num_regions); + + // Also commit auxiliary data + _prev_bitmap_mapper->commit_regions(index, num_regions); + _next_bitmap_mapper->commit_regions(index, num_regions); + + _bot_mapper->commit_regions(index, num_regions); + _cardtable_mapper->commit_regions(index, num_regions); + + _card_counts_mapper->commit_regions(index, num_regions); +} + +void HeapRegionSeq::uncommit_regions(uint start, size_t num_regions) { + guarantee(num_regions >= 1, err_msg("Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start)); + guarantee(_num_committed >= num_regions, "pre-condition"); + + // Print before uncommitting. + 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()); } - curr += 1; } - assert(num_so_far <= num, "post-condition"); - if (num_so_far == num) { - // we found enough space for the humongous object - assert(from <= first && first < len, "post-condition"); - assert(first < curr && (curr - first) == num, "post-condition"); - for (uint i = first; i < first + num; ++i) { - assert(at(i)->is_empty(), "post-condition"); + + _num_committed -= (uint)num_regions; + + _available_map.par_clear_range(start, start + num_regions, BitMap::unknown_range); + _heap_mapper->uncommit_regions(start, num_regions); + + // Also uncommit auxiliary data + _prev_bitmap_mapper->uncommit_regions(start, num_regions); + _next_bitmap_mapper->uncommit_regions(start, num_regions); + + _bot_mapper->uncommit_regions(start, num_regions); + _cardtable_mapper->uncommit_regions(start, num_regions); + + _card_counts_mapper->uncommit_regions(start, num_regions); +} + +void HeapRegionSeq::make_regions_available(uint start, uint num_regions) { + guarantee(num_regions > 0, "No point in calling this for zero regions"); + commit_regions(start, num_regions); + for (uint i = start; i < start + num_regions; i++) { + if (_regions.get_by_index(i) == NULL) { + HeapRegion* new_hr = new_heap_region(i); + _regions.set_by_index(i, new_hr); + _allocated_heapregions_length = MAX2(_allocated_heapregions_length, i + 1); } - return first; + } + + _available_map.par_set_range(start, start + num_regions, BitMap::unknown_range); + + for (uint i = start; i < start + num_regions; i++) { + assert(is_available(i), err_msg("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()); + } + HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(i); + MemRegion mr(bottom, bottom + HeapRegion::GrainWords); + + hr->initialize(mr); + insert_into_free_list(at(i)); + } +} + +uint HeapRegionSeq::expand_by(uint num_regions) { + return expand_at(0, num_regions); +} + +uint HeapRegionSeq::expand_at(uint start, uint num_regions) { + if (num_regions == 0) { + return 0; + } + + uint cur = start; + uint idx_last_found = 0; + uint num_last_found = 0; + + uint expanded = 0; + + while (expanded < num_regions && + (num_last_found = find_unavailable_from_idx(cur, &idx_last_found)) > 0) { + uint to_expand = MIN2(num_regions - expanded, num_last_found); + make_regions_available(idx_last_found, to_expand); + expanded += to_expand; + cur = idx_last_found + num_last_found + 1; + } + + verify_optional(); + return expanded; +} + +uint HeapRegionSeq::find_contiguous(size_t num, bool empty_only) { + uint found = 0; + size_t length_found = 0; + uint cur = 0; + + while (length_found < num && cur < max_length()) { + HeapRegion* hr = _regions.get_by_index(cur); + if ((!empty_only && !is_available(cur)) || (is_available(cur) && hr != NULL && hr->is_empty())) { + // This region is a potential candidate for allocation into. + length_found++; + } else { + // This region is not a candidate. The next region is the next possible one. + found = cur + 1; + length_found = 0; + } + cur++; + } + + if (length_found == num) { + for (uint i = found; i < (found + num); i++) { + HeapRegion* hr = _regions.get_by_index(i); + // sanity check + guarantee((!empty_only && !is_available(i)) || (is_available(i) && hr != NULL && hr->is_empty()), + err_msg("Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT + " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr))); + } + return found; } else { - // we failed to find enough space for the humongous object - return G1_NULL_HRS_INDEX; + return G1_NO_HRS_INDEX; } } -// Public - -void HeapRegionSeq::initialize(HeapWord* bottom, HeapWord* end) { - assert((uintptr_t) bottom % HeapRegion::GrainBytes == 0, - "bottom should be heap region aligned"); - assert((uintptr_t) end % HeapRegion::GrainBytes == 0, - "end should be heap region aligned"); - - _next_search_index = 0; - _allocated_length = 0; - - _regions.initialize(bottom, end, HeapRegion::GrainBytes); -} - -MemRegion HeapRegionSeq::expand_by(HeapWord* old_end, - HeapWord* new_end, - FreeRegionList* list) { - assert(old_end < new_end, "don't call it otherwise"); - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - - HeapWord* next_bottom = old_end; - assert(heap_bottom() <= next_bottom, "invariant"); - while (next_bottom < new_end) { - assert(next_bottom < heap_end(), "invariant"); - uint index = length(); - - assert(index < max_length(), "otherwise we cannot expand further"); - if (index == 0) { - // We have not allocated any regions so far - assert(next_bottom == heap_bottom(), "invariant"); - } else { - // next_bottom should match the end of the last/previous region - assert(next_bottom == at(index - 1)->end(), "invariant"); +HeapRegion* HeapRegionSeq::next_region_in_heap(const HeapRegion* r) const { + guarantee(r != NULL, "Start region must be a valid region"); + guarantee(is_available(r->hrs_index()), err_msg("Trying to iterate starting from region %u which is not in the heap", r->hrs_index())); + for (uint i = r->hrs_index() + 1; i < _allocated_heapregions_length; i++) { + HeapRegion* hr = _regions.get_by_index(i); + if (is_available(i)) { + return hr; } - - if (index == _allocated_length) { - // We have to allocate a new HeapRegion. - HeapRegion* new_hr = g1h->new_heap_region(index, next_bottom); - if (new_hr == NULL) { - // allocation failed, we bail out and return what we have done so far - return MemRegion(old_end, next_bottom); - } - assert(_regions.get_by_index(index) == NULL, "invariant"); - _regions.set_by_index(index, new_hr); - increment_allocated_length(); - } - // Have to increment the length first, otherwise we will get an - // assert failure at(index) below. - increment_length(); - HeapRegion* hr = at(index); - list->add_as_tail(hr); - - next_bottom = hr->end(); } - assert(next_bottom == new_end, "post-condition"); - return MemRegion(old_end, next_bottom); -} - -uint HeapRegionSeq::free_suffix() { - uint res = 0; - uint index = length(); - while (index > 0) { - index -= 1; - if (!at(index)->is_empty()) { - break; - } - res += 1; - } - return res; -} - -uint HeapRegionSeq::find_contiguous(uint num) { - assert(num > 1, "use this only for sequences of length 2 or greater"); - assert(_next_search_index <= length(), - err_msg("_next_search_index: %u should be valid and <= than %u", - _next_search_index, length())); - - uint start = _next_search_index; - uint res = find_contiguous_from(start, num); - if (res == G1_NULL_HRS_INDEX && start > 0) { - // Try starting from the beginning. If _next_search_index was 0, - // no point in doing this again. - res = find_contiguous_from(0, num); - } - if (res != G1_NULL_HRS_INDEX) { - assert(res < length(), err_msg("res: %u should be valid", res)); - _next_search_index = res + num; - assert(_next_search_index <= length(), - err_msg("_next_search_index: %u should be valid and <= than %u", - _next_search_index, length())); - } - return res; + return NULL; } void HeapRegionSeq::iterate(HeapRegionClosure* blk) const { - iterate_from((HeapRegion*) NULL, blk); -} + uint len = max_length(); -void HeapRegionSeq::iterate_from(HeapRegion* hr, HeapRegionClosure* blk) const { - uint hr_index = 0; - if (hr != NULL) { - hr_index = hr->hrs_index(); - } - - uint len = length(); - for (uint i = hr_index; i < len; i += 1) { + for (uint i = 0; i < len; i++) { + if (!is_available(i)) { + continue; + } + guarantee(at(i) != NULL, err_msg("Tried to access region %u that has a NULL HeapRegion*", i)); bool res = blk->doHeapRegion(at(i)); if (res) { blk->incomplete(); return; } } - for (uint i = 0; i < hr_index; i += 1) { - bool res = blk->doHeapRegion(at(i)); +} + +uint HeapRegionSeq::find_unavailable_from_idx(uint start_idx, uint* res_idx) const { + guarantee(res_idx != NULL, "checking"); + guarantee(start_idx <= (max_length() + 1), "checking"); + + uint num_regions = 0; + + uint cur = start_idx; + while (cur < max_length() && is_available(cur)) { + cur++; + } + if (cur == max_length()) { + return num_regions; + } + *res_idx = cur; + while (cur < max_length() && !is_available(cur)) { + cur++; + } + num_regions = cur - *res_idx; +#ifdef ASSERT + for (uint i = *res_idx; i < (*res_idx + num_regions); i++) { + assert(!is_available(i), "just checking"); + } + assert(cur == max_length() || num_regions == 0 || is_available(cur), + err_msg("The region at the current position %u must be available or at the end of the heap.", cur)); +#endif + return num_regions; +} + +uint HeapRegionSeq::start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const { + return num_regions * worker_i / num_workers; +} + +void HeapRegionSeq::par_iterate(HeapRegionClosure* blk, uint worker_id, uint num_workers, jint claim_value) const { + const uint start_index = start_region_for_worker(worker_id, num_workers, _allocated_heapregions_length); + + // Every worker will actually look at all regions, skipping over regions that + // are currently not committed. + // This also (potentially) iterates over regions newly allocated during GC. This + // is no problem except for some extra work. + for (uint count = 0; count < _allocated_heapregions_length; count++) { + const uint index = (start_index + count) % _allocated_heapregions_length; + assert(0 <= index && index < _allocated_heapregions_length, "sanity"); + // Skip over unavailable regions + if (!is_available(index)) { + continue; + } + HeapRegion* r = _regions.get_by_index(index); + // We'll ignore "continues humongous" regions (we'll process them + // when we come across their corresponding "start humongous" + // region) and regions already claimed. + if (r->claim_value() == claim_value || r->continuesHumongous()) { + continue; + } + // OK, try to claim it + if (!r->claimHeapRegion(claim_value)) { + continue; + } + // Success! + if (r->startsHumongous()) { + // If the region is "starts humongous" we'll iterate over its + // "continues humongous" first; in fact we'll do them + // first. The order is important. In one case, calling the + // closure on the "starts humongous" region might de-allocate + // and clear all its "continues humongous" regions and, as a + // result, we might end up processing them twice. So, we'll do + // them first (note: most closures will ignore them anyway) and + // then we'll do the "starts humongous" region. + for (uint ch_index = index + 1; ch_index < index + r->region_num(); ch_index++) { + HeapRegion* chr = _regions.get_by_index(ch_index); + + assert(chr->continuesHumongous(), "Must be humongous region"); + assert(chr->humongous_start_region() == r, + err_msg("Must work on humongous continuation of the original start region " + PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr))); + assert(chr->claim_value() != claim_value, + "Must not have been claimed yet because claiming of humongous continuation first claims the start region"); + + bool claim_result = chr->claimHeapRegion(claim_value); + // We should always be able to claim it; no one else should + // be trying to claim this region. + guarantee(claim_result, "We should always be able to claim the continuesHumongous part of the humongous object"); + + bool res2 = blk->doHeapRegion(chr); + if (res2) { + return; + } + + // Right now, this holds (i.e., no closure that actually + // does something with "continues humongous" regions + // clears them). We might have to weaken it in the future, + // but let's leave these two asserts here for extra safety. + assert(chr->continuesHumongous(), "should still be the case"); + assert(chr->humongous_start_region() == r, "sanity"); + } + } + + bool res = blk->doHeapRegion(r); if (res) { - blk->incomplete(); return; } } } uint HeapRegionSeq::shrink_by(uint num_regions_to_remove) { - // Reset this in case it's currently pointing into the regions that - // we just removed. - _next_search_index = 0; - assert(length() > 0, "the region sequence should not be empty"); - assert(length() <= _allocated_length, "invariant"); - assert(_allocated_length > 0, "we should have at least one region committed"); + assert(length() <= _allocated_heapregions_length, "invariant"); + assert(_allocated_heapregions_length > 0, "we should have at least one region committed"); assert(num_regions_to_remove < length(), "We should never remove all regions"); - uint i = 0; - for (; i < num_regions_to_remove; i++) { - HeapRegion* cur = at(length() - 1); - - if (!cur->is_empty()) { - // We have to give up if the region can not be moved - break; + if (num_regions_to_remove == 0) { + return 0; } - assert(!cur->isHumongous(), "Humongous regions should not be empty"); - decrement_length(); + uint removed = 0; + uint cur = _allocated_heapregions_length - 1; + uint idx_last_found = 0; + uint num_last_found = 0; + + while ((removed < num_regions_to_remove) && + (num_last_found = find_empty_from_idx_reverse(cur, &idx_last_found)) > 0) { + // Only allow uncommit from the end of the heap. + if ((idx_last_found + num_last_found) != _allocated_heapregions_length) { + return 0; + } + uint to_remove = MIN2(num_regions_to_remove - removed, num_last_found); + + uncommit_regions(idx_last_found + num_last_found - to_remove, to_remove); + + cur -= num_last_found; + removed += to_remove; } - return i; + + verify_optional(); + + return removed; } -#ifndef PRODUCT -void HeapRegionSeq::verify_optional() { - guarantee(length() <= _allocated_length, - err_msg("invariant: _length: %u _allocated_length: %u", - length(), _allocated_length)); - guarantee(_allocated_length <= max_length(), - err_msg("invariant: _allocated_length: %u _max_length: %u", - _allocated_length, max_length())); - guarantee(_next_search_index <= length(), - err_msg("invariant: _next_search_index: %u _length: %u", - _next_search_index, length())); +uint HeapRegionSeq::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const { + guarantee(start_idx < _allocated_heapregions_length, "checking"); + guarantee(res_idx != NULL, "checking"); + uint num_regions_found = 0; + + jlong cur = start_idx; + while (cur != -1 && !(is_available(cur) && at(cur)->is_empty())) { + cur--; + } + if (cur == -1) { + return num_regions_found; + } + jlong old_cur = cur; + // cur indexes the first empty region + while (cur != -1 && is_available(cur) && at(cur)->is_empty()) { + cur--; + } + *res_idx = cur + 1; + num_regions_found = old_cur - cur; + +#ifdef ASSERT + for (uint i = *res_idx; i < (*res_idx + num_regions_found); i++) { + assert(at(i)->is_empty(), "just checking"); + } +#endif + return num_regions_found; +} + +void HeapRegionSeq::verify() { + guarantee(length() <= _allocated_heapregions_length, + err_msg("invariant: _length: %u _allocated_length: %u", + length(), _allocated_heapregions_length)); + guarantee(_allocated_heapregions_length <= max_length(), + err_msg("invariant: _allocated_length: %u _max_length: %u", + _allocated_heapregions_length, max_length())); + + bool prev_committed = true; + uint num_committed = 0; HeapWord* prev_end = heap_bottom(); - for (uint i = 0; i < _allocated_length; i += 1) { + for (uint i = 0; i < _allocated_heapregions_length; i++) { + if (!is_available(i)) { + prev_committed = false; + continue; + } + num_committed++; HeapRegion* hr = _regions.get_by_index(i); guarantee(hr != NULL, err_msg("invariant: i: %u", i)); - guarantee(hr->bottom() == prev_end, + guarantee(!prev_committed || hr->bottom() == prev_end, err_msg("invariant i: %u "HR_FORMAT" prev_end: "PTR_FORMAT, i, HR_FORMAT_PARAMS(hr), p2i(prev_end))); guarantee(hr->hrs_index() == i, err_msg("invariant: i: %u hrs_index(): %u", i, hr->hrs_index())); - if (i < length()) { - // Asserts will fire if i is >= _length - HeapWord* addr = hr->bottom(); - guarantee(addr_to_region(addr) == hr, "sanity"); - } else { - guarantee(hr->is_empty(), "sanity"); - guarantee(!hr->isHumongous(), "sanity"); - // using assert instead of guarantee here since containing_set() - // is only available in non-product builds. - assert(hr->containing_set() == NULL, "sanity"); - } + // Asserts will fire if i is >= _length + HeapWord* addr = hr->bottom(); + guarantee(addr_to_region(addr) == hr, "sanity"); + // We cannot check whether the region is part of a particular set: at the time + // this method may be called, we have only completed allocation of the regions, + // but not put into a region set. + prev_committed = true; if (hr->startsHumongous()) { prev_end = hr->orig_end(); } else { prev_end = hr->end(); } } - for (uint i = _allocated_length; i < max_length(); i += 1) { + for (uint i = _allocated_heapregions_length; i < max_length(); i++) { guarantee(_regions.get_by_index(i) == NULL, err_msg("invariant i: %u", i)); } + + guarantee(num_committed == _num_committed, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed)); + _free_list.verify(); +} + +#ifndef PRODUCT +void HeapRegionSeq::verify_optional() { + verify(); } #endif // PRODUCT + diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp index 888b2ce5289..18b28fb93db 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp @@ -26,6 +26,8 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_HPP #include "gc_implementation/g1/g1BiasedArray.hpp" +#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" +#include "gc_implementation/g1/heapRegionSet.hpp" class HeapRegion; class HeapRegionClosure; @@ -33,16 +35,20 @@ class FreeRegionList; class G1HeapRegionTable : public G1BiasedMappedArray { protected: - virtual HeapRegion* default_value() const { return NULL; } + virtual HeapRegion* default_value() const { return NULL; } }; -// This class keeps track of the region metadata (i.e., HeapRegion -// instances). They are kept in the _regions array in address -// order. A region's index in the array corresponds to its index in -// the heap (i.e., 0 is the region at the bottom of the heap, 1 is -// the one after it, etc.). Two regions that are consecutive in the -// array should also be adjacent in the address space (i.e., -// region(i).end() == region(i+1).bottom(). +// This class keeps track of the actual heap memory, auxiliary data +// and its metadata (i.e., HeapRegion instances) and the list of free regions. +// +// This allows maximum flexibility for deciding what to commit or uncommit given +// a request from outside. +// +// HeapRegions are kept in the _regions array in address order. A region's +// index in the array corresponds to its index in the heap (i.e., 0 is the +// region at the bottom of the heap, 1 is the one after it, etc.). Two +// regions that are consecutive in the array should also be adjacent in the +// address space (i.e., region(i).end() == region(i+1).bottom(). // // We create a HeapRegion when we commit the region's address space // for the first time. When we uncommit the address space of a @@ -51,56 +57,94 @@ class G1HeapRegionTable : public G1BiasedMappedArray { // // We keep track of three lengths: // -// * _committed_length (returned by length()) is the number of currently -// committed regions. -// * _allocated_length (not exposed outside this class) is the -// number of regions for which we have HeapRegions. +// * _num_committed (returned by length()) is the number of currently +// committed regions. These may not be contiguous. +// * _allocated_heapregions_length (not exposed outside this class) is the +// number of regions+1 for which we have HeapRegions. // * max_length() returns the maximum number of regions the heap can have. // -// and maintain that: _committed_length <= _allocated_length <= max_length() class HeapRegionSeq: public CHeapObj { friend class VMStructs; G1HeapRegionTable _regions; - // The number of regions committed in the heap. - uint _committed_length; + G1RegionToSpaceMapper* _heap_mapper; + G1RegionToSpaceMapper* _prev_bitmap_mapper; + G1RegionToSpaceMapper* _next_bitmap_mapper; + G1RegionToSpaceMapper* _bot_mapper; + G1RegionToSpaceMapper* _cardtable_mapper; + G1RegionToSpaceMapper* _card_counts_mapper; - // A hint for which index to start searching from for humongous - // allocations. - uint _next_search_index; + FreeRegionList _free_list; - // The number of regions for which we have allocated HeapRegions for. - uint _allocated_length; + // Each bit in this bitmap indicates that the corresponding region is available + // for allocation. + BitMap _available_map; - // Find a contiguous set of empty regions of length num, starting - // from the given index. - uint find_contiguous_from(uint from, uint num); + // The number of regions committed in the heap. + uint _num_committed; - void increment_allocated_length() { - assert(_allocated_length < max_length(), "pre-condition"); - _allocated_length++; - } - - void increment_length() { - assert(length() < max_length(), "pre-condition"); - _committed_length++; - } - - void decrement_length() { - assert(length() > 0, "pre-condition"); - _committed_length--; - } + // Internal only. The highest heap region +1 we allocated a HeapRegion instance for. + uint _allocated_heapregions_length; HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); } HeapWord* heap_end() const {return _regions.end_address_mapped(); } + void make_regions_available(uint index, uint num_regions = 1); + + // Pass down commit calls to the VirtualSpace. + void commit_regions(uint index, size_t num_regions = 1); + void uncommit_regions(uint index, size_t num_regions = 1); + + // Notify other data structures about change in the heap layout. + void update_committed_space(HeapWord* old_end, HeapWord* new_end); + // Calculate the starting region for each worker during parallel iteration so + // that they do not all start from the same region. + uint start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const; + + // Find a contiguous set of empty or uncommitted regions of length num and return + // the index of the first region or G1_NO_HRS_INDEX if the search was unsuccessful. + // If only_empty is true, only empty regions are considered. + // Searches from bottom to top of the heap, doing a first-fit. + uint find_contiguous(size_t num, bool only_empty); + // Finds the next sequence of unavailable regions starting from start_idx. Returns the + // length of the sequence found. If this result is zero, no such sequence could be found, + // otherwise res_idx indicates the start index of these regions. + uint find_unavailable_from_idx(uint start_idx, uint* res_idx) const; + // Finds the next sequence of empty regions starting from start_idx, going backwards in + // the heap. Returns the length of the sequence found. If this value is zero, no + // sequence could be found, otherwise res_idx contains the start index of this range. + uint find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const; + // Allocate a new HeapRegion for the given index. + HeapRegion* new_heap_region(uint hrs_index); +#ifdef ASSERT +public: + bool is_free(HeapRegion* hr) const; +#endif + // Returns whether the given region is available for allocation. + bool is_available(uint region) const; + public: // Empty constructor, we'll initialize it with the initialize() method. - HeapRegionSeq() : _regions(), _committed_length(0), _next_search_index(0), _allocated_length(0) { } + HeapRegionSeq() : _regions(), _heap_mapper(NULL), _num_committed(0), + _next_bitmap_mapper(NULL), _prev_bitmap_mapper(NULL), _bot_mapper(NULL), + _allocated_heapregions_length(0), _available_map(), + _free_list("Free list", new MasterFreeRegionListMtSafeChecker()) + { } - void initialize(HeapWord* bottom, HeapWord* end); + void initialize(G1RegionToSpaceMapper* heap_storage, + G1RegionToSpaceMapper* prev_bitmap, + G1RegionToSpaceMapper* next_bitmap, + G1RegionToSpaceMapper* bot, + G1RegionToSpaceMapper* cardtable, + G1RegionToSpaceMapper* card_counts); + + // Return the "dummy" region used for G1AllocRegion. This is currently a hardwired + // new HeapRegion that owns HeapRegion at index 0. Since at the moment we commit + // the heap from the lowest address, this region (and its associated data + // structures) are available and we do not need to check further. + HeapRegion* get_dummy_region() { return new_heap_region(0); } // Return the HeapRegion at the given index. Assume that the index // is valid. @@ -110,45 +154,86 @@ class HeapRegionSeq: public CHeapObj { // HeapRegion, otherwise return NULL. inline HeapRegion* addr_to_region(HeapWord* addr) const; + // Insert the given region into the free region list. + inline void insert_into_free_list(HeapRegion* hr); + + // Insert the given region list into the global free region list. + void insert_list_into_free_list(FreeRegionList* list) { + _free_list.add_ordered(list); + } + + HeapRegion* allocate_free_region(bool is_old) { + HeapRegion* hr = _free_list.remove_region(is_old); + + if (hr != NULL) { + assert(hr->next() == NULL, "Single region should not have next"); + assert(is_available(hr->hrs_index()), "Must be committed"); + } + return hr; + } + + inline void allocate_free_regions_starting_at(uint first, uint num_regions); + + // Remove all regions from the free list. + void remove_all_free_regions() { + _free_list.remove_all(); + } + + // Return the number of committed free regions in the heap. + uint num_free_regions() const { + return _free_list.length(); + } + + size_t total_capacity_bytes() const { + return num_free_regions() * HeapRegion::GrainBytes; + } + + // Return the number of available (uncommitted) regions. + uint available() const { return max_length() - length(); } + // Return the number of regions that have been committed in the heap. - uint length() const { return _committed_length; } + uint length() const { return _num_committed; } // Return the maximum number of regions in the heap. uint max_length() const { return (uint)_regions.length(); } - // Expand the sequence to reflect that the heap has grown from - // old_end to new_end. Either create new HeapRegions, or re-use - // existing ones, and return them in the given list. Returns the - // memory region that covers the newly-created regions. If a - // HeapRegion allocation fails, the result memory region might be - // smaller than the desired one. - MemRegion expand_by(HeapWord* old_end, HeapWord* new_end, - FreeRegionList* list); + MemRegion reserved() const { return MemRegion(heap_bottom(), heap_end()); } - // Return the number of contiguous regions at the end of the sequence - // that are available for allocation. - uint free_suffix(); + // Expand the sequence to reflect that the heap has grown. Either create new + // HeapRegions, or re-use existing ones. Returns the number of regions the + // sequence was expanded by. If a HeapRegion allocation fails, the resulting + // number of regions might be smaller than what's desired. + uint expand_by(uint num_regions); - // Find a contiguous set of empty regions of length num and return - // the index of the first region or G1_NULL_HRS_INDEX if the - // search was unsuccessful. - uint find_contiguous(uint num); + // Makes sure that the regions from start to start+num_regions-1 are available + // for allocation. Returns the number of regions that were committed to achieve + // this. + uint expand_at(uint start, uint num_regions); + + // Find a contiguous set of empty regions of length num. Returns the start index of + // that set, or G1_NO_HRS_INDEX. + uint find_contiguous_only_empty(size_t num) { return find_contiguous(num, true); } + // Find a contiguous set of empty or unavailable regions of length num. Returns the + // start index of that set, or G1_NO_HRS_INDEX. + uint find_contiguous_empty_or_unavailable(size_t num) { return find_contiguous(num, false); } + + HeapRegion* next_region_in_heap(const HeapRegion* r) const; // Apply blk->doHeapRegion() on all committed regions in address order, // terminating the iteration early if doHeapRegion() returns true. void iterate(HeapRegionClosure* blk) const; - // As above, but start the iteration from hr and loop around. If hr - // is NULL, we start from the first region in the heap. - void iterate_from(HeapRegion* hr, HeapRegionClosure* blk) const; + void par_iterate(HeapRegionClosure* blk, uint worker_id, uint no_of_par_workers, jint claim_value) const; - // Tag as uncommitted as many regions that are completely free as - // possible, up to num_regions_to_remove, from the suffix of the committed - // sequence. Return the actual number of removed regions. + // Uncommit up to num_regions_to_remove regions that are completely free. + // Return the actual number of uncommitted regions. uint shrink_by(uint num_regions_to_remove); + void verify(); + // Do some sanity checking. void verify_optional() PRODUCT_RETURN; }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_HPP + diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp index 4028b7a4a5d..f5c1ffff9c3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp @@ -27,6 +27,7 @@ #include "gc_implementation/g1/heapRegion.hpp" #include "gc_implementation/g1/heapRegionSeq.hpp" +#include "gc_implementation/g1/heapRegionSet.inline.hpp" inline HeapRegion* HeapRegionSeq::addr_to_region(HeapWord* addr) const { assert(addr < heap_end(), @@ -35,16 +36,23 @@ inline HeapRegion* HeapRegionSeq::addr_to_region(HeapWord* addr) const { err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT, p2i(addr), p2i(heap_bottom()))); HeapRegion* hr = _regions.get_by_address(addr); - assert(hr != NULL, "invariant"); return hr; } inline HeapRegion* HeapRegionSeq::at(uint index) const { - assert(index < length(), "pre-condition"); + assert(is_available(index), "pre-condition"); HeapRegion* hr = _regions.get_by_index(index); assert(hr != NULL, "sanity"); assert(hr->hrs_index() == index, "sanity"); return hr; } +inline void HeapRegionSeq::insert_into_free_list(HeapRegion* hr) { + _free_list.add_ordered(hr); +} + +inline void HeapRegionSeq::allocate_free_regions_starting_at(uint first, uint num_regions) { + _free_list.remove_starting_at(at(first), num_regions); +} + #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_INLINE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp index fa5ab14287e..691ade1dcd4 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSet.inline.hpp" @@ -67,7 +68,7 @@ void HeapRegionSetBase::verify_start() { // Do the basic verification first before we do the checks over the regions. HeapRegionSetBase::verify(); - _verify_in_progress = true; + _verify_in_progress = true; } void HeapRegionSetBase::verify_end() { @@ -103,62 +104,7 @@ void FreeRegionList::set_unrealistically_long_length(uint len) { } void FreeRegionList::fill_in_ext_msg_extra(hrs_ext_msg* msg) { - msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, head(), tail()); -} - -void FreeRegionList::add_as_head_or_tail(FreeRegionList* from_list, bool as_head) { - check_mt_safety(); - from_list->check_mt_safety(); - - verify_optional(); - from_list->verify_optional(); - - if (from_list->is_empty()) { - return; - } - -#ifdef ASSERT - FreeRegionListIterator iter(from_list); - while (iter.more_available()) { - HeapRegion* hr = iter.get_next(); - // In set_containing_set() we check that we either set the value - // from NULL to non-NULL or vice versa to catch bugs. So, we have - // to NULL it first before setting it to the value. - hr->set_containing_set(NULL); - hr->set_containing_set(this); - } -#endif // ASSERT - - if (_head == NULL) { - assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant")); - _head = from_list->_head; - _tail = from_list->_tail; - } else { - assert(length() > 0 && _tail != NULL, hrs_ext_msg(this, "invariant")); - if (as_head) { - from_list->_tail->set_next(_head); - _head->set_prev(from_list->_tail); - _head = from_list->_head; - } else { - _tail->set_next(from_list->_head); - from_list->_head->set_prev(_tail); - _tail = from_list->_tail; - } - } - - _count.increment(from_list->length(), from_list->total_capacity_bytes()); - from_list->clear(); - - verify_optional(); - from_list->verify_optional(); -} - -void FreeRegionList::add_as_head(FreeRegionList* from_list) { - add_as_head_or_tail(from_list, true /* as_head */); -} - -void FreeRegionList::add_as_tail(FreeRegionList* from_list) { - add_as_head_or_tail(from_list, false /* as_head */); + msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, _head, _tail); } void FreeRegionList::remove_all() { @@ -191,11 +137,6 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { return; } - if (is_empty()) { - add_as_head(from_list); - return; - } - #ifdef ASSERT FreeRegionListIterator iter(from_list); while (iter.more_available()) { @@ -208,37 +149,43 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { } #endif // ASSERT - HeapRegion* curr_to = _head; - HeapRegion* curr_from = from_list->_head; - - while (curr_from != NULL) { - while (curr_to != NULL && curr_to->hrs_index() < curr_from->hrs_index()) { - curr_to = curr_to->next(); - } - - if (curr_to == NULL) { - // The rest of the from list should be added as tail - _tail->set_next(curr_from); - curr_from->set_prev(_tail); - curr_from = NULL; - } else { - HeapRegion* next_from = curr_from->next(); - - curr_from->set_next(curr_to); - curr_from->set_prev(curr_to->prev()); - if (curr_to->prev() == NULL) { - _head = curr_from; - } else { - curr_to->prev()->set_next(curr_from); - } - curr_to->set_prev(curr_from); - - curr_from = next_from; - } - } - - if (_tail->hrs_index() < from_list->_tail->hrs_index()) { + if (is_empty()) { + assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant")); + _head = from_list->_head; _tail = from_list->_tail; + } else { + HeapRegion* curr_to = _head; + HeapRegion* curr_from = from_list->_head; + + while (curr_from != NULL) { + while (curr_to != NULL && curr_to->hrs_index() < curr_from->hrs_index()) { + curr_to = curr_to->next(); + } + + if (curr_to == NULL) { + // The rest of the from list should be added as tail + _tail->set_next(curr_from); + curr_from->set_prev(_tail); + curr_from = NULL; + } else { + HeapRegion* next_from = curr_from->next(); + + curr_from->set_next(curr_to); + curr_from->set_prev(curr_to->prev()); + if (curr_to->prev() == NULL) { + _head = curr_from; + } else { + curr_to->prev()->set_next(curr_from); + } + curr_to->set_prev(curr_from); + + curr_from = next_from; + } + } + + if (_tail->hrs_index() < from_list->_tail->hrs_index()) { + _tail = from_list->_tail; + } } _count.increment(from_list->length(), from_list->total_capacity_bytes()); @@ -248,68 +195,59 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { from_list->verify_optional(); } -void FreeRegionList::remove_all_pending(uint target_count) { +void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) { check_mt_safety(); - assert(target_count > 1, hrs_ext_msg(this, "pre-condition")); + assert(num_regions >= 1, hrs_ext_msg(this, "pre-condition")); assert(!is_empty(), hrs_ext_msg(this, "pre-condition")); verify_optional(); DEBUG_ONLY(uint old_length = length();) - HeapRegion* curr = _head; + HeapRegion* curr = first; uint count = 0; - while (curr != NULL) { + while (count < num_regions) { verify_region(curr); HeapRegion* next = curr->next(); HeapRegion* prev = curr->prev(); - if (curr->pending_removal()) { - assert(count < target_count, - hrs_err_msg("[%s] should not come across more regions " - "pending for removal than target_count: %u", - name(), target_count)); + assert(count < num_regions, + hrs_err_msg("[%s] should not come across more regions " + "pending for removal than num_regions: %u", + name(), num_regions)); - if (prev == NULL) { - assert(_head == curr, hrs_ext_msg(this, "invariant")); - _head = next; - } else { - assert(_head != curr, hrs_ext_msg(this, "invariant")); - prev->set_next(next); - } - if (next == NULL) { - assert(_tail == curr, hrs_ext_msg(this, "invariant")); - _tail = prev; - } else { - assert(_tail != curr, hrs_ext_msg(this, "invariant")); - next->set_prev(prev); - } - if (_last = curr) { - _last = NULL; - } - - curr->set_next(NULL); - curr->set_prev(NULL); - remove(curr); - curr->set_pending_removal(false); - - count += 1; - - // If we have come across the target number of regions we can - // just bail out. However, for debugging purposes, we can just - // carry on iterating to make sure there are not more regions - // tagged with pending removal. - DEBUG_ONLY(if (count == target_count) break;) + if (prev == NULL) { + assert(_head == curr, hrs_ext_msg(this, "invariant")); + _head = next; + } else { + assert(_head != curr, hrs_ext_msg(this, "invariant")); + prev->set_next(next); } + if (next == NULL) { + assert(_tail == curr, hrs_ext_msg(this, "invariant")); + _tail = prev; + } else { + assert(_tail != curr, hrs_ext_msg(this, "invariant")); + next->set_prev(prev); + } + if (_last = curr) { + _last = NULL; + } + + curr->set_next(NULL); + curr->set_prev(NULL); + remove(curr); + + count++; curr = next; } - assert(count == target_count, - hrs_err_msg("[%s] count: %u should be == target_count: %u", - name(), count, target_count)); - assert(length() + target_count == old_length, + assert(count == num_regions, + hrs_err_msg("[%s] count: %u should be == num_regions: %u", + name(), count, num_regions)); + assert(length() + num_regions == old_length, hrs_err_msg("[%s] new length should be consistent " - "new length: %u old length: %u target_count: %u", - name(), length(), old_length, target_count)); + "new length: %u old length: %u num_regions: %u", + name(), length(), old_length, num_regions)); verify_optional(); } @@ -348,10 +286,12 @@ void FreeRegionList::print_on(outputStream* out, bool print_contents) { hr->print_on(out); } } + + out->cr(); } void FreeRegionList::verify_list() { - HeapRegion* curr = head(); + HeapRegion* curr = _head; HeapRegion* prev1 = NULL; HeapRegion* prev0 = NULL; uint count = 0; @@ -379,7 +319,7 @@ void FreeRegionList::verify_list() { curr = curr->next(); } - guarantee(tail() == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), tail()->hrs_index(), prev0->hrs_index())); + guarantee(_tail == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), _tail->hrs_index(), prev0->hrs_index())); guarantee(_tail == NULL || _tail->next() == NULL, "_tail should not have a next"); guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count)); guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, @@ -463,3 +403,41 @@ void HumongousRegionSetMtSafeChecker::check() { "master humongous set MT safety protocol outside a safepoint"); } } + +void FreeRegionList_test() { + FreeRegionList l("test"); + + const uint num_regions_in_test = 5; + // Create a fake heap. It does not need to be valid, as the HeapRegion constructor + // does not access it. + MemRegion heap(NULL, num_regions_in_test * HeapRegion::GrainWords); + // Allocate a fake BOT because the HeapRegion constructor initializes + // the BOT. + size_t bot_size = G1BlockOffsetSharedArray::compute_size(heap.word_size()); + HeapWord* bot_data = NEW_C_HEAP_ARRAY(HeapWord, bot_size, mtGC); + ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(heap.word_size())); + G1RegionToSpaceMapper* bot_storage = + G1RegionToSpaceMapper::create_mapper(bot_rs, + os::vm_page_size(), + HeapRegion::GrainBytes, + G1BlockOffsetSharedArray::N_bytes, + mtGC); + G1BlockOffsetSharedArray oa(heap, bot_storage); + bot_storage->commit_regions(0, num_regions_in_test); + HeapRegion hr0(0, &oa, heap); + HeapRegion hr1(1, &oa, heap); + HeapRegion hr2(2, &oa, heap); + HeapRegion hr3(3, &oa, heap); + HeapRegion hr4(4, &oa, heap); + l.add_ordered(&hr1); + l.add_ordered(&hr0); + l.add_ordered(&hr3); + l.add_ordered(&hr4); + l.add_ordered(&hr2); + assert(l.length() == num_regions_in_test, "wrong length"); + l.verify_list(); + + bot_storage->uncommit_regions(0, num_regions_in_test); + delete bot_storage; + FREE_C_HEAP_ARRAY(HeapWord, bot_data, mtGC); +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp index 8502763ccf1..5bbae915fda 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp @@ -162,7 +162,7 @@ public: // diagnosing failures. class hrs_ext_msg : public hrs_err_msg { public: - hrs_ext_msg(HeapRegionSetBase* set, const char* message) : hrs_err_msg("%s","") { + hrs_ext_msg(HeapRegionSetBase* set, const char* message) : hrs_err_msg("%s", "") { set->fill_in_ext_msg(this, message); } }; @@ -192,13 +192,9 @@ public: }; // A set that links all the regions added to it in a doubly-linked -// list. We should try to avoid doing operations that iterate over +// sorted list. We should try to avoid doing operations that iterate over // such lists in performance critical paths. Typically we should -// add / remove one region at a time or concatenate two lists. There are -// two ways to treat your lists, ordered and un-ordered. All un-ordered -// operations are done in constant time. To keep a list ordered only use -// add_ordered() to add elements to the list. If a list is not ordered -// from start, there is no way to sort it later. +// add / remove one region at a time or concatenate two lists. class FreeRegionListIterator; @@ -210,13 +206,13 @@ private: HeapRegion* _tail; // _last is used to keep track of where we added an element the last - // time in ordered lists. It helps to improve performance when adding - // several ordered items in a row. + // time. It helps to improve performance when adding several ordered items in a row. HeapRegion* _last; static uint _unrealistically_long_length; - void add_as_head_or_tail(FreeRegionList* from_list, bool as_head); + inline HeapRegion* remove_from_head_impl(); + inline HeapRegion* remove_from_tail_impl(); protected: virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg); @@ -232,8 +228,11 @@ public: void verify_list(); - HeapRegion* head() { return _head; } - HeapRegion* tail() { return _tail; } +#ifdef ASSERT + bool contains(HeapRegion* hr) const { + return hr->containing_set() == this; + } +#endif static void set_unrealistically_long_length(uint len); @@ -242,55 +241,20 @@ public: // is determined by hrs_index. inline void add_ordered(HeapRegion* hr); - // It adds hr to the list as the new head. The region should not be - // a member of another set. - inline void add_as_head(HeapRegion* hr); - - // It adds hr to the list as the new tail. The region should not be - // a member of another set. - inline void add_as_tail(HeapRegion* hr); - - // It removes and returns the head of the list. It assumes that the - // list is not empty so it will return a non-NULL value. - inline HeapRegion* remove_head(); - - // Convenience method. - inline HeapRegion* remove_head_or_null(); - - // Removes and returns the last element (_tail) of the list. It assumes - // that the list isn't empty so that it can return a non-NULL value. - inline HeapRegion* remove_tail(); - - // Convenience method - inline HeapRegion* remove_tail_or_null(); - // Removes from head or tail based on the given argument. - inline HeapRegion* remove_region(bool from_head); + HeapRegion* remove_region(bool from_head); // Merge two ordered lists. The result is also ordered. The order is // determined by hrs_index. void add_ordered(FreeRegionList* from_list); - // It moves the regions from from_list to this list and empties - // from_list. The new regions will appear in the same order as they - // were in from_list and be linked in the beginning of this list. - void add_as_head(FreeRegionList* from_list); - - // It moves the regions from from_list to this list and empties - // from_list. The new regions will appear in the same order as they - // were in from_list and be linked in the end of this list. - void add_as_tail(FreeRegionList* from_list); - // It empties the list by removing all regions from it. void remove_all(); - // It removes all regions in the list that are pending for removal - // (i.e., they have been tagged with "pending_removal"). The list - // must not be empty, target_count should reflect the exact number - // of regions that are pending for removal in the list, and - // target_count should be > 1 (currently, we never need to remove a - // single region using this). - void remove_all_pending(uint target_count); + // Remove all (contiguous) regions from first to first + num_regions -1 from + // this list. + // Num_regions must be > 1. + void remove_starting_at(HeapRegion* first, uint num_regions); virtual void verify(); @@ -298,7 +262,7 @@ public: }; // Iterator class that provides a convenient way to iterate over the -// regions of a HeapRegionLinkedList instance. +// regions of a FreeRegionList. class FreeRegionListIterator : public StackObj { private: @@ -324,7 +288,7 @@ public: } FreeRegionListIterator(FreeRegionList* list) : _curr(NULL), _list(list) { - _curr = list->head(); + _curr = list->_head; } }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp index 08f74a776ac..683c4c9202e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp @@ -30,7 +30,8 @@ inline void HeapRegionSetBase::add(HeapRegion* hr) { check_mt_safety(); assert(hr->containing_set() == NULL, hrs_ext_msg(this, "should not already have a containing set %u")); - assert(hr->next() == NULL && hr->prev() == NULL, hrs_ext_msg(this, "should not already be linked")); + assert(hr->next() == NULL, hrs_ext_msg(this, "should not already be linked")); + assert(hr->prev() == NULL, hrs_ext_msg(this, "should not already be linked")); _count.increment(1u, hr->capacity()); hr->set_containing_set(this); @@ -40,7 +41,8 @@ inline void HeapRegionSetBase::add(HeapRegion* hr) { inline void HeapRegionSetBase::remove(HeapRegion* hr) { check_mt_safety(); verify_region(hr); - assert(hr->next() == NULL && hr->prev() == NULL, hrs_ext_msg(this, "should already be unlinked")); + assert(hr->next() == NULL, hrs_ext_msg(this, "should already be unlinked")); + assert(hr->prev() == NULL, hrs_ext_msg(this, "should already be unlinked")); hr->set_containing_set(NULL); assert(_count.length() > 0, hrs_ext_msg(this, "pre-condition")); @@ -48,8 +50,7 @@ inline void HeapRegionSetBase::remove(HeapRegion* hr) { } inline void FreeRegionList::add_ordered(HeapRegion* hr) { - check_mt_safety(); - assert((length() == 0 && _head == NULL && _tail == NULL) || + assert((length() == 0 && _head == NULL && _tail == NULL && _last == NULL) || (length() > 0 && _head != NULL && _tail != NULL), hrs_ext_msg(this, "invariant")); // add() will verify the region and check mt safety. @@ -95,89 +96,48 @@ inline void FreeRegionList::add_ordered(HeapRegion* hr) { _last = hr; } -inline void FreeRegionList::add_as_head(HeapRegion* hr) { - assert((length() == 0 && _head == NULL && _tail == NULL) || - (length() > 0 && _head != NULL && _tail != NULL), - hrs_ext_msg(this, "invariant")); - // add() will verify the region and check mt safety. - add(hr); - - // Now link the region. - if (_head != NULL) { - hr->set_next(_head); - _head->set_prev(hr); - } else { - _tail = hr; - } - _head = hr; -} - -inline void FreeRegionList::add_as_tail(HeapRegion* hr) { - check_mt_safety(); - assert((length() == 0 && _head == NULL && _tail == NULL) || - (length() > 0 && _head != NULL && _tail != NULL), - hrs_ext_msg(this, "invariant")); - // add() will verify the region and check mt safety. - add(hr); - - // Now link the region. - if (_tail != NULL) { - _tail->set_next(hr); - hr->set_prev(_tail); - } else { - _head = hr; - } - _tail = hr; -} - -inline HeapRegion* FreeRegionList::remove_head() { - assert(!is_empty(), hrs_ext_msg(this, "the list should not be empty")); - assert(length() > 0 && _head != NULL && _tail != NULL, - hrs_ext_msg(this, "invariant")); - - // We need to unlink it first. - HeapRegion* hr = _head; - _head = hr->next(); +inline HeapRegion* FreeRegionList::remove_from_head_impl() { + HeapRegion* result = _head; + _head = result->next(); if (_head == NULL) { _tail = NULL; } else { _head->set_prev(NULL); } - hr->set_next(NULL); - - if (_last == hr) { - _last = NULL; - } - - // remove() will verify the region and check mt safety. - remove(hr); - return hr; + result->set_next(NULL); + return result; } -inline HeapRegion* FreeRegionList::remove_head_or_null() { - check_mt_safety(); - if (!is_empty()) { - return remove_head(); - } else { - return NULL; - } -} +inline HeapRegion* FreeRegionList::remove_from_tail_impl() { + HeapRegion* result = _tail; -inline HeapRegion* FreeRegionList::remove_tail() { - assert(!is_empty(), hrs_ext_msg(this, "The list should not be empty")); - assert(length() > 0 && _head != NULL && _tail != NULL, - hrs_ext_msg(this, "invariant")); - - // We need to unlink it first - HeapRegion* hr = _tail; - - _tail = hr->prev(); + _tail = result->prev(); if (_tail == NULL) { _head = NULL; } else { _tail->set_next(NULL); } - hr->set_prev(NULL); + result->set_prev(NULL); + return result; +} + +inline HeapRegion* FreeRegionList::remove_region(bool from_head) { + check_mt_safety(); + verify_optional(); + + if (is_empty()) { + return NULL; + } + assert(length() > 0 && _head != NULL && _tail != NULL, + hrs_ext_msg(this, "invariant")); + + HeapRegion* hr; + + if (from_head) { + hr = remove_from_head_impl(); + } else { + hr = remove_from_tail_impl(); + } if (_last == hr) { _last = NULL; @@ -188,22 +148,5 @@ inline HeapRegion* FreeRegionList::remove_tail() { return hr; } -inline HeapRegion* FreeRegionList::remove_tail_or_null() { - check_mt_safety(); - - if (!is_empty()) { - return remove_tail(); - } else { - return NULL; - } -} - -inline HeapRegion* FreeRegionList::remove_region(bool from_head) { - if (from_head) { - return remove_head_or_null(); - } else { - return remove_tail_or_null(); - } -} - #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_INLINE_HPP + diff --git a/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp b/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp index f32bfb0e3a3..4277ab55abe 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp @@ -43,10 +43,9 @@ nonstatic_field(G1HeapRegionTable, _shift_by, uint) \ \ nonstatic_field(HeapRegionSeq, _regions, G1HeapRegionTable) \ - nonstatic_field(HeapRegionSeq, _committed_length, uint) \ + nonstatic_field(HeapRegionSeq, _num_committed, uint) \ \ nonstatic_field(G1CollectedHeap, _hrs, HeapRegionSeq) \ - nonstatic_field(G1CollectedHeap, _g1_committed, MemRegion) \ nonstatic_field(G1CollectedHeap, _summary_bytes_used, size_t) \ nonstatic_field(G1CollectedHeap, _g1mm, G1MonitoringSupport*) \ nonstatic_field(G1CollectedHeap, _old_set, HeapRegionSetBase) \ diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp index bddc6f678a3..cc86629281e 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @@ -28,12 +28,12 @@ #include "gc_implementation/parNew/parOopClosures.inline.hpp" #include "gc_implementation/shared/adaptiveSizePolicy.hpp" #include "gc_implementation/shared/ageTable.hpp" -#include "gc_implementation/shared/parGCAllocBuffer.hpp" +#include "gc_implementation/shared/copyFailedInfo.hpp" #include "gc_implementation/shared/gcHeapSummary.hpp" #include "gc_implementation/shared/gcTimer.hpp" #include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/gcTraceTime.hpp" -#include "gc_implementation/shared/copyFailedInfo.hpp" +#include "gc_implementation/shared/parGCAllocBuffer.inline.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" #include "memory/defNewGeneration.inline.hpp" #include "memory/genCollectedHeap.hpp" @@ -252,7 +252,7 @@ HeapWord* ParScanThreadState::alloc_in_to_space_slow(size_t word_sz) { plab->set_word_size(buf_size); plab->set_buf(buf_space); record_survivor_plab(buf_space, buf_size); - obj = plab->allocate(word_sz); + obj = plab->allocate_aligned(word_sz, SurvivorAlignmentInBytes); // Note that we cannot compare buf_size < word_sz below // because of AlignmentReserve (see ParGCAllocBuffer::allocate()). assert(obj != NULL || plab->words_remaining() < word_sz, diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp index bde15f7b8f8..7685353ed1e 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp @@ -168,7 +168,7 @@ class ParScanThreadState { HeapWord* alloc_in_to_space_slow(size_t word_sz); HeapWord* alloc_in_to_space(size_t word_sz) { - HeapWord* obj = to_space_alloc_buffer()->allocate(word_sz); + HeapWord* obj = to_space_alloc_buffer()->allocate_aligned(word_sz, SurvivorAlignmentInBytes); if (obj != NULL) return obj; else return alloc_in_to_space_slow(word_sz); } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index b7d521a4884..5262c6bc55e 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -78,6 +78,7 @@ jint ParallelScavengeHeap::initialize() { (HeapWord*)(heap_rs.base() + heap_rs.size())); CardTableExtension* const barrier_set = new CardTableExtension(_reserved, 3); + barrier_set->initialize(); _barrier_set = barrier_set; oopDesc::set_bs(_barrier_set); if (_barrier_set == NULL) { diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp index e87529c734d..05c27a3f3da 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONLAB_HPP #include "gc_implementation/parallelScavenge/objectStartArray.hpp" +#include "gc_interface/collectedHeap.inline.hpp" #include "memory/allocation.hpp" // @@ -94,23 +95,9 @@ class PSYoungPromotionLAB : public PSPromotionLAB { PSYoungPromotionLAB() { } // Not MT safe - HeapWord* allocate(size_t size) { - // Can't assert this, when young fills, we keep the LAB around, but flushed. - // assert(_state != flushed, "Sanity"); - HeapWord* obj = top(); - HeapWord* new_top = obj + size; - // The 'new_top>obj' check is needed to detect overflow of obj+size. - if (new_top > obj && new_top <= end()) { - set_top(new_top); - assert(is_object_aligned((intptr_t)obj) && is_object_aligned((intptr_t)new_top), - "checking alignment"); - return obj; - } + inline HeapWord* allocate(size_t size); - return NULL; - } - - debug_only(virtual bool lab_is_valid(MemRegion lab)); + debug_only(virtual bool lab_is_valid(MemRegion lab);) }; class PSOldPromotionLAB : public PSPromotionLAB { diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.inline.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.inline.hpp new file mode 100644 index 00000000000..0e5d7e7f7f2 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.inline.hpp @@ -0,0 +1,52 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONLAB_INLINE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONLAB_INLINE_HPP + +#include "gc_implementation/parallelScavenge/psPromotionLAB.hpp" +#include "gc_interface/collectedHeap.inline.hpp" + +HeapWord* PSYoungPromotionLAB::allocate(size_t size) { + // Can't assert this, when young fills, we keep the LAB around, but flushed. + // assert(_state != flushed, "Sanity"); + HeapWord* obj = CollectedHeap::align_allocation_or_fail(top(), end(), SurvivorAlignmentInBytes); + if (obj == NULL) { + return NULL; + } + + HeapWord* new_top = obj + size; + // The 'new_top>obj' check is needed to detect overflow of obj+size. + if (new_top > obj && new_top <= end()) { + set_top(new_top); + assert(is_ptr_aligned(obj, SurvivorAlignmentInBytes) && is_object_aligned((intptr_t)new_top), + "checking alignment"); + return obj; + } else { + set_top(obj); + return NULL; + } +} + +#endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONLAB_INLINE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp index 356c2585168..b2de74d4175 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp @@ -27,6 +27,7 @@ #include "gc_implementation/parallelScavenge/psOldGen.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.hpp" +#include "gc_implementation/parallelScavenge/psPromotionLAB.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "oops/oop.psgc.inline.hpp" diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp index aede4e5b641..3a8f347bc8d 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp @@ -70,7 +70,7 @@ void VM_ParallelGCSystemGC::doit() { "must be a ParallelScavengeHeap"); GCCauseSetter gccs(heap, _gc_cause); - if (_gc_cause == GCCause::_gc_locker + if (_gc_cause == GCCause::_gc_locker || _gc_cause == GCCause::_wb_young_gc DEBUG_ONLY(|| _gc_cause == GCCause::_scavenge_alot)) { // If (and only if) the scavenge fails, this will invoke a full gc. heap->invoke_scavenge(); diff --git a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp b/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp index 3677ee26e28..6f1c5eb8eba 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp @@ -24,7 +24,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP #define SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP - +#include "gc_interface/collectedHeap.hpp" #include "memory/allocation.hpp" #include "memory/blockOffsetTable.hpp" #include "memory/threadLocalAllocBuffer.hpp" @@ -84,6 +84,9 @@ public: } } + // Allocate the object aligned to "alignment_in_bytes". + HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes); + // Undo the last allocation in the buffer, which is required to be of the // "obj" of the given "word_sz". void undo_allocation(HeapWord* obj, size_t word_sz) { diff --git a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.inline.hpp b/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.inline.hpp new file mode 100644 index 00000000000..352ce05a3e5 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.inline.hpp @@ -0,0 +1,44 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_PARGCALLOCBUFFER_INLINE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_PARGCALLOCBUFFER_INLINE_HPP + +#include "gc_implementation/shared/parGCAllocBuffer.hpp" +#include "gc_interface/collectedHeap.inline.hpp" + +HeapWord* ParGCAllocBuffer::allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes) { + + HeapWord* res = CollectedHeap::align_allocation_or_fail(_top, _end, alignment_in_bytes); + if (res == NULL) { + return NULL; + } + + // Set _top so that allocate(), which expects _top to be correctly set, + // can be used below. + _top = res; + return allocate(word_sz); +} + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_PARGCALLOCBUFFER_INLINE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp index bb7028ec9c1..b80332b2ab1 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp @@ -195,6 +195,7 @@ void VM_GenCollectFull::doit() { gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_level); } +// Returns true iff concurrent GCs unloads metadata. bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() { #if INCLUDE_ALL_GCS if (UseConcMarkSweepGC && CMSClassUnloadingEnabled) { @@ -202,7 +203,7 @@ bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() { return true; } - if (UseG1GC) { + if (UseG1GC && ClassUnloadingWithConcurrentMark) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); g1h->g1_policy()->set_initiate_conc_mark_if_possible(); diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp index d3c2fba9276..d4fa7ffc0ec 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp @@ -351,6 +351,12 @@ class CollectedHeap : public CHeapObj { fill_with_object(start, pointer_delta(end, start), zap); } + // Return the address "addr" aligned by "alignment_in_bytes" if such + // an address is below "end". Return NULL otherwise. + inline static HeapWord* align_allocation_or_fail(HeapWord* addr, + HeapWord* end, + unsigned short alignment_in_bytes); + // Some heaps may offer a contiguous region for shared non-blocking // allocation, via inlined code (by exporting the address of the top and // end fields defining the extent of the contiguous allocation region.) diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp index 89315a9424f..302d0c7cb3a 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp @@ -241,6 +241,44 @@ inline void CollectedHeap::oop_iterate_no_header(OopClosure* cl) { oop_iterate(&no_header_cl); } + +inline HeapWord* CollectedHeap::align_allocation_or_fail(HeapWord* addr, + HeapWord* end, + unsigned short alignment_in_bytes) { + if (alignment_in_bytes <= ObjectAlignmentInBytes) { + return addr; + } + + assert(is_ptr_aligned(addr, HeapWordSize), + err_msg("Address " PTR_FORMAT " is not properly aligned.", p2i(addr))); + assert(is_size_aligned(alignment_in_bytes, HeapWordSize), + err_msg("Alignment size %u is incorrect.", alignment_in_bytes)); + + HeapWord* new_addr = (HeapWord*) align_pointer_up(addr, alignment_in_bytes); + size_t padding = pointer_delta(new_addr, addr); + + if (padding == 0) { + return addr; + } + + if (padding < CollectedHeap::min_fill_size()) { + padding += alignment_in_bytes / HeapWordSize; + assert(padding >= CollectedHeap::min_fill_size(), + err_msg("alignment_in_bytes %u is expect to be larger " + "than the minimum object size", alignment_in_bytes)); + new_addr = addr + padding; + } + + assert(new_addr > addr, err_msg("Unexpected arithmetic overflow " + PTR_FORMAT " not greater than " PTR_FORMAT, p2i(new_addr), p2i(addr))); + if(new_addr < end) { + CollectedHeap::fill_with_object(addr, padding); + return new_addr; + } else { + return NULL; + } +} + #ifndef PRODUCT inline bool diff --git a/hotspot/src/share/vm/gc_interface/gcCause.cpp b/hotspot/src/share/vm/gc_interface/gcCause.cpp index 2588621aa6b..879bce11304 100644 --- a/hotspot/src/share/vm/gc_interface/gcCause.cpp +++ b/hotspot/src/share/vm/gc_interface/gcCause.cpp @@ -51,6 +51,9 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _heap_dump: return "Heap Dump Initiated GC"; + case _wb_young_gc: + return "WhiteBox Initiated Young GC"; + case _no_gc: return "No GC"; diff --git a/hotspot/src/share/vm/gc_interface/gcCause.hpp b/hotspot/src/share/vm/gc_interface/gcCause.hpp index 1df82dba700..31a7a9d3827 100644 --- a/hotspot/src/share/vm/gc_interface/gcCause.hpp +++ b/hotspot/src/share/vm/gc_interface/gcCause.hpp @@ -46,6 +46,7 @@ class GCCause : public AllStatic { _gc_locker, _heap_inspection, _heap_dump, + _wb_young_gc, /* implementation independent, but reserved for GC use */ _no_gc, diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp index 783066e0adb..de54137168e 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp @@ -280,9 +280,6 @@ class AbstractInterpreterGenerator: public StackObj { address generate_result_handler_for(BasicType type); address generate_slow_signature_handler(); - // entry point generator - address generate_method_entry(AbstractInterpreter::MethodKind kind); - void bang_stack_shadow_pages(bool native_call); void generate_all(); diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 323f67fc1f6..dc2a782ea05 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -3402,7 +3402,7 @@ BytecodeInterpreter::print() { tty->print_cr("osr._osr_buf: " INTPTR_FORMAT, (uintptr_t) this->_result._osr._osr_buf); tty->print_cr("osr._osr_entry: " INTPTR_FORMAT, (uintptr_t) this->_result._osr._osr_entry); tty->print_cr("prev_link: " INTPTR_FORMAT, (uintptr_t) this->_prev_link); - tty->print_cr("native_mirror: " INTPTR_FORMAT, (uintptr_t) this->_oop_temp); + tty->print_cr("native_mirror: " INTPTR_FORMAT, (uintptr_t) p2i(this->_oop_temp)); tty->print_cr("stack_base: " INTPTR_FORMAT, (uintptr_t) this->_stack_base); tty->print_cr("stack_limit: " INTPTR_FORMAT, (uintptr_t) this->_stack_limit); tty->print_cr("monitor_base: " INTPTR_FORMAT, (uintptr_t) this->_monitor_base); diff --git a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp index 0007aa8be25..c154a746f4d 100644 --- a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, 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 @@ -108,7 +108,7 @@ void CppInterpreterGenerator::generate_all() { } -#define method_entry(kind) Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind) +#define method_entry(kind) Interpreter::_entry_table[Interpreter::kind] = ((InterpreterGenerator*)this)->generate_method_entry(Interpreter::kind) { CodeletMark cm(_masm, "(kind = frame_manager)"); // all non-native method kinds diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp index 4807cd08398..00c116234da 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.cpp +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp @@ -29,6 +29,7 @@ #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" @@ -261,7 +262,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 - // AbstractInterpreterGenerator::generate_method_entry() for + // InterpreterGenerator::generate_method_entry() for // for details. switch (m->intrinsic_id()) { case vmIntrinsics::_dsin : return java_lang_math_sin ; @@ -521,3 +522,50 @@ 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 synchronized = false; + address entry_point = NULL; + + switch (kind) { + case Interpreter::zerolocals : break; + case Interpreter::zerolocals_synchronized: synchronized = true; break; + case Interpreter::native : entry_point = generate_native_entry(false); break; + case Interpreter::native_synchronized : entry_point = generate_native_entry(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 + : entry_point = generate_CRC32_update_entry(); break; + case Interpreter::java_util_zip_CRC32_updateBytes + : // fall thru + case Interpreter::java_util_zip_CRC32_updateByteBuffer + : entry_point = generate_CRC32_updateBytes_entry(kind); break; +#endif // CC_INTERP + default: + fatal(err_msg("unexpected method kind: %d", kind)); + break; + } + + if (entry_point) { + return entry_point; + } + + return generate_normal_entry(synchronized); +} diff --git a/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp index 7bc43eccb21..5c4242df884 100644 --- a/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp +++ b/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, 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 @@ -37,9 +37,11 @@ class InterpreterGenerator: public CC_INTERP_ONLY(CppInterpreterGenerator) NOT_CC_INTERP(TemplateInterpreterGenerator) { -public: + public: -InterpreterGenerator(StubQueue* _code); + InterpreterGenerator(StubQueue* _code); + // entry point generator + address generate_method_entry(AbstractInterpreter::MethodKind kind); #ifdef TARGET_ARCH_x86 # include "interpreterGenerator_x86.hpp" diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index 23d4bddca1b..ee7486041b9 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -987,17 +987,6 @@ ConstantPoolCacheEntry *cp_entry)) int index = cp_entry->field_index(); if ((ik->field_access_flags(index) & JVM_ACC_FIELD_ACCESS_WATCHED) == 0) return; - switch(cp_entry->flag_state()) { - case btos: // fall through - case ctos: // fall through - case stos: // fall through - case itos: // fall through - case ftos: // fall through - case ltos: // fall through - case dtos: // fall through - case atos: break; - default: ShouldNotReachHere(); return; - } bool is_static = (obj == NULL); HandleMark hm(thread); diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp index 9f28e20f9b7..d42da317345 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp @@ -364,7 +364,7 @@ void TemplateInterpreterGenerator::generate_all() { #define method_entry(kind) \ { CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \ - Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \ + Interpreter::_entry_table[Interpreter::kind] = ((InterpreterGenerator*)this)->generate_method_entry(Interpreter::kind); \ } // all non-native method kinds diff --git a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp index ee1b0f5acc5..e3740c47c4e 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -59,9 +59,6 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator { address generate_safept_entry_for(TosState state, address runtime_entry); void generate_throw_exception(); - // entry point generator -// address generate_method_entry(AbstractInterpreter::MethodKind kind); - // Instruction generation void generate_and_dispatch (Template* t, TosState tos_out = ilgl); void set_vtos_entry_points (Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep); diff --git a/hotspot/src/share/vm/memory/allocation.cpp b/hotspot/src/share/vm/memory/allocation.cpp index ac9ff11bb65..ec9a8497836 100644 --- a/hotspot/src/share/vm/memory/allocation.cpp +++ b/hotspot/src/share/vm/memory/allocation.cpp @@ -422,26 +422,23 @@ void Chunk::start_chunk_pool_cleaner_task() { } //------------------------------Arena------------------------------------------ -NOT_PRODUCT(volatile jint Arena::_instance_count = 0;) -Arena::Arena(size_t init_size) { +Arena::Arena(MEMFLAGS flag, size_t init_size) : _flags(flag), _size_in_bytes(0) { size_t round_size = (sizeof (char *)) - 1; init_size = (init_size+round_size) & ~round_size; _first = _chunk = new (AllocFailStrategy::EXIT_OOM, init_size) Chunk(init_size); _hwm = _chunk->bottom(); // Save the cached hwm, max _max = _chunk->top(); - _size_in_bytes = 0; + MemTracker::record_new_arena(flag); set_size_in_bytes(init_size); - NOT_PRODUCT(Atomic::inc(&_instance_count);) } -Arena::Arena() { +Arena::Arena(MEMFLAGS flag) : _flags(flag), _size_in_bytes(0) { _first = _chunk = new (AllocFailStrategy::EXIT_OOM, Chunk::init_size) Chunk(Chunk::init_size); _hwm = _chunk->bottom(); // Save the cached hwm, max _max = _chunk->top(); - _size_in_bytes = 0; + MemTracker::record_new_arena(flag); set_size_in_bytes(Chunk::init_size); - NOT_PRODUCT(Atomic::inc(&_instance_count);) } Arena *Arena::move_contents(Arena *copy) { @@ -463,7 +460,7 @@ Arena *Arena::move_contents(Arena *copy) { Arena::~Arena() { destruct_contents(); - NOT_PRODUCT(Atomic::dec(&_instance_count);) + MemTracker::record_arena_free(_flags); } void* Arena::operator new(size_t size) throw() { @@ -479,21 +476,21 @@ void* Arena::operator new (size_t size, const std::nothrow_t& nothrow_constant) // dynamic memory type binding void* Arena::operator new(size_t size, MEMFLAGS flags) throw() { #ifdef ASSERT - void* p = (void*)AllocateHeap(size, flags|otArena, CALLER_PC); + void* p = (void*)AllocateHeap(size, flags, CALLER_PC); if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p); return p; #else - return (void *) AllocateHeap(size, flags|otArena, CALLER_PC); + return (void *) AllocateHeap(size, flags, CALLER_PC); #endif } void* Arena::operator new(size_t size, const std::nothrow_t& nothrow_constant, MEMFLAGS flags) throw() { #ifdef ASSERT - void* p = os::malloc(size, flags|otArena, CALLER_PC); + void* p = os::malloc(size, flags, CALLER_PC); if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p); return p; #else - return os::malloc(size, flags|otArena, CALLER_PC); + return os::malloc(size, flags, CALLER_PC); #endif } @@ -518,8 +515,9 @@ void Arena::destruct_contents() { // change the size void Arena::set_size_in_bytes(size_t size) { if (_size_in_bytes != size) { + long delta = (long)(size - size_in_bytes()); _size_in_bytes = size; - MemTracker::record_arena_size((address)this, size); + MemTracker::record_arena_size_change(delta, _flags); } } diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp index fbfff65dad4..a1faa70871a 100644 --- a/hotspot/src/share/vm/memory/allocation.hpp +++ b/hotspot/src/share/vm/memory/allocation.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -133,51 +133,34 @@ class AllocatedObj { /* - * MemoryType bitmap layout: - * | 16 15 14 13 12 11 10 09 | 08 07 06 05 | 04 03 02 01 | - * | memory type | object | reserved | - * | | type | | + * Memory types */ enum MemoryType { // Memory type by sub systems. It occupies lower byte. - mtNone = 0x0000, // undefined - mtClass = 0x0100, // memory class for Java classes - mtThread = 0x0200, // memory for thread objects - mtThreadStack = 0x0300, - mtCode = 0x0400, // memory for generated code - mtGC = 0x0500, // memory for GC - mtCompiler = 0x0600, // memory for compiler - mtInternal = 0x0700, // memory used by VM, but does not belong to + mtJavaHeap = 0x00, // Java heap + mtClass = 0x01, // memory class for Java classes + mtThread = 0x02, // memory for thread objects + mtThreadStack = 0x03, + mtCode = 0x04, // memory for generated code + mtGC = 0x05, // memory for GC + mtCompiler = 0x06, // memory for compiler + mtInternal = 0x07, // memory used by VM, but does not belong to // any of above categories, and not used for // native memory tracking - mtOther = 0x0800, // memory not used by VM - mtSymbol = 0x0900, // symbol - mtNMT = 0x0A00, // memory used by native memory tracking - mtChunk = 0x0B00, // chunk that holds content of arenas - mtJavaHeap = 0x0C00, // Java heap - mtClassShared = 0x0D00, // class data sharing - mtTest = 0x0E00, // Test type for verifying NMT - mtTracing = 0x0F00, // memory used for Tracing - mt_number_of_types = 0x000F, // number of memory types (mtDontTrack + mtOther = 0x08, // memory not used by VM + mtSymbol = 0x09, // symbol + mtNMT = 0x0A, // memory used by native memory tracking + mtClassShared = 0x0B, // class data sharing + mtChunk = 0x0C, // chunk that holds content of arenas + mtTest = 0x0D, // Test type for verifying NMT + mtTracing = 0x0E, // memory used for Tracing + mtNone = 0x0F, // undefined + mt_number_of_types = 0x10 // number of memory types (mtDontTrack // is not included as validate type) - mtDontTrack = 0x0F00, // memory we do not or cannot track - mt_masks = 0x7F00, - - // object type mask - otArena = 0x0010, // an arena object - otNMTRecorder = 0x0020, // memory recorder object - ot_masks = 0x00F0 }; -#define IS_MEMORY_TYPE(flags, type) ((flags & mt_masks) == type) -#define HAS_VALID_MEMORY_TYPE(flags)((flags & mt_masks) != mtNone) -#define FLAGS_TO_MEMORY_TYPE(flags) (flags & mt_masks) +typedef MemoryType MEMFLAGS; -#define IS_ARENA_OBJ(flags) ((flags & ot_masks) == otArena) -#define IS_NMT_RECORDER(flags) ((flags & ot_masks) == otNMTRecorder) -#define NMT_CAN_TRACK(flags) (!IS_NMT_RECORDER(flags) && !(IS_MEMORY_TYPE(flags, mtDontTrack))) - -typedef unsigned short MEMFLAGS; #if INCLUDE_NMT @@ -189,27 +172,23 @@ const bool NMT_track_callsite = false; #endif // INCLUDE_NMT -// debug build does not inline -#if defined(_NMT_NOINLINE_) - #define CURRENT_PC (NMT_track_callsite ? os::get_caller_pc(1) : 0) - #define CALLER_PC (NMT_track_callsite ? os::get_caller_pc(2) : 0) - #define CALLER_CALLER_PC (NMT_track_callsite ? os::get_caller_pc(3) : 0) -#else - #define CURRENT_PC (NMT_track_callsite? os::get_caller_pc(0) : 0) - #define CALLER_PC (NMT_track_callsite ? os::get_caller_pc(1) : 0) - #define CALLER_CALLER_PC (NMT_track_callsite ? os::get_caller_pc(2) : 0) -#endif - +class NativeCallStack; template class CHeapObj ALLOCATION_SUPER_CLASS_SPEC { public: - _NOINLINE_ void* operator new(size_t size, address caller_pc = 0) throw(); + _NOINLINE_ void* operator new(size_t size, const NativeCallStack& stack) throw(); + _NOINLINE_ void* operator new(size_t size) throw(); _NOINLINE_ void* operator new (size_t size, const std::nothrow_t& nothrow_constant, - address caller_pc = 0) throw(); - _NOINLINE_ void* operator new [](size_t size, address caller_pc = 0) throw(); + const NativeCallStack& stack) throw(); + _NOINLINE_ void* operator new (size_t size, const std::nothrow_t& nothrow_constant) + throw(); + _NOINLINE_ void* operator new [](size_t size, const NativeCallStack& stack) throw(); + _NOINLINE_ void* operator new [](size_t size) throw(); _NOINLINE_ void* operator new [](size_t size, const std::nothrow_t& nothrow_constant, - address caller_pc = 0) throw(); + const NativeCallStack& stack) throw(); + _NOINLINE_ void* operator new [](size_t size, const std::nothrow_t& nothrow_constant) + throw(); void operator delete(void* p); void operator delete [] (void* p); }; @@ -286,7 +265,8 @@ class MetaspaceObj { f(ConstantPool) \ f(ConstantPoolCache) \ f(Annotation) \ - f(MethodCounters) + f(MethodCounters) \ + f(Deallocated) #define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type, #define METASPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name; @@ -384,13 +364,15 @@ class Chunk: CHeapObj { //------------------------------Arena------------------------------------------ // Fast allocation of memory -class Arena : public CHeapObj { +class Arena : public CHeapObj { protected: friend class ResourceMark; friend class HandleMark; friend class NoHandleMark; friend class VMStructs; + MEMFLAGS _flags; // Memory tracking flags + Chunk *_first; // First chunk Chunk *_chunk; // current chunk char *_hwm, *_max; // High water mark and max in current chunk @@ -418,8 +400,8 @@ protected: } public: - Arena(); - Arena(size_t init_size); + Arena(MEMFLAGS memflag); + Arena(MEMFLAGS memflag, size_t init_size); ~Arena(); void destruct_contents(); char* hwm() const { return _hwm; } @@ -518,8 +500,6 @@ protected: static void free_malloced_objects(Chunk* chunk, char* hwm, char* max, char* hwm2) PRODUCT_RETURN; static void free_all(char** start, char** end) PRODUCT_RETURN; - // how many arena instances - NOT_PRODUCT(static volatile jint _instance_count;) private: // Reset this Arena to empty, access will trigger grow if necessary void reset(void) { @@ -681,7 +661,7 @@ class ResourceObj ALLOCATION_SUPER_CLASS_SPEC { NEW_C_HEAP_ARRAY3(type, (size), memflags, pc, AllocFailStrategy::RETURN_NULL) #define NEW_C_HEAP_ARRAY_RETURN_NULL(type, size, memflags)\ - NEW_C_HEAP_ARRAY3(type, (size), memflags, (address)0, AllocFailStrategy::RETURN_NULL) + NEW_C_HEAP_ARRAY3(type, (size), memflags, CURRENT_PC, AllocFailStrategy::RETURN_NULL) #define REALLOC_C_HEAP_ARRAY(type, old, size, memflags)\ (type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), memflags)) diff --git a/hotspot/src/share/vm/memory/allocation.inline.hpp b/hotspot/src/share/vm/memory/allocation.inline.hpp index 806088b9bae..ddce9f5909b 100644 --- a/hotspot/src/share/vm/memory/allocation.inline.hpp +++ b/hotspot/src/share/vm/memory/allocation.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -27,6 +27,7 @@ #include "runtime/atomic.inline.hpp" #include "runtime/os.hpp" +#include "services/memTracker.hpp" // Explicit C-heap memory management @@ -49,12 +50,10 @@ inline void inc_stat_counter(volatile julong* dest, julong add_value) { #endif // allocate using malloc; will fail if no memory available -inline char* AllocateHeap(size_t size, MEMFLAGS flags, address pc = 0, +inline char* AllocateHeap(size_t size, MEMFLAGS flags, + const NativeCallStack& stack, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { - if (pc == 0) { - pc = CURRENT_PC; - } - char* p = (char*) os::malloc(size, flags, pc); + char* p = (char*) os::malloc(size, flags, stack); #ifdef ASSERT if (PrintMallocFree) trace_heap_malloc(size, "AllocateHeap", p); #endif @@ -63,10 +62,14 @@ inline char* AllocateHeap(size_t size, MEMFLAGS flags, address pc = 0, } return p; } - -inline char* ReallocateHeap(char *old, size_t size, MEMFLAGS flags, +inline char* AllocateHeap(size_t size, MEMFLAGS flags, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { - char* p = (char*) os::realloc(old, size, flags, CURRENT_PC); + return AllocateHeap(size, flags, CURRENT_PC, alloc_failmode); +} + +inline char* ReallocateHeap(char *old, size_t size, MEMFLAGS flag, + AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { + char* p = (char*) os::realloc(old, size, flag, CURRENT_PC); #ifdef ASSERT if (PrintMallocFree) trace_heap_malloc(size, "ReallocateHeap", p); #endif @@ -85,8 +88,22 @@ inline void FreeHeap(void* p, MEMFLAGS memflags = mtInternal) { template void* CHeapObj::operator new(size_t size, - address caller_pc) throw() { - void* p = (void*)AllocateHeap(size, F, (caller_pc != 0 ? caller_pc : CALLER_PC)); + const NativeCallStack& stack) throw() { + void* p = (void*)AllocateHeap(size, F, stack); +#ifdef ASSERT + if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p); +#endif + return p; +} + +template void* CHeapObj::operator new(size_t size) throw() { + return CHeapObj::operator new(size, CALLER_PC); +} + +template void* CHeapObj::operator new (size_t size, + const std::nothrow_t& nothrow_constant, const NativeCallStack& stack) throw() { + void* p = (void*)AllocateHeap(size, F, stack, + AllocFailStrategy::RETURN_NULL); #ifdef ASSERT if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p); #endif @@ -94,23 +111,28 @@ template void* CHeapObj::operator new(size_t size, } template void* CHeapObj::operator new (size_t size, - const std::nothrow_t& nothrow_constant, address caller_pc) throw() { - void* p = (void*)AllocateHeap(size, F, (caller_pc != 0 ? caller_pc : CALLER_PC), - AllocFailStrategy::RETURN_NULL); -#ifdef ASSERT - if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p); -#endif - return p; + const std::nothrow_t& nothrow_constant) throw() { + return CHeapObj::operator new(size, nothrow_constant, CALLER_PC); } template void* CHeapObj::operator new [](size_t size, - address caller_pc) throw() { - return CHeapObj::operator new(size, caller_pc); + const NativeCallStack& stack) throw() { + return CHeapObj::operator new(size, stack); +} + +template void* CHeapObj::operator new [](size_t size) + throw() { + return CHeapObj::operator new(size, CALLER_PC); } template void* CHeapObj::operator new [](size_t size, - const std::nothrow_t& nothrow_constant, address caller_pc) throw() { - return CHeapObj::operator new(size, nothrow_constant, caller_pc); + const std::nothrow_t& nothrow_constant, const NativeCallStack& stack) throw() { + return CHeapObj::operator new(size, nothrow_constant, stack); +} + +template void* CHeapObj::operator new [](size_t size, + const std::nothrow_t& nothrow_constant) throw() { + return CHeapObj::operator new(size, nothrow_constant, CALLER_PC); } template void CHeapObj::operator delete(void* p){ diff --git a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp index 1f56344c95d..30e8618d597 100644 --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp @@ -44,13 +44,6 @@ // enumerate ref fields that have been modified (since the last // enumeration.) -size_t CardTableModRefBS::cards_required(size_t covered_words) -{ - // Add one for a guard card, used to detect errors. - const size_t words = align_size_up(covered_words, card_size_in_words); - return words / card_size_in_words + 1; -} - size_t CardTableModRefBS::compute_byte_map_size() { assert(_guard_index == cards_required(_whole_heap.word_size()) - 1, @@ -64,27 +57,50 @@ CardTableModRefBS::CardTableModRefBS(MemRegion whole_heap, int max_covered_regions): ModRefBarrierSet(max_covered_regions), _whole_heap(whole_heap), - _guard_index(cards_required(whole_heap.word_size()) - 1), - _last_valid_index(_guard_index - 1), + _guard_index(0), + _guard_region(), + _last_valid_index(0), _page_size(os::vm_page_size()), - _byte_map_size(compute_byte_map_size()) + _byte_map_size(0), + _covered(NULL), + _committed(NULL), + _cur_covered_regions(0), + _byte_map(NULL), + byte_map_base(NULL), + // LNC functionality + _lowest_non_clean(NULL), + _lowest_non_clean_chunk_size(NULL), + _lowest_non_clean_base_chunk_index(NULL), + _last_LNC_resizing_collection(NULL) { _kind = BarrierSet::CardTableModRef; - HeapWord* low_bound = _whole_heap.start(); - HeapWord* high_bound = _whole_heap.end(); - assert((uintptr_t(low_bound) & (card_size - 1)) == 0, "heap must start at card boundary"); - assert((uintptr_t(high_bound) & (card_size - 1)) == 0, "heap must end at card boundary"); + assert((uintptr_t(_whole_heap.start()) & (card_size - 1)) == 0, "heap must start at card boundary"); + assert((uintptr_t(_whole_heap.end()) & (card_size - 1)) == 0, "heap must end at card boundary"); assert(card_size <= 512, "card_size must be less than 512"); // why? - _covered = new MemRegion[max_covered_regions]; - _committed = new MemRegion[max_covered_regions]; - if (_covered == NULL || _committed == NULL) { - vm_exit_during_initialization("couldn't alloc card table covered region set."); + _covered = new MemRegion[_max_covered_regions]; + if (_covered == NULL) { + vm_exit_during_initialization("Could not allocate card table covered region set."); } +} + +void CardTableModRefBS::initialize() { + _guard_index = cards_required(_whole_heap.word_size()) - 1; + _last_valid_index = _guard_index - 1; + + _byte_map_size = compute_byte_map_size(); + + HeapWord* low_bound = _whole_heap.start(); + HeapWord* high_bound = _whole_heap.end(); _cur_covered_regions = 0; + _committed = new MemRegion[_max_covered_regions]; + if (_committed == NULL) { + vm_exit_during_initialization("Could not allocate card table committed region set."); + } + const size_t rs_align = _page_size == (size_t) os::vm_page_size() ? 0 : MAX2(_page_size, (size_t) os::vm_allocation_granularity()); ReservedSpace heap_rs(_byte_map_size, rs_align, false); @@ -114,20 +130,20 @@ CardTableModRefBS::CardTableModRefBS(MemRegion whole_heap, !ExecMem, "card table last card"); *guard_card = last_card; - _lowest_non_clean = - NEW_C_HEAP_ARRAY(CardArr, max_covered_regions, mtGC); + _lowest_non_clean = + NEW_C_HEAP_ARRAY(CardArr, _max_covered_regions, mtGC); _lowest_non_clean_chunk_size = - NEW_C_HEAP_ARRAY(size_t, max_covered_regions, mtGC); + NEW_C_HEAP_ARRAY(size_t, _max_covered_regions, mtGC); _lowest_non_clean_base_chunk_index = - NEW_C_HEAP_ARRAY(uintptr_t, max_covered_regions, mtGC); + NEW_C_HEAP_ARRAY(uintptr_t, _max_covered_regions, mtGC); _last_LNC_resizing_collection = - NEW_C_HEAP_ARRAY(int, max_covered_regions, mtGC); + NEW_C_HEAP_ARRAY(int, _max_covered_regions, mtGC); if (_lowest_non_clean == NULL || _lowest_non_clean_chunk_size == NULL || _lowest_non_clean_base_chunk_index == NULL || _last_LNC_resizing_collection == NULL) vm_exit_during_initialization("couldn't allocate an LNC array."); - for (int i = 0; i < max_covered_regions; i++) { + for (int i = 0; i < _max_covered_regions; i++) { _lowest_non_clean[i] = NULL; _lowest_non_clean_chunk_size[i] = 0; _last_LNC_resizing_collection[i] = -1; @@ -650,7 +666,7 @@ void CardTableModRefBS::verify_region(MemRegion mr, jbyte val, bool val_equals) { jbyte* start = byte_for(mr.start()); jbyte* end = byte_for(mr.last()); - bool failures = false; + bool failures = false; for (jbyte* curr = start; curr <= end; ++curr) { jbyte curr_val = *curr; bool failed = (val_equals) ? (curr_val != val) : (curr_val == val); diff --git a/hotspot/src/share/vm/memory/cardTableModRefBS.hpp b/hotspot/src/share/vm/memory/cardTableModRefBS.hpp index 5e72b4640f9..c824e6185a0 100644 --- a/hotspot/src/share/vm/memory/cardTableModRefBS.hpp +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.hpp @@ -96,12 +96,12 @@ class CardTableModRefBS: public ModRefBarrierSet { // The declaration order of these const fields is important; see the // constructor before changing. const MemRegion _whole_heap; // the region covered by the card table - const size_t _guard_index; // index of very last element in the card + size_t _guard_index; // index of very last element in the card // table; it is set to a guard value // (last_card) and should never be modified - const size_t _last_valid_index; // index of the last valid element + size_t _last_valid_index; // index of the last valid element const size_t _page_size; // page size used when mapping _byte_map - const size_t _byte_map_size; // in bytes + size_t _byte_map_size; // in bytes jbyte* _byte_map; // the card marking array int _cur_covered_regions; @@ -123,7 +123,12 @@ class CardTableModRefBS: public ModRefBarrierSet { protected: // Initialization utilities; covered_words is the size of the covered region // in, um, words. - inline size_t cards_required(size_t covered_words); + inline size_t cards_required(size_t covered_words) { + // Add one for a guard card, used to detect errors. + const size_t words = align_size_up(covered_words, card_size_in_words); + return words / card_size_in_words + 1; + } + inline size_t compute_byte_map_size(); // Finds and return the index of the region, if any, to which the given @@ -137,7 +142,7 @@ class CardTableModRefBS: public ModRefBarrierSet { int find_covering_region_containing(HeapWord* addr); // Resize one of the regions covered by the remembered set. - void resize_covered_region(MemRegion new_region); + virtual void resize_covered_region(MemRegion new_region); // Returns the leftmost end of a committed region corresponding to a // covered region before covered region "ind", or else "NULL" if "ind" is @@ -282,6 +287,8 @@ public: CardTableModRefBS(MemRegion whole_heap, int max_covered_regions); ~CardTableModRefBS(); + virtual void initialize(); + // *** Barrier set functions. bool has_write_ref_pre_barrier() { return false; } diff --git a/hotspot/src/share/vm/memory/cardTableRS.cpp b/hotspot/src/share/vm/memory/cardTableRS.cpp index 7c9d3618673..90f72d19efd 100644 --- a/hotspot/src/share/vm/memory/cardTableRS.cpp +++ b/hotspot/src/share/vm/memory/cardTableRS.cpp @@ -54,9 +54,10 @@ CardTableRS::CardTableRS(MemRegion whole_heap, #else _ct_bs = new CardTableModRefBSForCTRS(whole_heap, max_covered_regions); #endif + _ct_bs->initialize(); set_bs(_ct_bs); _last_cur_val_in_gen = NEW_C_HEAP_ARRAY3(jbyte, GenCollectedHeap::max_gens + 1, - mtGC, 0, AllocFailStrategy::RETURN_NULL); + mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL); if (_last_cur_val_in_gen == NULL) { vm_exit_during_initialization("Could not create last_cur_val_in_gen array."); } diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index af6e39d05f0..6589766bd65 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -176,13 +176,9 @@ size_t CollectorPolicy::compute_heap_alignment() { size_t alignment = GenRemSet::max_alignment_constraint(); - // Parallel GC does its own alignment of the generations to avoid requiring a - // large page (256M on some platforms) for the permanent generation. The - // other collectors should also be updated to do their own alignment and then - // this use of lcm() should be removed. - if (UseLargePages && !UseParallelGC) { + if (UseLargePages) { // In presence of large pages we have to make sure that our - // alignment is large page aware + // alignment is large page aware. alignment = lcm(os::large_page_size(), alignment); } @@ -909,7 +905,8 @@ void MarkSweepPolicy::initialize_alignments() { } void MarkSweepPolicy::initialize_generations() { - _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, 0, AllocFailStrategy::RETURN_NULL); + _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, CURRENT_PC, + AllocFailStrategy::RETURN_NULL); if (_generations == NULL) { vm_exit_during_initialization("Unable to allocate gen spec"); } diff --git a/hotspot/src/share/vm/memory/defNewGeneration.cpp b/hotspot/src/share/vm/memory/defNewGeneration.cpp index 281228d28eb..0271b04c351 100644 --- a/hotspot/src/share/vm/memory/defNewGeneration.cpp +++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp @@ -790,7 +790,7 @@ oop DefNewGeneration::copy_to_survivor_space(oop old) { // Try allocating obj in to-space (unless too old) if (old->age() < tenuring_threshold()) { - obj = (oop) to()->allocate(s); + obj = (oop) to()->allocate_aligned(s); } // Otherwise try allocating obj tenured diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 2f5c0165893..4d6c57b816f 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -24,9 +24,14 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" +#include "classfile/sharedClassUtil.hpp" #include "classfile/symbolTable.hpp" +#include "classfile/systemDictionaryShared.hpp" #include "classfile/altHashing.hpp" #include "memory/filemap.hpp" +#include "memory/metadataFactory.hpp" +#include "memory/oopFactory.hpp" +#include "oops/objArrayOop.hpp" #include "runtime/arguments.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" @@ -42,7 +47,6 @@ #endif PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - extern address JVM_FunctionAtStart(); extern address JVM_FunctionAtEnd(); @@ -78,16 +82,27 @@ void FileMapInfo::fail_stop(const char *msg, ...) { void FileMapInfo::fail_continue(const char *msg, ...) { va_list ap; va_start(ap, msg); - if (RequireSharedSpaces) { - fail(msg, ap); + MetaspaceShared::set_archive_loading_failed(); + if (PrintSharedArchiveAndExit && _validating_classpath_entry_table) { + // If we are doing PrintSharedArchiveAndExit and some of the classpath entries + // do not validate, we can still continue "limping" to validate the remaining + // entries. No need to quit. + tty->print("["); + tty->vprint(msg, ap); + tty->print_cr("]"); } else { - if (PrintSharedSpaces) { - tty->print_cr("UseSharedSpaces: %s", msg); + if (RequireSharedSpaces) { + fail(msg, ap); + } else { + if (PrintSharedSpaces) { + tty->print_cr("UseSharedSpaces: %s", msg); + } } } va_end(ap); UseSharedSpaces = false; - close(); + assert(current_info() != NULL, "singleton must be registered"); + current_info()->close(); } // Fill in the fileMapInfo structure with data about this VM instance. @@ -122,67 +137,201 @@ template static void get_header_version(char (&header_version) [N]) { } } +FileMapInfo::FileMapInfo() { + assert(_current_info == NULL, "must be singleton"); // not thread safe + _current_info = this; + memset(this, 0, sizeof(FileMapInfo)); + _file_offset = 0; + _file_open = false; + _header = SharedClassUtil::allocate_file_map_header(); + _header->_version = _invalid_version; +} + +FileMapInfo::~FileMapInfo() { + assert(_current_info == this, "must be singleton"); // not thread safe + _current_info = NULL; +} + void FileMapInfo::populate_header(size_t alignment) { - _header._magic = 0xf00baba2; - _header._version = _current_version; - _header._alignment = alignment; - _header._obj_alignment = ObjectAlignmentInBytes; + _header->populate(this, alignment); +} + +size_t FileMapInfo::FileMapHeader::data_size() { + return SharedClassUtil::file_map_header_size() - sizeof(FileMapInfo::FileMapHeaderBase); +} + +void FileMapInfo::FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) { + _magic = 0xf00baba2; + _version = _current_version; + _alignment = alignment; + _obj_alignment = ObjectAlignmentInBytes; + _classpath_entry_table_size = mapinfo->_classpath_entry_table_size; + _classpath_entry_table = mapinfo->_classpath_entry_table; + _classpath_entry_size = mapinfo->_classpath_entry_size; // The following fields are for sanity checks for whether this archive // will function correctly with this JVM and the bootclasspath it's // invoked with. // JVM version string ... changes on each build. - get_header_version(_header._jvm_ident); + get_header_version(_jvm_ident); +} - // Build checks on classpath and jar files - _header._num_jars = 0; - ClassPathEntry *cpe = ClassLoader::classpath_entry(0); - for ( ; cpe != NULL; cpe = cpe->next()) { +void FileMapInfo::allocate_classpath_entry_table() { + int bytes = 0; + int count = 0; + char* strptr = NULL; + char* strptr_max = NULL; + Thread* THREAD = Thread::current(); - if (cpe->is_jar_file()) { - if (_header._num_jars >= JVM_SHARED_JARS_MAX) { - fail_stop("Too many jar files to share.", NULL); - } + ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); + size_t entry_size = SharedClassUtil::shared_class_path_entry_size(); - // Jar file - record timestamp and file size. - struct stat st; - const char *path = cpe->name(); - if (os::stat(path, &st) != 0) { - // If we can't access a jar file in the boot path, then we can't - // make assumptions about where classes get loaded from. - fail_stop("Unable to open jar file %s.", path); - } - _header._jar[_header._num_jars]._timestamp = st.st_mtime; - _header._jar[_header._num_jars]._filesize = st.st_size; - _header._num_jars++; - } else { + for (int pass=0; pass<2; pass++) { + ClassPathEntry *cpe = ClassLoader::classpath_entry(0); - // If directories appear in boot classpath, they must be empty to - // avoid having to verify each individual class file. - const char* name = ((ClassPathDirEntry*)cpe)->name(); - if (!os::dir_is_empty(name)) { - fail_stop("Boot classpath directory %s is not empty.", name); + for (int cur_entry = 0 ; cpe != NULL; cpe = cpe->next(), cur_entry++) { + const char *name = cpe->name(); + int name_bytes = (int)(strlen(name) + 1); + + if (pass == 0) { + count ++; + bytes += (int)entry_size; + bytes += name_bytes; + if (TraceClassPaths || (TraceClassLoading && Verbose)) { + tty->print_cr("[Add main shared path (%s) %s]", (cpe->is_jar_file() ? "jar" : "dir"), name); + } + } else { + SharedClassPathEntry* ent = shared_classpath(cur_entry); + if (cpe->is_jar_file()) { + struct stat st; + if (os::stat(name, &st) != 0) { + // The file/dir must exist, or it would not have been added + // into ClassLoader::classpath_entry(). + // + // If we can't access a jar file in the boot path, then we can't + // make assumptions about where classes get loaded from. + FileMapInfo::fail_stop("Unable to open jar file %s.", name); + } + + EXCEPTION_MARK; // The following call should never throw, but would exit VM on error. + SharedClassUtil::update_shared_classpath(cpe, ent, st.st_mtime, st.st_size, THREAD); + } else { + ent->_filesize = -1; + if (!os::dir_is_empty(name)) { + ClassLoader::exit_with_path_failure("Cannot have non-empty directory in archived classpaths", name); + } + } + ent->_name = strptr; + if (strptr + name_bytes <= strptr_max) { + strncpy(strptr, name, (size_t)name_bytes); // name_bytes includes trailing 0. + strptr += name_bytes; + } else { + assert(0, "miscalculated buffer size"); + } } } + + if (pass == 0) { + EXCEPTION_MARK; // The following call should never throw, but would exit VM on error. + Array* arr = MetadataFactory::new_array(loader_data, (bytes + 7)/8, THREAD); + strptr = (char*)(arr->data()); + strptr_max = strptr + bytes; + SharedClassPathEntry* table = (SharedClassPathEntry*)strptr; + strptr += entry_size * count; + + _classpath_entry_table_size = count; + _classpath_entry_table = table; + _classpath_entry_size = entry_size; + } } } +bool FileMapInfo::validate_classpath_entry_table() { + _validating_classpath_entry_table = true; + + int count = _header->_classpath_entry_table_size; + + _classpath_entry_table = _header->_classpath_entry_table; + _classpath_entry_size = _header->_classpath_entry_size; + + for (int i=0; i_name; + bool ok = true; + if (TraceClassPaths || (TraceClassLoading && Verbose)) { + tty->print_cr("[Checking shared classpath entry: %s]", name); + } + if (os::stat(name, &st) != 0) { + fail_continue("Required classpath entry does not exist: %s", name); + ok = false; + } else if (ent->is_dir()) { + if (!os::dir_is_empty(name)) { + fail_continue("directory is not empty: %s", name); + ok = false; + } + } else { + if (ent->_timestamp != st.st_mtime || + ent->_filesize != st.st_size) { + ok = false; + if (PrintSharedArchiveAndExit) { + fail_continue(ent->_timestamp != st.st_mtime ? + "Timestamp mismatch" : + "File size mismatch"); + } else { + fail_continue("A jar file is not the one used while building" + " the shared archive file: %s", name); + } + } + } + if (ok) { + if (TraceClassPaths || (TraceClassLoading && Verbose)) { + tty->print_cr("[ok]"); + } + } else if (!PrintSharedArchiveAndExit) { + _validating_classpath_entry_table = false; + return false; + } + } + + _classpath_entry_table_size = _header->_classpath_entry_table_size; + _validating_classpath_entry_table = false; + return true; +} + // Read the FileMapInfo information from the file. bool FileMapInfo::init_from_file(int fd) { - - size_t n = read(fd, &_header, sizeof(struct FileMapHeader)); - if (n != sizeof(struct FileMapHeader)) { + size_t sz = _header->data_size(); + char* addr = _header->data(); + size_t n = os::read(fd, addr, (unsigned int)sz); + if (n != sz) { fail_continue("Unable to read the file header."); return false; } - if (_header._version != current_version()) { + if (_header->_version != current_version()) { fail_continue("The shared archive file has the wrong version."); return false; } _file_offset = (long)n; + + size_t info_size = _header->_paths_misc_info_size; + _paths_misc_info = NEW_C_HEAP_ARRAY_RETURN_NULL(char, info_size, mtClass); + if (_paths_misc_info == NULL) { + fail_continue("Unable to read the file header."); + return false; + } + n = os::read(fd, _paths_misc_info, (unsigned int)info_size); + if (n != info_size) { + fail_continue("Unable to read the shared path info header."); + FREE_C_HEAP_ARRAY(char, _paths_misc_info, mtClass); + _paths_misc_info = NULL; + return false; + } + + _file_offset += (long)n; return true; } @@ -237,7 +386,16 @@ void FileMapInfo::open_for_write() { // Write the header to the file, seek to the next allocation boundary. void FileMapInfo::write_header() { - write_bytes_aligned(&_header, sizeof(FileMapHeader)); + int info_size = ClassLoader::get_shared_paths_misc_info_size(); + + _header->_paths_misc_info_size = info_size; + + align_file_position(); + size_t sz = _header->data_size(); + char* addr = _header->data(); + write_bytes(addr, (int)sz); // skip the C++ vtable + write_bytes(ClassLoader::get_shared_paths_misc_info(), info_size); + align_file_position(); } @@ -247,7 +405,7 @@ void FileMapInfo::write_space(int i, Metaspace* space, bool read_only) { align_file_position(); size_t used = space->used_bytes_slow(Metaspace::NonClassType); size_t capacity = space->capacity_bytes_slow(Metaspace::NonClassType); - struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[i]; + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; write_region(i, (char*)space->bottom(), used, capacity, read_only, false); } @@ -257,7 +415,7 @@ void FileMapInfo::write_space(int i, Metaspace* space, bool read_only) { void FileMapInfo::write_region(int region, char* base, size_t size, size_t capacity, bool read_only, bool allow_exec) { - struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[region]; + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[region]; if (_file_open) { guarantee(si->_file_offset == _file_offset, "file offset mismatch."); @@ -339,7 +497,7 @@ void FileMapInfo::close() { // JVM/TI RedefineClasses() support: // Remap the shared readonly space to shared readwrite, private. bool FileMapInfo::remap_shared_readonly_as_readwrite() { - struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[0]; + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[0]; if (!si->_read_only) { // the space is already readwrite so we are done return true; @@ -367,7 +525,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() { // Map the whole region at once, assumed to be allocated contiguously. ReservedSpace FileMapInfo::reserve_shared_memory() { - struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[0]; + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[0]; char* requested_addr = si->_base; size_t size = FileMapInfo::shared_spaces_size(); @@ -389,7 +547,7 @@ ReservedSpace FileMapInfo::reserve_shared_memory() { static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode"}; char* FileMapInfo::map_region(int i) { - struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[i]; + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; size_t used = si->_used; size_t alignment = os::vm_allocation_granularity(); size_t size = align_size_up(used, alignment); @@ -415,7 +573,7 @@ char* FileMapInfo::map_region(int i) { // Unmap a memory region in the address space. void FileMapInfo::unmap_region(int i) { - struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[i]; + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; size_t used = si->_used; size_t size = align_size_up(used, os::vm_allocation_granularity()); if (!os::unmap_memory(si->_base, size)) { @@ -432,12 +590,21 @@ void FileMapInfo::assert_mark(bool check) { FileMapInfo* FileMapInfo::_current_info = NULL; - +SharedClassPathEntry* FileMapInfo::_classpath_entry_table = NULL; +int FileMapInfo::_classpath_entry_table_size = 0; +size_t FileMapInfo::_classpath_entry_size = 0x1234baad; +bool FileMapInfo::_validating_classpath_entry_table = false; // Open the shared archive file, read and validate the header // information (version, boot classpath, etc.). If initialization // fails, shared spaces are disabled and the file is closed. [See // fail_continue.] +// +// Validation of the archive is done in two steps: +// +// [1] validate_header() - done here. This checks the header, including _paths_misc_info. +// [2] validate_classpath_entry_table - this is done later, because the table is in the RW +// region of the archive, which is not mapped yet. bool FileMapInfo::initialize() { assert(UseSharedSpaces, "UseSharedSpaces expected."); @@ -451,92 +618,66 @@ bool FileMapInfo::initialize() { } init_from_file(_fd); - if (!validate()) { + if (!validate_header()) { return false; } - SharedReadOnlySize = _header._space[0]._capacity; - SharedReadWriteSize = _header._space[1]._capacity; - SharedMiscDataSize = _header._space[2]._capacity; - SharedMiscCodeSize = _header._space[3]._capacity; + SharedReadOnlySize = _header->_space[0]._capacity; + SharedReadWriteSize = _header->_space[1]._capacity; + SharedMiscDataSize = _header->_space[2]._capacity; + SharedMiscCodeSize = _header->_space[3]._capacity; return true; } - -bool FileMapInfo::validate() { - if (_header._version != current_version()) { - fail_continue("The shared archive file is the wrong version."); +bool FileMapInfo::FileMapHeader::validate() { + if (_version != current_version()) { + FileMapInfo::fail_continue("The shared archive file is the wrong version."); return false; } - if (_header._magic != (int)0xf00baba2) { - fail_continue("The shared archive file has a bad magic number."); + if (_magic != (int)0xf00baba2) { + FileMapInfo::fail_continue("The shared archive file has a bad magic number."); return false; } char header_version[JVM_IDENT_MAX]; get_header_version(header_version); - if (strncmp(_header._jvm_ident, header_version, JVM_IDENT_MAX-1) != 0) { - fail_continue("The shared archive file was created by a different" - " version or build of HotSpot."); - return false; - } - if (_header._obj_alignment != ObjectAlignmentInBytes) { - fail_continue("The shared archive file's ObjectAlignmentInBytes of %d" - " does not equal the current ObjectAlignmentInBytes of %d.", - _header._obj_alignment, ObjectAlignmentInBytes); - return false; - } - - // Cannot verify interpreter yet, as it can only be created after the GC - // heap has been initialized. - - if (_header._num_jars >= JVM_SHARED_JARS_MAX) { - fail_continue("Too many jar files to share."); - return false; - } - - // Build checks on classpath and jar files - int num_jars_now = 0; - ClassPathEntry *cpe = ClassLoader::classpath_entry(0); - for ( ; cpe != NULL; cpe = cpe->next()) { - - if (cpe->is_jar_file()) { - if (num_jars_now < _header._num_jars) { - - // Jar file - verify timestamp and file size. - struct stat st; - const char *path = cpe->name(); - if (os::stat(path, &st) != 0) { - fail_continue("Unable to open jar file %s.", path); - return false; - } - if (_header._jar[num_jars_now]._timestamp != st.st_mtime || - _header._jar[num_jars_now]._filesize != st.st_size) { - fail_continue("A jar file is not the one used while building" - " the shared archive file."); - return false; - } - } - ++num_jars_now; - } else { - - // If directories appear in boot classpath, they must be empty to - // avoid having to verify each individual class file. - const char* name = ((ClassPathDirEntry*)cpe)->name(); - if (!os::dir_is_empty(name)) { - fail_continue("Boot classpath directory %s is not empty.", name); - return false; - } + if (strncmp(_jvm_ident, header_version, JVM_IDENT_MAX-1) != 0) { + if (TraceClassPaths) { + tty->print_cr("Expected: %s", header_version); + tty->print_cr("Actual: %s", _jvm_ident); } + FileMapInfo::fail_continue("The shared archive file was created by a different" + " version or build of HotSpot"); + return false; } - if (num_jars_now < _header._num_jars) { - fail_continue("The number of jar files in the boot classpath is" - " less than the number the shared archive was created with."); + if (_obj_alignment != ObjectAlignmentInBytes) { + FileMapInfo::fail_continue("The shared archive file's ObjectAlignmentInBytes of %d" + " does not equal the current ObjectAlignmentInBytes of %d.", + _obj_alignment, ObjectAlignmentInBytes); return false; } return true; } +bool FileMapInfo::validate_header() { + bool status = _header->validate(); + + if (status) { + if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) { + if (!PrintSharedArchiveAndExit) { + fail_continue("shared class paths mismatch (hint: enable -XX:+TraceClassPaths to diagnose the failure)"); + status = false; + } + } + } + + if (_paths_misc_info != NULL) { + FREE_C_HEAP_ARRAY(char, _paths_misc_info, mtClass); + _paths_misc_info = NULL; + } + return status; +} + // The following method is provided to see whether a given pointer // falls in the mapped shared space. // Param: @@ -545,8 +686,8 @@ bool FileMapInfo::validate() { // True if the p is within the mapped shared space, otherwise, false. bool FileMapInfo::is_in_shared_space(const void* p) { for (int i = 0; i < MetaspaceShared::n_regions; i++) { - if (p >= _header._space[i]._base && - p < _header._space[i]._base + _header._space[i]._used) { + if (p >= _header->_space[i]._base && + p < _header->_space[i]._base + _header->_space[i]._used) { return true; } } @@ -557,7 +698,7 @@ bool FileMapInfo::is_in_shared_space(const void* p) { void FileMapInfo::print_shared_spaces() { gclog_or_tty->print_cr("Shared Spaces:"); for (int i = 0; i < MetaspaceShared::n_regions; i++) { - struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[i]; + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; gclog_or_tty->print(" %s " INTPTR_FORMAT "-" INTPTR_FORMAT, shared_region_name[i], si->_base, si->_base + si->_used); @@ -570,9 +711,9 @@ void FileMapInfo::stop_sharing_and_unmap(const char* msg) { if (map_info) { map_info->fail_continue(msg); for (int i = 0; i < MetaspaceShared::n_regions; i++) { - if (map_info->_header._space[i]._base != NULL) { + if (map_info->_header->_space[i]._base != NULL) { map_info->unmap_region(i); - map_info->_header._space[i]._base = NULL; + map_info->_header->_space[i]._base = NULL; } } } else if (DumpSharedSpaces) { diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index 166486fa3f0..b2b722a91aa 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.hpp @@ -37,30 +37,55 @@ // misc data (block offset table, string table, symbols, dictionary, etc.) // tag(666) -static const int JVM_SHARED_JARS_MAX = 128; -static const int JVM_SPACENAME_MAX = 128; static const int JVM_IDENT_MAX = 256; -static const int JVM_ARCH_MAX = 12; - class Metaspace; +class SharedClassPathEntry VALUE_OBJ_CLASS_SPEC { +public: + const char *_name; + time_t _timestamp; // jar timestamp, 0 if is directory + long _filesize; // jar file size, -1 if is directory + bool is_dir() { + return _filesize == -1; + } +}; + class FileMapInfo : public CHeapObj { private: + friend class ManifestStream; enum { _invalid_version = -1, - _current_version = 1 + _current_version = 2 }; bool _file_open; int _fd; long _file_offset; +private: + static SharedClassPathEntry* _classpath_entry_table; + static int _classpath_entry_table_size; + static size_t _classpath_entry_size; + static bool _validating_classpath_entry_table; + // FileMapHeader describes the shared space data in the file to be // mapped. This structure gets written to a file. It is not a class, so // that the compilers don't add any compiler-private data to it. - struct FileMapHeader { +public: + struct FileMapHeaderBase : public CHeapObj { + virtual bool validate() = 0; + virtual void populate(FileMapInfo* info, size_t alignment) = 0; + }; + struct FileMapHeader : FileMapHeaderBase { + // Use data() and data_size() to memcopy to/from the FileMapHeader. We need to + // avoid read/writing the C++ vtable pointer. + static size_t data_size(); + char* data() { + return ((char*)this) + sizeof(FileMapHeaderBase); + } + int _magic; // identify file type. int _version; // (from enum, above.) size_t _alignment; // how shared archive should be aligned @@ -78,44 +103,64 @@ private: // The following fields are all sanity checks for whether this archive // will function correctly with this JVM and the bootclasspath it's // invoked with. - char _arch[JVM_ARCH_MAX]; // architecture char _jvm_ident[JVM_IDENT_MAX]; // identifier for jvm - int _num_jars; // Number of jars in bootclasspath - // Per jar file data: timestamp, size. + // The _paths_misc_info is a variable-size structure that records "miscellaneous" + // information during dumping. It is generated and validated by the + // SharedPathsMiscInfo class. See SharedPathsMiscInfo.hpp and sharedClassUtil.hpp for + // detailed description. + // + // The _paths_misc_info data is stored as a byte array in the archive file header, + // immediately after the _header field. This information is used only when + // checking the validity of the archive and is deallocated after the archive is loaded. + // + // Note that the _paths_misc_info does NOT include information for JAR files + // that existed during dump time. Their information is stored in _classpath_entry_table. + int _paths_misc_info_size; + + // The following is a table of all the class path entries that were used + // during dumping. At run time, we require these files to exist and have the same + // size/modification time, or else the archive will refuse to load. + // + // All of these entries must be JAR files. The dumping process would fail if a non-empty + // directory was specified in the classpaths. If an empty directory was specified + // it is checked by the _paths_misc_info as described above. + // + // FIXME -- if JAR files in the tail of the list were specified but not used during dumping, + // they should be removed from this table, to save space and to avoid spurious + // loading failures during runtime. + int _classpath_entry_table_size; + size_t _classpath_entry_size; + SharedClassPathEntry* _classpath_entry_table; + + virtual bool validate(); + virtual void populate(FileMapInfo* info, size_t alignment); + }; + + FileMapHeader * _header; - struct { - time_t _timestamp; // jar timestamp. - long _filesize; // jar file size. - } _jar[JVM_SHARED_JARS_MAX]; - } _header; const char* _full_path; + char* _paths_misc_info; static FileMapInfo* _current_info; bool init_from_file(int fd); void align_file_position(); + bool validate_header_impl(); public: - FileMapInfo() { - _file_offset = 0; - _file_open = false; - _header._version = _invalid_version; - } + FileMapInfo(); + ~FileMapInfo(); static int current_version() { return _current_version; } void populate_header(size_t alignment); - bool validate(); + bool validate_header(); void invalidate(); - int version() { return _header._version; } - size_t alignment() { return _header._alignment; } - size_t space_capacity(int i) { return _header._space[i]._capacity; } - char* region_base(int i) { return _header._space[i]._base; } - struct FileMapHeader* header() { return &_header; } - - static void set_current_info(FileMapInfo* info) { - CDS_ONLY(_current_info = info;) - } + int version() { return _header->_version; } + size_t alignment() { return _header->_alignment; } + size_t space_capacity(int i) { return _header->_space[i]._capacity; } + char* region_base(int i) { return _header->_space[i]._base; } + struct FileMapHeader* header() { return _header; } static FileMapInfo* current_info() { CDS_ONLY(return _current_info;) @@ -146,7 +191,7 @@ public: // Errors. static void fail_stop(const char *msg, ...); - void fail_continue(const char *msg, ...); + static void fail_continue(const char *msg, ...); // Return true if given address is in the mapped shared space. bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false); @@ -160,6 +205,22 @@ public: // Stop CDS sharing and unmap CDS regions. static void stop_sharing_and_unmap(const char* msg); + + static void allocate_classpath_entry_table(); + bool validate_classpath_entry_table(); + + static SharedClassPathEntry* shared_classpath(int index) { + char* p = (char*)_classpath_entry_table; + p += _classpath_entry_size * index; + return (SharedClassPathEntry*)p; + } + static const char* shared_classpath_name(int index) { + return shared_classpath(index)->_name; + } + + static int get_number_of_share_classpaths() { + return _classpath_entry_table_size; + } }; #endif // SHARE_VM_MEMORY_FILEMAP_HPP diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 4b5deb03c05..9cd841f038a 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -708,15 +708,18 @@ void GenCollectedHeap::collect(GCCause::Cause cause) { #else // INCLUDE_ALL_GCS ShouldNotReachHere(); #endif // INCLUDE_ALL_GCS + } else if (cause == GCCause::_wb_young_gc) { + // minor collection for WhiteBox API + collect(cause, 0); } else { #ifdef ASSERT - if (cause == GCCause::_scavenge_alot) { - // minor collection only - collect(cause, 0); - } else { - // Stop-the-world full collection - collect(cause, n_gens() - 1); - } + if (cause == GCCause::_scavenge_alot) { + // minor collection only + collect(cause, 0); + } else { + // Stop-the-world full collection + collect(cause, n_gens() - 1); + } #else // Stop-the-world full collection collect(cause, n_gens() - 1); diff --git a/hotspot/src/share/vm/memory/heapInspection.cpp b/hotspot/src/share/vm/memory/heapInspection.cpp index 7a4c6fc8752..cc8f4fc061a 100644 --- a/hotspot/src/share/vm/memory/heapInspection.cpp +++ b/hotspot/src/share/vm/memory/heapInspection.cpp @@ -135,7 +135,7 @@ KlassInfoTable::KlassInfoTable(bool need_class_stats) { _ref = (HeapWord*) Universe::boolArrayKlassObj(); _buckets = (KlassInfoBucket*) AllocateHeap(sizeof(KlassInfoBucket) * _num_buckets, - mtInternal, 0, AllocFailStrategy::RETURN_NULL); + mtInternal, CURRENT_PC, AllocFailStrategy::RETURN_NULL); if (_buckets != NULL) { _size = _num_buckets; for (int index = 0; index < _size; index++) { diff --git a/hotspot/src/share/vm/memory/memRegion.cpp b/hotspot/src/share/vm/memory/memRegion.cpp index 9eb2be56930..8c33ddca1de 100644 --- a/hotspot/src/share/vm/memory/memRegion.cpp +++ b/hotspot/src/share/vm/memory/memRegion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -103,11 +103,13 @@ MemRegion MemRegion::minus(const MemRegion mr2) const { } void* MemRegion::operator new(size_t size) throw() { - return (address)AllocateHeap(size, mtGC, 0, AllocFailStrategy::RETURN_NULL); + return (address)AllocateHeap(size, mtGC, CURRENT_PC, + AllocFailStrategy::RETURN_NULL); } void* MemRegion::operator new [](size_t size) throw() { - return (address)AllocateHeap(size, mtGC, 0, AllocFailStrategy::RETURN_NULL); + return (address)AllocateHeap(size, mtGC, CURRENT_PC, + AllocFailStrategy::RETURN_NULL); } void MemRegion::operator delete(void* p) { FreeHeap(p, mtGC); diff --git a/hotspot/src/share/vm/memory/metadataFactory.hpp b/hotspot/src/share/vm/memory/metadataFactory.hpp index dbb936fdf57..0f9936802cd 100644 --- a/hotspot/src/share/vm/memory/metadataFactory.hpp +++ b/hotspot/src/share/vm/memory/metadataFactory.hpp @@ -79,6 +79,12 @@ class MetadataFactory : AllStatic { // Deallocation method for metadata template static void free_metadata(ClassLoaderData* loader_data, T md) { + if (DumpSharedSpaces) { + // FIXME: the freeing code is buggy, especially when PrintSharedSpaces is enabled. + // Disable for now -- this means if you specify bad classes in your classlist you + // may have wasted space inside the archive. + return; + } if (md != NULL) { assert(loader_data != NULL, "shouldn't pass null"); int size = md->size(); diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 2f52e388d52..678af113ff9 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -413,6 +413,7 @@ static bool should_commit_large_pages_when_reserving(size_t bytes) { VirtualSpaceNode::VirtualSpaceNode(size_t bytes) : _top(NULL), _next(NULL), _rs(), _container_count(0) { assert_is_size_aligned(bytes, Metaspace::reserve_alignment()); +#if INCLUDE_CDS // This allocates memory with mmap. For DumpSharedspaces, try to reserve // configurable address, generally at the top of the Java heap so other // memory addresses don't conflict. @@ -428,7 +429,9 @@ VirtualSpaceNode::VirtualSpaceNode(size_t bytes) : _top(NULL), _next(NULL), _rs( _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages); } MetaspaceShared::set_shared_rs(&_rs); - } else { + } else +#endif + { bool large_pages = should_commit_large_pages_when_reserving(bytes); _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages); @@ -2939,11 +2942,14 @@ void Metaspace::set_narrow_klass_base_and_shift(address metaspace_base, address // between the lower base and higher address. address lower_base; address higher_address; +#if INCLUDE_CDS if (UseSharedSpaces) { higher_address = MAX2((address)(cds_base + FileMapInfo::shared_spaces_size()), (address)(metaspace_base + compressed_class_space_size())); lower_base = MIN2(metaspace_base, cds_base); - } else { + } else +#endif + { higher_address = metaspace_base + compressed_class_space_size(); lower_base = metaspace_base; @@ -2964,6 +2970,7 @@ void Metaspace::set_narrow_klass_base_and_shift(address metaspace_base, address } } +#if INCLUDE_CDS // Return TRUE if the specified metaspace_base and cds_base are close enough // to work with compressed klass pointers. bool Metaspace::can_use_cds_with_metaspace_addr(char* metaspace_base, address cds_base) { @@ -2974,6 +2981,7 @@ bool Metaspace::can_use_cds_with_metaspace_addr(char* metaspace_base, address cd (address)(metaspace_base + compressed_class_space_size())); return ((uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax); } +#endif // Try to allocate the metaspace at the requested addr. void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base) { @@ -2993,6 +3001,7 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a large_pages, requested_addr, 0); if (!metaspace_rs.is_reserved()) { +#if INCLUDE_CDS if (UseSharedSpaces) { size_t increment = align_size_up(1*G, _reserve_alignment); @@ -3007,7 +3016,7 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a _reserve_alignment, large_pages, addr, 0); } } - +#endif // If no successful allocation then try to allocate the space anywhere. If // that fails then OOM doom. At this point we cannot try allocating the // metaspace as if UseCompressedClassPointers is off because too much @@ -3026,12 +3035,13 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a // If we got here then the metaspace got allocated. MemTracker::record_virtual_memory_type((address)metaspace_rs.base(), mtClass); +#if INCLUDE_CDS // Verify that we can use shared spaces. Otherwise, turn off CDS. if (UseSharedSpaces && !can_use_cds_with_metaspace_addr(metaspace_rs.base(), cds_base)) { FileMapInfo::stop_sharing_and_unmap( "Could not allocate metaspace at a compatible address"); } - +#endif set_narrow_klass_base_and_shift((address)metaspace_rs.base(), UseSharedSpaces ? (address)cds_base : 0); @@ -3115,6 +3125,7 @@ void Metaspace::global_initialize() { MetaspaceShared::set_max_alignment(max_alignment); if (DumpSharedSpaces) { +#if INCLUDE_CDS SharedReadOnlySize = align_size_up(SharedReadOnlySize, max_alignment); SharedReadWriteSize = align_size_up(SharedReadWriteSize, max_alignment); SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment); @@ -3152,23 +3163,22 @@ void Metaspace::global_initialize() { } Universe::set_narrow_klass_shift(0); -#endif - +#endif // _LP64 +#endif // INCLUDE_CDS } else { +#if INCLUDE_CDS // If using shared space, open the file that contains the shared space // and map in the memory before initializing the rest of metaspace (so // the addresses don't conflict) address cds_address = NULL; if (UseSharedSpaces) { FileMapInfo* mapinfo = new FileMapInfo(); - memset(mapinfo, 0, sizeof(FileMapInfo)); // Open the shared archive file, read and validate the header. If // initialization fails, shared spaces [UseSharedSpaces] are // disabled and the file is closed. // Map in spaces now also if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) { - FileMapInfo::set_current_info(mapinfo); cds_total = FileMapInfo::shared_spaces_size(); cds_address = (address)mapinfo->region_base(0); } else { @@ -3176,21 +3186,23 @@ void Metaspace::global_initialize() { "archive file not closed or shared spaces not disabled."); } } - +#endif // INCLUDE_CDS #ifdef _LP64 // If UseCompressedClassPointers is set then allocate the metaspace area // above the heap and above the CDS area (if it exists). if (using_class_space()) { if (UseSharedSpaces) { +#if INCLUDE_CDS char* cds_end = (char*)(cds_address + cds_total); cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment); allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address); +#endif } else { char* base = (char*)align_ptr_up(Universe::heap()->reserved_region().end(), _reserve_alignment); allocate_metaspace_compressed_klass_ptrs(base, 0); } } -#endif +#endif // _LP64 // Initialize these before initializing the VirtualSpaceList _first_chunk_word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord; @@ -3380,6 +3392,10 @@ void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { assert(!SafepointSynchronize::is_at_safepoint() || Thread::current()->is_VM_thread(), "should be the VM thread"); + if (DumpSharedSpaces && PrintSharedSpaces) { + record_deallocation(ptr, vsm()->get_raw_word_size(word_size)); + } + MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag); if (word_size < TreeChunk >::min_size()) { @@ -3417,8 +3433,9 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, if (result == NULL) { report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite); } - - space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size)); + if (PrintSharedSpaces) { + space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size)); + } // Zero initialize. Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0); @@ -3517,15 +3534,55 @@ const char* Metaspace::metadata_type_name(Metaspace::MetadataType mdtype) { void Metaspace::record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size) { assert(DumpSharedSpaces, "sanity"); - AllocRecord *rec = new AllocRecord((address)ptr, type, (int)word_size * HeapWordSize); + int byte_size = (int)word_size * HeapWordSize; + AllocRecord *rec = new AllocRecord((address)ptr, type, byte_size); + if (_alloc_record_head == NULL) { _alloc_record_head = _alloc_record_tail = rec; - } else { + } else if (_alloc_record_tail->_ptr + _alloc_record_tail->_byte_size == (address)ptr) { _alloc_record_tail->_next = rec; _alloc_record_tail = rec; + } else { + // slow linear search, but this doesn't happen that often, and only when dumping + for (AllocRecord *old = _alloc_record_head; old; old = old->_next) { + if (old->_ptr == ptr) { + assert(old->_type == MetaspaceObj::DeallocatedType, "sanity"); + int remain_bytes = old->_byte_size - byte_size; + assert(remain_bytes >= 0, "sanity"); + old->_type = type; + + if (remain_bytes == 0) { + delete(rec); + } else { + address remain_ptr = address(ptr) + byte_size; + rec->_ptr = remain_ptr; + rec->_byte_size = remain_bytes; + rec->_type = MetaspaceObj::DeallocatedType; + rec->_next = old->_next; + old->_byte_size = byte_size; + old->_next = rec; + } + return; + } + } + assert(0, "reallocating a freed pointer that was not recorded"); } } +void Metaspace::record_deallocation(void* ptr, size_t word_size) { + assert(DumpSharedSpaces, "sanity"); + + for (AllocRecord *rec = _alloc_record_head; rec; rec = rec->_next) { + if (rec->_ptr == ptr) { + assert(rec->_byte_size == (int)word_size * HeapWordSize, "sanity"); + rec->_type = MetaspaceObj::DeallocatedType; + return; + } + } + + assert(0, "deallocating a pointer that was not recorded"); +} + void Metaspace::iterate(Metaspace::AllocRecordClosure *closure) { assert(DumpSharedSpaces, "unimplemented for !DumpSharedSpaces"); diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index 545bf0e7fbd..ef9ad65b088 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -171,9 +171,10 @@ class Metaspace : public CHeapObj { static const MetaspaceTracer* tracer() { return _tracer; } private: - // This is used by DumpSharedSpaces only, where only _vsm is used. So we will + // These 2 methods are used by DumpSharedSpaces only, where only _vsm is used. So we will // maintain a single list for now. void record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size); + void record_deallocation(void* ptr, size_t word_size); #ifdef _LP64 static void set_narrow_klass_base_and_shift(address metaspace_base, address cds_base); diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 8aff392b5a1..f9e3b17ec9d 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -26,6 +26,7 @@ #include "classfile/dictionary.hpp" #include "classfile/loaderConstraints.hpp" #include "classfile/placeholders.hpp" +#include "classfile/sharedClassUtil.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" @@ -47,6 +48,10 @@ int MetaspaceShared::_max_alignment = 0; ReservedSpace* MetaspaceShared::_shared_rs = NULL; +bool MetaspaceShared::_link_classes_made_progress; +bool MetaspaceShared::_check_classes_made_progress; +bool MetaspaceShared::_has_error_classes; +bool MetaspaceShared::_archive_loading_failed = false; // Read/write a data stream for restoring/preserving metadata pointers and // miscellaneous data from/to the shared archive file. @@ -446,6 +451,23 @@ void VM_PopulateDumpSharedSpace::doit() { SystemDictionary::classes_do(collect_classes); tty->print_cr("Number of classes %d", _global_klass_objects->length()); + { + int num_type_array = 0, num_obj_array = 0, num_inst = 0; + for (int i = 0; i < _global_klass_objects->length(); i++) { + Klass* k = _global_klass_objects->at(i); + if (k->oop_is_instance()) { + num_inst ++; + } else if (k->oop_is_objArray()) { + num_obj_array ++; + } else { + assert(k->oop_is_typeArray(), "sanity"); + num_type_array ++; + } + } + tty->print_cr(" instance classes = %5d", num_inst); + tty->print_cr(" obj array classes = %5d", num_obj_array); + tty->print_cr(" type array classes = %5d", num_type_array); + } // Update all the fingerprints in the shared methods. tty->print("Calculating fingerprints ... "); @@ -611,38 +633,58 @@ void VM_PopulateDumpSharedSpace::doit() { #undef fmt_space } -static void link_shared_classes(Klass* obj, TRAPS) { + +void MetaspaceShared::link_one_shared_class(Klass* obj, TRAPS) { Klass* k = obj; if (k->oop_is_instance()) { InstanceKlass* ik = (InstanceKlass*) k; // Link the class to cause the bytecodes to be rewritten and the - // cpcache to be created. - if (ik->init_state() < InstanceKlass::linked) { - ik->link_class(THREAD); - guarantee(!HAS_PENDING_EXCEPTION, "exception in class rewriting"); + // cpcache to be created. Class verification is done according + // to -Xverify setting. + _link_classes_made_progress |= try_link_class(ik, THREAD); + guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class"); + } +} + +void MetaspaceShared::check_one_shared_class(Klass* k) { + if (k->oop_is_instance() && InstanceKlass::cast(k)->check_sharing_error_state()) { + _check_classes_made_progress = true; + } +} + +void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) { + // We need to iterate because verification may cause additional classes + // to be loaded. + do { + _link_classes_made_progress = false; + SystemDictionary::classes_do(link_one_shared_class, THREAD); + guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class"); + } while (_link_classes_made_progress); + + if (_has_error_classes) { + // Mark all classes whose super class or interfaces failed verification. + do { + // Not completely sure if we need to do this iteratively. Anyway, + // we should come here only if there are unverifiable classes, which + // shouldn't happen in normal cases. So better safe than sorry. + _check_classes_made_progress = false; + SystemDictionary::classes_do(check_one_shared_class); + } while (_check_classes_made_progress); + + if (IgnoreUnverifiableClassesDuringDump) { + // This is useful when running JCK or SQE tests. You should not + // enable this when running real apps. + SystemDictionary::remove_classes_in_error_state(); + } else { + tty->print_cr("Please remove the unverifiable classes from your class list and try again"); + exit(1); } } } - -// Support for a simple checksum of the contents of the class list -// file to prevent trivial tampering. The algorithm matches that in -// the MakeClassList program used by the J2SE build process. -#define JSUM_SEED ((jlong)CONST64(0xcafebabebabecafe)) -static jlong -jsum(jlong start, const char *buf, const int len) -{ - jlong h = start; - char *p = (char *)buf, *e = p + len; - while (p < e) { - char c = *p++; - if (c <= ' ') { - /* Skip spaces and control characters */ - continue; - } - h = 31 * h + c; - } - return h; +void MetaspaceShared::prepare_for_dumping() { + ClassLoader::initialize_shared_path(); + FileMapInfo::allocate_classpath_entry_table(); } // Preload classes from a list, populate the shared spaces and dump to a @@ -651,72 +693,112 @@ void MetaspaceShared::preload_and_dump(TRAPS) { TraceTime timer("Dump Shared Spaces", TraceStartupTime); ResourceMark rm; + tty->print_cr("Allocated shared space: %d bytes at " PTR_FORMAT, + MetaspaceShared::shared_rs()->size(), + MetaspaceShared::shared_rs()->base()); + // Preload classes to be shared. // Should use some os:: method rather than fopen() here. aB. - // Construct the path to the class list (in jre/lib) - // Walk up two directories from the location of the VM and - // optionally tack on "lib" (depending on platform) - char class_list_path[JVM_MAXPATHLEN]; - os::jvm_path(class_list_path, sizeof(class_list_path)); - for (int i = 0; i < 3; i++) { - char *end = strrchr(class_list_path, *os::file_separator()); - if (end != NULL) *end = '\0'; - } - int class_list_path_len = (int)strlen(class_list_path); - if (class_list_path_len >= 3) { - if (strcmp(class_list_path + class_list_path_len - 3, "lib") != 0) { - strcat(class_list_path, os::file_separator()); - strcat(class_list_path, "lib"); + const char* class_list_path; + if (SharedClassListFile == NULL) { + // Construct the path to the class list (in jre/lib) + // Walk up two directories from the location of the VM and + // optionally tack on "lib" (depending on platform) + char class_list_path_str[JVM_MAXPATHLEN]; + os::jvm_path(class_list_path_str, sizeof(class_list_path_str)); + for (int i = 0; i < 3; i++) { + char *end = strrchr(class_list_path_str, *os::file_separator()); + if (end != NULL) *end = '\0'; } + int class_list_path_len = (int)strlen(class_list_path_str); + if (class_list_path_len >= 3) { + if (strcmp(class_list_path_str + class_list_path_len - 3, "lib") != 0) { + strcat(class_list_path_str, os::file_separator()); + strcat(class_list_path_str, "lib"); + } + } + strcat(class_list_path_str, os::file_separator()); + strcat(class_list_path_str, "classlist"); + class_list_path = class_list_path_str; + } else { + class_list_path = SharedClassListFile; } - strcat(class_list_path, os::file_separator()); - strcat(class_list_path, "classlist"); + int class_count = 0; + GrowableArray* class_promote_order = new GrowableArray(); + + // sun.io.Converters + static const char obj_array_sig[] = "[[Ljava/lang/Object;"; + SymbolTable::new_permanent_symbol(obj_array_sig, THREAD); + + // java.util.HashMap + static const char map_entry_array_sig[] = "[Ljava/util/Map$Entry;"; + SymbolTable::new_permanent_symbol(map_entry_array_sig, THREAD); + + tty->print_cr("Loading classes to share ..."); + _has_error_classes = false; + class_count += preload_and_dump(class_list_path, class_promote_order, + THREAD); + if (ExtraSharedClassListFile) { + class_count += preload_and_dump(ExtraSharedClassListFile, class_promote_order, + THREAD); + } + tty->print_cr("Loading classes to share: done."); + + if (PrintSharedSpaces) { + tty->print_cr("Shared spaces: preloaded %d classes", class_count); + } + + // Rewrite and link classes + tty->print_cr("Rewriting and linking classes ..."); + + // Link any classes which got missed. This would happen if we have loaded classes that + // were not explicitly specified in the classlist. E.g., if an interface implemented by class K + // fails verification, all other interfaces that were not specified in the classlist but + // are implemented by K are not verified. + link_and_cleanup_shared_classes(CATCH); + tty->print_cr("Rewriting and linking classes: done"); + + // Create and dump the shared spaces. Everything so far is loaded + // with the null class loader. + ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); + VM_PopulateDumpSharedSpace op(loader_data, class_promote_order); + VMThread::execute(&op); + + // Since various initialization steps have been undone by this process, + // it is not reasonable to continue running a java process. + exit(0); +} + +int MetaspaceShared::preload_and_dump(const char * class_list_path, + GrowableArray* class_promote_order, + TRAPS) { FILE* file = fopen(class_list_path, "r"); + char class_name[256]; + int class_count = 0; + if (file != NULL) { - jlong computed_jsum = JSUM_SEED; - jlong file_jsum = 0; - - char class_name[256]; - int class_count = 0; - GrowableArray* class_promote_order = new GrowableArray(); - - // sun.io.Converters - static const char obj_array_sig[] = "[[Ljava/lang/Object;"; - SymbolTable::new_permanent_symbol(obj_array_sig, THREAD); - - // java.util.HashMap - static const char map_entry_array_sig[] = "[Ljava/util/Map$Entry;"; - SymbolTable::new_permanent_symbol(map_entry_array_sig, THREAD); - - tty->print("Loading classes to share ... "); while ((fgets(class_name, sizeof class_name, file)) != NULL) { - if (*class_name == '#') { - jint fsh, fsl; - if (sscanf(class_name, "# %8x%8x\n", &fsh, &fsl) == 2) { - file_jsum = ((jlong)(fsh) << 32) | (fsl & 0xffffffff); - } - + if (*class_name == '#') { // comment continue; } // Remove trailing newline size_t name_len = strlen(class_name); - class_name[name_len-1] = '\0'; - - computed_jsum = jsum(computed_jsum, class_name, (const int)name_len - 1); + if (class_name[name_len-1] == '\n') { + class_name[name_len-1] = '\0'; + } // Got a class name - load it. TempNewSymbol class_name_symbol = SymbolTable::new_permanent_symbol(class_name, THREAD); guarantee(!HAS_PENDING_EXCEPTION, "Exception creating a symbol."); Klass* klass = SystemDictionary::resolve_or_null(class_name_symbol, THREAD); - guarantee(!HAS_PENDING_EXCEPTION, "Exception resolving a class."); + CLEAR_PENDING_EXCEPTION; if (klass != NULL) { if (PrintSharedSpaces && Verbose && WizardMode) { tty->print_cr("Shared spaces preloaded: %s", class_name); } - InstanceKlass* ik = InstanceKlass::cast(klass); // Should be class load order as per -XX:+TraceClassLoadingPreorder @@ -726,52 +808,14 @@ void MetaspaceShared::preload_and_dump(TRAPS) { // cpcache to be created. The linking is done as soon as classes // are loaded in order that the related data structures (klass and // cpCache) are located together. - - if (ik->init_state() < InstanceKlass::linked) { - ik->link_class(THREAD); - guarantee(!(HAS_PENDING_EXCEPTION), "exception in class rewriting"); - } - - // TODO: Resolve klasses in constant pool - ik->constants()->resolve_class_constants(THREAD); + try_link_class(ik, THREAD); + guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class"); class_count++; } else { - if (PrintSharedSpaces && Verbose && WizardMode) { - tty->cr(); - tty->print_cr(" Preload failed: %s", class_name); - } + //tty->print_cr("Preload failed: %s", class_name); } - file_jsum = 0; // Checksum must be on last line of file } - if (computed_jsum != file_jsum) { - tty->cr(); - tty->print_cr("Preload failed: checksum of class list was incorrect."); - exit(1); - } - - tty->print_cr("done. "); - - if (PrintSharedSpaces) { - tty->print_cr("Shared spaces: preloaded %d classes", class_count); - } - - // Rewrite and unlink classes. - tty->print("Rewriting and linking classes ... "); - - // Link any classes which got missed. (It's not quite clear why - // they got missed.) This iteration would be unsafe if we weren't - // single-threaded at this point; however we can't do it on the VM - // thread because it requires object allocation. - SystemDictionary::classes_do(link_shared_classes, CATCH); - tty->print_cr("done. "); - - // Create and dump the shared spaces. Everything so far is loaded - // with the null class loader. - ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); - VM_PopulateDumpSharedSpace op(loader_data, class_promote_order); - VMThread::execute(&op); - } else { char errmsg[JVM_MAXPATHLEN]; os::lasterror(errmsg, JVM_MAXPATHLEN); @@ -779,11 +823,39 @@ void MetaspaceShared::preload_and_dump(TRAPS) { exit(1); } - // Since various initialization steps have been undone by this process, - // it is not reasonable to continue running a java process. - exit(0); + return class_count; } +// Returns true if the class's status has changed +bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) { + assert(DumpSharedSpaces, "should only be called during dumping"); + if (ik->init_state() < InstanceKlass::linked) { + bool saved = BytecodeVerificationLocal; + if (!SharedClassUtil::is_shared_boot_class(ik)) { + // The verification decision is based on BytecodeVerificationRemote + // for non-system classes. Since we are using the NULL classloader + // to load non-system classes during dumping, we need to temporarily + // change BytecodeVerificationLocal to be the same as + // BytecodeVerificationRemote. Note this can cause the parent system + // classes also being verified. The extra overhead is acceptable during + // dumping. + BytecodeVerificationLocal = BytecodeVerificationRemote; + } + ik->link_class(THREAD); + if (HAS_PENDING_EXCEPTION) { + ResourceMark rm; + tty->print_cr("Preload Error: Verification failed for %s", + ik->external_name()); + CLEAR_PENDING_EXCEPTION; + ik->set_in_error_state(); + _has_error_classes = true; + } + BytecodeVerificationLocal = saved; + return true; + } else { + return false; + } +} // Closure for serializing initialization data in from a data area // (ptr_array) read from the shared file. @@ -867,7 +939,8 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { (_rw_base = mapinfo->map_region(rw)) != NULL && (_md_base = mapinfo->map_region(md)) != NULL && (_mc_base = mapinfo->map_region(mc)) != NULL && - (image_alignment == (size_t)max_alignment())) { + (image_alignment == (size_t)max_alignment()) && + mapinfo->validate_classpath_entry_table()) { // Success (no need to do anything) return true; } else { @@ -884,7 +957,7 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { // If -Xshare:on is specified, print out the error message and exit VM, // otherwise, set UseSharedSpaces to false and continue. if (RequireSharedSpaces) { - vm_exit_during_initialization("Unable to use shared archive.", NULL); + vm_exit_during_initialization("Unable to use shared archive.", "Failed map_region for using -Xshare:on."); } else { FLAG_SET_DEFAULT(UseSharedSpaces, false); } @@ -984,6 +1057,20 @@ void MetaspaceShared::initialize_shared_spaces() { // Close the mapinfo file mapinfo->close(); + + if (PrintSharedArchiveAndExit) { + if (PrintSharedDictionary) { + tty->print_cr("\nShared classes:\n"); + SystemDictionary::print_shared(false); + } + if (_archive_loading_failed) { + tty->print_cr("archive is invalid"); + vm_exit(1); + } else { + tty->print_cr("archive is valid"); + vm_exit(0); + } + } } // JVM/TI RedefineClasses() support: diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp index 12c8af510f0..b724196c77f 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp @@ -38,7 +38,10 @@ class MetaspaceShared : AllStatic { // CDS support static ReservedSpace* _shared_rs; static int _max_alignment; - + static bool _link_classes_made_progress; + static bool _check_classes_made_progress; + static bool _has_error_classes; + static bool _archive_loading_failed; public: enum { vtbl_list_size = 17, // number of entries in the shared space vtable list. @@ -67,7 +70,11 @@ class MetaspaceShared : AllStatic { NOT_CDS(return 0); } + static void prepare_for_dumping() NOT_CDS_RETURN; static void preload_and_dump(TRAPS) NOT_CDS_RETURN; + static int preload_and_dump(const char * class_list_path, + GrowableArray* class_promote_order, + TRAPS) NOT_CDS_RETURN; static ReservedSpace* shared_rs() { CDS_ONLY(return _shared_rs); @@ -78,6 +85,9 @@ class MetaspaceShared : AllStatic { CDS_ONLY(_shared_rs = rs;) } + static void set_archive_loading_failed() { + _archive_loading_failed = true; + } static bool map_shared_spaces(FileMapInfo* mapinfo) NOT_CDS_RETURN_(false); static void initialize_shared_spaces() NOT_CDS_RETURN; @@ -97,5 +107,10 @@ class MetaspaceShared : AllStatic { static bool remap_shared_readonly_as_readwrite() NOT_CDS_RETURN_(true); static void print_shared_spaces(); + + static bool try_link_class(InstanceKlass* ik, TRAPS); + static void link_one_shared_class(Klass* obj, TRAPS); + static void check_one_shared_class(Klass* obj); + static void link_and_cleanup_shared_classes(TRAPS); }; #endif // SHARE_VM_MEMORY_METASPACE_SHARED_HPP diff --git a/hotspot/src/share/vm/memory/resourceArea.hpp b/hotspot/src/share/vm/memory/resourceArea.hpp index e1cafe7f048..02dffc7a4b4 100644 --- a/hotspot/src/share/vm/memory/resourceArea.hpp +++ b/hotspot/src/share/vm/memory/resourceArea.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -49,11 +49,11 @@ class ResourceArea: public Arena { debug_only(static int _warned;) // to suppress multiple warnings public: - ResourceArea() { + ResourceArea() : Arena(mtThread) { debug_only(_nesting = 0;) } - ResourceArea(size_t init_size) : Arena(init_size) { + ResourceArea(size_t init_size) : Arena(mtThread, init_size) { debug_only(_nesting = 0;); } @@ -64,7 +64,7 @@ public: if (UseMallocOnly) { // use malloc, but save pointer in res. area for later freeing char** save = (char**)internal_malloc_4(sizeof(char*)); - return (*save = (char*)os::malloc(size, mtThread)); + return (*save = (char*)os::malloc(size, mtThread, CURRENT_PC)); } #endif return (char*)Amalloc(size, alloc_failmode); diff --git a/hotspot/src/share/vm/memory/sharedHeap.cpp b/hotspot/src/share/vm/memory/sharedHeap.cpp index e0a5d9961cb..5d268c38515 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.cpp +++ b/hotspot/src/share/vm/memory/sharedHeap.cpp @@ -159,9 +159,9 @@ SharedHeap::StrongRootsScope::~StrongRootsScope() { Monitor* SharedHeap::StrongRootsScope::_lock = new Monitor(Mutex::leaf, "StrongRootsScope lock", false); void SharedHeap::StrongRootsScope::mark_worker_done_with_threads(uint n_workers) { - // The Thread work barrier is only needed by G1. + // The Thread work barrier is only needed by G1 Class Unloading. // No need to use the barrier if this is single-threaded code. - if (UseG1GC && n_workers > 0) { + if (UseG1GC && ClassUnloadingWithConcurrentMark && n_workers > 0) { uint new_value = (uint)Atomic::add(1, &_n_workers_done_with_threads); if (new_value == n_workers) { // This thread is last. Notify the others. @@ -172,6 +172,9 @@ void SharedHeap::StrongRootsScope::mark_worker_done_with_threads(uint n_workers) } void SharedHeap::StrongRootsScope::wait_until_all_workers_done_with_threads(uint n_workers) { + assert(UseG1GC, "Currently only used by G1"); + assert(ClassUnloadingWithConcurrentMark, "Currently only needed when doing G1 Class Unloading"); + // No need to use the barrier if this is single-threaded code. if (n_workers > 0 && (uint)_n_workers_done_with_threads != n_workers) { MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag); diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index 330dd3fdef9..41f1a72150a 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -28,6 +28,7 @@ #include "gc_implementation/shared/liveRange.hpp" #include "gc_implementation/shared/markSweep.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" +#include "gc_interface/collectedHeap.inline.hpp" #include "memory/blockOffsetTable.inline.hpp" #include "memory/defNewGeneration.hpp" #include "memory/genCollectedHeap.hpp" @@ -720,6 +721,27 @@ inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size, } while (true); } +HeapWord* ContiguousSpace::allocate_aligned(size_t size) { + assert(Heap_lock->owned_by_self() || (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread()), "not locked"); + HeapWord* end_value = end(); + + HeapWord* obj = CollectedHeap::align_allocation_or_fail(top(), end_value, SurvivorAlignmentInBytes); + if (obj == NULL) { + return NULL; + } + + if (pointer_delta(end_value, obj) >= size) { + HeapWord* new_top = obj + size; + set_top(new_top); + assert(is_ptr_aligned(obj, SurvivorAlignmentInBytes) && is_aligned(new_top), + "checking alignment"); + return obj; + } else { + set_top(obj); + return NULL; + } +} + // Requires locking. HeapWord* ContiguousSpace::allocate(size_t size) { return allocate_impl(size, end()); diff --git a/hotspot/src/share/vm/memory/space.hpp b/hotspot/src/share/vm/memory/space.hpp index 0653884e043..f78a8c7ab4b 100644 --- a/hotspot/src/share/vm/memory/space.hpp +++ b/hotspot/src/share/vm/memory/space.hpp @@ -526,6 +526,7 @@ class ContiguousSpace: public CompactibleSpace { // Allocation (return NULL if full) virtual HeapWord* allocate(size_t word_size); virtual HeapWord* par_allocate(size_t word_size); + HeapWord* allocate_aligned(size_t word_size); // Iteration void oop_iterate(ExtendedOopClosure* cl); diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 8ea866f4dec..a85ec509dff 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -26,6 +26,9 @@ #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" +#if INCLUDE_CDS +#include "classfile/sharedClassUtil.hpp" +#endif #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -34,6 +37,7 @@ #include "gc_interface/collectedHeap.inline.hpp" #include "interpreter/interpreter.hpp" #include "memory/cardTableModRefBS.hpp" +#include "memory/filemap.hpp" #include "memory/gcLocker.inline.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/genRemSet.hpp" @@ -239,8 +243,9 @@ void Universe::check_alignment(uintx size, uintx alignment, const char* name) { void initialize_basic_type_klass(Klass* k, TRAPS) { Klass* ok = SystemDictionary::Object_klass(); if (UseSharedSpaces) { + ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); assert(k->super() == ok, "u3"); - k->restore_unshareable_info(CHECK); + k->restore_unshareable_info(loader_data, Handle(), CHECK); } else { k->initialize_supers(ok, CHECK); } @@ -666,6 +671,10 @@ jint universe_init() { SymbolTable::create_table(); StringTable::create_table(); ClassLoader::create_package_info_table(); + + if (DumpSharedSpaces) { + MetaspaceShared::prepare_for_dumping(); + } } return JNI_OK; @@ -1155,6 +1164,11 @@ bool universe_post_init() { MemoryService::add_metaspace_memory_pools(); MemoryService::set_universe_heap(Universe::_collectedHeap); +#if INCLUDE_CDS + if (UseSharedSpaces) { + SharedClassUtil::initialize(CHECK_false); + } +#endif return true; } diff --git a/hotspot/src/share/vm/oops/arrayKlass.cpp b/hotspot/src/share/vm/oops/arrayKlass.cpp index e8a367a3766..726c21db2da 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlass.cpp @@ -186,8 +186,9 @@ void ArrayKlass::remove_unshareable_info() { set_component_mirror(NULL); } -void ArrayKlass::restore_unshareable_info(TRAPS) { - Klass::restore_unshareable_info(CHECK); +void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { + assert(loader_data == ClassLoaderData::the_null_class_loader_data(), "array classes belong to null loader"); + Klass::restore_unshareable_info(loader_data, protection_domain, CHECK); // Klass recreates the component mirror also } diff --git a/hotspot/src/share/vm/oops/arrayKlass.hpp b/hotspot/src/share/vm/oops/arrayKlass.hpp index f42d96e1679..3b55e031616 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.hpp +++ b/hotspot/src/share/vm/oops/arrayKlass.hpp @@ -137,7 +137,7 @@ class ArrayKlass: public Klass { // CDS support - remove and restore oops from metadata. Oops are not shared. virtual void remove_unshareable_info(); - virtual void restore_unshareable_info(TRAPS); + virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS); // Printing void print_on(outputStream* st) const; diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 2dba59265b1..9e6ef6ffad9 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -2303,12 +2303,14 @@ void InstanceKlass::remove_unshareable_info() { array_klasses_do(remove_unshareable_in_class); } -void restore_unshareable_in_class(Klass* k, TRAPS) { - k->restore_unshareable_info(CHECK); +static void restore_unshareable_in_class(Klass* k, TRAPS) { + // Array classes have null protection domain. + // --> see ArrayKlass::complete_create_array_klass() + k->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK); } -void InstanceKlass::restore_unshareable_info(TRAPS) { - Klass::restore_unshareable_info(CHECK); +void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { + Klass::restore_unshareable_info(loader_data, protection_domain, CHECK); instanceKlassHandle ik(THREAD, this); Array* methods = ik->methods(); @@ -2334,6 +2336,38 @@ void InstanceKlass::restore_unshareable_info(TRAPS) { ik->array_klasses_do(restore_unshareable_in_class, CHECK); } +// returns true IFF is_in_error_state() has been changed as a result of this call. +bool InstanceKlass::check_sharing_error_state() { + assert(DumpSharedSpaces, "should only be called during dumping"); + bool old_state = is_in_error_state(); + + if (!is_in_error_state()) { + bool bad = false; + for (InstanceKlass* sup = java_super(); sup; sup = sup->java_super()) { + if (sup->is_in_error_state()) { + bad = true; + break; + } + } + if (!bad) { + Array* interfaces = transitive_interfaces(); + for (int i = 0; i < interfaces->length(); i++) { + Klass* iface = interfaces->at(i); + if (InstanceKlass::cast(iface)->is_in_error_state()) { + bad = true; + break; + } + } + } + + if (bad) { + set_in_error_state(); + } + } + + return (old_state != is_in_error_state()); +} + static void clear_all_breakpoints(Method* m) { m->clear_all_breakpoints(); } diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index f2904057146..737bf70364b 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -980,6 +980,13 @@ class InstanceKlass: public Klass { u2 idnum_allocated_count() const { return _idnum_allocated_count; } +public: + void set_in_error_state() { + assert(DumpSharedSpaces, "only call this when dumping archive"); + _init_state = initialization_error; + } + bool check_sharing_error_state(); + private: // initialization state #ifdef ASSERT @@ -1038,7 +1045,7 @@ private: public: // CDS support - remove and restore oops from metadata. Oops are not shared. virtual void remove_unshareable_info(); - virtual void restore_unshareable_info(TRAPS); + virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS); // jvm support jint compute_modifier_flags(TRAPS) const; diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index 1df975312c7..810c8d729cd 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -184,6 +184,7 @@ Klass::Klass() { // The klass doesn't have any references at this point. clear_modified_oops(); clear_accumulated_modified_oops(); + _shared_class_path_index = -1; } jint Klass::array_layout_helper(BasicType etype) { @@ -500,13 +501,12 @@ void Klass::remove_unshareable_info() { set_class_loader_data(NULL); } -void Klass::restore_unshareable_info(TRAPS) { +void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { TRACE_INIT_ID(this); // If an exception happened during CDS restore, some of these fields may already be // set. We leave the class on the CLD list, even if incomplete so that we don't // modify the CLD list outside a safepoint. if (class_loader_data() == NULL) { - ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); // Restore class_loader_data to the null class loader data set_class_loader_data(loader_data); @@ -515,12 +515,12 @@ void Klass::restore_unshareable_info(TRAPS) { loader_data->add_class(this); } - // Recreate the class mirror. The protection_domain is always null for - // boot loader, for now. + // Recreate the class mirror. // Only recreate it if not present. A previous attempt to restore may have // gotten an OOM later but keep the mirror if it was created. if (java_mirror() == NULL) { - java_lang_Class::create_mirror(this, Handle(NULL), Handle(NULL), CHECK); + Handle loader = loader_data->class_loader(); + java_lang_Class::create_mirror(this, loader, protection_domain, CHECK); } } diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index e443dddeed8..620dffa0e1b 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -147,6 +147,16 @@ class Klass : public Metadata { jbyte _modified_oops; // Card Table Equivalent (YC/CMS support) jbyte _accumulated_modified_oops; // Mod Union Equivalent (CMS support) +private: + // This is an index into FileMapHeader::_classpath_entry_table[], to + // associate this class with the JAR file where it's loaded from during + // dump time. If a class is not loaded from the shared archive, this field is + // -1. + jshort _shared_class_path_index; + + friend class SharedClassUtil; +protected: + // Constructor Klass(); @@ -253,6 +263,15 @@ class Klass : public Metadata { void clear_accumulated_modified_oops() { _accumulated_modified_oops = 0; } bool has_accumulated_modified_oops() { return _accumulated_modified_oops == 1; } + int shared_classpath_index() const { + return _shared_class_path_index; + }; + + void set_shared_classpath_index(int index) { + _shared_class_path_index = index; + }; + + protected: // internal accessors void set_subklass(Klass* s); void set_next_sibling(Klass* s); @@ -422,7 +441,7 @@ class Klass : public Metadata { public: // CDS support - remove and restore oops from metadata. Oops are not shared. virtual void remove_unshareable_info(); - virtual void restore_unshareable_info(TRAPS); + virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS); protected: // computes the subtype relationship diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 54fa43a7212..589d758e38c 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -283,6 +283,13 @@ address Method::bcp_from(int bci) const { return bcp; } +address Method::bcp_from(address bcp) const { + if (is_native() && bcp == NULL) { + return code_base(); + } else { + return bcp; + } +} int Method::size(bool is_native) { // If native, then include pointers for native_function and signature_handler diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 23752b4f8f5..16e7f7a813f 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -648,7 +648,8 @@ class Method : public Metadata { // Returns the byte code index from the byte code pointer int bci_from(address bcp) const; - address bcp_from(int bci) const; + address bcp_from(int bci) const; + address bcp_from(address bcp) const; int validate_bci_from_bcp(address bcp) const; int validate_bci(int bci) const; diff --git a/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp b/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp index 5a8d4d0afaf..b613e4ee73f 100644 --- a/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp @@ -55,8 +55,6 @@ inline void oopDesc::follow_contents(ParCompactionManager* cm) { klass()->oop_follow_contents(cm, this); } -// Used by parallel old GC. - inline oop oopDesc::forward_to_atomic(oop p) { assert(ParNewGeneration::is_legal_forward_ptr(p), "illegal forwarding pointer value."); diff --git a/hotspot/src/share/vm/opto/callGenerator.cpp b/hotspot/src/share/vm/opto/callGenerator.cpp index 246446167ca..0b3ee7a7279 100644 --- a/hotspot/src/share/vm/opto/callGenerator.cpp +++ b/hotspot/src/share/vm/opto/callGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -357,7 +357,7 @@ void LateInlineCallGenerator::do_late_inline() { // Make sure the state is a MergeMem for parsing. if (!map->in(TypeFunc::Memory)->is_MergeMem()) { - Node* mem = MergeMemNode::make(C, map->in(TypeFunc::Memory)); + Node* mem = MergeMemNode::make(map->in(TypeFunc::Memory)); C->initial_gvn()->set_type_bottom(mem); map->set_req(TypeFunc::Memory, mem); } diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index 275052bf8a9..04d91ff034a 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -688,7 +688,7 @@ Node *CallNode::match( const ProjNode *proj, const Matcher *match ) { return new MachProjNode(this,proj->_con,RegMask::Empty,MachProjNode::unmatched_proj); case TypeFunc::Parms+1: // For LONG & DOUBLE returns - assert(tf()->_range->field_at(TypeFunc::Parms+1) == Type::HALF, ""); + assert(tf()->range()->field_at(TypeFunc::Parms+1) == Type::HALF, ""); // 2nd half of doubles and longs return new MachProjNode(this,proj->_con, RegMask::Empty, (uint)OptoReg::Bad); @@ -778,7 +778,7 @@ bool CallNode::has_non_debug_use(Node *n) { } // Returns the unique CheckCastPP of a call -// or 'this' if there are several CheckCastPP +// or 'this' if there are several CheckCastPP or unexpected uses // or returns NULL if there is no one. Node *CallNode::result_cast() { Node *cast = NULL; @@ -794,6 +794,13 @@ Node *CallNode::result_cast() { return this; // more than 1 CheckCastPP } cast = use; + } else if (!use->is_Initialize() && + !use->is_AddP()) { + // Expected uses are restricted to a CheckCastPP, an Initialize + // node, and AddP nodes. If we encounter any other use (a Phi + // node can be seen in rare cases) return this to prevent + // incorrect optimizations. + return this; } } return cast; @@ -1808,3 +1815,57 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) { } return result; } + +ArrayCopyNode::ArrayCopyNode(Compile* C, bool alloc_tightly_coupled) + : CallNode(arraycopy_type(), NULL, TypeRawPtr::BOTTOM), _alloc_tightly_coupled(alloc_tightly_coupled), _kind(ArrayCopy) { + init_class_id(Class_ArrayCopy); + init_flags(Flag_is_macro); + C->add_macro_node(this); +} + +uint ArrayCopyNode::size_of() const { return sizeof(*this); } + +ArrayCopyNode* ArrayCopyNode::make(GraphKit* kit, bool may_throw, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* length, + bool alloc_tightly_coupled, + Node* src_length, Node* dest_length, + Node* src_klass, Node* dest_klass) { + + ArrayCopyNode* ac = new ArrayCopyNode(kit->C, alloc_tightly_coupled); + Node* prev_mem = kit->set_predefined_input_for_runtime_call(ac); + + ac->init_req(ArrayCopyNode::Src, src); + ac->init_req(ArrayCopyNode::SrcPos, src_offset); + ac->init_req(ArrayCopyNode::Dest, dest); + ac->init_req(ArrayCopyNode::DestPos, dest_offset); + ac->init_req(ArrayCopyNode::Length, length); + ac->init_req(ArrayCopyNode::SrcLen, src_length); + ac->init_req(ArrayCopyNode::DestLen, dest_length); + ac->init_req(ArrayCopyNode::SrcKlass, src_klass); + ac->init_req(ArrayCopyNode::DestKlass, dest_klass); + + if (may_throw) { + ac->set_req(TypeFunc::I_O , kit->i_o()); + kit->add_safepoint_edges(ac, false); + } + + return ac; +} + +void ArrayCopyNode::connect_outputs(GraphKit* kit) { + kit->set_all_memory_call(this, true); + kit->set_control(kit->gvn().transform(new ProjNode(this,TypeFunc::Control))); + kit->set_i_o(kit->gvn().transform(new ProjNode(this, TypeFunc::I_O))); + kit->make_slow_call_ex(this, kit->env()->Throwable_klass(), true); + kit->set_all_memory_call(this); +} + +#ifndef PRODUCT +const char* ArrayCopyNode::_kind_names[] = {"arraycopy", "arraycopy, validated arguments", "clone", "oop array clone", "CopyOf", "CopyOfRange"}; +void ArrayCopyNode::dump_spec(outputStream *st) const { + CallNode::dump_spec(st); + st->print(" (%s%s)", _kind_names[_kind], _alloc_tightly_coupled ? ", tightly coupled allocation" : ""); +} +#endif diff --git a/hotspot/src/share/vm/opto/callnode.hpp b/hotspot/src/share/vm/opto/callnode.hpp index 6eb78b0cb7b..2d6df8a5829 100644 --- a/hotspot/src/share/vm/opto/callnode.hpp +++ b/hotspot/src/share/vm/opto/callnode.hpp @@ -1063,4 +1063,108 @@ public: virtual bool guaranteed_safepoint() { return false; } }; +class GraphKit; + +class ArrayCopyNode : public CallNode { +private: + + // What kind of arraycopy variant is this? + enum { + ArrayCopy, // System.arraycopy() + ArrayCopyNoTest, // System.arraycopy(), all arguments validated + CloneBasic, // A clone that can be copied by 64 bit chunks + CloneOop, // An oop array clone + CopyOf, // Arrays.copyOf() + CopyOfRange // Arrays.copyOfRange() + } _kind; + +#ifndef PRODUCT + static const char* _kind_names[CopyOfRange+1]; +#endif + // Is the alloc obtained with + // AllocateArrayNode::Ideal_array_allocation() tighly coupled + // (arraycopy follows immediately the allocation)? + // We cache the result of LibraryCallKit::tightly_coupled_allocation + // here because it's much easier to find whether there's a tightly + // couple allocation at parse time than at macro expansion time. At + // macro expansion time, for every use of the allocation node we + // would need to figure out whether it happens after the arraycopy (and + // can be ignored) or between the allocation and the arraycopy. At + // parse time, it's straightforward because whatever happens after + // the arraycopy is not parsed yet so doesn't exist when + // LibraryCallKit::tightly_coupled_allocation() is called. + bool _alloc_tightly_coupled; + + static const TypeFunc* arraycopy_type() { + const Type** fields = TypeTuple::fields(ParmLimit - TypeFunc::Parms); + fields[Src] = TypeInstPtr::BOTTOM; + fields[SrcPos] = TypeInt::INT; + fields[Dest] = TypeInstPtr::BOTTOM; + fields[DestPos] = TypeInt::INT; + fields[Length] = TypeInt::INT; + fields[SrcLen] = TypeInt::INT; + fields[DestLen] = TypeInt::INT; + fields[SrcKlass] = TypeKlassPtr::BOTTOM; + fields[DestKlass] = TypeKlassPtr::BOTTOM; + const TypeTuple *domain = TypeTuple::make(ParmLimit, fields); + + // create result type (range) + fields = TypeTuple::fields(0); + + const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields); + + return TypeFunc::make(domain, range); + } + + ArrayCopyNode(Compile* C, bool alloc_tightly_coupled); + +public: + + enum { + Src = TypeFunc::Parms, + SrcPos, + Dest, + DestPos, + Length, + SrcLen, + DestLen, + SrcKlass, + DestKlass, + ParmLimit + }; + + static ArrayCopyNode* make(GraphKit* kit, bool may_throw, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* length, + bool alloc_tightly_coupled, + Node* src_length = NULL, Node* dest_length = NULL, + Node* src_klass = NULL, Node* dest_klass = NULL); + + void connect_outputs(GraphKit* kit); + + bool is_arraycopy() const { return _kind == ArrayCopy; } + bool is_arraycopy_notest() const { return _kind == ArrayCopyNoTest; } + bool is_clonebasic() const { return _kind == CloneBasic; } + bool is_cloneoop() const { return _kind == CloneOop; } + bool is_copyof() const { return _kind == CopyOf; } + bool is_copyofrange() const { return _kind == CopyOfRange; } + + void set_arraycopy() { _kind = ArrayCopy; } + void set_arraycopy_notest() { _kind = ArrayCopyNoTest; } + void set_clonebasic() { _kind = CloneBasic; } + void set_cloneoop() { _kind = CloneOop; } + void set_copyof() { _kind = CopyOf; } + void set_copyofrange() { _kind = CopyOfRange; } + + virtual int Opcode() const; + virtual uint size_of() const; // Size is bigger + virtual bool guaranteed_safepoint() { return false; } + + bool is_alloc_tightly_coupled() const { return _alloc_tightly_coupled; } + +#ifndef PRODUCT + virtual void dump_spec(outputStream *st) const; +#endif +}; #endif // SHARE_VM_OPTO_CALLNODE_HPP diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp index d99118edc83..ab633c106a6 100644 --- a/hotspot/src/share/vm/opto/cfgnode.cpp +++ b/hotspot/src/share/vm/opto/cfgnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -108,6 +108,7 @@ static Node *merge_region(RegionNode *region, PhaseGVN *phase) { rreq++; // One more input to Region } // Found a region to merge into Region + igvn->_worklist.push(r); // Clobber pointer to the now dead 'r' region->set_req(i, phase->C->top()); } @@ -449,6 +450,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Remove TOP or NULL input paths. If only 1 input path remains, this Region // degrades to a copy. bool add_to_worklist = false; + bool modified = false; int cnt = 0; // Count of values merging DEBUG_ONLY( int cnt_orig = req(); ) // Save original inputs count int del_it = 0; // The last input path we delete @@ -459,6 +461,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Remove useless control copy inputs if( n->is_Region() && n->as_Region()->is_copy() ) { set_req(i, n->nonnull_req()); + modified = true; i--; continue; } @@ -466,12 +469,14 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node *call = n->in(0); if (call->is_Call() && call->as_Call()->entry_point() == OptoRuntime::rethrow_stub()) { set_req(i, call->in(0)); + modified = true; i--; continue; } } if( phase->type(n) == Type::TOP ) { set_req(i, NULL); // Ignore TOP inputs + modified = true; i--; continue; } @@ -691,7 +696,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { } } - return NULL; + return modified ? this : NULL; } @@ -1871,7 +1876,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { igvn->register_new_node_with_optimizer(new_base); hook->add_req(new_base); } - MergeMemNode* result = MergeMemNode::make(phase->C, new_base); + MergeMemNode* result = MergeMemNode::make(new_base); for (uint i = 1; i < req(); ++i) { Node *ii = in(i); if (ii->is_MergeMem()) { diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index 822d83a9c23..50c7d596bf2 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -1620,7 +1620,7 @@ void PhaseChaitin::fixup_spills() { C->check_node_count(0, "out of nodes fixing spills"); if (C->failing()) return; // Transform node - MachNode *cisc = mach->cisc_version(stk_offset, C)->as_Mach(); + MachNode *cisc = mach->cisc_version(stk_offset)->as_Mach(); cisc->set_req(inp,fp); // Base register is frame pointer if( cisc->oper_input_base() > 1 && mach->oper_input_base() <= 1 ) { assert( cisc->oper_input_base() == 2, "Only adding one edge"); diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index 54a63db1a98..238e3491862 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -37,6 +37,7 @@ macro(Allocate) macro(AllocateArray) macro(AndI) macro(AndL) +macro(ArrayCopy) macro(AryEq) macro(AtanD) macro(Binary) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 585f9315241..a70e538d744 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -647,6 +647,10 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr _printer(IdealGraphPrinter::printer()), #endif _congraph(NULL), + _comp_arena(mtCompiler), + _node_arena(mtCompiler), + _old_arena(mtCompiler), + _Compile_types(mtCompiler), _replay_inline_data(NULL), _late_inlines(comp_arena(), 2, 0, NULL), _string_late_inlines(comp_arena(), 2, 0, NULL), @@ -954,6 +958,10 @@ Compile::Compile( ciEnv* ci_env, _in_dump_cnt(0), _printer(NULL), #endif + _comp_arena(mtCompiler), + _node_arena(mtCompiler), + _old_arena(mtCompiler), + _Compile_types(mtCompiler), _dead_node_list(comp_arena()), _dead_node_count(0), _congraph(NULL), @@ -1039,6 +1047,7 @@ void Compile::Init(int aliaslevel) { _node_note_array = NULL; _default_node_notes = NULL; + DEBUG_ONLY( _modified_nodes = NULL; ) // Used in Optimize() _immutable_memory = NULL; // filled in at first inquiry @@ -1247,6 +1256,18 @@ void Compile::print_missing_nodes() { } } } +void Compile::record_modified_node(Node* n) { + if (_modified_nodes != NULL && !_inlining_incrementally && + n->outcnt() != 0 && !n->is_Con()) { + _modified_nodes->push(n); + } +} + +void Compile::remove_modified_node(Node* n) { + if (_modified_nodes != NULL) { + _modified_nodes->remove(n); + } +} #endif #ifndef PRODUCT @@ -2035,6 +2056,9 @@ void Compile::Optimize() { // Iterative Global Value Numbering, including ideal transforms // Initialize IterGVN with types and values from parse-time GVN PhaseIterGVN igvn(initial_gvn()); +#ifdef ASSERT + _modified_nodes = new (comp_arena()) Unique_Node_List(comp_arena()); +#endif { NOT_PRODUCT( TracePhase t2("iterGVN", &_t_iterGVN, TimeCompiler); ) igvn.optimize(); @@ -2197,6 +2221,7 @@ void Compile::Optimize() { } } + DEBUG_ONLY( _modified_nodes = NULL; ) } // (End scope of igvn; run destructor if necessary for asserts.) process_print_inlining(); @@ -2825,7 +2850,7 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { // oops implicit null check is not generated. // This will allow to generate normal oop implicit null check. if (Matcher::gen_narrow_oop_implicit_null_checks()) - new_in2 = ConNode::make(this, TypeNarrowOop::NULL_PTR); + new_in2 = ConNode::make(TypeNarrowOop::NULL_PTR); // // This transformation together with CastPP transformation above // will generated code for implicit NULL checks for compressed oops. @@ -2864,9 +2889,9 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { // NullCheck base_reg // } else if (t->isa_oopptr()) { - new_in2 = ConNode::make(this, t->make_narrowoop()); + new_in2 = ConNode::make(t->make_narrowoop()); } else if (t->isa_klassptr()) { - new_in2 = ConNode::make(this, t->make_narrowklass()); + new_in2 = ConNode::make(t->make_narrowklass()); } } if (new_in2 != NULL) { @@ -2899,11 +2924,11 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { const Type* t = in1->bottom_type(); if (t == TypePtr::NULL_PTR) { assert(t->isa_oopptr(), "null klass?"); - n->subsume_by(ConNode::make(this, TypeNarrowOop::NULL_PTR), this); + n->subsume_by(ConNode::make(TypeNarrowOop::NULL_PTR), this); } else if (t->isa_oopptr()) { - n->subsume_by(ConNode::make(this, t->make_narrowoop()), this); + n->subsume_by(ConNode::make(t->make_narrowoop()), this); } else if (t->isa_klassptr()) { - n->subsume_by(ConNode::make(this, t->make_narrowklass()), this); + n->subsume_by(ConNode::make(t->make_narrowklass()), this); } } if (in1->outcnt() == 0) { @@ -2964,7 +2989,7 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { if (d) { // Replace them with a fused divmod if supported if (Matcher::has_match_rule(Op_DivModI)) { - DivModINode* divmod = DivModINode::make(this, n); + DivModINode* divmod = DivModINode::make(n); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -2984,7 +3009,7 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { if (d) { // Replace them with a fused divmod if supported if (Matcher::has_match_rule(Op_DivModL)) { - DivModLNode* divmod = DivModLNode::make(this, n); + DivModLNode* divmod = DivModLNode::make(n); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3010,7 +3035,7 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { if (n->req()-1 > 2) { // Replace many operand PackNodes with a binary tree for matching PackNode* p = (PackNode*) n; - Node* btp = p->binary_tree_pack(this, 1, n->req()); + Node* btp = p->binary_tree_pack(1, n->req()); n->subsume_by(btp, this); } break; @@ -3035,11 +3060,11 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { if (t != NULL && t->is_con()) { juint shift = t->get_con(); if (shift > mask) { // Unsigned cmp - n->set_req(2, ConNode::make(this, TypeInt::make(shift & mask))); + n->set_req(2, ConNode::make(TypeInt::make(shift & mask))); } } else { if (t == NULL || t->_lo < 0 || t->_hi > (int)mask) { - Node* shift = new AndINode(in2, ConNode::make(this, TypeInt::make(mask))); + Node* shift = new AndINode(in2, ConNode::make(TypeInt::make(mask))); n->set_req(2, shift); } } @@ -3770,6 +3795,56 @@ void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n } } +//----------------------------static_subtype_check----------------------------- +// Shortcut important common cases when superklass is exact: +// (0) superklass is java.lang.Object (can occur in reflective code) +// (1) subklass is already limited to a subtype of superklass => always ok +// (2) subklass does not overlap with superklass => always fail +// (3) superklass has NO subtypes and we can check with a simple compare. +int Compile::static_subtype_check(ciKlass* superk, ciKlass* subk) { + if (StressReflectiveCode) { + return SSC_full_test; // Let caller generate the general case. + } + + if (superk == env()->Object_klass()) { + return SSC_always_true; // (0) this test cannot fail + } + + ciType* superelem = superk; + if (superelem->is_array_klass()) + superelem = superelem->as_array_klass()->base_element_type(); + + if (!subk->is_interface()) { // cannot trust static interface types yet + if (subk->is_subtype_of(superk)) { + return SSC_always_true; // (1) false path dead; no dynamic test needed + } + if (!(superelem->is_klass() && superelem->as_klass()->is_interface()) && + !superk->is_subtype_of(subk)) { + return SSC_always_false; + } + } + + // If casting to an instance klass, it must have no subtypes + if (superk->is_interface()) { + // Cannot trust interfaces yet. + // %%% S.B. superk->nof_implementors() == 1 + } else if (superelem->is_instance_klass()) { + ciInstanceKlass* ik = superelem->as_instance_klass(); + if (!ik->has_subklass() && !ik->is_interface()) { + if (!ik->is_final()) { + // Add a dependency if there is a chance of a later subclass. + dependencies()->assert_leaf_type(ik); + } + return SSC_easy_test; // (3) caller can do a simple ptr comparison + } + } else { + // A primitive array type has no subtypes. + return SSC_easy_test; // (3) caller can do a simple ptr comparison + } + + return SSC_full_test; +} + // The message about the current inlining is accumulated in // _print_inlining_stream and transfered into the _print_inlining_list // once we know whether inlining succeeds or not. For regular @@ -4031,6 +4106,7 @@ void Compile::cleanup_expensive_nodes(PhaseIterGVN &igvn) { int j = 0; int identical = 0; int i = 0; + bool modified = false; for (; i < _expensive_nodes->length()-1; i++) { assert(j <= i, "can't write beyond current index"); if (_expensive_nodes->at(i)->Opcode() == _expensive_nodes->at(i+1)->Opcode()) { @@ -4043,20 +4119,23 @@ void Compile::cleanup_expensive_nodes(PhaseIterGVN &igvn) { identical = 0; } else { Node* n = _expensive_nodes->at(i); - igvn.hash_delete(n); - n->set_req(0, NULL); + igvn.replace_input_of(n, 0, NULL); igvn.hash_insert(n); + modified = true; } } if (identical > 0) { _expensive_nodes->at_put(j++, _expensive_nodes->at(i)); } else if (_expensive_nodes->length() >= 1) { Node* n = _expensive_nodes->at(i); - igvn.hash_delete(n); - n->set_req(0, NULL); + igvn.replace_input_of(n, 0, NULL); igvn.hash_insert(n); + modified = true; } _expensive_nodes->trunc_to(j); + if (modified) { + igvn.optimize(); + } } void Compile::add_expensive_node(Node * n) { diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 29380e1f898..5a98e8e254d 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -344,6 +344,8 @@ class Compile : public Phase { VectorSet _dead_node_list; // Set of dead nodes uint _dead_node_count; // Number of dead nodes; VectorSet::Size() is O(N). // So use this to keep count and make the call O(1). + DEBUG_ONLY( Unique_Node_List* _modified_nodes; ) // List of nodes which inputs were modified + debug_only(static int _debug_idx;) // Monotonic counter (not reset), use -XX:BreakAtNode= Arena _node_arena; // Arena for new-space Nodes Arena _old_arena; // Arena for old-space Nodes, lifetime during xform @@ -766,6 +768,11 @@ class Compile : public Phase { void print_missing_nodes(); #endif + // Record modified nodes to check that they are put on IGVN worklist + void record_modified_node(Node* n) NOT_DEBUG_RETURN; + void remove_modified_node(Node* n) NOT_DEBUG_RETURN; + DEBUG_ONLY( Unique_Node_List* modified_nodes() const { return _modified_nodes; } ) + // Constant table ConstantTable& constant_table() { return _constant_table; } @@ -1193,6 +1200,10 @@ class Compile : public Phase { // Definitions of pd methods static void pd_compiler2_init(); + // Static parse-time type checking logic for gen_subtype_check: + enum { SSC_always_false, SSC_always_true, SSC_easy_test, SSC_full_test }; + int static_subtype_check(ciKlass* superk, ciKlass* subk); + // Auxiliary method for randomized fuzzing/stressing static bool randomized_select(int count); }; diff --git a/hotspot/src/share/vm/opto/connode.cpp b/hotspot/src/share/vm/opto/connode.cpp index 485e8df7951..fa074f97b3d 100644 --- a/hotspot/src/share/vm/opto/connode.cpp +++ b/hotspot/src/share/vm/opto/connode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -43,7 +43,7 @@ uint ConNode::hash() const { } //------------------------------make------------------------------------------- -ConNode *ConNode::make( Compile* C, const Type *t ) { +ConNode *ConNode::make(const Type *t) { switch( t->basic_type() ) { case T_INT: return new ConINode( t->is_int() ); case T_LONG: return new ConLNode( t->is_long() ); diff --git a/hotspot/src/share/vm/opto/connode.hpp b/hotspot/src/share/vm/opto/connode.hpp index 446b807a846..d1c68862ebf 100644 --- a/hotspot/src/share/vm/opto/connode.hpp +++ b/hotspot/src/share/vm/opto/connode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, 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 @@ -46,7 +46,7 @@ public: virtual const RegMask &in_RegMask(uint) const { return RegMask::Empty; } // Polymorphic factory method: - static ConNode* make( Compile* C, const Type *t ); + static ConNode* make(const Type *t); }; //------------------------------ConINode--------------------------------------- @@ -57,7 +57,7 @@ public: virtual int Opcode() const; // Factory method: - static ConINode* make( Compile* C, int con ) { + static ConINode* make(int con) { return new ConINode( TypeInt::make(con) ); } @@ -71,7 +71,7 @@ public: virtual int Opcode() const; // Factory methods: - static ConPNode* make( Compile *C ,address con ) { + static ConPNode* make(address con) { if (con == NULL) return new ConPNode( TypePtr::NULL_PTR ) ; else @@ -105,7 +105,7 @@ public: virtual int Opcode() const; // Factory method: - static ConLNode* make( Compile *C ,jlong con ) { + static ConLNode* make(jlong con) { return new ConLNode( TypeLong::make(con) ); } @@ -119,7 +119,7 @@ public: virtual int Opcode() const; // Factory method: - static ConFNode* make( Compile *C, float con ) { + static ConFNode* make(float con) { return new ConFNode( TypeF::make(con) ); } @@ -133,7 +133,7 @@ public: virtual int Opcode() const; // Factory method: - static ConDNode* make( Compile *C, double con ) { + static ConDNode* make(double con) { return new ConDNode( TypeD::make(con) ); } diff --git a/hotspot/src/share/vm/opto/divnode.cpp b/hotspot/src/share/vm/opto/divnode.cpp index 8a27c24e37e..4677d00a9f7 100644 --- a/hotspot/src/share/vm/opto/divnode.cpp +++ b/hotspot/src/share/vm/opto/divnode.cpp @@ -479,7 +479,10 @@ Node *DivINode::Ideal(PhaseGVN *phase, bool can_reshape) { if (i == 0) return NULL; // Dividing by zero constant does not idealize - set_req(0,NULL); // Dividing by a not-zero constant; no faulting + if (in(0) != NULL) { + phase->igvn_rehash_node_delayed(this); + set_req(0, NULL); // Dividing by a not-zero constant; no faulting + } // Dividing by MININT does not optimize as a power-of-2 shift. if( i == min_jint ) return NULL; @@ -578,7 +581,10 @@ Node *DivLNode::Ideal( PhaseGVN *phase, bool can_reshape) { if (l == 0) return NULL; // Dividing by zero constant does not idealize - set_req(0,NULL); // Dividing by a not-zero constant; no faulting + if (in(0) != NULL) { + phase->igvn_rehash_node_delayed(this); + set_req(0, NULL); // Dividing by a not-zero constant; no faulting + } // Dividing by MINLONG does not optimize as a power-of-2 shift. if( l == min_jlong ) return NULL; @@ -1274,7 +1280,7 @@ DivModNode::DivModNode( Node *c, Node *dividend, Node *divisor ) : MultiNode(3) } //------------------------------make------------------------------------------ -DivModINode* DivModINode::make(Compile* C, Node* div_or_mod) { +DivModINode* DivModINode::make(Node* div_or_mod) { Node* n = div_or_mod; assert(n->Opcode() == Op_DivI || n->Opcode() == Op_ModI, "only div or mod input pattern accepted"); @@ -1286,7 +1292,7 @@ DivModINode* DivModINode::make(Compile* C, Node* div_or_mod) { } //------------------------------make------------------------------------------ -DivModLNode* DivModLNode::make(Compile* C, Node* div_or_mod) { +DivModLNode* DivModLNode::make(Node* div_or_mod) { Node* n = div_or_mod; assert(n->Opcode() == Op_DivL || n->Opcode() == Op_ModL, "only div or mod input pattern accepted"); diff --git a/hotspot/src/share/vm/opto/divnode.hpp b/hotspot/src/share/vm/opto/divnode.hpp index 03f5be546bc..195803e2000 100644 --- a/hotspot/src/share/vm/opto/divnode.hpp +++ b/hotspot/src/share/vm/opto/divnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, 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 @@ -168,7 +168,7 @@ public: virtual Node *match( const ProjNode *proj, const Matcher *m ); // Make a divmod and associated projections from a div or mod. - static DivModINode* make(Compile* C, Node* div_or_mod); + static DivModINode* make(Node* div_or_mod); }; //------------------------------DivModLNode--------------------------------------- @@ -181,7 +181,7 @@ public: virtual Node *match( const ProjNode *proj, const Matcher *m ); // Make a divmod and associated projections from a div or mod. - static DivModLNode* make(Compile* C, Node* div_or_mod); + static DivModLNode* make(Node* div_or_mod); }; #endif // SHARE_VM_OPTO_DIVNODE_HPP diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 10791a5991d..a4c84b63846 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -1452,7 +1452,6 @@ int ConnectionGraph::find_init_values(JavaObjectNode* pta, PointsToNode* init_va return 0; InitializeNode* ini = alloc->as_Allocate()->initialization(); - Compile* C = _compile; bool visited_bottom_offset = false; GrowableArray offsets_worklist; diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index e7269aa514e..8b8969fc370 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -591,7 +591,7 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) { C->log()->elem("hot_throw preallocated='1' reason='%s'", Deoptimization::trap_reason_name(reason)); const TypeInstPtr* ex_con = TypeInstPtr::make(ex_obj); - Node* ex_node = _gvn.transform( ConNode::make(C, ex_con) ); + Node* ex_node = _gvn.transform(ConNode::make(ex_con)); // Clear the detail message of the preallocated exception object. // Weblogic sometimes mutates the detail message of exceptions @@ -706,7 +706,7 @@ SafePointNode* GraphKit::clone_map() { if (map() == NULL) return NULL; // Clone the memory edge first - Node* mem = MergeMemNode::make(C, map()->memory()); + Node* mem = MergeMemNode::make(map()->memory()); gvn().set_type_bottom(mem); SafePointNode *clonemap = (SafePointNode*)map()->clone(); @@ -1135,7 +1135,7 @@ Node* GraphKit::ConvI2UL(Node* offset) { return longcon((julong) offset_con); } Node* conv = _gvn.transform( new ConvI2LNode(offset)); - Node* mask = _gvn.transform( ConLNode::make(C, (julong) max_juint) ); + Node* mask = _gvn.transform(ConLNode::make((julong) max_juint)); return _gvn.transform( new AndLNode(conv, mask) ); } @@ -1435,7 +1435,7 @@ Node* GraphKit::reset_memory() { //------------------------------set_all_memory--------------------------------- void GraphKit::set_all_memory(Node* newmem) { - Node* mergemem = MergeMemNode::make(C, newmem); + Node* mergemem = MergeMemNode::make(newmem); gvn().set_type_bottom(mergemem); map()->set_memory(mergemem); } @@ -1464,9 +1464,9 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, Node* mem = memory(adr_idx); Node* ld; if (require_atomic_access && bt == T_LONG) { - ld = LoadLNode::make_atomic(C, ctl, mem, adr, adr_type, t, mo); + ld = LoadLNode::make_atomic(ctl, mem, adr, adr_type, t, mo); } else if (require_atomic_access && bt == T_DOUBLE) { - ld = LoadDNode::make_atomic(C, ctl, mem, adr, adr_type, t, mo); + ld = LoadDNode::make_atomic(ctl, mem, adr, adr_type, t, mo); } else { ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo); } @@ -1488,9 +1488,9 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt, Node *mem = memory(adr_idx); Node* st; if (require_atomic_access && bt == T_LONG) { - st = StoreLNode::make_atomic(C, ctl, mem, adr, adr_type, val, mo); + st = StoreLNode::make_atomic(ctl, mem, adr, adr_type, val, mo); } else if (require_atomic_access && bt == T_DOUBLE) { - st = StoreDNode::make_atomic(C, ctl, mem, adr, adr_type, val, mo); + st = StoreDNode::make_atomic(ctl, mem, adr, adr_type, val, mo); } else { st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo); } @@ -2084,9 +2084,9 @@ Node* GraphKit::just_allocated_object(Node* current_control) { void GraphKit::round_double_arguments(ciMethod* dest_method) { // (Note: TypeFunc::make has a cache that makes this fast.) const TypeFunc* tf = TypeFunc::make(dest_method); - int nargs = tf->_domain->_cnt - TypeFunc::Parms; + int nargs = tf->domain()->cnt() - TypeFunc::Parms; for (int j = 0; j < nargs; j++) { - const Type *targ = tf->_domain->field_at(j + TypeFunc::Parms); + const Type *targ = tf->domain()->field_at(j + TypeFunc::Parms); if( targ->basic_type() == T_DOUBLE ) { // If any parameters are doubles, they must be rounded before // the call, dstore_rounding does gvn.transform @@ -2188,10 +2188,10 @@ void GraphKit::record_profiled_arguments_for_speculation(ciMethod* dest_method, return; } const TypeFunc* tf = TypeFunc::make(dest_method); - int nargs = tf->_domain->_cnt - TypeFunc::Parms; + int nargs = tf->domain()->cnt() - TypeFunc::Parms; int skip = Bytecodes::has_receiver(bc) ? 1 : 0; for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) { - const Type *targ = tf->_domain->field_at(j + TypeFunc::Parms); + const Type *targ = tf->domain()->field_at(j + TypeFunc::Parms); if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) { bool maybe_null = true; ciKlass* better_type = NULL; @@ -2520,6 +2520,21 @@ void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool sep set_control(norm); } +static IfNode* gen_subtype_check_compare(Node* ctrl, Node* in1, Node* in2, BoolTest::mask test, float p, PhaseGVN* gvn, BasicType bt) { + Node* cmp = NULL; + switch(bt) { + case T_INT: cmp = new CmpINode(in1, in2); break; + case T_ADDRESS: cmp = new CmpPNode(in1, in2); break; + default: fatal(err_msg("unexpected comparison type %s", type2name(bt))); + } + gvn->transform(cmp); + Node* bol = gvn->transform(new BoolNode(cmp, test)); + IfNode* iff = new IfNode(ctrl, bol, p, COUNT_UNKNOWN); + gvn->transform(iff); + if (!bol->is_Con()) gvn->record_for_igvn(iff); + return iff; +} + //-------------------------------gen_subtype_check----------------------------- // Generate a subtyping check. Takes as input the subtype and supertype. @@ -2529,16 +2544,17 @@ void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool sep // but that's not exposed to the optimizer. This call also doesn't take in an // Object; if you wish to check an Object you need to load the Object's class // prior to coming here. -Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { +Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, MergeMemNode* mem, PhaseGVN* gvn) { + Compile* C = gvn->C; // Fast check for identical types, perhaps identical constants. // The types can even be identical non-constants, in cases // involving Array.newInstance, Object.clone, etc. if (subklass == superklass) - return top(); // false path is dead; no test needed. + return C->top(); // false path is dead; no test needed. - if (_gvn.type(superklass)->singleton()) { - ciKlass* superk = _gvn.type(superklass)->is_klassptr()->klass(); - ciKlass* subk = _gvn.type(subklass)->is_klassptr()->klass(); + if (gvn->type(superklass)->singleton()) { + ciKlass* superk = gvn->type(superklass)->is_klassptr()->klass(); + ciKlass* subk = gvn->type(subklass)->is_klassptr()->klass(); // In the common case of an exact superklass, try to fold up the // test before generating code. You may ask, why not just generate @@ -2549,25 +2565,23 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { // Foo[] fa = blah(); Foo x = fa[0]; fa[1] = x; // Here, the type of 'fa' is often exact, so the store check // of fa[1]=x will fold up, without testing the nullness of x. - switch (static_subtype_check(superk, subk)) { - case SSC_always_false: + switch (C->static_subtype_check(superk, subk)) { + case Compile::SSC_always_false: { - Node* always_fail = control(); - set_control(top()); + Node* always_fail = *ctrl; + *ctrl = gvn->C->top(); return always_fail; } - case SSC_always_true: - return top(); - case SSC_easy_test: + case Compile::SSC_always_true: + return C->top(); + case Compile::SSC_easy_test: { // Just do a direct pointer compare and be done. - Node* cmp = _gvn.transform( new CmpPNode(subklass, superklass) ); - Node* bol = _gvn.transform( new BoolNode(cmp, BoolTest::eq) ); - IfNode* iff = create_and_xform_if(control(), bol, PROB_STATIC_FREQUENT, COUNT_UNKNOWN); - set_control( _gvn.transform( new IfTrueNode (iff) ) ); - return _gvn.transform( new IfFalseNode(iff) ); + IfNode* iff = gen_subtype_check_compare(*ctrl, subklass, superklass, BoolTest::eq, PROB_STATIC_FREQUENT, gvn, T_ADDRESS); + *ctrl = gvn->transform(new IfTrueNode(iff)); + return gvn->transform(new IfFalseNode(iff)); } - case SSC_full_test: + case Compile::SSC_full_test: break; default: ShouldNotReachHere(); @@ -2579,11 +2593,11 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { // will always succeed. We could leave a dependency behind to ensure this. // First load the super-klass's check-offset - Node *p1 = basic_plus_adr( superklass, superklass, in_bytes(Klass::super_check_offset_offset()) ); - Node *chk_off = _gvn.transform(new LoadINode(NULL, memory(p1), p1, _gvn.type(p1)->is_ptr(), - TypeInt::INT, MemNode::unordered)); + Node *p1 = gvn->transform(new AddPNode(superklass, superklass, gvn->MakeConX(in_bytes(Klass::super_check_offset_offset())))); + Node* m = mem->memory_at(C->get_alias_index(gvn->type(p1)->is_ptr())); + Node *chk_off = gvn->transform(new LoadINode(NULL, m, p1, gvn->type(p1)->is_ptr(), TypeInt::INT, MemNode::unordered)); int cacheoff_con = in_bytes(Klass::secondary_super_cache_offset()); - bool might_be_cache = (find_int_con(chk_off, cacheoff_con) == cacheoff_con); + bool might_be_cache = (gvn->find_int_con(chk_off, cacheoff_con) == cacheoff_con); // Load from the sub-klass's super-class display list, or a 1-word cache of // the secondary superclass list, or a failing value with a sentinel offset @@ -2591,42 +2605,44 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { // hierarchy and we have to scan the secondary superclass list the hard way. // Worst-case type is a little odd: NULL is allowed as a result (usually // klass loads can never produce a NULL). - Node *chk_off_X = ConvI2X(chk_off); - Node *p2 = _gvn.transform( new AddPNode(subklass,subklass,chk_off_X) ); + Node *chk_off_X = chk_off; +#ifdef _LP64 + chk_off_X = gvn->transform(new ConvI2LNode(chk_off_X)); +#endif + Node *p2 = gvn->transform(new AddPNode(subklass,subklass,chk_off_X)); // For some types like interfaces the following loadKlass is from a 1-word // cache which is mutable so can't use immutable memory. Other // types load from the super-class display table which is immutable. - Node *kmem = might_be_cache ? memory(p2) : immutable_memory(); - Node *nkls = _gvn.transform( LoadKlassNode::make( _gvn, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL ) ); + m = mem->memory_at(C->get_alias_index(gvn->type(p2)->is_ptr())); + Node *kmem = might_be_cache ? m : C->immutable_memory(); + Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL)); // Compile speed common case: ARE a subtype and we canNOT fail if( superklass == nkls ) - return top(); // false path is dead; no test needed. + return C->top(); // false path is dead; no test needed. // See if we get an immediate positive hit. Happens roughly 83% of the // time. Test to see if the value loaded just previously from the subklass // is exactly the superklass. - Node *cmp1 = _gvn.transform( new CmpPNode( superklass, nkls ) ); - Node *bol1 = _gvn.transform( new BoolNode( cmp1, BoolTest::eq ) ); - IfNode *iff1 = create_and_xform_if( control(), bol1, PROB_LIKELY(0.83f), COUNT_UNKNOWN ); - Node *iftrue1 = _gvn.transform( new IfTrueNode ( iff1 ) ); - set_control( _gvn.transform( new IfFalseNode( iff1 ) ) ); + IfNode *iff1 = gen_subtype_check_compare(*ctrl, superklass, nkls, BoolTest::eq, PROB_LIKELY(0.83f), gvn, T_ADDRESS); + Node *iftrue1 = gvn->transform( new IfTrueNode (iff1)); + *ctrl = gvn->transform(new IfFalseNode(iff1)); // Compile speed common case: Check for being deterministic right now. If // chk_off is a constant and not equal to cacheoff then we are NOT a // subklass. In this case we need exactly the 1 test above and we can // return those results immediately. if (!might_be_cache) { - Node* not_subtype_ctrl = control(); - set_control(iftrue1); // We need exactly the 1 test above + Node* not_subtype_ctrl = *ctrl; + *ctrl = iftrue1; // We need exactly the 1 test above return not_subtype_ctrl; } // Gather the various success & failures here RegionNode *r_ok_subtype = new RegionNode(4); - record_for_igvn(r_ok_subtype); + gvn->record_for_igvn(r_ok_subtype); RegionNode *r_not_subtype = new RegionNode(3); - record_for_igvn(r_not_subtype); + gvn->record_for_igvn(r_not_subtype); r_ok_subtype->init_req(1, iftrue1); @@ -2635,21 +2651,17 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { // check-offset points into the subklass display list or the 1-element // cache. If it points to the display (and NOT the cache) and the display // missed then it's not a subtype. - Node *cacheoff = _gvn.intcon(cacheoff_con); - Node *cmp2 = _gvn.transform( new CmpINode( chk_off, cacheoff ) ); - Node *bol2 = _gvn.transform( new BoolNode( cmp2, BoolTest::ne ) ); - IfNode *iff2 = create_and_xform_if( control(), bol2, PROB_LIKELY(0.63f), COUNT_UNKNOWN ); - r_not_subtype->init_req(1, _gvn.transform( new IfTrueNode (iff2) ) ); - set_control( _gvn.transform( new IfFalseNode(iff2) ) ); + Node *cacheoff = gvn->intcon(cacheoff_con); + IfNode *iff2 = gen_subtype_check_compare(*ctrl, chk_off, cacheoff, BoolTest::ne, PROB_LIKELY(0.63f), gvn, T_INT); + r_not_subtype->init_req(1, gvn->transform(new IfTrueNode (iff2))); + *ctrl = gvn->transform(new IfFalseNode(iff2)); // Check for self. Very rare to get here, but it is taken 1/3 the time. // No performance impact (too rare) but allows sharing of secondary arrays // which has some footprint reduction. - Node *cmp3 = _gvn.transform( new CmpPNode( subklass, superklass ) ); - Node *bol3 = _gvn.transform( new BoolNode( cmp3, BoolTest::eq ) ); - IfNode *iff3 = create_and_xform_if( control(), bol3, PROB_LIKELY(0.36f), COUNT_UNKNOWN ); - r_ok_subtype->init_req(2, _gvn.transform( new IfTrueNode ( iff3 ) ) ); - set_control( _gvn.transform( new IfFalseNode( iff3 ) ) ); + IfNode *iff3 = gen_subtype_check_compare(*ctrl, subklass, superklass, BoolTest::eq, PROB_LIKELY(0.36f), gvn, T_ADDRESS); + r_ok_subtype->init_req(2, gvn->transform(new IfTrueNode(iff3))); + *ctrl = gvn->transform(new IfFalseNode(iff3)); // -- Roads not taken here: -- // We could also have chosen to perform the self-check at the beginning @@ -2672,68 +2684,16 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { // out of line, and it can only improve I-cache density. // The decision to inline or out-of-line this final check is platform // dependent, and is found in the AD file definition of PartialSubtypeCheck. - Node* psc = _gvn.transform( - new PartialSubtypeCheckNode(control(), subklass, superklass) ); + Node* psc = gvn->transform( + new PartialSubtypeCheckNode(*ctrl, subklass, superklass)); - Node *cmp4 = _gvn.transform( new CmpPNode( psc, null() ) ); - Node *bol4 = _gvn.transform( new BoolNode( cmp4, BoolTest::ne ) ); - IfNode *iff4 = create_and_xform_if( control(), bol4, PROB_FAIR, COUNT_UNKNOWN ); - r_not_subtype->init_req(2, _gvn.transform( new IfTrueNode (iff4) ) ); - r_ok_subtype ->init_req(3, _gvn.transform( new IfFalseNode(iff4) ) ); + IfNode *iff4 = gen_subtype_check_compare(*ctrl, psc, gvn->zerocon(T_OBJECT), BoolTest::ne, PROB_FAIR, gvn, T_ADDRESS); + r_not_subtype->init_req(2, gvn->transform(new IfTrueNode (iff4))); + r_ok_subtype ->init_req(3, gvn->transform(new IfFalseNode(iff4))); // Return false path; set default control to true path. - set_control( _gvn.transform(r_ok_subtype) ); - return _gvn.transform(r_not_subtype); -} - -//----------------------------static_subtype_check----------------------------- -// Shortcut important common cases when superklass is exact: -// (0) superklass is java.lang.Object (can occur in reflective code) -// (1) subklass is already limited to a subtype of superklass => always ok -// (2) subklass does not overlap with superklass => always fail -// (3) superklass has NO subtypes and we can check with a simple compare. -int GraphKit::static_subtype_check(ciKlass* superk, ciKlass* subk) { - if (StressReflectiveCode) { - return SSC_full_test; // Let caller generate the general case. - } - - if (superk == env()->Object_klass()) { - return SSC_always_true; // (0) this test cannot fail - } - - ciType* superelem = superk; - if (superelem->is_array_klass()) - superelem = superelem->as_array_klass()->base_element_type(); - - if (!subk->is_interface()) { // cannot trust static interface types yet - if (subk->is_subtype_of(superk)) { - return SSC_always_true; // (1) false path dead; no dynamic test needed - } - if (!(superelem->is_klass() && superelem->as_klass()->is_interface()) && - !superk->is_subtype_of(subk)) { - return SSC_always_false; - } - } - - // If casting to an instance klass, it must have no subtypes - if (superk->is_interface()) { - // Cannot trust interfaces yet. - // %%% S.B. superk->nof_implementors() == 1 - } else if (superelem->is_instance_klass()) { - ciInstanceKlass* ik = superelem->as_instance_klass(); - if (!ik->has_subklass() && !ik->is_interface()) { - if (!ik->is_final()) { - // Add a dependency if there is a chance of a later subclass. - C->dependencies()->assert_leaf_type(ik); - } - return SSC_easy_test; // (3) caller can do a simple ptr comparison - } - } else { - // A primitive array type has no subtypes. - return SSC_easy_test; // (3) caller can do a simple ptr comparison - } - - return SSC_full_test; + *ctrl = gvn->transform(r_ok_subtype); + return gvn->transform(r_not_subtype); } // Profile-driven exact type check: @@ -2813,7 +2773,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj, ciKlass* exact_kls = spec_klass == NULL ? profile_has_unique_klass() : spec_klass; if (exact_kls != NULL) {// no cast failures here if (require_klass == NULL || - static_subtype_check(require_klass, exact_kls) == SSC_always_true) { + C->static_subtype_check(require_klass, exact_kls) == Compile::SSC_always_true) { // If we narrow the type to match what the type profile sees or // the speculative type, we can then remove the rest of the // cast. @@ -2833,7 +2793,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj, } return exact_obj; } - // assert(ssc == SSC_always_true)... except maybe the profile lied to us. + // assert(ssc == Compile::SSC_always_true)... except maybe the profile lied to us. } return NULL; @@ -2938,8 +2898,8 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac ciKlass* superk = _gvn.type(superklass)->is_klassptr()->klass(); ciKlass* subk = _gvn.type(obj)->is_oopptr()->klass(); if (subk != NULL && subk->is_loaded()) { - int static_res = static_subtype_check(superk, subk); - known_statically = (static_res == SSC_always_true || static_res == SSC_always_false); + int static_res = C->static_subtype_check(superk, subk); + known_statically = (static_res == Compile::SSC_always_true || static_res == Compile::SSC_always_false); } } @@ -3007,13 +2967,13 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, if (tk->singleton()) { const TypeOopPtr* objtp = _gvn.type(obj)->isa_oopptr(); if (objtp != NULL && objtp->klass() != NULL) { - switch (static_subtype_check(tk->klass(), objtp->klass())) { - case SSC_always_true: + switch (C->static_subtype_check(tk->klass(), objtp->klass())) { + case Compile::SSC_always_true: // If we know the type check always succeed then we don't use // the profiling data at this bytecode. Don't lose it, feed it // to the type system as a speculative type. return record_profiled_receiver_for_speculation(obj); - case SSC_always_false: + case Compile::SSC_always_false: // It needs a null check because a null will *pass* the cast check. // A non-null value will always produce an exception. return null_assert(obj); @@ -3364,7 +3324,7 @@ Node* GraphKit::set_output_for_allocation(AllocateNode* alloc, // This will allow us to observe initializations when they occur, // and link them properly (as a group) to the InitializeNode. assert(init->in(InitializeNode::Memory) == malloc, ""); - MergeMemNode* minit_in = MergeMemNode::make(C, malloc); + MergeMemNode* minit_in = MergeMemNode::make(malloc); init->set_req(InitializeNode::Memory, minit_in); record_for_igvn(minit_in); // fold it up later, if possible Node* minit_out = memory(rawidx); diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index 683be5c9060..26f5dfd21c1 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -829,17 +829,13 @@ class GraphKit : public Phase { Node* gen_checkcast( Node *subobj, Node* superkls, Node* *failure_control = NULL ); - // Generate a subtyping check. Takes as input the subtype and supertype. - // Returns 2 values: sets the default control() to the true path and - // returns the false path. Only reads from constant memory taken from the - // default memory; does not write anything. It also doesn't take in an - // Object; if you wish to check an Object you need to load the Object's - // class prior to coming here. - Node* gen_subtype_check(Node* subklass, Node* superklass); - - // Static parse-time type checking logic for gen_subtype_check: - enum { SSC_always_false, SSC_always_true, SSC_easy_test, SSC_full_test }; - int static_subtype_check(ciKlass* superk, ciKlass* subk); + Node* gen_subtype_check(Node* subklass, Node* superklass) { + MergeMemNode* mem = merged_memory(); + Node* ctrl = control(); + Node* n = Phase::gen_subtype_check(subklass, superklass, &ctrl, mem, &_gvn); + set_control(ctrl); + return n; + } // Exact type check used for predicted calls and casts. // Rewrites (*casted_receiver) to be casted to the stronger type. diff --git a/hotspot/src/share/vm/opto/idealKit.cpp b/hotspot/src/share/vm/opto/idealKit.cpp index a0a9cbe62cc..3038982e648 100644 --- a/hotspot/src/share/vm/opto/idealKit.cpp +++ b/hotspot/src/share/vm/opto/idealKit.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -320,7 +320,7 @@ Node* IdealKit::copy_cvstate() { Node* ns = new_cvstate(); for (uint i = 0; i < ns->req(); i++) ns->init_req(i, _cvstate->in(i)); // We must clone memory since it will be updated as we do stores. - ns->set_req(TypeFunc::Memory, MergeMemNode::make(C, ns->in(TypeFunc::Memory))); + ns->set_req(TypeFunc::Memory, MergeMemNode::make(ns->in(TypeFunc::Memory))); return ns; } @@ -359,7 +359,7 @@ Node* IdealKit::load(Node* ctl, Node* mem = memory(adr_idx); Node* ld; if (require_atomic_access && bt == T_LONG) { - ld = LoadLNode::make_atomic(C, ctl, mem, adr, adr_type, t, MemNode::unordered); + ld = LoadLNode::make_atomic(ctl, mem, adr, adr_type, t, MemNode::unordered); } else { ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, MemNode::unordered); } @@ -375,7 +375,7 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt, Node *mem = memory(adr_idx); Node* st; if (require_atomic_access && bt == T_LONG) { - st = StoreLNode::make_atomic(C, ctl, mem, adr, adr_type, val, mo); + st = StoreLNode::make_atomic(ctl, mem, adr, adr_type, val, mo); } else { st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo); } diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index 96551a804d2..c0080c81d57 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -503,7 +503,7 @@ int IfNode::is_range_check(Node* &range, Node* &index, jint &offset) { jint off = 0; if (l->is_top()) { return 0; - } else if (l->is_Add()) { + } else if (l->Opcode() == Op_AddI) { if ((off = l->in(1)->find_int_con(0)) != 0) { ind = l->in(2); } else if ((off = l->in(2)->find_int_con(0)) != 0) { diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index a601752d4cd..187d2699768 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -464,7 +464,9 @@ Node* PhaseCFG::select(Block* block, Node_List &worklist, GrowableArray &re iop == Op_CreateEx || // Create-exception must start block iop == Op_CheckCastPP ) { - worklist.map(i,worklist.pop()); + // select the node n + // remove n from worklist and retain the order of remaining nodes + worklist.remove((uint)i); return n; } @@ -550,7 +552,9 @@ Node* PhaseCFG::select(Block* block, Node_List &worklist, GrowableArray &re assert(idx >= 0, "index should be set"); Node *n = worklist[(uint)idx]; // Get the winner - worklist.map((uint)idx, worklist.pop()); // Compress worklist + // select the node n + // remove n from worklist and retain the order of remaining nodes + worklist.remove((uint)idx); return n; } diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 8e01709fcda..8339cce6ea4 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -146,15 +146,10 @@ class LibraryCallKit : public GraphKit { Node* generate_negative_guard(Node* index, RegionNode* region, // resulting CastII of index: Node* *pos_index = NULL); - Node* generate_nonpositive_guard(Node* index, bool never_negative, - // resulting CastII of index: - Node* *pos_index = NULL); Node* generate_limit_guard(Node* offset, Node* subseq_length, Node* array_length, RegionNode* region); Node* generate_current_thread(Node* &tls_output); - address basictype2arraycopy(BasicType t, Node *src_offset, Node *dest_offset, - bool disjoint_bases, const char* &name, bool dest_uninitialized); Node* load_mirror_from_klass(Node* klass); Node* load_klass_from_mirror_common(Node* mirror, bool never_see_null, RegionNode* region, int null_path, @@ -264,47 +259,8 @@ class LibraryCallKit : public GraphKit { // Helper functions for inlining arraycopy bool inline_arraycopy(); - void generate_arraycopy(const TypePtr* adr_type, - BasicType basic_elem_type, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, - bool disjoint_bases = false, - bool length_never_negative = false, - RegionNode* slow_region = NULL); AllocateArrayNode* tightly_coupled_allocation(Node* ptr, RegionNode* slow_region); - void generate_clear_array(const TypePtr* adr_type, - Node* dest, - BasicType basic_elem_type, - Node* slice_off, - Node* slice_len, - Node* slice_end); - bool generate_block_arraycopy(const TypePtr* adr_type, - BasicType basic_elem_type, - AllocateNode* alloc, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* dest_size, bool dest_uninitialized); - void generate_slow_arraycopy(const TypePtr* adr_type, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, bool dest_uninitialized); - Node* generate_checkcast_arraycopy(const TypePtr* adr_type, - Node* dest_elem_klass, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, bool dest_uninitialized); - Node* generate_generic_arraycopy(const TypePtr* adr_type, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, bool dest_uninitialized); - void generate_unchecked_arraycopy(const TypePtr* adr_type, - BasicType basic_elem_type, - bool disjoint_bases, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, bool dest_uninitialized); typedef enum { LS_xadd, LS_xchg, LS_cmpxchg } LoadStoreKind; bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind); bool inline_unsafe_ordered_store(BasicType type); @@ -1049,25 +1005,6 @@ inline Node* LibraryCallKit::generate_negative_guard(Node* index, RegionNode* re return is_neg; } -inline Node* LibraryCallKit::generate_nonpositive_guard(Node* index, bool never_negative, - Node* *pos_index) { - if (stopped()) - return NULL; // already stopped - if (_gvn.type(index)->higher_equal(TypeInt::POS1)) // [1,maxint] - return NULL; // index is already adequately typed - Node* cmp_le = _gvn.transform(new CmpINode(index, intcon(0))); - BoolTest::mask le_or_eq = (never_negative ? BoolTest::eq : BoolTest::le); - Node* bol_le = _gvn.transform(new BoolNode(cmp_le, le_or_eq)); - Node* is_notp = generate_guard(bol_le, NULL, PROB_MIN); - if (is_notp != NULL && pos_index != NULL) { - // Emulate effect of Parse::adjust_map_after_if. - Node* ccast = new CastIINode(index, TypeInt::POS1); - ccast->set_req(0, control()); - (*pos_index) = _gvn.transform(ccast); - } - return is_notp; -} - // Make sure that 'position' is a valid limit index, in [0..length]. // There are two equivalent plans for checking this: // A. (offset + copyLength) unsigned<= arrayLength @@ -1905,7 +1842,7 @@ bool LibraryCallKit::inline_pow() { Node *bolyplus1 = _gvn.transform(new BoolNode( cmpyplus1, BoolTest::eq )); Node* correctedsign = NULL; if (ConditionalMoveLimit != 0) { - correctedsign = _gvn.transform( CMoveNode::make(C, NULL, bolyplus1, signnode, longcon(0), TypeLong::LONG)); + 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); @@ -1934,7 +1871,7 @@ bool LibraryCallKit::inline_pow() { // (1&(long)y)==1?-DPow(abs(x), y):DPow(abs(x), y) Node *signresult = NULL; if (ConditionalMoveLimit != 0) { - signresult = _gvn.transform( CMoveNode::make(C, NULL, bol3, absxpowy, negabsxpowy, Type::DOUBLE)); + 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); @@ -2268,7 +2205,7 @@ LibraryCallKit::generate_min_max(vmIntrinsics::ID id, Node* x0, Node* y0) { // which could hinder other optimizations. // Since Math.min/max is often used with arraycopy, we want // tightly_coupled_allocation to be able to see beyond min/max expressions. - Node* cmov = CMoveNode::make(C, NULL, best_bol, + Node* cmov = CMoveNode::make(NULL, best_bol, answer_if_false, answer_if_true, TypeInt::make(lo, hi, widen)); @@ -2658,7 +2595,8 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder); if (!is_store) { - Node* p = make_load(control(), adr, value_type, type, adr_type, MemNode::unordered, is_volatile); + MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; + Node* p = make_load(control(), adr, value_type, type, adr_type, mo, is_volatile); // load value switch (type) { case T_BOOLEAN: @@ -3928,13 +3866,18 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { // oop stores need checking. // Extreme case: Arrays.copyOf((Integer[])x, 10, String[].class). // This will fail a store-check if x contains any non-nulls. - bool disjoint_bases = true; - // if start > orig_length then the length of the copy may be - // negative. - bool length_never_negative = !is_copyOfRange; - generate_arraycopy(TypeAryPtr::OOPS, T_OBJECT, - original, start, newcopy, intcon(0), moved, - disjoint_bases, length_never_negative); + + Node* alloc = tightly_coupled_allocation(newcopy, NULL); + + ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, alloc != NULL); + if (!is_copyOfRange) { + ac->set_copyof(); + } else { + ac->set_copyofrange(); + } + Node* n = _gvn.transform(ac); + assert(n == ac, "cannot disappear"); + ac->connect_outputs(this); } } // original reexecute is set back here @@ -4445,10 +4388,12 @@ void LibraryCallKit::copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, b countx = _gvn.transform(new URShiftXNode(countx, intcon(LogBytesPerLong) )); const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM; - bool disjoint_bases = true; - generate_unchecked_arraycopy(raw_adr_type, T_LONG, disjoint_bases, - src, NULL, dest, NULL, countx, - /*dest_uninitialized*/true); + + ArrayCopyNode* ac = ArrayCopyNode::make(this, false, src, NULL, dest, NULL, countx, false); + ac->set_clonebasic(); + Node* n = _gvn.transform(ac); + assert(n == ac, "cannot disappear"); + set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type); // If necessary, emit some card marks afterwards. (Non-arrays only.) if (card_mark) { @@ -4557,12 +4502,13 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { PreserveJVMState pjvms2(this); set_control(is_obja); // Generate a direct call to the right arraycopy function(s). - bool disjoint_bases = true; - bool length_never_negative = true; - generate_arraycopy(TypeAryPtr::OOPS, T_OBJECT, - obj, intcon(0), alloc_obj, intcon(0), - obj_length, - disjoint_bases, length_never_negative); + Node* alloc = tightly_coupled_allocation(alloc_obj, NULL); + ArrayCopyNode* ac = ArrayCopyNode::make(this, true, obj, intcon(0), alloc_obj, intcon(0), obj_length, alloc != NULL); + ac->set_cloneoop(); + Node* n = _gvn.transform(ac); + assert(n == ac, "cannot disappear"); + ac->connect_outputs(this); + result_reg->init_req(_objArray_path, control()); result_val->init_req(_objArray_path, alloc_obj); result_i_o ->set_req(_objArray_path, i_o()); @@ -4656,42 +4602,6 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { return true; } -//------------------------------basictype2arraycopy---------------------------- -address LibraryCallKit::basictype2arraycopy(BasicType t, - Node* src_offset, - Node* dest_offset, - bool disjoint_bases, - const char* &name, - bool dest_uninitialized) { - const TypeInt* src_offset_inttype = gvn().find_int_type(src_offset);; - const TypeInt* dest_offset_inttype = gvn().find_int_type(dest_offset);; - - bool aligned = false; - bool disjoint = disjoint_bases; - - // if the offsets are the same, we can treat the memory regions as - // disjoint, because either the memory regions are in different arrays, - // or they are identical (which we can treat as disjoint.) We can also - // treat a copy with a destination index less that the source index - // as disjoint since a low->high copy will work correctly in this case. - if (src_offset_inttype != NULL && src_offset_inttype->is_con() && - dest_offset_inttype != NULL && dest_offset_inttype->is_con()) { - // both indices are constants - int s_offs = src_offset_inttype->get_con(); - int d_offs = dest_offset_inttype->get_con(); - int element_size = type2aelembytes(t); - aligned = ((arrayOopDesc::base_offset_in_bytes(t) + s_offs * element_size) % HeapWordSize == 0) && - ((arrayOopDesc::base_offset_in_bytes(t) + d_offs * element_size) % HeapWordSize == 0); - if (s_offs >= d_offs) disjoint = true; - } else if (src_offset == dest_offset && src_offset != NULL) { - // This can occur if the offsets are identical non-constants. - disjoint = true; - } - - return StubRoutines::select_arraycopy_function(t, aligned, disjoint, name, dest_uninitialized); -} - - //------------------------------inline_arraycopy----------------------- // public static native void java.lang.System.arraycopy(Object src, int srcPos, // Object dest, int destPos, @@ -4704,13 +4614,26 @@ bool LibraryCallKit::inline_arraycopy() { Node* dest_offset = argument(3); // type: int Node* length = argument(4); // type: int - // Compile time checks. If any of these checks cannot be verified at compile time, - // we do not make a fast path for this call. Instead, we let the call remain as it - // is. The checks we choose to mandate at compile time are: - // + // The following tests must be performed // (1) src and dest are arrays. - const Type* src_type = src->Value(&_gvn); - const Type* dest_type = dest->Value(&_gvn); + // (2) src and dest arrays must have elements of the same BasicType + // (3) src and dest must not be null. + // (4) src_offset must not be negative. + // (5) dest_offset must not be negative. + // (6) length must not be negative. + // (7) src_offset + length must not exceed length of src. + // (8) dest_offset + length must not exceed length of dest. + // (9) each element of an oop array must be assignable + + // (3) src and dest must not be null. + // always do this here because we need the JVM state for uncommon traps + src = null_check(src, T_ARRAY); + dest = null_check(dest, T_ARRAY); + + bool notest = false; + + const Type* src_type = _gvn.type(src); + const Type* dest_type = _gvn.type(dest); const TypeAryPtr* top_src = src_type->isa_aryptr(); const TypeAryPtr* top_dest = dest_type->isa_aryptr(); @@ -4768,556 +4691,119 @@ bool LibraryCallKit::inline_arraycopy() { } } - if (!has_src || !has_dest) { - // Conservatively insert a memory barrier on all memory slices. - // Do not let writes into the source float below the arraycopy. - insert_mem_bar(Op_MemBarCPUOrder); + if (has_src && has_dest) { + BasicType src_elem = top_src->klass()->as_array_klass()->element_type()->basic_type(); + BasicType dest_elem = top_dest->klass()->as_array_klass()->element_type()->basic_type(); + if (src_elem == T_ARRAY) src_elem = T_OBJECT; + if (dest_elem == T_ARRAY) dest_elem = T_OBJECT; - // Call StubRoutines::generic_arraycopy stub. - generate_arraycopy(TypeRawPtr::BOTTOM, T_CONFLICT, - src, src_offset, dest, dest_offset, length); - - // Do not let reads from the destination float above the arraycopy. - // Since we cannot type the arrays, we don't know which slices - // might be affected. We could restrict this barrier only to those - // memory slices which pertain to array elements--but don't bother. - if (!InsertMemBarAfterArraycopy) - // (If InsertMemBarAfterArraycopy, there is already one in place.) - insert_mem_bar(Op_MemBarCPUOrder); - return true; - } - - // (2) src and dest arrays must have elements of the same BasicType - // Figure out the size and type of the elements we will be copying. - BasicType src_elem = top_src->klass()->as_array_klass()->element_type()->basic_type(); - BasicType dest_elem = top_dest->klass()->as_array_klass()->element_type()->basic_type(); - if (src_elem == T_ARRAY) src_elem = T_OBJECT; - if (dest_elem == T_ARRAY) dest_elem = T_OBJECT; - - if (src_elem != dest_elem || dest_elem == T_VOID) { - // The component types are not the same or are not recognized. Punt. - // (But, avoid the native method wrapper to JVM_ArrayCopy.) - generate_slow_arraycopy(TypePtr::BOTTOM, - src, src_offset, dest, dest_offset, length, - /*dest_uninitialized*/false); - return true; - } - - if (src_elem == T_OBJECT) { - // If both arrays are object arrays then having the exact types - // for both will remove the need for a subtype check at runtime - // before the call and may make it possible to pick a faster copy - // routine (without a subtype check on every element) - // Do we have the exact type of src? - bool could_have_src = src_spec; - // Do we have the exact type of dest? - bool could_have_dest = dest_spec; - ciKlass* src_k = top_src->klass(); - ciKlass* dest_k = top_dest->klass(); - if (!src_spec) { - src_k = src_type->speculative_type_not_null(); - if (src_k != NULL && src_k->is_array_klass()) { + if (src_elem == dest_elem && src_elem == T_OBJECT) { + // If both arrays are object arrays then having the exact types + // for both will remove the need for a subtype check at runtime + // before the call and may make it possible to pick a faster copy + // routine (without a subtype check on every element) + // Do we have the exact type of src? + bool could_have_src = src_spec; + // Do we have the exact type of dest? + bool could_have_dest = dest_spec; + ciKlass* src_k = top_src->klass(); + ciKlass* dest_k = top_dest->klass(); + if (!src_spec) { + src_k = src_type->speculative_type_not_null(); + if (src_k != NULL && src_k->is_array_klass()) { could_have_src = true; - } - } - if (!dest_spec) { - dest_k = dest_type->speculative_type_not_null(); - if (dest_k != NULL && dest_k->is_array_klass()) { - could_have_dest = true; - } - } - if (could_have_src && could_have_dest) { - // If we can have both exact types, emit the missing guards - if (could_have_src && !src_spec) { - src = maybe_cast_profiled_obj(src, src_k); - } - if (could_have_dest && !dest_spec) { - dest = maybe_cast_profiled_obj(dest, dest_k); - } - } - } - - //--------------------------------------------------------------------------- - // We will make a fast path for this call to arraycopy. - - // We have the following tests left to perform: - // - // (3) src and dest must not be null. - // (4) src_offset must not be negative. - // (5) dest_offset must not be negative. - // (6) length must not be negative. - // (7) src_offset + length must not exceed length of src. - // (8) dest_offset + length must not exceed length of dest. - // (9) each element of an oop array must be assignable - - RegionNode* slow_region = new RegionNode(1); - record_for_igvn(slow_region); - - // (3) operands must not be null - // We currently perform our null checks with the null_check routine. - // This means that the null exceptions will be reported in the caller - // rather than (correctly) reported inside of the native arraycopy call. - // This should be corrected, given time. We do our null check with the - // stack pointer restored. - src = null_check(src, T_ARRAY); - dest = null_check(dest, T_ARRAY); - - // (4) src_offset must not be negative. - generate_negative_guard(src_offset, slow_region); - - // (5) dest_offset must not be negative. - generate_negative_guard(dest_offset, slow_region); - - // (6) length must not be negative (moved to generate_arraycopy()). - // generate_negative_guard(length, slow_region); - - // (7) src_offset + length must not exceed length of src. - generate_limit_guard(src_offset, length, - load_array_length(src), - slow_region); - - // (8) dest_offset + length must not exceed length of dest. - generate_limit_guard(dest_offset, length, - load_array_length(dest), - slow_region); - - // (9) each element of an oop array must be assignable - // The generate_arraycopy subroutine checks this. - - // This is where the memory effects are placed: - const TypePtr* adr_type = TypeAryPtr::get_array_body_type(dest_elem); - generate_arraycopy(adr_type, dest_elem, - src, src_offset, dest, dest_offset, length, - false, false, slow_region); - - return true; -} - -//-----------------------------generate_arraycopy---------------------- -// Generate an optimized call to arraycopy. -// Caller must guard against non-arrays. -// Caller must determine a common array basic-type for both arrays. -// Caller must validate offsets against array bounds. -// The slow_region has already collected guard failure paths -// (such as out of bounds length or non-conformable array types). -// The generated code has this shape, in general: -// -// if (length == 0) return // via zero_path -// slowval = -1 -// if (types unknown) { -// slowval = call generic copy loop -// if (slowval == 0) return // via checked_path -// } else if (indexes in bounds) { -// if ((is object array) && !(array type check)) { -// slowval = call checked copy loop -// if (slowval == 0) return // via checked_path -// } else { -// call bulk copy loop -// return // via fast_path -// } -// } -// // adjust params for remaining work: -// if (slowval != -1) { -// n = -1^slowval; src_offset += n; dest_offset += n; length -= n -// } -// slow_region: -// call slow arraycopy(src, src_offset, dest, dest_offset, length) -// return // via slow_call_path -// -// This routine is used from several intrinsics: System.arraycopy, -// Object.clone (the array subcase), and Arrays.copyOf[Range]. -// -void -LibraryCallKit::generate_arraycopy(const TypePtr* adr_type, - BasicType basic_elem_type, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, - bool disjoint_bases, - bool length_never_negative, - RegionNode* slow_region) { - - if (slow_region == NULL) { - slow_region = new RegionNode(1); - record_for_igvn(slow_region); - } - - Node* original_dest = dest; - AllocateArrayNode* alloc = NULL; // used for zeroing, if needed - bool dest_uninitialized = false; - - // See if this is the initialization of a newly-allocated array. - // If so, we will take responsibility here for initializing it to zero. - // (Note: Because tightly_coupled_allocation performs checks on the - // out-edges of the dest, we need to avoid making derived pointers - // from it until we have checked its uses.) - if (ReduceBulkZeroing - && !ZeroTLAB // pointless if already zeroed - && basic_elem_type != T_CONFLICT // avoid corner case - && !src->eqv_uncast(dest) - && ((alloc = tightly_coupled_allocation(dest, slow_region)) - != NULL) - && _gvn.find_int_con(alloc->in(AllocateNode::ALength), 1) > 0 - && alloc->maybe_set_complete(&_gvn)) { - // "You break it, you buy it." - InitializeNode* init = alloc->initialization(); - assert(init->is_complete(), "we just did this"); - init->set_complete_with_arraycopy(); - assert(dest->is_CheckCastPP(), "sanity"); - assert(dest->in(0)->in(0) == init, "dest pinned"); - adr_type = TypeRawPtr::BOTTOM; // all initializations are into raw memory - // From this point on, every exit path is responsible for - // initializing any non-copied parts of the object to zero. - // Also, if this flag is set we make sure that arraycopy interacts properly - // with G1, eliding pre-barriers. See CR 6627983. - dest_uninitialized = true; - } else { - // No zeroing elimination here. - alloc = NULL; - //original_dest = dest; - //dest_uninitialized = false; - } - - // Results are placed here: - enum { fast_path = 1, // normal void-returning assembly stub - checked_path = 2, // special assembly stub with cleanup - slow_call_path = 3, // something went wrong; call the VM - zero_path = 4, // bypass when length of copy is zero - bcopy_path = 5, // copy primitive array by 64-bit blocks - PATH_LIMIT = 6 - }; - RegionNode* result_region = new RegionNode(PATH_LIMIT); - PhiNode* result_i_o = new PhiNode(result_region, Type::ABIO); - PhiNode* result_memory = new PhiNode(result_region, Type::MEMORY, adr_type); - record_for_igvn(result_region); - _gvn.set_type_bottom(result_i_o); - _gvn.set_type_bottom(result_memory); - assert(adr_type != TypePtr::BOTTOM, "must be RawMem or a T[] slice"); - - // The slow_control path: - Node* slow_control; - Node* slow_i_o = i_o(); - Node* slow_mem = memory(adr_type); - debug_only(slow_control = (Node*) badAddress); - - // Checked control path: - Node* checked_control = top(); - Node* checked_mem = NULL; - Node* checked_i_o = NULL; - Node* checked_value = NULL; - - if (basic_elem_type == T_CONFLICT) { - assert(!dest_uninitialized, ""); - Node* cv = generate_generic_arraycopy(adr_type, - src, src_offset, dest, dest_offset, - copy_length, dest_uninitialized); - if (cv == NULL) cv = intcon(-1); // failure (no stub available) - checked_control = control(); - checked_i_o = i_o(); - checked_mem = memory(adr_type); - checked_value = cv; - set_control(top()); // no fast path - } - - Node* not_pos = generate_nonpositive_guard(copy_length, length_never_negative); - if (not_pos != NULL) { - PreserveJVMState pjvms(this); - set_control(not_pos); - - // (6) length must not be negative. - if (!length_never_negative) { - generate_negative_guard(copy_length, slow_region); - } - - // copy_length is 0. - if (!stopped() && dest_uninitialized) { - Node* dest_length = alloc->in(AllocateNode::ALength); - if (copy_length->eqv_uncast(dest_length) - || _gvn.find_int_con(dest_length, 1) <= 0) { - // There is no zeroing to do. No need for a secondary raw memory barrier. - } else { - // Clear the whole thing since there are no source elements to copy. - generate_clear_array(adr_type, dest, basic_elem_type, - intcon(0), NULL, - alloc->in(AllocateNode::AllocSize)); - // Use a secondary InitializeNode as raw memory barrier. - // Currently it is needed only on this path since other - // paths have stub or runtime calls as raw memory barriers. - InitializeNode* init = insert_mem_bar_volatile(Op_Initialize, - Compile::AliasIdxRaw, - top())->as_Initialize(); - init->set_complete(&_gvn); // (there is no corresponding AllocateNode) - } - } - - // Present the results of the fast call. - result_region->init_req(zero_path, control()); - result_i_o ->init_req(zero_path, i_o()); - result_memory->init_req(zero_path, memory(adr_type)); - } - - if (!stopped() && dest_uninitialized) { - // We have to initialize the *uncopied* part of the array to zero. - // The copy destination is the slice dest[off..off+len]. The other slices - // are dest_head = dest[0..off] and dest_tail = dest[off+len..dest.length]. - Node* dest_size = alloc->in(AllocateNode::AllocSize); - Node* dest_length = alloc->in(AllocateNode::ALength); - Node* dest_tail = _gvn.transform(new AddINode(dest_offset, copy_length)); - - // If there is a head section that needs zeroing, do it now. - if (find_int_con(dest_offset, -1) != 0) { - generate_clear_array(adr_type, dest, basic_elem_type, - intcon(0), dest_offset, - NULL); - } - - // Next, perform a dynamic check on the tail length. - // It is often zero, and we can win big if we prove this. - // There are two wins: Avoid generating the ClearArray - // with its attendant messy index arithmetic, and upgrade - // the copy to a more hardware-friendly word size of 64 bits. - Node* tail_ctl = NULL; - if (!stopped() && !dest_tail->eqv_uncast(dest_length)) { - Node* cmp_lt = _gvn.transform(new CmpINode(dest_tail, dest_length)); - Node* bol_lt = _gvn.transform(new BoolNode(cmp_lt, BoolTest::lt)); - tail_ctl = generate_slow_guard(bol_lt, NULL); - assert(tail_ctl != NULL || !stopped(), "must be an outcome"); - } - - // At this point, let's assume there is no tail. - if (!stopped() && alloc != NULL && basic_elem_type != T_OBJECT) { - // There is no tail. Try an upgrade to a 64-bit copy. - bool didit = false; - { PreserveJVMState pjvms(this); - didit = generate_block_arraycopy(adr_type, basic_elem_type, alloc, - src, src_offset, dest, dest_offset, - dest_size, dest_uninitialized); - if (didit) { - // Present the results of the block-copying fast call. - result_region->init_req(bcopy_path, control()); - result_i_o ->init_req(bcopy_path, i_o()); - result_memory->init_req(bcopy_path, memory(adr_type)); } } - if (didit) - set_control(top()); // no regular fast path - } - - // Clear the tail, if any. - if (tail_ctl != NULL) { - Node* notail_ctl = stopped() ? NULL : control(); - set_control(tail_ctl); - if (notail_ctl == NULL) { - generate_clear_array(adr_type, dest, basic_elem_type, - dest_tail, NULL, - dest_size); - } else { - // Make a local merge. - Node* done_ctl = new RegionNode(3); - Node* done_mem = new PhiNode(done_ctl, Type::MEMORY, adr_type); - done_ctl->init_req(1, notail_ctl); - done_mem->init_req(1, memory(adr_type)); - generate_clear_array(adr_type, dest, basic_elem_type, - dest_tail, NULL, - dest_size); - done_ctl->init_req(2, control()); - done_mem->init_req(2, memory(adr_type)); - set_control( _gvn.transform(done_ctl)); - set_memory( _gvn.transform(done_mem), adr_type ); + if (!dest_spec) { + dest_k = dest_type->speculative_type_not_null(); + if (dest_k != NULL && dest_k->is_array_klass()) { + could_have_dest = true; + } + } + if (could_have_src && could_have_dest) { + // If we can have both exact types, emit the missing guards + if (could_have_src && !src_spec) { + src = maybe_cast_profiled_obj(src, src_k); + } + if (could_have_dest && !dest_spec) { + dest = maybe_cast_profiled_obj(dest, dest_k); + } } } } - BasicType copy_type = basic_elem_type; - assert(basic_elem_type != T_ARRAY, "caller must fix this"); - if (!stopped() && copy_type == T_OBJECT) { - // If src and dest have compatible element types, we can copy bits. - // Types S[] and D[] are compatible if D is a supertype of S. - // - // If they are not, we will use checked_oop_disjoint_arraycopy, - // which performs a fast optimistic per-oop check, and backs off - // further to JVM_ArrayCopy on the first per-oop check that fails. - // (Actually, we don't move raw bits only; the GC requires card marks.) + if (!too_many_traps(Deoptimization::Reason_intrinsic) && !src->is_top() && !dest->is_top()) { + // validate arguments: enables transformation the ArrayCopyNode + notest = true; - // Get the Klass* for both src and dest + RegionNode* slow_region = new RegionNode(1); + record_for_igvn(slow_region); + + // (1) src and dest are arrays. + generate_non_array_guard(load_object_klass(src), slow_region); + generate_non_array_guard(load_object_klass(dest), slow_region); + + // (2) src and dest arrays must have elements of the same BasicType + // done at macro expansion or at Ideal transformation time + + // (4) src_offset must not be negative. + generate_negative_guard(src_offset, slow_region); + + // (5) dest_offset must not be negative. + generate_negative_guard(dest_offset, slow_region); + + // (7) src_offset + length must not exceed length of src. + generate_limit_guard(src_offset, length, + load_array_length(src), + slow_region); + + // (8) dest_offset + length must not exceed length of dest. + generate_limit_guard(dest_offset, length, + load_array_length(dest), + slow_region); + + // (9) each element of an oop array must be assignable Node* src_klass = load_object_klass(src); Node* dest_klass = load_object_klass(dest); - - // Generate the subtype check. - // This might fold up statically, or then again it might not. - // - // Non-static example: Copying List.elements to a new String[]. - // The backing store for a List is always an Object[], - // but its elements are always type String, if the generic types - // are correct at the source level. - // - // Test S[] against D[], not S against D, because (probably) - // the secondary supertype cache is less busy for S[] than S. - // This usually only matters when D is an interface. Node* not_subtype_ctrl = gen_subtype_check(src_klass, dest_klass); - // Plug failing path into checked_oop_disjoint_arraycopy + if (not_subtype_ctrl != top()) { PreserveJVMState pjvms(this); set_control(not_subtype_ctrl); - // (At this point we can assume disjoint_bases, since types differ.) - int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); - Node* p1 = basic_plus_adr(dest_klass, ek_offset); - Node* n1 = LoadKlassNode::make(_gvn, immutable_memory(), p1, TypeRawPtr::BOTTOM); - Node* dest_elem_klass = _gvn.transform(n1); - Node* cv = generate_checkcast_arraycopy(adr_type, - dest_elem_klass, - src, src_offset, dest, dest_offset, - ConvI2X(copy_length), dest_uninitialized); - if (cv == NULL) cv = intcon(-1); // failure (no stub available) - checked_control = control(); - checked_i_o = i_o(); - checked_mem = memory(adr_type); - checked_value = cv; + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_make_not_entrant); + assert(stopped(), "Should be stopped"); } - // At this point we know we do not need type checks on oop stores. - - // Let's see if we need card marks: - if (alloc != NULL && use_ReduceInitialCardMarks()) { - // If we do not need card marks, copy using the jint or jlong stub. - copy_type = LP64_ONLY(UseCompressedOops ? T_INT : T_LONG) NOT_LP64(T_INT); - assert(type2aelembytes(basic_elem_type) == type2aelembytes(copy_type), - "sizes agree"); + { + PreserveJVMState pjvms(this); + set_control(_gvn.transform(slow_region)); + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_make_not_entrant); + assert(stopped(), "Should be stopped"); } } - if (!stopped()) { - // Generate the fast path, if possible. - PreserveJVMState pjvms(this); - generate_unchecked_arraycopy(adr_type, copy_type, disjoint_bases, - src, src_offset, dest, dest_offset, - ConvI2X(copy_length), dest_uninitialized); - - // Present the results of the fast call. - result_region->init_req(fast_path, control()); - result_i_o ->init_req(fast_path, i_o()); - result_memory->init_req(fast_path, memory(adr_type)); + if (stopped()) { + return true; } - // Here are all the slow paths up to this point, in one bundle: - slow_control = top(); - if (slow_region != NULL) - slow_control = _gvn.transform(slow_region); - DEBUG_ONLY(slow_region = (RegionNode*)badAddress); + AllocateArrayNode* alloc = tightly_coupled_allocation(dest, NULL); + ArrayCopyNode* ac = ArrayCopyNode::make(this, true, src, src_offset, dest, dest_offset, length, alloc != NULL, + // Create LoadRange and LoadKlass nodes for use during macro expansion here + // so the compiler has a chance to eliminate them: during macro expansion, + // we have to set their control (CastPP nodes are eliminated). + load_array_length(src), load_array_length(dest), + load_object_klass(src), load_object_klass(dest)); - set_control(checked_control); - if (!stopped()) { - // Clean up after the checked call. - // The returned value is either 0 or -1^K, - // where K = number of partially transferred array elements. - Node* cmp = _gvn.transform(new CmpINode(checked_value, intcon(0))); - Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::eq)); - IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); - - // If it is 0, we are done, so transfer to the end. - Node* checks_done = _gvn.transform(new IfTrueNode(iff)); - result_region->init_req(checked_path, checks_done); - result_i_o ->init_req(checked_path, checked_i_o); - result_memory->init_req(checked_path, checked_mem); - - // If it is not zero, merge into the slow call. - set_control( _gvn.transform(new IfFalseNode(iff) )); - RegionNode* slow_reg2 = new RegionNode(3); - PhiNode* slow_i_o2 = new PhiNode(slow_reg2, Type::ABIO); - PhiNode* slow_mem2 = new PhiNode(slow_reg2, Type::MEMORY, adr_type); - record_for_igvn(slow_reg2); - slow_reg2 ->init_req(1, slow_control); - slow_i_o2 ->init_req(1, slow_i_o); - slow_mem2 ->init_req(1, slow_mem); - slow_reg2 ->init_req(2, control()); - slow_i_o2 ->init_req(2, checked_i_o); - slow_mem2 ->init_req(2, checked_mem); - - slow_control = _gvn.transform(slow_reg2); - slow_i_o = _gvn.transform(slow_i_o2); - slow_mem = _gvn.transform(slow_mem2); - - if (alloc != NULL) { - // We'll restart from the very beginning, after zeroing the whole thing. - // This can cause double writes, but that's OK since dest is brand new. - // So we ignore the low 31 bits of the value returned from the stub. - } else { - // We must continue the copy exactly where it failed, or else - // another thread might see the wrong number of writes to dest. - Node* checked_offset = _gvn.transform(new XorINode(checked_value, intcon(-1))); - Node* slow_offset = new PhiNode(slow_reg2, TypeInt::INT); - slow_offset->init_req(1, intcon(0)); - slow_offset->init_req(2, checked_offset); - slow_offset = _gvn.transform(slow_offset); - - // Adjust the arguments by the conditionally incoming offset. - Node* src_off_plus = _gvn.transform(new AddINode(src_offset, slow_offset)); - Node* dest_off_plus = _gvn.transform(new AddINode(dest_offset, slow_offset)); - Node* length_minus = _gvn.transform(new SubINode(copy_length, slow_offset)); - - // Tweak the node variables to adjust the code produced below: - src_offset = src_off_plus; - dest_offset = dest_off_plus; - copy_length = length_minus; - } + if (notest) { + ac->set_arraycopy_notest(); } - set_control(slow_control); - if (!stopped()) { - // Generate the slow path, if needed. - PreserveJVMState pjvms(this); // replace_in_map may trash the map + Node* n = _gvn.transform(ac); + assert(n == ac, "cannot disappear"); + ac->connect_outputs(this); - set_memory(slow_mem, adr_type); - set_i_o(slow_i_o); - - if (dest_uninitialized) { - generate_clear_array(adr_type, dest, basic_elem_type, - intcon(0), NULL, - alloc->in(AllocateNode::AllocSize)); - } - - generate_slow_arraycopy(adr_type, - src, src_offset, dest, dest_offset, - copy_length, /*dest_uninitialized*/false); - - result_region->init_req(slow_call_path, control()); - result_i_o ->init_req(slow_call_path, i_o()); - result_memory->init_req(slow_call_path, memory(adr_type)); - } - - // Remove unused edges. - for (uint i = 1; i < result_region->req(); i++) { - if (result_region->in(i) == NULL) - result_region->init_req(i, top()); - } - - // Finished; return the combined state. - set_control( _gvn.transform(result_region)); - set_i_o( _gvn.transform(result_i_o) ); - set_memory( _gvn.transform(result_memory), adr_type ); - - // The memory edges above are precise in order to model effects around - // array copies accurately to allow value numbering of field loads around - // arraycopy. Such field loads, both before and after, are common in Java - // collections and similar classes involving header/array data structures. - // - // But with low number of register or when some registers are used or killed - // by arraycopy calls it causes registers spilling on stack. See 6544710. - // The next memory barrier is added to avoid it. If the arraycopy can be - // optimized away (which it can, sometimes) then we can manually remove - // the membar also. - // - // Do not let reads from the cloned object float above the arraycopy. - if (alloc != NULL) { - // Do not let stores that initialize this object be reordered with - // a subsequent store that would make this object accessible by - // other threads. - // Record what AllocateNode this StoreStore protects so that - // escape analysis can go from the MemBarStoreStoreNode to the - // AllocateNode and eliminate the MemBarStoreStoreNode if possible - // based on the escape status of the AllocateNode. - insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress)); - } else if (InsertMemBarAfterArraycopy) - insert_mem_bar(Op_MemBarCPUOrder); + return true; } @@ -5397,305 +4883,6 @@ LibraryCallKit::tightly_coupled_allocation(Node* ptr, return alloc; } -// Helper for initialization of arrays, creating a ClearArray. -// It writes zero bits in [start..end), within the body of an array object. -// The memory effects are all chained onto the 'adr_type' alias category. -// -// Since the object is otherwise uninitialized, we are free -// to put a little "slop" around the edges of the cleared area, -// as long as it does not go back into the array's header, -// or beyond the array end within the heap. -// -// The lower edge can be rounded down to the nearest jint and the -// upper edge can be rounded up to the nearest MinObjAlignmentInBytes. -// -// Arguments: -// adr_type memory slice where writes are generated -// dest oop of the destination array -// basic_elem_type element type of the destination -// slice_idx array index of first element to store -// slice_len number of elements to store (or NULL) -// dest_size total size in bytes of the array object -// -// Exactly one of slice_len or dest_size must be non-NULL. -// If dest_size is non-NULL, zeroing extends to the end of the object. -// If slice_len is non-NULL, the slice_idx value must be a constant. -void -LibraryCallKit::generate_clear_array(const TypePtr* adr_type, - Node* dest, - BasicType basic_elem_type, - Node* slice_idx, - Node* slice_len, - Node* dest_size) { - // one or the other but not both of slice_len and dest_size: - assert((slice_len != NULL? 1: 0) + (dest_size != NULL? 1: 0) == 1, ""); - if (slice_len == NULL) slice_len = top(); - if (dest_size == NULL) dest_size = top(); - - // operate on this memory slice: - Node* mem = memory(adr_type); // memory slice to operate on - - // scaling and rounding of indexes: - int scale = exact_log2(type2aelembytes(basic_elem_type)); - int abase = arrayOopDesc::base_offset_in_bytes(basic_elem_type); - int clear_low = (-1 << scale) & (BytesPerInt - 1); - int bump_bit = (-1 << scale) & BytesPerInt; - - // determine constant starts and ends - const intptr_t BIG_NEG = -128; - assert(BIG_NEG + 2*abase < 0, "neg enough"); - intptr_t slice_idx_con = (intptr_t) find_int_con(slice_idx, BIG_NEG); - intptr_t slice_len_con = (intptr_t) find_int_con(slice_len, BIG_NEG); - if (slice_len_con == 0) { - return; // nothing to do here - } - intptr_t start_con = (abase + (slice_idx_con << scale)) & ~clear_low; - intptr_t end_con = find_intptr_t_con(dest_size, -1); - if (slice_idx_con >= 0 && slice_len_con >= 0) { - assert(end_con < 0, "not two cons"); - end_con = round_to(abase + ((slice_idx_con + slice_len_con) << scale), - BytesPerLong); - } - - if (start_con >= 0 && end_con >= 0) { - // Constant start and end. Simple. - mem = ClearArrayNode::clear_memory(control(), mem, dest, - start_con, end_con, &_gvn); - } else if (start_con >= 0 && dest_size != top()) { - // Constant start, pre-rounded end after the tail of the array. - Node* end = dest_size; - mem = ClearArrayNode::clear_memory(control(), mem, dest, - start_con, end, &_gvn); - } else if (start_con >= 0 && slice_len != top()) { - // Constant start, non-constant end. End needs rounding up. - // End offset = round_up(abase + ((slice_idx_con + slice_len) << scale), 8) - intptr_t end_base = abase + (slice_idx_con << scale); - int end_round = (-1 << scale) & (BytesPerLong - 1); - Node* end = ConvI2X(slice_len); - if (scale != 0) - end = _gvn.transform(new LShiftXNode(end, intcon(scale) )); - end_base += end_round; - end = _gvn.transform(new AddXNode(end, MakeConX(end_base))); - end = _gvn.transform(new AndXNode(end, MakeConX(~end_round))); - mem = ClearArrayNode::clear_memory(control(), mem, dest, - start_con, end, &_gvn); - } else if (start_con < 0 && dest_size != top()) { - // Non-constant start, pre-rounded end after the tail of the array. - // This is almost certainly a "round-to-end" operation. - Node* start = slice_idx; - start = ConvI2X(start); - if (scale != 0) - start = _gvn.transform(new LShiftXNode( start, intcon(scale) )); - start = _gvn.transform(new AddXNode(start, MakeConX(abase))); - if ((bump_bit | clear_low) != 0) { - int to_clear = (bump_bit | clear_low); - // Align up mod 8, then store a jint zero unconditionally - // just before the mod-8 boundary. - if (((abase + bump_bit) & ~to_clear) - bump_bit - < arrayOopDesc::length_offset_in_bytes() + BytesPerInt) { - bump_bit = 0; - assert((abase & to_clear) == 0, "array base must be long-aligned"); - } else { - // Bump 'start' up to (or past) the next jint boundary: - start = _gvn.transform(new AddXNode(start, MakeConX(bump_bit))); - assert((abase & clear_low) == 0, "array base must be int-aligned"); - } - // Round bumped 'start' down to jlong boundary in body of array. - start = _gvn.transform(new AndXNode(start, MakeConX(~to_clear))); - if (bump_bit != 0) { - // Store a zero to the immediately preceding jint: - Node* x1 = _gvn.transform(new AddXNode(start, MakeConX(-bump_bit))); - Node* p1 = basic_plus_adr(dest, x1); - mem = StoreNode::make(_gvn, control(), mem, p1, adr_type, intcon(0), T_INT, MemNode::unordered); - mem = _gvn.transform(mem); - } - } - Node* end = dest_size; // pre-rounded - mem = ClearArrayNode::clear_memory(control(), mem, dest, - start, end, &_gvn); - } else { - // Non-constant start, unrounded non-constant end. - // (Nobody zeroes a random midsection of an array using this routine.) - ShouldNotReachHere(); // fix caller - } - - // Done. - set_memory(mem, adr_type); -} - - -bool -LibraryCallKit::generate_block_arraycopy(const TypePtr* adr_type, - BasicType basic_elem_type, - AllocateNode* alloc, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* dest_size, bool dest_uninitialized) { - // See if there is an advantage from block transfer. - int scale = exact_log2(type2aelembytes(basic_elem_type)); - if (scale >= LogBytesPerLong) - return false; // it is already a block transfer - - // Look at the alignment of the starting offsets. - int abase = arrayOopDesc::base_offset_in_bytes(basic_elem_type); - - intptr_t src_off_con = (intptr_t) find_int_con(src_offset, -1); - intptr_t dest_off_con = (intptr_t) find_int_con(dest_offset, -1); - if (src_off_con < 0 || dest_off_con < 0) - // At present, we can only understand constants. - return false; - - intptr_t src_off = abase + (src_off_con << scale); - intptr_t dest_off = abase + (dest_off_con << scale); - - if (((src_off | dest_off) & (BytesPerLong-1)) != 0) { - // Non-aligned; too bad. - // One more chance: Pick off an initial 32-bit word. - // This is a common case, since abase can be odd mod 8. - if (((src_off | dest_off) & (BytesPerLong-1)) == BytesPerInt && - ((src_off ^ dest_off) & (BytesPerLong-1)) == 0) { - Node* sptr = basic_plus_adr(src, src_off); - Node* dptr = basic_plus_adr(dest, dest_off); - Node* sval = make_load(control(), sptr, TypeInt::INT, T_INT, adr_type, MemNode::unordered); - store_to_memory(control(), dptr, sval, T_INT, adr_type, MemNode::unordered); - src_off += BytesPerInt; - dest_off += BytesPerInt; - } else { - return false; - } - } - assert(src_off % BytesPerLong == 0, ""); - assert(dest_off % BytesPerLong == 0, ""); - - // Do this copy by giant steps. - Node* sptr = basic_plus_adr(src, src_off); - Node* dptr = basic_plus_adr(dest, dest_off); - Node* countx = dest_size; - countx = _gvn.transform(new SubXNode(countx, MakeConX(dest_off))); - countx = _gvn.transform(new URShiftXNode(countx, intcon(LogBytesPerLong))); - - bool disjoint_bases = true; // since alloc != NULL - generate_unchecked_arraycopy(adr_type, T_LONG, disjoint_bases, - sptr, NULL, dptr, NULL, countx, dest_uninitialized); - - return true; -} - - -// Helper function; generates code for the slow case. -// We make a call to a runtime method which emulates the native method, -// but without the native wrapper overhead. -void -LibraryCallKit::generate_slow_arraycopy(const TypePtr* adr_type, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, bool dest_uninitialized) { - assert(!dest_uninitialized, "Invariant"); - Node* call = make_runtime_call(RC_NO_LEAF | RC_UNCOMMON, - OptoRuntime::slow_arraycopy_Type(), - OptoRuntime::slow_arraycopy_Java(), - "slow_arraycopy", adr_type, - src, src_offset, dest, dest_offset, - copy_length); - - // Handle exceptions thrown by this fellow: - make_slow_call_ex(call, env()->Throwable_klass(), false); -} - -// Helper function; generates code for cases requiring runtime checks. -Node* -LibraryCallKit::generate_checkcast_arraycopy(const TypePtr* adr_type, - Node* dest_elem_klass, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, bool dest_uninitialized) { - if (stopped()) return NULL; - - address copyfunc_addr = StubRoutines::checkcast_arraycopy(dest_uninitialized); - if (copyfunc_addr == NULL) { // Stub was not generated, go slow path. - return NULL; - } - - // Pick out the parameters required to perform a store-check - // for the target array. This is an optimistic check. It will - // look in each non-null element's class, at the desired klass's - // super_check_offset, for the desired klass. - int sco_offset = in_bytes(Klass::super_check_offset_offset()); - Node* p3 = basic_plus_adr(dest_elem_klass, sco_offset); - Node* n3 = new LoadINode(NULL, memory(p3), p3, _gvn.type(p3)->is_ptr(), TypeInt::INT, MemNode::unordered); - Node* check_offset = ConvI2X(_gvn.transform(n3)); - Node* check_value = dest_elem_klass; - - Node* src_start = array_element_address(src, src_offset, T_OBJECT); - Node* dest_start = array_element_address(dest, dest_offset, T_OBJECT); - - // (We know the arrays are never conjoint, because their types differ.) - Node* call = make_runtime_call(RC_LEAF|RC_NO_FP, - OptoRuntime::checkcast_arraycopy_Type(), - copyfunc_addr, "checkcast_arraycopy", adr_type, - // five arguments, of which two are - // intptr_t (jlong in LP64) - src_start, dest_start, - copy_length XTOP, - check_offset XTOP, - check_value); - - return _gvn.transform(new ProjNode(call, TypeFunc::Parms)); -} - - -// Helper function; generates code for cases requiring runtime checks. -Node* -LibraryCallKit::generate_generic_arraycopy(const TypePtr* adr_type, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, bool dest_uninitialized) { - assert(!dest_uninitialized, "Invariant"); - if (stopped()) return NULL; - address copyfunc_addr = StubRoutines::generic_arraycopy(); - if (copyfunc_addr == NULL) { // Stub was not generated, go slow path. - return NULL; - } - - Node* call = make_runtime_call(RC_LEAF|RC_NO_FP, - OptoRuntime::generic_arraycopy_Type(), - copyfunc_addr, "generic_arraycopy", adr_type, - src, src_offset, dest, dest_offset, copy_length); - - return _gvn.transform(new ProjNode(call, TypeFunc::Parms)); -} - -// Helper function; generates the fast out-of-line call to an arraycopy stub. -void -LibraryCallKit::generate_unchecked_arraycopy(const TypePtr* adr_type, - BasicType basic_elem_type, - bool disjoint_bases, - Node* src, Node* src_offset, - Node* dest, Node* dest_offset, - Node* copy_length, bool dest_uninitialized) { - if (stopped()) return; // nothing to do - - 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, basic_elem_type); - dest_start = array_element_address(dest, dest_offset, basic_elem_type); - } - - // Figure out which arraycopy runtime method to call. - const char* copyfunc_name = "arraycopy"; - address copyfunc_addr = - basictype2arraycopy(basic_elem_type, src_offset, dest_offset, - disjoint_bases, copyfunc_name, dest_uninitialized); - - // Call it. Note that the count_ix value is not scaled to a byte-size. - make_runtime_call(RC_LEAF|RC_NO_FP, - OptoRuntime::fast_arraycopy_Type(), - copyfunc_addr, copyfunc_name, adr_type, - src_start, dest_start, copy_length XTOP); -} - //-------------inline_encodeISOArray----------------------------------- // encode char[] to byte[] in ISO_8859_1 bool LibraryCallKit::inline_encodeISOArray() { @@ -5915,8 +5102,19 @@ Node * LibraryCallKit::load_field_from_object(Node * fromObj, const char * field type = Type::get_const_basic_type(bt); } + if (support_IRIW_for_not_multiple_copy_atomic_cpu && is_vol) { + insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier + } // Build the load. - Node* loadedField = make_load(NULL, adr, type, bt, adr_type, MemNode::unordered, is_vol); + MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered; + Node* loadedField = make_load(NULL, adr, type, bt, adr_type, mo, is_vol); + // If reference is volatile, prevent following memory ops from + // floating up past the volatile read. Also prevents commoning + // another volatile read. + if (is_vol) { + // Memory barrier includes bogus read of value to force load BEFORE membar + insert_mem_bar(Op_MemBarAcquire, loadedField); + } return loadedField; } diff --git a/hotspot/src/share/vm/opto/loopPredicate.cpp b/hotspot/src/share/vm/opto/loopPredicate.cpp index 4f2ddd3d068..2539ae4d402 100644 --- a/hotspot/src/share/vm/opto/loopPredicate.cpp +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp @@ -107,8 +107,7 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* rgn = new RegionNode(1); rgn->add_req(uncommon_proj); register_control(rgn, loop, uncommon_proj); - _igvn.hash_delete(call); - call->set_req(0, rgn); + _igvn.replace_input_of(call, 0, rgn); // When called from beautify_loops() idom is not constructed yet. if (_idom != NULL) { set_idom(call, rgn, dom_depth(rgn)); @@ -166,8 +165,7 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* if (new_entry == NULL) { // Attach if_cont to iff - _igvn.hash_delete(iff); - iff->set_req(0, if_cont); + _igvn.replace_input_of(iff, 0, if_cont); if (_idom != NULL) { set_idom(iff, if_cont, dom_depth(iff)); } @@ -194,8 +192,7 @@ ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* n rgn = new RegionNode(1); register_new_node_with_optimizer(rgn); rgn->add_req(uncommon_proj); - hash_delete(call); - call->set_req(0, rgn); + replace_input_of(call, 0, rgn); } else { // Find region's edge corresponding to uncommon_proj for (; proj_index < rgn->req(); proj_index++) @@ -766,9 +763,7 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { loop->dump_head(); } #endif - } else if ((cl != NULL) && (proj->_con == predicate_proj->_con) && - loop->is_range_check_if(iff, this, invar)) { - + } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) { // Range check for counted loops const Node* cmp = bol->in(1)->as_Cmp(); Node* idx = cmp->in(1); @@ -803,18 +798,31 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { } // Test the lower bound - Node* lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false); + BoolNode* lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false); + // Negate test if necessary + bool negated = false; + if (proj->_con != predicate_proj->_con) { + lower_bound_bol = new BoolNode(lower_bound_bol->in(1), lower_bound_bol->_test.negate()); + register_new_node(lower_bound_bol, ctrl); + negated = true; + } IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If(); _igvn.hash_delete(lower_bound_iff); lower_bound_iff->set_req(1, lower_bound_bol); - if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx); + if (TraceLoopPredicate) tty->print_cr("lower bound check if: %s %d ", negated ? " negated" : "", lower_bound_iff->_idx); // Test the upper bound - Node* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true); + BoolNode* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true); + negated = false; + if (proj->_con != predicate_proj->_con) { + upper_bound_bol = new BoolNode(upper_bound_bol->in(1), upper_bound_bol->_test.negate()); + register_new_node(upper_bound_bol, ctrl); + negated = true; + } IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If(); _igvn.hash_delete(upper_bound_iff); upper_bound_iff->set_req(1, upper_bound_bol); - if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx); + if (TraceLoopPredicate) tty->print_cr("upper bound check if: %s %d ", negated ? " negated" : "", lower_bound_iff->_idx); // Fall through into rest of the clean up code which will move // any dependent nodes onto the upper bound test. diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 73ec0617370..9701cfd2cf2 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -924,15 +924,13 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_ if( bol->outcnt() != 1 ) { bol = bol->clone(); register_new_node(bol,main_end->in(CountedLoopEndNode::TestControl)); - _igvn.hash_delete(main_end); - main_end->set_req(CountedLoopEndNode::TestValue, bol); + _igvn.replace_input_of(main_end, CountedLoopEndNode::TestValue, bol); } // Need only 1 user of 'cmp' because I will be hacking the loop bounds. if( cmp->outcnt() != 1 ) { cmp = cmp->clone(); register_new_node(cmp,main_end->in(CountedLoopEndNode::TestControl)); - _igvn.hash_delete(bol); - bol->set_req(1, cmp); + _igvn.replace_input_of(bol, 1, cmp); } //------------------------------ @@ -1118,8 +1116,7 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_ Node* pre_bol = pre_end->in(CountedLoopEndNode::TestValue)->as_Bool(); BoolNode* new_bol0 = new BoolNode(pre_bol->in(1), new_test); register_new_node( new_bol0, pre_head->in(0) ); - _igvn.hash_delete(pre_end); - pre_end->set_req(CountedLoopEndNode::TestValue, new_bol0); + _igvn.replace_input_of(pre_end, CountedLoopEndNode::TestValue, new_bol0); // Modify main loop guard condition assert(min_iff->in(CountedLoopEndNode::TestValue) == min_bol, "guard okay"); BoolNode* new_bol1 = new BoolNode(min_bol->in(1), new_test); @@ -1130,8 +1127,7 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_ BoolNode* main_bol = main_end->in(CountedLoopEndNode::TestValue)->as_Bool(); BoolNode* new_bol2 = new BoolNode(main_bol->in(1), new_test); register_new_node( new_bol2, main_end->in(CountedLoopEndNode::TestControl) ); - _igvn.hash_delete(main_end); - main_end->set_req(CountedLoopEndNode::TestValue, new_bol2); + _igvn.replace_input_of(main_end, CountedLoopEndNode::TestValue, new_bol2); } // Flag main loop @@ -1346,8 +1342,7 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad Node* bol2 = loop_end->in(1)->clone(); bol2->set_req(1, cmp2); register_new_node(bol2, ctrl2); - _igvn.hash_delete(loop_end); - loop_end->set_req(1, bol2); + _igvn.replace_input_of(loop_end, 1, bol2); } // Step 3: Find the min-trip test guaranteed before a 'main' loop. // Make it a 1-trip test (means at least 2 trips). @@ -1356,8 +1351,7 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad // can edit it's inputs directly. Hammer in the new limit for the // minimum-trip guard. assert(opaq->outcnt() == 1, ""); - _igvn.hash_delete(opaq); - opaq->set_req(1, new_limit); + _igvn.replace_input_of(opaq, 1, new_limit); } // Adjust max trip count. The trip count is intentionally rounded @@ -1407,8 +1401,7 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad register_new_node( cmp2, ctrl2 ); Node *bol2 = new BoolNode( cmp2, loop_end->test_trip() ); register_new_node( bol2, ctrl2 ); - _igvn.hash_delete(loop_end); - loop_end->set_req(CountedLoopEndNode::TestValue, bol2); + _igvn.replace_input_of(loop_end, CountedLoopEndNode::TestValue, bol2); // Step 3: Find the min-trip test guaranteed before a 'main' loop. // Make it a 1-trip test (means at least 2 trips). @@ -1997,8 +1990,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { : (Node*)new MaxINode(pre_limit, orig_limit); register_new_node(pre_limit, pre_ctrl); } - _igvn.hash_delete(pre_opaq); - pre_opaq->set_req(1, pre_limit); + _igvn.replace_input_of(pre_opaq, 1, pre_limit); // Note:: we are making the main loop limit no longer precise; // need to round up based on stride. @@ -2027,10 +2019,9 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { Node *main_bol = main_cle->in(1); // Hacking loop bounds; need private copies of exit test if( main_bol->outcnt() > 1 ) {// BoolNode shared? - _igvn.hash_delete(main_cle); main_bol = main_bol->clone();// Clone a private BoolNode register_new_node( main_bol, main_cle->in(0) ); - main_cle->set_req(1,main_bol); + _igvn.replace_input_of(main_cle, 1, main_bol); } Node *main_cmp = main_bol->in(1); if( main_cmp->outcnt() > 1 ) { // CmpNode shared? diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index 5ee44d084bd..5ca0ab059db 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -133,7 +133,7 @@ Node *PhaseIdealLoop::get_early_ctrl( Node *n ) { // Return earliest legal location assert(early == find_non_split_ctrl(early), "unexpected early control"); - if (n->is_expensive()) { + if (n->is_expensive() && !_verify_only && !_verify_me) { assert(n->in(0), "should have control input"); early = get_early_ctrl_for_expensive(n, early); } @@ -226,8 +226,7 @@ Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) { } if (ctl != n->in(0)) { - _igvn.hash_delete(n); - n->set_req(0, ctl); + _igvn.replace_input_of(n, 0, ctl); _igvn.hash_insert(n); } @@ -521,8 +520,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { assert(check_iff->in(1)->Opcode() == Op_Conv2B && check_iff->in(1)->in(1)->Opcode() == Op_Opaque1, ""); Node* opq = check_iff->in(1)->in(1); - _igvn.hash_delete(opq); - opq->set_req(1, bol); + _igvn.replace_input_of(opq, 1, bol); // Update ctrl. set_ctrl(opq, check_iff->in(0)); set_ctrl(check_iff->in(1), check_iff->in(0)); @@ -690,7 +688,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { incr->set_req(2,stride); incr = _igvn.register_new_node_with_optimizer(incr); set_early_ctrl( incr ); - _igvn.hash_delete(phi); + _igvn.rehash_node_delayed(phi); phi->set_req_X( LoopNode::LoopBackControl, incr, &_igvn ); // If phi type is more restrictive than Int, raise to @@ -743,8 +741,8 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { iffalse = iff2; iftrue = ift2; } else { - _igvn.hash_delete(iffalse); - _igvn.hash_delete(iftrue); + _igvn.rehash_node_delayed(iffalse); + _igvn.rehash_node_delayed(iftrue); iffalse->set_req_X( 0, le, &_igvn ); iftrue ->set_req_X( 0, le, &_igvn ); } @@ -1257,6 +1255,7 @@ void IdealLoopTree::split_fall_in( PhaseIdealLoop *phase, int fall_in_cnt ) { _head->del_req(i); } } + igvn.rehash_node_delayed(_head); // Transform landing pad igvn.register_new_node_with_optimizer(landing_pad, _head); // Insert landing pad into the header @@ -1397,7 +1396,7 @@ void IdealLoopTree::merge_many_backedges( PhaseIdealLoop *phase ) { igvn.register_new_node_with_optimizer(r, _head); // Plug region into end of loop _head, followed by hot_tail while( _head->req() > 3 ) _head->del_req( _head->req()-1 ); - _head->set_req(2, r); + igvn.replace_input_of(_head, 2, r); if( hot_idx ) _head->add_req(hot_tail); // Split all the Phis up between '_head' loop and the Region 'r' @@ -1419,7 +1418,7 @@ void IdealLoopTree::merge_many_backedges( PhaseIdealLoop *phase ) { igvn.register_new_node_with_optimizer(phi, n); // Add the merge phi to the old Phi while( n->req() > 3 ) n->del_req( n->req()-1 ); - n->set_req(2, phi); + igvn.replace_input_of(n, 2, phi); if( hot_idx ) n->add_req(hot_phi); } } @@ -1495,13 +1494,14 @@ bool IdealLoopTree::beautify_loops( PhaseIdealLoop *phase ) { if( fall_in_cnt > 1 ) { // Since I am just swapping inputs I do not need to update def-use info Node *tmp = _head->in(1); + igvn.rehash_node_delayed(_head); _head->set_req( 1, _head->in(fall_in_cnt) ); _head->set_req( fall_in_cnt, tmp ); // Swap also all Phis for (DUIterator_Fast imax, i = _head->fast_outs(imax); i < imax; i++) { Node* phi = _head->fast_out(i); if( phi->is_Phi() ) { - igvn.hash_delete(phi); // Yank from hash before hacking edges + igvn.rehash_node_delayed(phi); // Yank from hash before hacking edges tmp = phi->in(1); phi->set_req( 1, phi->in(fall_in_cnt) ); phi->set_req( fall_in_cnt, tmp ); @@ -2905,6 +2905,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { uint k = 0; // Probably cfg->in(0) while( cfg->in(k) != m ) k++; // But check incase cfg is a Region cfg->set_req( k, if_t ); // Now point to NeverBranch + _igvn._worklist.push(cfg); // Now create the never-taken loop exit Node *if_f = new CProjNode( iff, 1 ); diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index e25a6b0762e..20ad4ff1f6d 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -625,7 +625,7 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { set_ctrl(inp, cmov_ctrl); } } - Node *cmov = CMoveNode::make( C, cmov_ctrl, iff->in(1), phi->in(1+flip), phi->in(2-flip), _igvn.type(phi) ); + Node *cmov = CMoveNode::make(cmov_ctrl, iff->in(1), phi->in(1+flip), phi->in(2-flip), _igvn.type(phi)); register_new_node( cmov, cmov_ctrl ); _igvn.replace_node( phi, cmov ); #ifndef PRODUCT @@ -2574,7 +2574,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { new_head->set_unswitch_count(head->unswitch_count()); // Preserve _igvn.register_new_node_with_optimizer(new_head); assert(first_not_peeled->in(0) == last_peel, "last_peel <- first_not_peeled"); - first_not_peeled->set_req(0, new_head); + _igvn.replace_input_of(first_not_peeled, 0, new_head); set_loop(new_head, loop); loop->_body.push(new_head); not_peel.set(new_head->_idx); diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp index 69139e104f7..a2112199f26 100644 --- a/hotspot/src/share/vm/opto/machnode.cpp +++ b/hotspot/src/share/vm/opto/machnode.cpp @@ -178,7 +178,7 @@ uint MachNode::cmp( const Node &node ) const { } // Return an equivalent instruction using memory for cisc_operand position -MachNode *MachNode::cisc_version(int offset, Compile* C) { +MachNode *MachNode::cisc_version(int offset) { ShouldNotCallThis(); return NULL; } @@ -411,7 +411,7 @@ int MachNode::operand_index(const MachOper *oper) const { //------------------------------peephole--------------------------------------- // Apply peephole rule(s) to this instruction -MachNode *MachNode::peephole( Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile* C ) { +MachNode *MachNode::peephole(Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted) { return NULL; } diff --git a/hotspot/src/share/vm/opto/machnode.hpp b/hotspot/src/share/vm/opto/machnode.hpp index 78ab196b3a5..a557c02e6c6 100644 --- a/hotspot/src/share/vm/opto/machnode.hpp +++ b/hotspot/src/share/vm/opto/machnode.hpp @@ -152,7 +152,7 @@ public: virtual uint cmp( const MachOper &oper ) const; // Virtual clone, since I do not know how big the MachOper is. - virtual MachOper *clone(Compile* C) const = 0; + virtual MachOper *clone() const = 0; // Return ideal Type from simple operands. Fail for complex operands. virtual const Type *type() const; @@ -202,10 +202,10 @@ public: // Copy inputs and operands to new node of instruction. // Called from cisc_version() and short_branch_version(). // !!!! The method's body is defined in ad_.cpp file. - void fill_new_machnode(MachNode *n, Compile* C) const; + void fill_new_machnode(MachNode *n) const; // Return an equivalent instruction using memory for cisc_operand position - virtual MachNode *cisc_version(int offset, Compile* C); + virtual MachNode *cisc_version(int offset); // Modify this instruction's register mask to use stack version for cisc_operand virtual void use_cisc_RegMask(); @@ -317,7 +317,7 @@ public: virtual const class TypePtr *adr_type() const; // Apply peephole rule(s) to this instruction - virtual MachNode *peephole( Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile* C ); + virtual MachNode *peephole(Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted); // Top-level ideal Opcode matched virtual int ideal_Opcode() const { return Op_Node; } @@ -627,7 +627,7 @@ public: virtual void save_label(Label** label, uint* block_num) = 0; // Support for short branches - virtual MachNode *short_branch_version(Compile* C) { return NULL; } + virtual MachNode *short_branch_version() { return NULL; } virtual bool pinned() const { return true; }; }; @@ -985,7 +985,7 @@ public: labelOper(labelOper* l) : _label(l->_label) , _block_num(l->_block_num) {} - virtual MachOper *clone(Compile* C) const; + virtual MachOper *clone() const; virtual Label *label() const { assert(_label != NULL, "need Label"); return _label; } @@ -1012,7 +1012,7 @@ public: methodOper() : _method(0) {} methodOper(intptr_t method) : _method(method) {} - virtual MachOper *clone(Compile* C) const; + virtual MachOper *clone() const; virtual intptr_t method() const { return _method; } diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 5b1f4397642..40cc26aa0d1 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -94,7 +94,8 @@ void PhaseMacroExpand::copy_call_debug_info(CallNode *oldcall, CallNode * newcal newcall->add_req(old_in); } - newcall->set_jvms(oldcall->jvms()); + // JVMS may be shared so clone it before we modify it + newcall->set_jvms(oldcall->jvms() != NULL ? oldcall->jvms()->clone_deep(C) : NULL); for (JVMState *jvms = newcall->jvms(); jvms != NULL; jvms = jvms->caller()) { jvms->set_map(newcall); jvms->set_locoff(jvms->locoff()+jvms_adj); @@ -702,6 +703,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray result_cast(); + assert(res == NULL || res->is_CheckCastPP(), "unexpected AllocateNode result"); const TypeOopPtr* res_type = NULL; if (res != NULL) { // Could be NULL when there are no users res_type = _igvn.type(res)->isa_oopptr(); @@ -791,6 +793,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray del_req(last--); } + _igvn._worklist.push(sfpt); // rollback processed safepoints while (safepoints_done.length() > 0) { SafePointNode* sfpt_done = safepoints_done.pop(); @@ -815,6 +818,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray debug_start(); int end = jvms->debug_end(); sfpt->replace_edges_in_range(res, sobj, start, end); + _igvn._worklist.push(sfpt); safepoints_done.append_if_missing(sfpt); // keep it for rollback } return true; @@ -1034,6 +1039,8 @@ bool PhaseMacroExpand::eliminate_boxing_node(CallStaticJavaNode *boxing) { return false; } + assert(boxing->result_cast() == NULL, "unexpected boxing node result"); + extract_call_projections(boxing); const TypeTuple* r = boxing->tf()->range(); @@ -1775,6 +1782,7 @@ Node* PhaseMacroExpand::prefetch_allocation(Node* i_o, Node*& needgc_false, Node *pf_region = new RegionNode(3); Node *pf_phi_rawmem = new PhiNode( pf_region, Type::MEMORY, TypeRawPtr::BOTTOM ); + transform_later(pf_region); // Generate several prefetch instructions. uint lines = (length != NULL) ? AllocatePrefetchLines : AllocateInstancePrefetchLines; @@ -2462,6 +2470,8 @@ void PhaseMacroExpand::eliminate_macro_nodes() { assert(!n->as_AbstractLock()->is_eliminated(), "sanity"); _has_locks = true; break; + case Node::Class_ArrayCopy: + break; default: assert(n->Opcode() == Op_LoopLimit || n->Opcode() == Op_Opaque1 || @@ -2537,6 +2547,25 @@ bool PhaseMacroExpand::expand_macro_nodes() { } } + // expand arraycopy "macro" nodes first + // For ReduceBulkZeroing, we must first process all arraycopy nodes + // before the allocate nodes are expanded. + int macro_idx = C->macro_count() - 1; + while (macro_idx >= 0) { + Node * n = C->macro_node(macro_idx); + assert(n->is_macro(), "only macro nodes expected here"); + if (_igvn.type(n) == Type::TOP || n->in(0)->is_top() ) { + // node is unreachable, so don't try to expand it + C->remove_macro_node(n); + } else if (n->is_ArrayCopy()){ + int macro_count = C->macro_count(); + expand_arraycopy_node(n->as_ArrayCopy()); + assert(C->macro_count() < macro_count, "must have deleted a node from macro list"); + } + if (C->failing()) return true; + macro_idx --; + } + // expand "macro" nodes // nodes are removed from the macro list as they are processed while (C->macro_count() > 0) { diff --git a/hotspot/src/share/vm/opto/macro.hpp b/hotspot/src/share/vm/opto/macro.hpp index 5cefbb1c063..3cb2e8a2bcf 100644 --- a/hotspot/src/share/vm/opto/macro.hpp +++ b/hotspot/src/share/vm/opto/macro.hpp @@ -37,7 +37,7 @@ class PhaseMacroExpand : public Phase { private: PhaseIterGVN &_igvn; - // Helper methods roughly modelled after GraphKit: + // Helper methods roughly modeled after GraphKit: Node* top() const { return C->top(); } Node* intcon(jint con) const { return _igvn.intcon(con); } Node* longcon(jlong con) const { return _igvn.longcon(con); } @@ -101,6 +101,86 @@ private: void expand_lock_node(LockNode *lock); void expand_unlock_node(UnlockNode *unlock); + // More helper methods modeled after GraphKit for array copy + void insert_mem_bar(Node** ctrl, Node** mem, int opcode, Node* precedent = NULL); + Node* array_element_address(Node* ary, Node* idx, BasicType elembt); + Node* ConvI2L(Node* offset); + Node* make_leaf_call(Node* ctrl, Node* mem, + const TypeFunc* call_type, address call_addr, + const char* call_name, + const TypePtr* adr_type, + Node* parm0 = NULL, Node* parm1 = NULL, + Node* parm2 = NULL, Node* parm3 = NULL, + Node* parm4 = NULL, Node* parm5 = NULL, + Node* parm6 = NULL, Node* parm7 = NULL); + + // helper methods modeled after LibraryCallKit for array copy + Node* generate_guard(Node** ctrl, Node* test, RegionNode* region, float true_prob); + Node* generate_slow_guard(Node** ctrl, Node* test, RegionNode* region); + void generate_negative_guard(Node** ctrl, Node* index, RegionNode* region); + void generate_limit_guard(Node** ctrl, Node* offset, Node* subseq_length, Node* array_length, RegionNode* region); + + // More helper methods for array copy + Node* generate_nonpositive_guard(Node** ctrl, Node* index, bool never_negative); + void finish_arraycopy_call(Node* call, Node** ctrl, MergeMemNode** mem, const TypePtr* adr_type); + address basictype2arraycopy(BasicType t, + Node* src_offset, + Node* dest_offset, + bool disjoint_bases, + const char* &name, + bool dest_uninitialized); + Node* generate_arraycopy(ArrayCopyNode *ac, + AllocateArrayNode* alloc, + Node** ctrl, MergeMemNode* mem, Node** io, + const TypePtr* adr_type, + BasicType basic_elem_type, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, + bool disjoint_bases = false, + bool length_never_negative = false, + RegionNode* slow_region = NULL); + void generate_clear_array(Node* ctrl, MergeMemNode* merge_mem, + const TypePtr* adr_type, + Node* dest, + BasicType basic_elem_type, + Node* slice_idx, + Node* slice_len, + Node* dest_size); + bool generate_block_arraycopy(Node** ctrl, MergeMemNode** mem, Node* io, + const TypePtr* adr_type, + BasicType basic_elem_type, + AllocateNode* alloc, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* dest_size, bool dest_uninitialized); + MergeMemNode* generate_slow_arraycopy(ArrayCopyNode *ac, + Node** ctrl, Node* mem, Node** io, + const TypePtr* adr_type, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, bool dest_uninitialized); + Node* generate_checkcast_arraycopy(Node** ctrl, MergeMemNode** mem, + const TypePtr* adr_type, + Node* dest_elem_klass, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, bool dest_uninitialized); + Node* generate_generic_arraycopy(Node** ctrl, MergeMemNode** mem, + const TypePtr* adr_type, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, bool dest_uninitialized); + void generate_unchecked_arraycopy(Node** ctrl, MergeMemNode** mem, + const TypePtr* adr_type, + BasicType basic_elem_type, + bool disjoint_bases, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, bool dest_uninitialized); + + void expand_arraycopy_node(ArrayCopyNode *ac); + int replace_input(Node *use, Node *oldref, Node *newref); void copy_call_debug_info(CallNode *oldcall, CallNode * newcall); Node* opt_bits_test(Node* ctrl, Node* region, int edge, Node* word, int mask, int bits, bool return_fast_path = false); diff --git a/hotspot/src/share/vm/opto/macroArrayCopy.cpp b/hotspot/src/share/vm/opto/macroArrayCopy.cpp new file mode 100644 index 00000000000..e2676651e5d --- /dev/null +++ b/hotspot/src/share/vm/opto/macroArrayCopy.cpp @@ -0,0 +1,1233 @@ +/* + * Copyright (c) 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. + * + */ + +#include "precompiled.hpp" +#include "oops/objArrayKlass.hpp" +#include "opto/convertnode.hpp" +#include "opto/graphKit.hpp" +#include "opto/macro.hpp" +#include "opto/runtime.hpp" + + +void PhaseMacroExpand::insert_mem_bar(Node** ctrl, Node** mem, int opcode, Node* precedent) { + MemBarNode* mb = MemBarNode::make(C, opcode, Compile::AliasIdxBot, precedent); + mb->init_req(TypeFunc::Control, *ctrl); + mb->init_req(TypeFunc::Memory, *mem); + transform_later(mb); + *ctrl = new ProjNode(mb,TypeFunc::Control); + transform_later(*ctrl); + Node* mem_proj = new ProjNode(mb,TypeFunc::Memory); + transform_later(mem_proj); + *mem = mem_proj; +} + +Node* PhaseMacroExpand::array_element_address(Node* ary, Node* idx, BasicType elembt) { + uint shift = exact_log2(type2aelembytes(elembt)); + uint header = arrayOopDesc::base_offset_in_bytes(elembt); + Node* base = basic_plus_adr(ary, header); +#ifdef _LP64 + // see comment in GraphKit::array_element_address + int index_max = max_jint - 1; // array size is max_jint, index is one less + const TypeLong* lidxtype = TypeLong::make(CONST64(0), index_max, Type::WidenMax); + idx = transform_later( new ConvI2LNode(idx, lidxtype) ); +#endif + Node* scale = new LShiftXNode(idx, intcon(shift)); + transform_later(scale); + return basic_plus_adr(ary, base, scale); +} + +Node* PhaseMacroExpand::ConvI2L(Node* offset) { + return transform_later(new ConvI2LNode(offset)); +} + +Node* PhaseMacroExpand::make_leaf_call(Node* ctrl, Node* mem, + const TypeFunc* call_type, address call_addr, + const char* call_name, + const TypePtr* adr_type, + Node* parm0, Node* parm1, + Node* parm2, Node* parm3, + Node* parm4, Node* parm5, + Node* parm6, Node* parm7) { + int size = call_type->domain()->cnt(); + Node* call = new CallLeafNoFPNode(call_type, call_addr, call_name, adr_type); + call->init_req(TypeFunc::Control, ctrl); + call->init_req(TypeFunc::I_O , top()); + call->init_req(TypeFunc::Memory , mem); + call->init_req(TypeFunc::ReturnAdr, top()); + call->init_req(TypeFunc::FramePtr, top()); + + // Hook each parm in order. Stop looking at the first NULL. + if (parm0 != NULL) { call->init_req(TypeFunc::Parms+0, parm0); + if (parm1 != NULL) { call->init_req(TypeFunc::Parms+1, parm1); + if (parm2 != NULL) { call->init_req(TypeFunc::Parms+2, parm2); + if (parm3 != NULL) { call->init_req(TypeFunc::Parms+3, parm3); + if (parm4 != NULL) { call->init_req(TypeFunc::Parms+4, parm4); + if (parm5 != NULL) { call->init_req(TypeFunc::Parms+5, parm5); + if (parm6 != NULL) { call->init_req(TypeFunc::Parms+6, parm6); + if (parm7 != NULL) { call->init_req(TypeFunc::Parms+7, parm7); + /* close each nested if ===> */ } } } } } } } } + assert(call->in(call->req()-1) != NULL, "must initialize all parms"); + + return call; +} + + +//------------------------------generate_guard--------------------------- +// Helper function for generating guarded fast-slow graph structures. +// The given 'test', if true, guards a slow path. If the test fails +// then a fast path can be taken. (We generally hope it fails.) +// In all cases, GraphKit::control() is updated to the fast path. +// The returned value represents the control for the slow path. +// The return value is never 'top'; it is either a valid control +// or NULL if it is obvious that the slow path can never be taken. +// Also, if region and the slow control are not NULL, the slow edge +// is appended to the region. +Node* PhaseMacroExpand::generate_guard(Node** ctrl, Node* test, RegionNode* region, float true_prob) { + if ((*ctrl)->is_top()) { + // Already short circuited. + return NULL; + } + // Build an if node and its projections. + // If test is true we take the slow path, which we assume is uncommon. + if (_igvn.type(test) == TypeInt::ZERO) { + // The slow branch is never taken. No need to build this guard. + return NULL; + } + + IfNode* iff = new IfNode(*ctrl, test, true_prob, COUNT_UNKNOWN); + transform_later(iff); + + Node* if_slow = new IfTrueNode(iff); + transform_later(if_slow); + + if (region != NULL) { + region->add_req(if_slow); + } + + Node* if_fast = new IfFalseNode(iff); + transform_later(if_fast); + + *ctrl = if_fast; + + return if_slow; +} + +inline Node* PhaseMacroExpand::generate_slow_guard(Node** ctrl, Node* test, RegionNode* region) { + return generate_guard(ctrl, test, region, PROB_UNLIKELY_MAG(3)); +} + +void PhaseMacroExpand::generate_negative_guard(Node** ctrl, Node* index, RegionNode* region) { + if ((*ctrl)->is_top()) + return; // already stopped + if (_igvn.type(index)->higher_equal(TypeInt::POS)) // [0,maxint] + return; // index is already adequately typed + Node* cmp_lt = new CmpINode(index, intcon(0)); + transform_later(cmp_lt); + Node* bol_lt = new BoolNode(cmp_lt, BoolTest::lt); + transform_later(bol_lt); + generate_guard(ctrl, bol_lt, region, PROB_MIN); +} + +void PhaseMacroExpand::generate_limit_guard(Node** ctrl, Node* offset, Node* subseq_length, Node* array_length, RegionNode* region) { + if ((*ctrl)->is_top()) + return; // already stopped + bool zero_offset = _igvn.type(offset) == TypeInt::ZERO; + if (zero_offset && subseq_length->eqv_uncast(array_length)) + return; // common case of whole-array copy + Node* last = subseq_length; + if (!zero_offset) { // last += offset + last = new AddINode(last, offset); + transform_later(last); + } + Node* cmp_lt = new CmpUNode(array_length, last); + transform_later(cmp_lt); + Node* bol_lt = new BoolNode(cmp_lt, BoolTest::lt); + transform_later(bol_lt); + generate_guard(ctrl, bol_lt, region, PROB_MIN); +} + +Node* PhaseMacroExpand::generate_nonpositive_guard(Node** ctrl, Node* index, bool never_negative) { + if ((*ctrl)->is_top()) return NULL; + + if (_igvn.type(index)->higher_equal(TypeInt::POS1)) // [1,maxint] + return NULL; // index is already adequately typed + Node* cmp_le = new CmpINode(index, intcon(0)); + transform_later(cmp_le); + BoolTest::mask le_or_eq = (never_negative ? BoolTest::eq : BoolTest::le); + Node* bol_le = new BoolNode(cmp_le, le_or_eq); + transform_later(bol_le); + Node* is_notp = generate_guard(ctrl, bol_le, NULL, PROB_MIN); + + return is_notp; +} + +void PhaseMacroExpand::finish_arraycopy_call(Node* call, Node** ctrl, MergeMemNode** mem, const TypePtr* adr_type) { + transform_later(call); + + *ctrl = new ProjNode(call,TypeFunc::Control); + transform_later(*ctrl); + Node* newmem = new ProjNode(call, TypeFunc::Memory); + transform_later(newmem); + + uint alias_idx = C->get_alias_index(adr_type); + if (alias_idx != Compile::AliasIdxBot) { + *mem = MergeMemNode::make(*mem); + (*mem)->set_memory_at(alias_idx, newmem); + } else { + *mem = MergeMemNode::make(newmem); + } + transform_later(*mem); +} + +address PhaseMacroExpand::basictype2arraycopy(BasicType t, + Node* src_offset, + Node* dest_offset, + bool disjoint_bases, + const char* &name, + bool dest_uninitialized) { + const TypeInt* src_offset_inttype = _igvn.find_int_type(src_offset);; + const TypeInt* dest_offset_inttype = _igvn.find_int_type(dest_offset);; + + bool aligned = false; + bool disjoint = disjoint_bases; + + // if the offsets are the same, we can treat the memory regions as + // disjoint, because either the memory regions are in different arrays, + // or they are identical (which we can treat as disjoint.) We can also + // treat a copy with a destination index less that the source index + // as disjoint since a low->high copy will work correctly in this case. + if (src_offset_inttype != NULL && src_offset_inttype->is_con() && + dest_offset_inttype != NULL && dest_offset_inttype->is_con()) { + // both indices are constants + int s_offs = src_offset_inttype->get_con(); + int d_offs = dest_offset_inttype->get_con(); + int element_size = type2aelembytes(t); + aligned = ((arrayOopDesc::base_offset_in_bytes(t) + s_offs * element_size) % HeapWordSize == 0) && + ((arrayOopDesc::base_offset_in_bytes(t) + d_offs * element_size) % HeapWordSize == 0); + if (s_offs >= d_offs) disjoint = true; + } else if (src_offset == dest_offset && src_offset != NULL) { + // This can occur if the offsets are identical non-constants. + disjoint = true; + } + + return StubRoutines::select_arraycopy_function(t, aligned, disjoint, name, dest_uninitialized); +} + +#define COMMA , +#define XTOP LP64_ONLY(COMMA top()) + +// Generate an optimized call to arraycopy. +// Caller must guard against non-arrays. +// Caller must determine a common array basic-type for both arrays. +// Caller must validate offsets against array bounds. +// The slow_region has already collected guard failure paths +// (such as out of bounds length or non-conformable array types). +// The generated code has this shape, in general: +// +// if (length == 0) return // via zero_path +// slowval = -1 +// if (types unknown) { +// slowval = call generic copy loop +// if (slowval == 0) return // via checked_path +// } else if (indexes in bounds) { +// if ((is object array) && !(array type check)) { +// slowval = call checked copy loop +// if (slowval == 0) return // via checked_path +// } else { +// call bulk copy loop +// return // via fast_path +// } +// } +// // adjust params for remaining work: +// if (slowval != -1) { +// n = -1^slowval; src_offset += n; dest_offset += n; length -= n +// } +// slow_region: +// call slow arraycopy(src, src_offset, dest, dest_offset, length) +// return // via slow_call_path +// +// This routine is used from several intrinsics: System.arraycopy, +// Object.clone (the array subcase), and Arrays.copyOf[Range]. +// +Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode* alloc, + Node** ctrl, MergeMemNode* mem, Node** io, + const TypePtr* adr_type, + BasicType basic_elem_type, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, + bool disjoint_bases, + bool length_never_negative, + RegionNode* slow_region) { + if (slow_region == NULL) { + slow_region = new RegionNode(1); + transform_later(slow_region); + } + + Node* original_dest = dest; + bool dest_uninitialized = false; + + // See if this is the initialization of a newly-allocated array. + // If so, we will take responsibility here for initializing it to zero. + // (Note: Because tightly_coupled_allocation performs checks on the + // out-edges of the dest, we need to avoid making derived pointers + // from it until we have checked its uses.) + if (ReduceBulkZeroing + && !ZeroTLAB // pointless if already zeroed + && basic_elem_type != T_CONFLICT // avoid corner case + && !src->eqv_uncast(dest) + && alloc != NULL + && _igvn.find_int_con(alloc->in(AllocateNode::ALength), 1) > 0 + && alloc->maybe_set_complete(&_igvn)) { + // "You break it, you buy it." + InitializeNode* init = alloc->initialization(); + assert(init->is_complete(), "we just did this"); + init->set_complete_with_arraycopy(); + assert(dest->is_CheckCastPP(), "sanity"); + assert(dest->in(0)->in(0) == init, "dest pinned"); + adr_type = TypeRawPtr::BOTTOM; // all initializations are into raw memory + // From this point on, every exit path is responsible for + // initializing any non-copied parts of the object to zero. + // Also, if this flag is set we make sure that arraycopy interacts properly + // with G1, eliding pre-barriers. See CR 6627983. + dest_uninitialized = true; + } else { + // No zeroing elimination here. + alloc = NULL; + //original_dest = dest; + //dest_uninitialized = false; + } + + uint alias_idx = C->get_alias_index(adr_type); + + // Results are placed here: + enum { fast_path = 1, // normal void-returning assembly stub + checked_path = 2, // special assembly stub with cleanup + slow_call_path = 3, // something went wrong; call the VM + zero_path = 4, // bypass when length of copy is zero + bcopy_path = 5, // copy primitive array by 64-bit blocks + PATH_LIMIT = 6 + }; + RegionNode* result_region = new RegionNode(PATH_LIMIT); + PhiNode* result_i_o = new PhiNode(result_region, Type::ABIO); + PhiNode* result_memory = new PhiNode(result_region, Type::MEMORY, adr_type); + assert(adr_type != TypePtr::BOTTOM, "must be RawMem or a T[] slice"); + transform_later(result_region); + transform_later(result_i_o); + transform_later(result_memory); + + // The slow_control path: + Node* slow_control; + Node* slow_i_o = *io; + Node* slow_mem = mem->memory_at(alias_idx); + DEBUG_ONLY(slow_control = (Node*) badAddress); + + // Checked control path: + Node* checked_control = top(); + Node* checked_mem = NULL; + Node* checked_i_o = NULL; + Node* checked_value = NULL; + + if (basic_elem_type == T_CONFLICT) { + assert(!dest_uninitialized, ""); + Node* cv = generate_generic_arraycopy(ctrl, &mem, + adr_type, + src, src_offset, dest, dest_offset, + copy_length, dest_uninitialized); + if (cv == NULL) cv = intcon(-1); // failure (no stub available) + checked_control = *ctrl; + checked_i_o = *io; + checked_mem = mem->memory_at(alias_idx); + checked_value = cv; + *ctrl = top(); + } + + Node* not_pos = generate_nonpositive_guard(ctrl, copy_length, length_never_negative); + if (not_pos != NULL) { + Node* local_ctrl = not_pos, *local_io = *io; + MergeMemNode* local_mem = MergeMemNode::make(mem); + transform_later(local_mem); + + // (6) length must not be negative. + if (!length_never_negative) { + generate_negative_guard(&local_ctrl, copy_length, slow_region); + } + + // copy_length is 0. + if (dest_uninitialized) { + assert(!local_ctrl->is_top(), "no ctrl?"); + Node* dest_length = alloc->in(AllocateNode::ALength); + if (copy_length->eqv_uncast(dest_length) + || _igvn.find_int_con(dest_length, 1) <= 0) { + // There is no zeroing to do. No need for a secondary raw memory barrier. + } else { + // Clear the whole thing since there are no source elements to copy. + generate_clear_array(local_ctrl, local_mem, + adr_type, dest, basic_elem_type, + intcon(0), NULL, + alloc->in(AllocateNode::AllocSize)); + // Use a secondary InitializeNode as raw memory barrier. + // Currently it is needed only on this path since other + // paths have stub or runtime calls as raw memory barriers. + MemBarNode* mb = MemBarNode::make(C, Op_Initialize, + Compile::AliasIdxRaw, + top()); + transform_later(mb); + mb->set_req(TypeFunc::Control,local_ctrl); + mb->set_req(TypeFunc::Memory, local_mem->memory_at(Compile::AliasIdxRaw)); + local_ctrl = transform_later(new ProjNode(mb, TypeFunc::Control)); + local_mem->set_memory_at(Compile::AliasIdxRaw, transform_later(new ProjNode(mb, TypeFunc::Memory))); + + InitializeNode* init = mb->as_Initialize(); + init->set_complete(&_igvn); // (there is no corresponding AllocateNode) + } + } + + // Present the results of the fast call. + result_region->init_req(zero_path, local_ctrl); + result_i_o ->init_req(zero_path, local_io); + result_memory->init_req(zero_path, local_mem->memory_at(alias_idx)); + } + + if (!(*ctrl)->is_top() && dest_uninitialized) { + // We have to initialize the *uncopied* part of the array to zero. + // The copy destination is the slice dest[off..off+len]. The other slices + // are dest_head = dest[0..off] and dest_tail = dest[off+len..dest.length]. + Node* dest_size = alloc->in(AllocateNode::AllocSize); + Node* dest_length = alloc->in(AllocateNode::ALength); + Node* dest_tail = transform_later( new AddINode(dest_offset, copy_length)); + + // If there is a head section that needs zeroing, do it now. + if (_igvn.find_int_con(dest_offset, -1) != 0) { + generate_clear_array(*ctrl, mem, + adr_type, dest, basic_elem_type, + intcon(0), dest_offset, + NULL); + } + + // Next, perform a dynamic check on the tail length. + // It is often zero, and we can win big if we prove this. + // There are two wins: Avoid generating the ClearArray + // with its attendant messy index arithmetic, and upgrade + // the copy to a more hardware-friendly word size of 64 bits. + Node* tail_ctl = NULL; + if (!(*ctrl)->is_top() && !dest_tail->eqv_uncast(dest_length)) { + Node* cmp_lt = transform_later( new CmpINode(dest_tail, dest_length) ); + Node* bol_lt = transform_later( new BoolNode(cmp_lt, BoolTest::lt) ); + tail_ctl = generate_slow_guard(ctrl, bol_lt, NULL); + assert(tail_ctl != NULL || !(*ctrl)->is_top(), "must be an outcome"); + } + + // At this point, let's assume there is no tail. + if (!(*ctrl)->is_top() && alloc != NULL && basic_elem_type != T_OBJECT) { + // There is no tail. Try an upgrade to a 64-bit copy. + bool didit = false; + { + Node* local_ctrl = *ctrl, *local_io = *io; + MergeMemNode* local_mem = MergeMemNode::make(mem); + transform_later(local_mem); + + didit = generate_block_arraycopy(&local_ctrl, &local_mem, local_io, + adr_type, basic_elem_type, alloc, + src, src_offset, dest, dest_offset, + dest_size, dest_uninitialized); + if (didit) { + // Present the results of the block-copying fast call. + result_region->init_req(bcopy_path, local_ctrl); + result_i_o ->init_req(bcopy_path, local_io); + result_memory->init_req(bcopy_path, local_mem->memory_at(alias_idx)); + } + } + if (didit) { + *ctrl = top(); // no regular fast path + } + } + + // Clear the tail, if any. + if (tail_ctl != NULL) { + Node* notail_ctl = (*ctrl)->is_top() ? NULL : *ctrl; + *ctrl = tail_ctl; + if (notail_ctl == NULL) { + generate_clear_array(*ctrl, mem, + adr_type, dest, basic_elem_type, + dest_tail, NULL, + dest_size); + } else { + // Make a local merge. + Node* done_ctl = transform_later(new RegionNode(3)); + Node* done_mem = transform_later(new PhiNode(done_ctl, Type::MEMORY, adr_type)); + done_ctl->init_req(1, notail_ctl); + done_mem->init_req(1, mem->memory_at(alias_idx)); + generate_clear_array(*ctrl, mem, + adr_type, dest, basic_elem_type, + dest_tail, NULL, + dest_size); + done_ctl->init_req(2, *ctrl); + done_mem->init_req(2, mem->memory_at(alias_idx)); + *ctrl = done_ctl; + mem->set_memory_at(alias_idx, done_mem); + } + } + } + + BasicType copy_type = basic_elem_type; + assert(basic_elem_type != T_ARRAY, "caller must fix this"); + if (!(*ctrl)->is_top() && copy_type == T_OBJECT) { + // If src and dest have compatible element types, we can copy bits. + // Types S[] and D[] are compatible if D is a supertype of S. + // + // If they are not, we will use checked_oop_disjoint_arraycopy, + // which performs a fast optimistic per-oop check, and backs off + // further to JVM_ArrayCopy on the first per-oop check that fails. + // (Actually, we don't move raw bits only; the GC requires card marks.) + + // Get the klass* for both src and dest + Node* src_klass = ac->in(ArrayCopyNode::SrcKlass); + Node* dest_klass = ac->in(ArrayCopyNode::DestKlass); + + // Generate the subtype check. + // This might fold up statically, or then again it might not. + // + // Non-static example: Copying List.elements to a new String[]. + // The backing store for a List is always an Object[], + // but its elements are always type String, if the generic types + // are correct at the source level. + // + // Test S[] against D[], not S against D, because (probably) + // the secondary supertype cache is less busy for S[] than S. + // This usually only matters when D is an interface. + Node* not_subtype_ctrl = ac->is_arraycopy_notest() ? top() : Phase::gen_subtype_check(src_klass, dest_klass, ctrl, mem, &_igvn); + // Plug failing path into checked_oop_disjoint_arraycopy + if (not_subtype_ctrl != top()) { + Node* local_ctrl = not_subtype_ctrl; + MergeMemNode* local_mem = MergeMemNode::make(mem); + transform_later(local_mem); + + // (At this point we can assume disjoint_bases, since types differ.) + int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); + Node* p1 = basic_plus_adr(dest_klass, ek_offset); + Node* n1 = LoadKlassNode::make(_igvn, C->immutable_memory(), p1, TypeRawPtr::BOTTOM); + Node* dest_elem_klass = transform_later(n1); + Node* cv = generate_checkcast_arraycopy(&local_ctrl, &local_mem, + adr_type, + dest_elem_klass, + src, src_offset, dest, dest_offset, + ConvI2X(copy_length), dest_uninitialized); + if (cv == NULL) cv = intcon(-1); // failure (no stub available) + checked_control = local_ctrl; + checked_i_o = *io; + checked_mem = local_mem->memory_at(alias_idx); + checked_value = cv; + } + // At this point we know we do not need type checks on oop stores. + + // Let's see if we need card marks: + if (alloc != NULL && GraphKit::use_ReduceInitialCardMarks()) { + // If we do not need card marks, copy using the jint or jlong stub. + copy_type = LP64_ONLY(UseCompressedOops ? T_INT : T_LONG) NOT_LP64(T_INT); + assert(type2aelembytes(basic_elem_type) == type2aelembytes(copy_type), + "sizes agree"); + } + } + + if (!(*ctrl)->is_top()) { + // Generate the fast path, if possible. + Node* local_ctrl = *ctrl; + MergeMemNode* local_mem = MergeMemNode::make(mem); + transform_later(local_mem); + + generate_unchecked_arraycopy(&local_ctrl, &local_mem, + adr_type, copy_type, disjoint_bases, + src, src_offset, dest, dest_offset, + ConvI2X(copy_length), dest_uninitialized); + + // Present the results of the fast call. + result_region->init_req(fast_path, local_ctrl); + result_i_o ->init_req(fast_path, *io); + result_memory->init_req(fast_path, local_mem->memory_at(alias_idx)); + } + + // Here are all the slow paths up to this point, in one bundle: + assert(slow_region != NULL, "allocated on entry"); + slow_control = slow_region; + DEBUG_ONLY(slow_region = (RegionNode*)badAddress); + + *ctrl = checked_control; + if (!(*ctrl)->is_top()) { + // Clean up after the checked call. + // The returned value is either 0 or -1^K, + // where K = number of partially transferred array elements. + Node* cmp = new CmpINode(checked_value, intcon(0)); + transform_later(cmp); + Node* bol = new BoolNode(cmp, BoolTest::eq); + transform_later(bol); + IfNode* iff = new IfNode(*ctrl, bol, PROB_MAX, COUNT_UNKNOWN); + transform_later(iff); + + // If it is 0, we are done, so transfer to the end. + Node* checks_done = new IfTrueNode(iff); + transform_later(checks_done); + result_region->init_req(checked_path, checks_done); + result_i_o ->init_req(checked_path, checked_i_o); + result_memory->init_req(checked_path, checked_mem); + + // If it is not zero, merge into the slow call. + *ctrl = new IfFalseNode(iff); + transform_later(*ctrl); + RegionNode* slow_reg2 = new RegionNode(3); + PhiNode* slow_i_o2 = new PhiNode(slow_reg2, Type::ABIO); + PhiNode* slow_mem2 = new PhiNode(slow_reg2, Type::MEMORY, adr_type); + transform_later(slow_reg2); + transform_later(slow_i_o2); + transform_later(slow_mem2); + slow_reg2 ->init_req(1, slow_control); + slow_i_o2 ->init_req(1, slow_i_o); + slow_mem2 ->init_req(1, slow_mem); + slow_reg2 ->init_req(2, *ctrl); + slow_i_o2 ->init_req(2, checked_i_o); + slow_mem2 ->init_req(2, checked_mem); + + slow_control = slow_reg2; + slow_i_o = slow_i_o2; + slow_mem = slow_mem2; + + if (alloc != NULL) { + // We'll restart from the very beginning, after zeroing the whole thing. + // This can cause double writes, but that's OK since dest is brand new. + // So we ignore the low 31 bits of the value returned from the stub. + } else { + // We must continue the copy exactly where it failed, or else + // another thread might see the wrong number of writes to dest. + Node* checked_offset = new XorINode(checked_value, intcon(-1)); + Node* slow_offset = new PhiNode(slow_reg2, TypeInt::INT); + transform_later(checked_offset); + transform_later(slow_offset); + slow_offset->init_req(1, intcon(0)); + slow_offset->init_req(2, checked_offset); + + // Adjust the arguments by the conditionally incoming offset. + Node* src_off_plus = new AddINode(src_offset, slow_offset); + transform_later(src_off_plus); + Node* dest_off_plus = new AddINode(dest_offset, slow_offset); + transform_later(dest_off_plus); + Node* length_minus = new SubINode(copy_length, slow_offset); + transform_later(length_minus); + + // Tweak the node variables to adjust the code produced below: + src_offset = src_off_plus; + dest_offset = dest_off_plus; + copy_length = length_minus; + } + } + *ctrl = slow_control; + if (!(*ctrl)->is_top()) { + Node* local_ctrl = *ctrl, *local_io = slow_i_o; + MergeMemNode* local_mem = MergeMemNode::make(mem); + transform_later(local_mem); + + // Generate the slow path, if needed. + local_mem->set_memory_at(alias_idx, slow_mem); + + if (dest_uninitialized) { + generate_clear_array(local_ctrl, local_mem, + adr_type, dest, basic_elem_type, + intcon(0), NULL, + alloc->in(AllocateNode::AllocSize)); + } + + local_mem = generate_slow_arraycopy(ac, + &local_ctrl, local_mem, &local_io, + adr_type, + src, src_offset, dest, dest_offset, + copy_length, /*dest_uninitialized*/false); + + result_region->init_req(slow_call_path, local_ctrl); + result_i_o ->init_req(slow_call_path, local_io); + result_memory->init_req(slow_call_path, local_mem->memory_at(alias_idx)); + } else { + ShouldNotReachHere(); // no call to generate_slow_arraycopy: + // projections were not extracted + } + + // Remove unused edges. + for (uint i = 1; i < result_region->req(); i++) { + if (result_region->in(i) == NULL) { + result_region->init_req(i, top()); + } + } + + // Finished; return the combined state. + *ctrl = result_region; + *io = result_i_o; + mem->set_memory_at(alias_idx, result_memory); + + // mem no longer guaranteed to stay a MergeMemNode + Node* out_mem = mem; + DEBUG_ONLY(mem = NULL); + + // The memory edges above are precise in order to model effects around + // array copies accurately to allow value numbering of field loads around + // arraycopy. Such field loads, both before and after, are common in Java + // collections and similar classes involving header/array data structures. + // + // But with low number of register or when some registers are used or killed + // by arraycopy calls it causes registers spilling on stack. See 6544710. + // The next memory barrier is added to avoid it. If the arraycopy can be + // optimized away (which it can, sometimes) then we can manually remove + // the membar also. + // + // Do not let reads from the cloned object float above the arraycopy. + if (alloc != NULL && !alloc->initialization()->does_not_escape()) { + // Do not let stores that initialize this object be reordered with + // a subsequent store that would make this object accessible by + // other threads. + insert_mem_bar(ctrl, &out_mem, Op_MemBarStoreStore); + } else if (InsertMemBarAfterArraycopy) { + insert_mem_bar(ctrl, &out_mem, Op_MemBarCPUOrder); + } + + _igvn.replace_node(_memproj_fallthrough, out_mem); + _igvn.replace_node(_ioproj_fallthrough, *io); + _igvn.replace_node(_fallthroughcatchproj, *ctrl); + + return out_mem; +} + +// Helper for initialization of arrays, creating a ClearArray. +// It writes zero bits in [start..end), within the body of an array object. +// The memory effects are all chained onto the 'adr_type' alias category. +// +// Since the object is otherwise uninitialized, we are free +// to put a little "slop" around the edges of the cleared area, +// as long as it does not go back into the array's header, +// or beyond the array end within the heap. +// +// The lower edge can be rounded down to the nearest jint and the +// upper edge can be rounded up to the nearest MinObjAlignmentInBytes. +// +// Arguments: +// adr_type memory slice where writes are generated +// dest oop of the destination array +// basic_elem_type element type of the destination +// slice_idx array index of first element to store +// slice_len number of elements to store (or NULL) +// dest_size total size in bytes of the array object +// +// Exactly one of slice_len or dest_size must be non-NULL. +// If dest_size is non-NULL, zeroing extends to the end of the object. +// If slice_len is non-NULL, the slice_idx value must be a constant. +void PhaseMacroExpand::generate_clear_array(Node* ctrl, MergeMemNode* merge_mem, + const TypePtr* adr_type, + Node* dest, + BasicType basic_elem_type, + Node* slice_idx, + Node* slice_len, + Node* dest_size) { + // one or the other but not both of slice_len and dest_size: + assert((slice_len != NULL? 1: 0) + (dest_size != NULL? 1: 0) == 1, ""); + if (slice_len == NULL) slice_len = top(); + if (dest_size == NULL) dest_size = top(); + + uint alias_idx = C->get_alias_index(adr_type); + + // operate on this memory slice: + Node* mem = merge_mem->memory_at(alias_idx); // memory slice to operate on + + // scaling and rounding of indexes: + int scale = exact_log2(type2aelembytes(basic_elem_type)); + int abase = arrayOopDesc::base_offset_in_bytes(basic_elem_type); + int clear_low = (-1 << scale) & (BytesPerInt - 1); + int bump_bit = (-1 << scale) & BytesPerInt; + + // determine constant starts and ends + const intptr_t BIG_NEG = -128; + assert(BIG_NEG + 2*abase < 0, "neg enough"); + intptr_t slice_idx_con = (intptr_t) _igvn.find_int_con(slice_idx, BIG_NEG); + intptr_t slice_len_con = (intptr_t) _igvn.find_int_con(slice_len, BIG_NEG); + if (slice_len_con == 0) { + return; // nothing to do here + } + intptr_t start_con = (abase + (slice_idx_con << scale)) & ~clear_low; + intptr_t end_con = _igvn.find_intptr_t_con(dest_size, -1); + if (slice_idx_con >= 0 && slice_len_con >= 0) { + assert(end_con < 0, "not two cons"); + end_con = round_to(abase + ((slice_idx_con + slice_len_con) << scale), + BytesPerLong); + } + + if (start_con >= 0 && end_con >= 0) { + // Constant start and end. Simple. + mem = ClearArrayNode::clear_memory(ctrl, mem, dest, + start_con, end_con, &_igvn); + } else if (start_con >= 0 && dest_size != top()) { + // Constant start, pre-rounded end after the tail of the array. + Node* end = dest_size; + mem = ClearArrayNode::clear_memory(ctrl, mem, dest, + start_con, end, &_igvn); + } else if (start_con >= 0 && slice_len != top()) { + // Constant start, non-constant end. End needs rounding up. + // End offset = round_up(abase + ((slice_idx_con + slice_len) << scale), 8) + intptr_t end_base = abase + (slice_idx_con << scale); + int end_round = (-1 << scale) & (BytesPerLong - 1); + Node* end = ConvI2X(slice_len); + if (scale != 0) + end = transform_later(new LShiftXNode(end, intcon(scale) )); + end_base += end_round; + end = transform_later(new AddXNode(end, MakeConX(end_base)) ); + end = transform_later(new AndXNode(end, MakeConX(~end_round)) ); + mem = ClearArrayNode::clear_memory(ctrl, mem, dest, + start_con, end, &_igvn); + } else if (start_con < 0 && dest_size != top()) { + // Non-constant start, pre-rounded end after the tail of the array. + // This is almost certainly a "round-to-end" operation. + Node* start = slice_idx; + start = ConvI2X(start); + if (scale != 0) + start = transform_later(new LShiftXNode( start, intcon(scale) )); + start = transform_later(new AddXNode(start, MakeConX(abase)) ); + if ((bump_bit | clear_low) != 0) { + int to_clear = (bump_bit | clear_low); + // Align up mod 8, then store a jint zero unconditionally + // just before the mod-8 boundary. + if (((abase + bump_bit) & ~to_clear) - bump_bit + < arrayOopDesc::length_offset_in_bytes() + BytesPerInt) { + bump_bit = 0; + assert((abase & to_clear) == 0, "array base must be long-aligned"); + } else { + // Bump 'start' up to (or past) the next jint boundary: + start = transform_later( new AddXNode(start, MakeConX(bump_bit)) ); + assert((abase & clear_low) == 0, "array base must be int-aligned"); + } + // Round bumped 'start' down to jlong boundary in body of array. + start = transform_later(new AndXNode(start, MakeConX(~to_clear)) ); + if (bump_bit != 0) { + // Store a zero to the immediately preceding jint: + Node* x1 = transform_later(new AddXNode(start, MakeConX(-bump_bit)) ); + Node* p1 = basic_plus_adr(dest, x1); + mem = StoreNode::make(_igvn, ctrl, mem, p1, adr_type, intcon(0), T_INT, MemNode::unordered); + mem = transform_later(mem); + } + } + Node* end = dest_size; // pre-rounded + mem = ClearArrayNode::clear_memory(ctrl, mem, dest, + start, end, &_igvn); + } else { + // Non-constant start, unrounded non-constant end. + // (Nobody zeroes a random midsection of an array using this routine.) + ShouldNotReachHere(); // fix caller + } + + // Done. + merge_mem->set_memory_at(alias_idx, mem); +} + +bool PhaseMacroExpand::generate_block_arraycopy(Node** ctrl, MergeMemNode** mem, Node* io, + const TypePtr* adr_type, + BasicType basic_elem_type, + AllocateNode* alloc, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* dest_size, bool dest_uninitialized) { + // See if there is an advantage from block transfer. + int scale = exact_log2(type2aelembytes(basic_elem_type)); + if (scale >= LogBytesPerLong) + return false; // it is already a block transfer + + // Look at the alignment of the starting offsets. + int abase = arrayOopDesc::base_offset_in_bytes(basic_elem_type); + + intptr_t src_off_con = (intptr_t) _igvn.find_int_con(src_offset, -1); + intptr_t dest_off_con = (intptr_t) _igvn.find_int_con(dest_offset, -1); + if (src_off_con < 0 || dest_off_con < 0) { + // At present, we can only understand constants. + return false; + } + + intptr_t src_off = abase + (src_off_con << scale); + intptr_t dest_off = abase + (dest_off_con << scale); + + if (((src_off | dest_off) & (BytesPerLong-1)) != 0) { + // Non-aligned; too bad. + // One more chance: Pick off an initial 32-bit word. + // This is a common case, since abase can be odd mod 8. + if (((src_off | dest_off) & (BytesPerLong-1)) == BytesPerInt && + ((src_off ^ dest_off) & (BytesPerLong-1)) == 0) { + Node* sptr = basic_plus_adr(src, src_off); + Node* dptr = basic_plus_adr(dest, dest_off); + uint alias_idx = C->get_alias_index(adr_type); + Node* sval = transform_later(LoadNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), sptr, adr_type, TypeInt::INT, T_INT, MemNode::unordered)); + Node* st = transform_later(StoreNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), dptr, adr_type, sval, T_INT, MemNode::unordered)); + (*mem)->set_memory_at(alias_idx, st); + src_off += BytesPerInt; + dest_off += BytesPerInt; + } else { + return false; + } + } + assert(src_off % BytesPerLong == 0, ""); + assert(dest_off % BytesPerLong == 0, ""); + + // Do this copy by giant steps. + Node* sptr = basic_plus_adr(src, src_off); + Node* dptr = basic_plus_adr(dest, dest_off); + Node* countx = dest_size; + countx = transform_later(new SubXNode(countx, MakeConX(dest_off))); + countx = transform_later(new URShiftXNode(countx, intcon(LogBytesPerLong))); + + bool disjoint_bases = true; // since alloc != NULL + generate_unchecked_arraycopy(ctrl, mem, + adr_type, T_LONG, disjoint_bases, + sptr, NULL, dptr, NULL, countx, dest_uninitialized); + + return true; +} + +// Helper function; generates code for the slow case. +// We make a call to a runtime method which emulates the native method, +// but without the native wrapper overhead. +MergeMemNode* PhaseMacroExpand::generate_slow_arraycopy(ArrayCopyNode *ac, + Node** ctrl, Node* mem, Node** io, + const TypePtr* adr_type, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, bool dest_uninitialized) { + assert(!dest_uninitialized, "Invariant"); + + const TypeFunc* call_type = OptoRuntime::slow_arraycopy_Type(); + CallNode* call = new CallStaticJavaNode(call_type, OptoRuntime::slow_arraycopy_Java(), + "slow_arraycopy", + ac->jvms()->bci(), TypePtr::BOTTOM); + + call->init_req(TypeFunc::Control, *ctrl); + call->init_req(TypeFunc::I_O , *io); + call->init_req(TypeFunc::Memory , mem); + call->init_req(TypeFunc::ReturnAdr, top()); + call->init_req(TypeFunc::FramePtr, top()); + call->init_req(TypeFunc::Parms+0, src); + call->init_req(TypeFunc::Parms+1, src_offset); + call->init_req(TypeFunc::Parms+2, dest); + call->init_req(TypeFunc::Parms+3, dest_offset); + call->init_req(TypeFunc::Parms+4, copy_length); + copy_call_debug_info(ac, call); + + call->set_cnt(PROB_UNLIKELY_MAG(4)); // Same effect as RC_UNCOMMON. + _igvn.replace_node(ac, call); + transform_later(call); + + extract_call_projections(call); + *ctrl = _fallthroughcatchproj->clone(); + transform_later(*ctrl); + + Node* m = _memproj_fallthrough->clone(); + transform_later(m); + + uint alias_idx = C->get_alias_index(adr_type); + MergeMemNode* out_mem; + if (alias_idx != Compile::AliasIdxBot) { + out_mem = MergeMemNode::make(mem); + out_mem->set_memory_at(alias_idx, m); + } else { + out_mem = MergeMemNode::make(m); + } + transform_later(out_mem); + + *io = _ioproj_fallthrough->clone(); + transform_later(*io); + + return out_mem; +} + +// Helper function; generates code for cases requiring runtime checks. +Node* PhaseMacroExpand::generate_checkcast_arraycopy(Node** ctrl, MergeMemNode** mem, + const TypePtr* adr_type, + Node* dest_elem_klass, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, bool dest_uninitialized) { + if ((*ctrl)->is_top()) return NULL; + + address copyfunc_addr = StubRoutines::checkcast_arraycopy(dest_uninitialized); + if (copyfunc_addr == NULL) { // Stub was not generated, go slow path. + return NULL; + } + + // Pick out the parameters required to perform a store-check + // for the target array. This is an optimistic check. It will + // look in each non-null element's class, at the desired klass's + // super_check_offset, for the desired klass. + int sco_offset = in_bytes(Klass::super_check_offset_offset()); + Node* p3 = basic_plus_adr(dest_elem_klass, sco_offset); + Node* n3 = new LoadINode(NULL, *mem /*memory(p3)*/, p3, _igvn.type(p3)->is_ptr(), TypeInt::INT, MemNode::unordered); + Node* check_offset = ConvI2X(transform_later(n3)); + Node* check_value = dest_elem_klass; + + Node* src_start = array_element_address(src, src_offset, T_OBJECT); + Node* dest_start = array_element_address(dest, dest_offset, T_OBJECT); + + const TypeFunc* call_type = OptoRuntime::checkcast_arraycopy_Type(); + Node* call = make_leaf_call(*ctrl, *mem, call_type, copyfunc_addr, "checkcast_arraycopy", adr_type, + src_start, dest_start, copy_length XTOP, check_offset XTOP, check_value); + + finish_arraycopy_call(call, ctrl, mem, adr_type); + + Node* proj = new ProjNode(call, TypeFunc::Parms); + transform_later(proj); + + return proj; +} + +// Helper function; generates code for cases requiring runtime checks. +Node* PhaseMacroExpand::generate_generic_arraycopy(Node** ctrl, MergeMemNode** mem, + const TypePtr* adr_type, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, bool dest_uninitialized) { + if ((*ctrl)->is_top()) return NULL; + assert(!dest_uninitialized, "Invariant"); + + address copyfunc_addr = StubRoutines::generic_arraycopy(); + if (copyfunc_addr == NULL) { // Stub was not generated, go slow path. + return NULL; + } + + const TypeFunc* call_type = OptoRuntime::generic_arraycopy_Type(); + Node* call = make_leaf_call(*ctrl, *mem, call_type, copyfunc_addr, "generic_arraycopy", adr_type, + src, src_offset, dest, dest_offset, copy_length); + + finish_arraycopy_call(call, ctrl, mem, adr_type); + + Node* proj = new ProjNode(call, TypeFunc::Parms); + transform_later(proj); + + return proj; +} + +// Helper function; generates the fast out-of-line call to an arraycopy stub. +void PhaseMacroExpand::generate_unchecked_arraycopy(Node** ctrl, MergeMemNode** mem, + const TypePtr* adr_type, + BasicType basic_elem_type, + bool disjoint_bases, + Node* src, Node* src_offset, + Node* dest, Node* dest_offset, + Node* copy_length, bool dest_uninitialized) { + if ((*ctrl)->is_top()) return; + + Node* src_start = src; + Node* dest_start = dest; + if (src_offset != NULL || dest_offset != NULL) { + src_start = array_element_address(src, src_offset, basic_elem_type); + dest_start = array_element_address(dest, dest_offset, basic_elem_type); + } + + // Figure out which arraycopy runtime method to call. + const char* copyfunc_name = "arraycopy"; + address copyfunc_addr = + basictype2arraycopy(basic_elem_type, src_offset, dest_offset, + disjoint_bases, copyfunc_name, dest_uninitialized); + + const TypeFunc* call_type = OptoRuntime::fast_arraycopy_Type(); + Node* call = make_leaf_call(*ctrl, *mem, call_type, copyfunc_addr, copyfunc_name, adr_type, + src_start, dest_start, copy_length XTOP); + + finish_arraycopy_call(call, ctrl, mem, adr_type); +} + +void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) { + Node* ctrl = ac->in(TypeFunc::Control); + Node* io = ac->in(TypeFunc::I_O); + Node* src = ac->in(ArrayCopyNode::Src); + Node* src_offset = ac->in(ArrayCopyNode::SrcPos); + Node* dest = ac->in(ArrayCopyNode::Dest); + Node* dest_offset = ac->in(ArrayCopyNode::DestPos); + Node* length = ac->in(ArrayCopyNode::Length); + MergeMemNode* merge_mem = NULL; + + if (ac->is_clonebasic()) { + assert (src_offset == NULL && dest_offset == NULL, "for clone offsets should be null"); + Node* mem = ac->in(TypeFunc::Memory); + const char* copyfunc_name = "arraycopy"; + address copyfunc_addr = + basictype2arraycopy(T_LONG, NULL, NULL, + true, copyfunc_name, true); + + const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM; + const TypeFunc* call_type = OptoRuntime::fast_arraycopy_Type(); + + Node* call = make_leaf_call(ctrl, mem, call_type, copyfunc_addr, copyfunc_name, raw_adr_type, src, dest, length XTOP); + transform_later(call); + + _igvn.replace_node(ac, call); + return; + } else if (ac->is_copyof() || ac->is_copyofrange() || ac->is_cloneoop()) { + Node* mem = ac->in(TypeFunc::Memory); + merge_mem = MergeMemNode::make(mem); + transform_later(merge_mem); + + RegionNode* slow_region = new RegionNode(1); + transform_later(slow_region); + + AllocateArrayNode* alloc = NULL; + if (ac->is_alloc_tightly_coupled()) { + alloc = AllocateArrayNode::Ideal_array_allocation(dest, &_igvn); + assert(alloc != NULL, "expect alloc"); + } + + generate_arraycopy(ac, alloc, &ctrl, merge_mem, &io, + TypeAryPtr::OOPS, T_OBJECT, + src, src_offset, dest, dest_offset, length, + true, !ac->is_copyofrange()); + + return; + } + + AllocateArrayNode* alloc = NULL; + if (ac->is_alloc_tightly_coupled()) { + alloc = AllocateArrayNode::Ideal_array_allocation(dest, &_igvn); + assert(alloc != NULL, "expect alloc"); + } + + assert(ac->is_arraycopy() || ac->is_arraycopy_notest(), "should be an arraycopy"); + + // Compile time checks. If any of these checks cannot be verified at compile time, + // we do not make a fast path for this call. Instead, we let the call remain as it + // is. The checks we choose to mandate at compile time are: + // + // (1) src and dest are arrays. + const Type* src_type = src->Value(&_igvn); + const Type* dest_type = dest->Value(&_igvn); + const TypeAryPtr* top_src = src_type->isa_aryptr(); + const TypeAryPtr* top_dest = dest_type->isa_aryptr(); + + if (top_src == NULL || top_src->klass() == NULL || + top_dest == NULL || top_dest->klass() == NULL) { + // Conservatively insert a memory barrier on all memory slices. + // Do not let writes into the source float below the arraycopy. + { + Node* mem = ac->in(TypeFunc::Memory); + insert_mem_bar(&ctrl, &mem, Op_MemBarCPUOrder); + + merge_mem = MergeMemNode::make(mem); + transform_later(merge_mem); + } + + // Call StubRoutines::generic_arraycopy stub. + Node* mem = generate_arraycopy(ac, NULL, &ctrl, merge_mem, &io, + TypeRawPtr::BOTTOM, T_CONFLICT, + src, src_offset, dest, dest_offset, length); + + // Do not let reads from the destination float above the arraycopy. + // Since we cannot type the arrays, we don't know which slices + // might be affected. We could restrict this barrier only to those + // memory slices which pertain to array elements--but don't bother. + if (!InsertMemBarAfterArraycopy) { + // (If InsertMemBarAfterArraycopy, there is already one in place.) + insert_mem_bar(&ctrl, &mem, Op_MemBarCPUOrder); + } + return; + } + // (2) src and dest arrays must have elements of the same BasicType + // Figure out the size and type of the elements we will be copying. + BasicType src_elem = top_src->klass()->as_array_klass()->element_type()->basic_type(); + BasicType dest_elem = top_dest->klass()->as_array_klass()->element_type()->basic_type(); + if (src_elem == T_ARRAY) src_elem = T_OBJECT; + if (dest_elem == T_ARRAY) dest_elem = T_OBJECT; + + if (src_elem != dest_elem || dest_elem == T_VOID) { + // The component types are not the same or are not recognized. Punt. + // (But, avoid the native method wrapper to JVM_ArrayCopy.) + { + Node* mem = ac->in(TypeFunc::Memory); + merge_mem = generate_slow_arraycopy(ac, &ctrl, mem, &io, TypePtr::BOTTOM, src, src_offset, dest, dest_offset, length, false); + } + + _igvn.replace_node(_memproj_fallthrough, merge_mem); + _igvn.replace_node(_ioproj_fallthrough, io); + _igvn.replace_node(_fallthroughcatchproj, ctrl); + return; + } + + //--------------------------------------------------------------------------- + // We will make a fast path for this call to arraycopy. + + // We have the following tests left to perform: + // + // (3) src and dest must not be null. + // (4) src_offset must not be negative. + // (5) dest_offset must not be negative. + // (6) length must not be negative. + // (7) src_offset + length must not exceed length of src. + // (8) dest_offset + length must not exceed length of dest. + // (9) each element of an oop array must be assignable + + { + Node* mem = ac->in(TypeFunc::Memory); + merge_mem = MergeMemNode::make(mem); + transform_later(merge_mem); + } + + RegionNode* slow_region = new RegionNode(1); + transform_later(slow_region); + + if (!ac->is_arraycopy_notest()) { + // (3) operands must not be null + // We currently perform our null checks with the null_check routine. + // This means that the null exceptions will be reported in the caller + // rather than (correctly) reported inside of the native arraycopy call. + // This should be corrected, given time. We do our null check with the + // stack pointer restored. + // null checks done library_call.cpp + + // (4) src_offset must not be negative. + generate_negative_guard(&ctrl, src_offset, slow_region); + + // (5) dest_offset must not be negative. + generate_negative_guard(&ctrl, dest_offset, slow_region); + + // (6) length must not be negative (moved to generate_arraycopy()). + // generate_negative_guard(length, slow_region); + + // (7) src_offset + length must not exceed length of src. + Node* alen = ac->in(ArrayCopyNode::SrcLen); + generate_limit_guard(&ctrl, + src_offset, length, + alen, + slow_region); + + // (8) dest_offset + length must not exceed length of dest. + alen = ac->in(ArrayCopyNode::DestLen); + generate_limit_guard(&ctrl, + dest_offset, length, + alen, + slow_region); + + // (9) each element of an oop array must be assignable + // The generate_arraycopy subroutine checks this. + } + // This is where the memory effects are placed: + const TypePtr* adr_type = TypeAryPtr::get_array_body_type(dest_elem); + generate_arraycopy(ac, alloc, &ctrl, merge_mem, &io, + adr_type, dest_elem, + src, src_offset, dest, dest_offset, length, + false, false, slow_region); +} diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index cce4a739473..8ecb54b2dc9 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -305,7 +305,7 @@ void Matcher::match( ) { // to avoid false sharing if the corresponding mach node is not used. // The corresponding mach node is only used in rare cases for derived // pointers. - Node* new_ideal_null = ConNode::make(C, TypePtr::NULL_PTR); + Node* new_ideal_null = ConNode::make(TypePtr::NULL_PTR); // Swap out to old-space; emptying new-space Arena *old = C->node_arena()->move_contents(C->old_arena()); @@ -1643,8 +1643,8 @@ MachNode *Matcher::ReduceInst( State *s, int rule, Node *&mem ) { } // Build the object to represent this state & prepare for recursive calls - MachNode *mach = s->MachNodeGenerator( rule, C ); - mach->_opnds[0] = s->MachOperGenerator( _reduceOp[rule], C ); + MachNode *mach = s->MachNodeGenerator(rule); + mach->_opnds[0] = s->MachOperGenerator(_reduceOp[rule]); assert( mach->_opnds[0] != NULL, "Missing result operand" ); Node *leaf = s->_leaf; // Check for instruction or instruction chain rule @@ -1756,13 +1756,13 @@ void Matcher::ReduceInst_Chain_Rule( State *s, int rule, Node *&mem, MachNode *m assert( 0 <= opnd_class_instance && opnd_class_instance < NUM_OPERANDS, "Bad AD file: Instruction chain rule must chain from operand"); // Insert operand into array of operands for this instruction - mach->_opnds[1] = s->MachOperGenerator( opnd_class_instance, C ); + mach->_opnds[1] = s->MachOperGenerator(opnd_class_instance); ReduceOper( s, newrule, mem, mach ); } else { // Chain from the result of an instruction assert( newrule >= _LAST_MACH_OPER, "Do NOT chain from internal operand"); - mach->_opnds[1] = s->MachOperGenerator( _reduceOp[catch_op], C ); + mach->_opnds[1] = s->MachOperGenerator(_reduceOp[catch_op]); Node *mem1 = (Node*)1; debug_only(Node *save_mem_node = _mem_node;) mach->add_req( ReduceInst(s, newrule, mem1) ); @@ -1807,7 +1807,7 @@ uint Matcher::ReduceInst_Interior( State *s, int rule, Node *&mem, MachNode *mac if( newrule < NUM_OPERANDS ) { // Operand/operandClass or internalOp/instruction? // Operand/operandClass // Insert operand into array of operands for this instruction - mach->_opnds[num_opnds++] = newstate->MachOperGenerator( opnd_class_instance, C ); + mach->_opnds[num_opnds++] = newstate->MachOperGenerator(opnd_class_instance); ReduceOper( newstate, newrule, mem, mach ); } else { // Child is internal operand or new instruction @@ -1818,7 +1818,7 @@ uint Matcher::ReduceInst_Interior( State *s, int rule, Node *&mem, MachNode *mac } else { // instruction --> call build operand( ) to catch result // --> ReduceInst( newrule ) - mach->_opnds[num_opnds++] = s->MachOperGenerator( _reduceOp[catch_op], C ); + mach->_opnds[num_opnds++] = s->MachOperGenerator(_reduceOp[catch_op]); Node *mem1 = (Node*)1; debug_only(Node *save_mem_node = _mem_node;) mach->add_req( ReduceInst( newstate, newrule, mem1 ) ); diff --git a/hotspot/src/share/vm/opto/mathexactnode.cpp b/hotspot/src/share/vm/opto/mathexactnode.cpp index 00466ad3d50..a96656854f5 100644 --- a/hotspot/src/share/vm/opto/mathexactnode.cpp +++ b/hotspot/src/share/vm/opto/mathexactnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -191,7 +191,7 @@ struct IdealHelper { NativeType val1 = TypeClass::as_self(type1)->get_con(); NativeType val2 = TypeClass::as_self(type2)->get_con(); if (node->will_overflow(val1, val2) == false) { - Node* con_result = ConINode::make(phase->C, 0); + Node* con_result = ConINode::make(0); return con_result; } return NULL; diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 1c4d2bd773e..694a1eccda6 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -933,12 +933,12 @@ Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypeP return (LoadNode*)NULL; } -LoadLNode* LoadLNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) { +LoadLNode* LoadLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) { bool require_atomic = true; return new LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, require_atomic); } -LoadDNode* LoadDNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) { +LoadDNode* LoadDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) { bool require_atomic = true; return new LoadDNode(ctl, mem, adr, adr_type, rt, mo, require_atomic); } @@ -1471,6 +1471,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* ctrl = in(MemNode::Control); Node* address = in(MemNode::Address); + bool progress = false; // Skip up past a SafePoint control. Cannot do this for Stores because // pointer stores & cardmarks must stay on the same side of a SafePoint. @@ -1478,6 +1479,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) { phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw ) { ctrl = ctrl->in(0); set_req(MemNode::Control,ctrl); + progress = true; } intptr_t ignore = 0; @@ -1490,6 +1492,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) { && all_controls_dominate(base, phase->C->start())) { // A method-invariant, non-null address (constant or 'this' argument). set_req(MemNode::Control, NULL); + progress = true; } } @@ -1550,7 +1553,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) { } } - return NULL; // No further progress + return progress ? this : NULL; } // Helper to recognize certain Klass fields which are invariant across @@ -2014,7 +2017,6 @@ const Type* LoadSNode::Value(PhaseTransform *phase) const { //----------------------------LoadKlassNode::make------------------------------ // Polymorphic factory method: Node *LoadKlassNode::make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk ) { - Compile* C = gvn.C; Node *ctl = NULL; // sanity check the alias category against the created node type const TypePtr *adr_type = adr->bottom_type()->isa_ptr(); @@ -2379,12 +2381,12 @@ StoreNode* StoreNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const return (StoreNode*)NULL; } -StoreLNode* StoreLNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo) { +StoreLNode* StoreLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo) { bool require_atomic = true; return new StoreLNode(ctl, mem, adr, adr_type, val, mo, require_atomic); } -StoreDNode* StoreDNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo) { +StoreDNode* StoreDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo) { bool require_atomic = true; return new StoreDNode(ctl, mem, adr, adr_type, val, mo, require_atomic); } @@ -2460,7 +2462,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { // and I need to disappear. if (moved != NULL) { // %%% hack to ensure that Ideal returns a new node: - mem = MergeMemNode::make(phase->C, mem); + mem = MergeMemNode::make(mem); return mem; // fold me away } } @@ -2820,7 +2822,6 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest, intptr_t start_offset, Node* end_offset, PhaseGVN* phase) { - Compile* C = phase->C; intptr_t offset = start_offset; int unit = BytesPerLong; @@ -2847,7 +2848,6 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest, return mem; } - Compile* C = phase->C; int unit = BytesPerLong; Node* zbase = start_offset; Node* zend = end_offset; @@ -2875,7 +2875,6 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest, return mem; } - Compile* C = phase->C; assert((end_offset % BytesPerInt) == 0, "odd end offset"); intptr_t done_offset = end_offset; if ((done_offset % BytesPerLong) != 0) { @@ -2944,6 +2943,7 @@ Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) { return NULL; } + bool progress = false; // Eliminate volatile MemBars for scalar replaced objects. if (can_reshape && req() == (Precedent+1)) { bool eliminate = false; @@ -2966,6 +2966,7 @@ Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) { phase->is_IterGVN()->_worklist.push(my_mem); // remove dead node later my_mem = NULL; } + progress = true; } if (my_mem != NULL && my_mem->is_Mem()) { const TypeOopPtr* t_oop = my_mem->in(MemNode::Address)->bottom_type()->isa_oopptr(); @@ -2995,7 +2996,7 @@ Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) { return new ConINode(TypeInt::ZERO); } } - return NULL; + return progress ? this : NULL; } //------------------------------Value------------------------------------------ @@ -3497,6 +3498,7 @@ Node* InitializeNode::capture_store(StoreNode* st, intptr_t start, // if it redundantly stored the same value (or zero to fresh memory). // In any case, wire it in: + phase->igvn_rehash_node_delayed(this); set_req(i, new_st); // The caller may now kill the old guy. @@ -4126,7 +4128,7 @@ MergeMemNode::MergeMemNode(Node *new_base) : Node(1+Compile::AliasIdxRaw) { // Make a new, untransformed MergeMem with the same base as 'mem'. // If mem is itself a MergeMem, populate the result with the same edges. -MergeMemNode* MergeMemNode::make(Compile* C, Node* mem) { +MergeMemNode* MergeMemNode::make(Node* mem) { return new MergeMemNode(mem); } diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index 000ccdcbbbc..4a7064ad6d6 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -333,7 +333,7 @@ public: virtual int store_Opcode() const { return Op_StoreL; } virtual BasicType memory_type() const { return T_LONG; } bool require_atomic_access() const { return _require_atomic_access; } - static LoadLNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, + static LoadLNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { @@ -384,7 +384,7 @@ public: virtual int store_Opcode() const { return Op_StoreD; } virtual BasicType memory_type() const { return T_DOUBLE; } bool require_atomic_access() const { return _require_atomic_access; } - static LoadDNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, + static LoadDNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { @@ -593,7 +593,7 @@ public: virtual int Opcode() const; virtual BasicType memory_type() const { return T_LONG; } bool require_atomic_access() const { return _require_atomic_access; } - static StoreLNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo); + static StoreLNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { StoreNode::dump_spec(st); @@ -629,7 +629,7 @@ public: virtual int Opcode() const; virtual BasicType memory_type() const { return T_DOUBLE; } bool require_atomic_access() const { return _require_atomic_access; } - static StoreDNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo); + static StoreDNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { StoreNode::dump_spec(st); @@ -1138,7 +1138,7 @@ public: // If the input is a whole memory state, clone it with all its slices intact. // Otherwise, make a new memory state with just that base memory input. // In either case, the result is a newly created MergeMem. - static MergeMemNode* make(Compile* C, Node* base_memory); + static MergeMemNode* make(Node* base_memory); virtual int Opcode() const; virtual Node *Identity( PhaseTransform *phase ); diff --git a/hotspot/src/share/vm/opto/movenode.cpp b/hotspot/src/share/vm/opto/movenode.cpp index b7e32deb2e4..234cdebf031 100644 --- a/hotspot/src/share/vm/opto/movenode.cpp +++ b/hotspot/src/share/vm/opto/movenode.cpp @@ -88,7 +88,7 @@ Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { if( in(Condition)->is_Bool() ) { BoolNode* b = in(Condition)->as_Bool(); BoolNode* b2 = b->negate(phase); - return make( phase->C, in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type ); + return make(in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type); } } return NULL; @@ -158,7 +158,7 @@ const Type *CMoveNode::Value( PhaseTransform *phase ) const { //------------------------------make------------------------------------------- // Make a correctly-flavored CMove. Since _type is directly determined // from the inputs we do not need to specify it here. -CMoveNode *CMoveNode::make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t ) { +CMoveNode *CMoveNode::make(Node *c, Node *bol, Node *left, Node *right, const Type *t) { switch( t->basic_type() ) { case T_INT: return new CMoveINode( bol, left, right, t->is_int() ); case T_FLOAT: return new CMoveFNode( bol, left, right, t ); @@ -196,7 +196,7 @@ Node *CMoveINode::Ideal(PhaseGVN *phase, bool can_reshape) { if( in(Condition)->is_Bool() ) { BoolNode* b = in(Condition)->as_Bool(); BoolNode* b2 = b->negate(phase); - return make( phase->C, in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type ); + return make(in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type); } } diff --git a/hotspot/src/share/vm/opto/movenode.hpp b/hotspot/src/share/vm/opto/movenode.hpp index 8aac944ed92..bb99f7ba083 100644 --- a/hotspot/src/share/vm/opto/movenode.hpp +++ b/hotspot/src/share/vm/opto/movenode.hpp @@ -47,7 +47,7 @@ class CMoveNode : public TypeNode { virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type *Value( PhaseTransform *phase ) const; virtual Node *Identity( PhaseTransform *phase ); - static CMoveNode *make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t ); + static CMoveNode *make(Node *c, Node *bol, Node *left, Node *right, const Type *t); // Helper function to spot cmove graph shapes static Node *is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ); }; diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index f48e87c0c33..c7cd9cd5c37 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -507,7 +507,7 @@ Node *Node::clone() const { (const void*)(&mthis->_opnds), 1)); mach->_opnds = to; for ( uint i = 0; i < nopnds; ++i ) { - to[i] = from[i]->clone(C); + to[i] = from[i]->clone(); } } // cloning CallNode may need to clone JVMState @@ -620,6 +620,7 @@ void Node::destruct() { *(address*)this = badAddress; // smash the C++ vtbl, probably _in = _out = (Node**) badAddress; _max = _cnt = _outmax = _outcnt = 0; + compile->remove_modified_node(this); #endif } @@ -765,6 +766,7 @@ void Node::del_req( uint idx ) { if (n != NULL) n->del_out((Node *)this); _in[idx] = in(--_cnt); // Compact the array _in[_cnt] = NULL; // NULL out emptied slot + Compile::current()->record_modified_node(this); } //------------------------------del_req_ordered-------------------------------- @@ -780,6 +782,7 @@ void Node::del_req_ordered( uint idx ) { Copy::conjoint_words_to_lower((HeapWord*)&_in[idx+1], (HeapWord*)&_in[idx], ((_cnt-idx-1)*sizeof(Node*))); } _in[--_cnt] = NULL; // NULL out emptied slot + Compile::current()->record_modified_node(this); } //------------------------------ins_req---------------------------------------- @@ -1080,6 +1083,9 @@ bool Node::has_special_unique_user() const { if( this->is_Store() ) { // Condition for back-to-back stores folding. return n->Opcode() == op && n->in(MemNode::Memory) == this; + } else if (this->is_Load()) { + // Condition for removing an unused LoadNode from the MemBarAcquire precedence input + return n->Opcode() == Op_MemBarAcquire; } else if( op == Op_AddL ) { // Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y)) return n->Opcode() == Op_ConvL2I && n->in(1) == this; @@ -1297,6 +1303,7 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) { // Done with outputs. igvn->hash_delete(dead); igvn->_worklist.remove(dead); + igvn->C->remove_modified_node(dead); igvn->set_type(dead, Type::TOP); if (dead->is_macro()) { igvn->C->remove_macro_node(dead); diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index 5bb9c6873d7..bcf6911df52 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -40,6 +40,7 @@ class AddPNode; class AliasInfo; class AllocateArrayNode; class AllocateNode; +class ArrayCopyNode; class Block; class BoolNode; class BoxLockNode; @@ -398,6 +399,7 @@ protected: if (*p != NULL) (*p)->del_out((Node *)this); (*p) = n; if (n != NULL) n->add_out((Node *)this); + Compile::current()->record_modified_node(this); } // Light version of set_req() to init inputs after node creation. void init_req( uint i, Node *n ) { @@ -409,6 +411,7 @@ protected: assert( _in[i] == NULL, "sanity"); _in[i] = n; if (n != NULL) n->add_out((Node *)this); + Compile::current()->record_modified_node(this); } // Find first occurrence of n among my edges: int find_edge(Node* n); @@ -559,6 +562,7 @@ public: DEFINE_CLASS_ID(AbstractLock, Call, 3) DEFINE_CLASS_ID(Lock, AbstractLock, 0) DEFINE_CLASS_ID(Unlock, AbstractLock, 1) + DEFINE_CLASS_ID(ArrayCopy, Call, 4) DEFINE_CLASS_ID(MultiBranch, Multi, 1) DEFINE_CLASS_ID(PCTable, MultiBranch, 0) DEFINE_CLASS_ID(Catch, PCTable, 0) @@ -705,6 +709,7 @@ public: DEFINE_CLASS_QUERY(AddP) DEFINE_CLASS_QUERY(Allocate) DEFINE_CLASS_QUERY(AllocateArray) + DEFINE_CLASS_QUERY(ArrayCopy) DEFINE_CLASS_QUERY(Bool) DEFINE_CLASS_QUERY(BoxLock) DEFINE_CLASS_QUERY(Call) diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 15bf30b393a..16ec69c219d 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -526,7 +526,7 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size if (_matcher->is_short_branch_offset(mach->rule(), br_size, offset)) { // We've got a winner. Replace this branch. - MachNode* replacement = mach->as_MachBranch()->short_branch_version(this); + MachNode* replacement = mach->as_MachBranch()->short_branch_version(); // Update the jmp_size. int new_size = replacement->size(_regalloc); @@ -785,9 +785,10 @@ void Compile::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, // grow downwards in all implementations. // (If, on some machine, the interpreter's Java locals or stack // were to grow upwards, the embedded doubles would be word-swapped.) - jint *dp = (jint*)&d; - array->append(new ConstantIntValue(dp[1])); - array->append(new ConstantIntValue(dp[0])); + jlong_accessor acc; + acc.long_value = jlong_cast(d); + array->append(new ConstantIntValue(acc.words[1])); + array->append(new ConstantIntValue(acc.words[0])); #endif break; } @@ -804,9 +805,10 @@ void Compile::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, // grow downwards in all implementations. // (If, on some machine, the interpreter's Java locals or stack // were to grow upwards, the embedded doubles would be word-swapped.) - jint *dp = (jint*)&d; - array->append(new ConstantIntValue(dp[1])); - array->append(new ConstantIntValue(dp[0])); + jlong_accessor acc; + acc.long_value = d; + array->append(new ConstantIntValue(acc.words[1])); + array->append(new ConstantIntValue(acc.words[0])); #endif break; } @@ -1174,7 +1176,7 @@ CodeBuffer* Compile::init_buffer(uint* blk_starts) { // fill in the nop array for bundling computations MachNode *_nop_list[Bundle::_nop_count]; - Bundle::initialize_nops(_nop_list, this); + Bundle::initialize_nops(_nop_list); return cb; } @@ -1408,7 +1410,7 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { if (_matcher->is_short_branch_offset(mach->rule(), br_size, offset)) { // We've got a winner. Replace this branch. - MachNode* replacement = mach->as_MachBranch()->short_branch_version(this); + MachNode* replacement = mach->as_MachBranch()->short_branch_version(); // Update the jmp_size. int new_size = replacement->size(_regalloc); diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index a758f72acdc..118cb62db5c 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -575,12 +575,13 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) decrement_age(); } } - if (depth() == 1) { + + if (depth() == 1 && !failing()) { // Add check to deoptimize the nmethod if RTM state was changed rtm_deopt(); } - // Check for bailouts during method entry. + // Check for bailouts during method entry or RTM state check setup. if (failing()) { if (log) log->done("parse"); C->set_default_node_notes(caller_nn); @@ -1756,7 +1757,7 @@ void Parse::merge_memory_edges(MergeMemNode* n, int pnum, bool nophi) { if (remerge == NULL) { assert(base != NULL, ""); assert(base->in(0) != NULL, "should not be xformed away"); - remerge = MergeMemNode::make(C, base->in(pnum)); + remerge = MergeMemNode::make(base->in(pnum)); gvn().set_type(remerge, Type::MEMORY); base->set_req(pnum, remerge); } @@ -2199,7 +2200,7 @@ void Parse::add_safepoint() { // down below a SafePoint. // Clone the current memory state - Node* mem = MergeMemNode::make(C, map()->memory()); + Node* mem = MergeMemNode::make(map()->memory()); mem = _gvn.transform(mem); @@ -2213,7 +2214,7 @@ void Parse::add_safepoint() { // Create a node for the polling address if( add_poll_param ) { - Node *polladr = ConPNode::make(C, (address)os::get_polling_page()); + Node *polladr = ConPNode::make((address)os::get_polling_page()); sfpnt->init_req(TypeFunc::Parms+0, _gvn.transform(polladr)); } diff --git a/hotspot/src/share/vm/opto/parseHelper.cpp b/hotspot/src/share/vm/opto/parseHelper.cpp index 45d627d2500..a71fb8f7752 100644 --- a/hotspot/src/share/vm/opto/parseHelper.cpp +++ b/hotspot/src/share/vm/opto/parseHelper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -47,7 +47,7 @@ void GraphKit::make_dtrace_method_entry_exit(ciMethod* method, bool is_entry) { // Get method const TypePtr* method_type = TypeMetadataPtr::make(method); - Node *method_node = _gvn.transform( ConNode::make(C, method_type) ); + Node *method_node = _gvn.transform(ConNode::make(method_type)); kill_dead_locals(); diff --git a/hotspot/src/share/vm/opto/phase.hpp b/hotspot/src/share/vm/opto/phase.hpp index b06e3470df4..df7f896f8ae 100644 --- a/hotspot/src/share/vm/opto/phase.hpp +++ b/hotspot/src/share/vm/opto/phase.hpp @@ -27,7 +27,10 @@ #include "runtime/timer.hpp" -class Compile; +class IfNode; +class MergeMemNode; +class Node; +class PhaseGVN; //------------------------------Phase------------------------------------------ // Most optimizations are done in Phases. Creating a phase does any long @@ -114,9 +117,20 @@ protected: static elapsedTimer _t_instrSched; static elapsedTimer _t_buildOopMaps; #endif + + // Generate a subtyping check. Takes as input the subtype and supertype. + // Returns 2 values: sets the default control() to the true path and + // returns the false path. Only reads from constant memory taken from the + // default memory; does not write anything. It also doesn't take in an + // Object; if you wish to check an Object you need to load the Object's + // class prior to coming here. + // Used in GraphKit and PhaseMacroExpand + static Node* gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, MergeMemNode* mem, PhaseGVN* gvn); + public: Compile * C; Phase( PhaseNumber pnum ); + #ifndef PRODUCT static void print_timers(); #endif diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index b4470dcef53..3e063ae987e 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -615,7 +615,7 @@ ConNode* PhaseTransform::makecon(const Type *t) { // Make an idealized constant - one of ConINode, ConPNode, etc. ConNode* PhaseValues::uncached_makecon(const Type *t) { assert(t->singleton(), "must be a constant"); - ConNode* x = ConNode::make(C, t); + ConNode* x = ConNode::make(t); ConNode* k = (ConNode*)hash_find_insert(x); // Value numbering if (k == NULL) { set_type(x, t); // Missed, provide type mapping @@ -933,9 +933,32 @@ void PhaseIterGVN::init_verifyPhaseIterGVN() { for (int i = 0; i < _verify_window_size; i++) { _verify_window[i] = NULL; } +#ifdef ASSERT + // Verify that all modified nodes are on _worklist + Unique_Node_List* modified_list = C->modified_nodes(); + while (modified_list != NULL && modified_list->size()) { + Node* n = modified_list->pop(); + if (n->outcnt() != 0 && !n->is_Con() && !_worklist.member(n)) { + n->dump(); + assert(false, "modified node is not on IGVN._worklist"); + } + } +#endif } void PhaseIterGVN::verify_PhaseIterGVN() { +#ifdef ASSERT + // Verify nodes with changed inputs. + Unique_Node_List* modified_list = C->modified_nodes(); + while (modified_list != NULL && modified_list->size()) { + Node* n = modified_list->pop(); + if (n->outcnt() != 0 && !n->is_Con()) { // skip dead and Con nodes + n->dump(); + assert(false, "modified node was not processed by IGVN.transform_old()"); + } + } +#endif + C->verify_graph_edges(); if( VerifyOpto && allow_progress() ) { // Must turn off allow_progress to enable assert and break recursion @@ -964,6 +987,14 @@ void PhaseIterGVN::verify_PhaseIterGVN() { (int) _verify_counter, (int) _verify_full_passes); } } + +#ifdef ASSERT + while (modified_list->size()) { + Node* n = modified_list->pop(); + n->dump(); + assert(false, "VerifyIterativeGVN: new modified node was added"); + } +#endif } #endif /* PRODUCT */ @@ -1066,6 +1097,7 @@ Node *PhaseIterGVN::transform_old(Node* n) { Node* k = n; DEBUG_ONLY(dead_loop_check(k);) DEBUG_ONLY(bool is_new = (k->outcnt() == 0);) + C->remove_modified_node(k); Node* i = k->Ideal(this, /*can_reshape=*/true); assert(i != k || is_new || i->outcnt() > 0, "don't return dead nodes"); #ifndef PRODUCT @@ -1107,6 +1139,7 @@ Node *PhaseIterGVN::transform_old(Node* n) { DEBUG_ONLY(dead_loop_check(k);) // Try idealizing again DEBUG_ONLY(is_new = (k->outcnt() == 0);) + C->remove_modified_node(k); i = k->Ideal(this, /*can_reshape=*/true); assert(i != k || is_new || (i->outcnt() > 0), "don't return dead nodes"); #ifndef PRODUCT @@ -1259,6 +1292,7 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { _stack.pop(); // Remove dead node from iterative worklist _worklist.remove(dead); + C->remove_modified_node(dead); // Constant node that has no out-edges and has only one in-edge from // root is usually dead. However, sometimes reshaping walk makes // it reachable by adding use edges. So, we will NOT count Con nodes @@ -1288,7 +1322,7 @@ void PhaseIterGVN::subsume_node( Node *old, Node *nn ) { for (DUIterator_Last imin, i = old->last_outs(imin); i >= imin; ) { Node* use = old->last_out(i); // for each use... // use might need re-hashing (but it won't if it's a new node) - bool is_in_table = _table.hash_delete( use ); + rehash_node_delayed(use); // Update use-def info as well // We remove all occurrences of old within use->in, // so as to avoid rehashing any node more than once. @@ -1300,11 +1334,6 @@ void PhaseIterGVN::subsume_node( Node *old, Node *nn ) { ++num_edges; } } - // Insert into GVN hash table if unique - // If a duplicate, 'use' will be cleaned up when pulled off worklist - if( is_in_table ) { - hash_find_insert(use); - } i -= num_edges; // we deleted 1 or more copies of this edge } @@ -1599,7 +1628,7 @@ Node *PhaseCCP::transform_once( Node *n ) { if( t == Type::TOP ) { // cache my top node on the Compile instance if( C->cached_top_node() == NULL || C->cached_top_node()->in(0) == NULL ) { - C->set_cached_top_node( ConNode::make(C, Type::TOP) ); + C->set_cached_top_node(ConNode::make(Type::TOP)); set_type(C->top(), Type::TOP); } nn = C->top(); @@ -1725,7 +1754,7 @@ void PhasePeephole::do_transform() { MachNode *m = n->as_Mach(); int deleted_count = 0; // check for peephole opportunities - MachNode *m2 = m->peephole( block, instruction_index, _regalloc, deleted_count, C ); + MachNode *m2 = m->peephole(block, instruction_index, _regalloc, deleted_count); if( m2 != NULL ) { #ifndef PRODUCT if( PrintOptoPeephole ) { diff --git a/hotspot/src/share/vm/opto/phaseX.hpp b/hotspot/src/share/vm/opto/phaseX.hpp index ccb24819e7c..c3749dbcf70 100644 --- a/hotspot/src/share/vm/opto/phaseX.hpp +++ b/hotspot/src/share/vm/opto/phaseX.hpp @@ -311,6 +311,9 @@ public: const Type* limit_type) const { ShouldNotCallThis(); return NULL; } + // Delayed node rehash if this is an IGVN phase + virtual void igvn_rehash_node_delayed(Node* n) {} + #ifndef PRODUCT void dump_old2new_map() const; void dump_new( uint new_lidx ) const; @@ -387,6 +390,9 @@ public: // in a faster or cheaper fashion. Node *transform( Node *n ); Node *transform_no_reclaim( Node *n ); + virtual void record_for_igvn(Node *n) { + C->record_for_igvn(n); + } void replace_with(PhaseGVN* gvn) { _table.replace_with(&gvn->_table); @@ -415,9 +421,6 @@ class PhaseIterGVN : public PhaseGVN { protected: - // Idealize new Node 'n' with respect to its inputs and its value - virtual Node *transform( Node *a_node ); - // Warm up hash table, type table and initial worklist void init_worklist( Node *a_root ); @@ -431,6 +434,10 @@ public: PhaseIterGVN( PhaseGVN *gvn ); // Used after Parser PhaseIterGVN( PhaseIterGVN *igvn, const char *dummy ); // Used after +VerifyOpto + // Idealize new Node 'n' with respect to its inputs and its value + virtual Node *transform( Node *a_node ); + virtual void record_for_igvn(Node *n) { } + virtual PhaseIterGVN *is_IterGVN() { return this; } Unique_Node_List _worklist; // Iterative worklist @@ -488,6 +495,10 @@ public: _worklist.push(n); } + void igvn_rehash_node_delayed(Node* n) { + rehash_node_delayed(n); + } + // Replace ith edge of "n" with "in" void replace_input_of(Node* n, int i, Node* in) { rehash_node_delayed(n); diff --git a/hotspot/src/share/vm/opto/rootnode.cpp b/hotspot/src/share/vm/opto/rootnode.cpp index 56775ed7e01..4cf51528df5 100644 --- a/hotspot/src/share/vm/opto/rootnode.cpp +++ b/hotspot/src/share/vm/opto/rootnode.cpp @@ -35,10 +35,12 @@ //------------------------------Ideal------------------------------------------ // Remove dead inputs Node *RootNode::Ideal(PhaseGVN *phase, bool can_reshape) { + bool modified = false; for( uint i = 1; i < req(); i++ ) { // For all inputs // Check for and remove dead inputs if( phase->type(in(i)) == Type::TOP ) { del_req(i--); // Delete TOP inputs + modified = true; } } @@ -56,7 +58,7 @@ Node *RootNode::Ideal(PhaseGVN *phase, bool can_reshape) { // If we want to get the rest of the win later, we should pattern match // simple recursive call trees to closed-form solutions. - return NULL; // No further opportunities exposed + return modified ? this : NULL; } //============================================================================= diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 2a2fb131dfd..0bf5c9da587 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -1381,11 +1381,11 @@ NamedCounter* OptoRuntime::new_named_counter(JVMState* youngest_jvms, NamedCount } NamedCounter* c; if (tag == NamedCounter::BiasedLockingCounter) { - c = new BiasedLockingNamedCounter(strdup(st.as_string())); + c = new BiasedLockingNamedCounter(st.as_string()); } else if (tag == NamedCounter::RTMLockingCounter) { - c = new RTMLockingNamedCounter(strdup(st.as_string())); + c = new RTMLockingNamedCounter(st.as_string()); } else { - c = new NamedCounter(strdup(st.as_string()), tag); + c = new NamedCounter(st.as_string(), tag); } // atomically add the new counter to the head of the list. We only diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp index b5e8bc34d98..612afc58807 100644 --- a/hotspot/src/share/vm/opto/runtime.hpp +++ b/hotspot/src/share/vm/opto/runtime.hpp @@ -75,11 +75,17 @@ private: public: NamedCounter(const char *n, CounterTag tag = NoTag): - _name(n), + _name(n == NULL ? NULL : os::strdup(n)), _count(0), _next(NULL), _tag(tag) {} + ~NamedCounter() { + if (_name != NULL) { + os::free((void*)_name); + } + } + const char * name() const { return _name; } int count() const { return _count; } address addr() { return (address)&_count; } diff --git a/hotspot/src/share/vm/opto/stringopts.cpp b/hotspot/src/share/vm/opto/stringopts.cpp index fcca4684833..1d9bae5a6ac 100644 --- a/hotspot/src/share/vm/opto/stringopts.cpp +++ b/hotspot/src/share/vm/opto/stringopts.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -1438,7 +1438,7 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) { } // Make sure the memory state is a MergeMem for parsing. if (!map->in(TypeFunc::Memory)->is_MergeMem()) { - map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory))); + map->set_req(TypeFunc::Memory, MergeMemNode::make(map->in(TypeFunc::Memory))); } jvms->set_map(map); diff --git a/hotspot/src/share/vm/opto/subnode.cpp b/hotspot/src/share/vm/opto/subnode.cpp index e5f24b6ca6c..1fe558c18d3 100644 --- a/hotspot/src/share/vm/opto/subnode.cpp +++ b/hotspot/src/share/vm/opto/subnode.cpp @@ -1168,7 +1168,6 @@ uint BoolNode::cmp( const Node &n ) const { Node* BoolNode::make_predicate(Node* test_value, PhaseGVN* phase) { if (test_value->is_Con()) return test_value; if (test_value->is_Bool()) return test_value; - Compile* C = phase->C; if (test_value->is_CMove() && test_value->in(CMoveNode::Condition)->is_Bool()) { BoolNode* bol = test_value->in(CMoveNode::Condition)->as_Bool(); @@ -1191,7 +1190,7 @@ Node* BoolNode::make_predicate(Node* test_value, PhaseGVN* phase) { //--------------------------------as_int_value--------------------------------- Node* BoolNode::as_int_value(PhaseGVN* phase) { // Inverse to make_predicate. The CMove probably boils down to a Conv2B. - Node* cmov = CMoveNode::make(phase->C, NULL, this, + Node* cmov = CMoveNode::make(NULL, this, phase->intcon(0), phase->intcon(1), TypeInt::BOOL); return phase->transform(cmov); @@ -1199,10 +1198,57 @@ Node* BoolNode::as_int_value(PhaseGVN* phase) { //----------------------------------negate------------------------------------- BoolNode* BoolNode::negate(PhaseGVN* phase) { - Compile* C = phase->C; return new BoolNode(in(1), _test.negate()); } +// Change "bool eq/ne (cmp (add/sub A B) C)" into false/true if add/sub +// overflows and we can prove that C is not in the two resulting ranges. +// This optimization is similar to the one performed by CmpUNode::Value(). +Node* BoolNode::fold_cmpI(PhaseGVN* phase, SubNode* cmp, Node* cmp1, int cmp_op, + int cmp1_op, const TypeInt* cmp2_type) { + // Only optimize eq/ne integer comparison of add/sub + if((_test._test == BoolTest::eq || _test._test == BoolTest::ne) && + (cmp_op == Op_CmpI) && (cmp1_op == Op_AddI || cmp1_op == Op_SubI)) { + // Skip cases were inputs of add/sub are not integers or of bottom type + const TypeInt* r0 = phase->type(cmp1->in(1))->isa_int(); + const TypeInt* r1 = phase->type(cmp1->in(2))->isa_int(); + if ((r0 != NULL) && (r0 != TypeInt::INT) && + (r1 != NULL) && (r1 != TypeInt::INT) && + (cmp2_type != TypeInt::INT)) { + // Compute exact (long) type range of add/sub result + jlong lo_long = r0->_lo; + jlong hi_long = r0->_hi; + if (cmp1_op == Op_AddI) { + lo_long += r1->_lo; + hi_long += r1->_hi; + } else { + lo_long -= r1->_hi; + hi_long -= r1->_lo; + } + // Check for over-/underflow by casting to integer + int lo_int = (int)lo_long; + int hi_int = (int)hi_long; + bool underflow = lo_long != (jlong)lo_int; + bool overflow = hi_long != (jlong)hi_int; + if ((underflow != overflow) && (hi_int < lo_int)) { + // Overflow on one boundary, compute resulting type ranges: + // tr1 [MIN_INT, hi_int] and tr2 [lo_int, MAX_INT] + int w = MAX2(r0->_widen, r1->_widen); // _widen does not matter here + const TypeInt* tr1 = TypeInt::make(min_jint, hi_int, w); + const TypeInt* tr2 = TypeInt::make(lo_int, max_jint, w); + // Compare second input of cmp to both type ranges + const Type* sub_tr1 = cmp->sub(tr1, cmp2_type); + const Type* sub_tr2 = cmp->sub(tr2, cmp2_type); + if (sub_tr1 == TypeInt::CC_LT && sub_tr2 == TypeInt::CC_GT) { + // The result of the add/sub will never equal cmp2. Replace BoolNode + // by false (0) if it tests for equality and by true (1) otherwise. + return ConINode::make((_test._test == BoolTest::eq) ? 0 : 1); + } + } + } + } + return NULL; +} //------------------------------Ideal------------------------------------------ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) { @@ -1296,6 +1342,9 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) { return new BoolNode( ncmp, _test.commute() ); } + // Try to optimize signed integer comparison + return fold_cmpI(phase, cmp->as_Sub(), cmp1, cop, cmp1_op, cmp2_type); + // The transformation below is not valid for either signed or unsigned // comparisons due to wraparound concerns at MAX_VALUE and MIN_VALUE. // This transformation can be resurrected when we are able to @@ -1340,8 +1389,6 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) { // phase->type( cmp2->in(2) ) == TypeInt::ONE ) // return clone_cmp( cmp, cmp1, cmp2->in(1), phase, BoolTest::le ); // } - - return NULL; } //------------------------------Value------------------------------------------ diff --git a/hotspot/src/share/vm/opto/subnode.hpp b/hotspot/src/share/vm/opto/subnode.hpp index da5d7e378cd..f809a3b90c7 100644 --- a/hotspot/src/share/vm/opto/subnode.hpp +++ b/hotspot/src/share/vm/opto/subnode.hpp @@ -286,6 +286,10 @@ class BoolNode : public Node { virtual uint hash() const; virtual uint cmp( const Node &n ) const; virtual uint size_of() const; + + // Try to optimize signed integer comparison + Node* fold_cmpI(PhaseGVN* phase, SubNode* cmp, Node* cmp1, int cmp_op, + int cmp1_op, const TypeInt* cmp2_type); public: const BoolTest _test; BoolNode( Node *cc, BoolTest::mask t): _test(t), Node(0,cc) { diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 72fabf9cc22..e20a187c6da 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -1378,9 +1378,23 @@ void SuperWord::output() { if (n->is_Load()) { Node* ctl = n->in(MemNode::Control); Node* mem = first->in(MemNode::Memory); + SWPointer p1(n->as_Mem(), this); + // Identify the memory dependency for the new loadVector node by + // walking up through memory chain. + // This is done to give flexibility to the new loadVector node so that + // it can move above independent storeVector nodes. + while (mem->is_StoreVector()) { + SWPointer p2(mem->as_Mem(), this); + int cmp = p1.cmp(p2); + if (SWPointer::not_equal(cmp) || !SWPointer::comparable(cmp)) { + mem = mem->in(MemNode::Memory); + } else { + break; // dependent memory + } + } Node* adr = low_adr->in(MemNode::Address); const TypePtr* atyp = n->adr_type(); - vn = LoadVectorNode::make(C, opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n)); + vn = LoadVectorNode::make(opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n)); vlen_in_bytes = vn->as_LoadVector()->memory_size(); } else if (n->is_Store()) { // Promote value to be stored to vector @@ -1389,7 +1403,7 @@ void SuperWord::output() { Node* mem = first->in(MemNode::Memory); Node* adr = low_adr->in(MemNode::Address); const TypePtr* atyp = n->adr_type(); - vn = StoreVectorNode::make(C, opc, ctl, mem, adr, atyp, val, vlen); + vn = StoreVectorNode::make(opc, ctl, mem, adr, atyp, val, vlen); vlen_in_bytes = vn->as_StoreVector()->memory_size(); } else if (n->req() == 3) { // Promote operands to vector @@ -1401,7 +1415,7 @@ void SuperWord::output() { in1 = in2; in2 = tmp; } - vn = VectorNode::make(C, opc, in1, in2, vlen, velt_basic_type(n)); + vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); vlen_in_bytes = vn->as_Vector()->length_in_bytes(); } else { ShouldNotReachHere(); @@ -1450,11 +1464,11 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) { if (t != NULL && t->is_con()) { juint shift = t->get_con(); if (shift > mask) { // Unsigned cmp - cnt = ConNode::make(C, TypeInt::make(shift & mask)); + cnt = ConNode::make(TypeInt::make(shift & mask)); } } else { if (t == NULL || t->_lo < 0 || t->_hi > (int)mask) { - cnt = ConNode::make(C, TypeInt::make(mask)); + cnt = ConNode::make(TypeInt::make(mask)); _igvn.register_new_node_with_optimizer(cnt); cnt = new AndINode(opd, cnt); _igvn.register_new_node_with_optimizer(cnt); @@ -1462,7 +1476,7 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) { } assert(opd->bottom_type()->isa_int(), "int type only"); // Move non constant shift count into vector register. - cnt = VectorNode::shift_count(C, p0, cnt, vlen, velt_basic_type(p0)); + cnt = VectorNode::shift_count(p0, cnt, vlen, velt_basic_type(p0)); } if (cnt != opd) { _igvn.register_new_node_with_optimizer(cnt); @@ -1475,7 +1489,7 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) { // p0's vector. Use p0's type because size of operand's container in // vector should match p0's size regardless operand's size. const Type* p0_t = velt_type(p0); - VectorNode* vn = VectorNode::scalar2vector(_phase->C, opd, vlen, p0_t); + VectorNode* vn = VectorNode::scalar2vector(opd, vlen, p0_t); _igvn.register_new_node_with_optimizer(vn); _phase->set_ctrl(vn, _phase->get_ctrl(opd)); @@ -1490,7 +1504,7 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) { // Insert pack operation BasicType bt = velt_basic_type(p0); - PackNode* pk = PackNode::make(_phase->C, opd, vlen, bt); + PackNode* pk = PackNode::make(opd, vlen, bt); DEBUG_ONLY( const BasicType opd_bt = opd->bottom_type()->basic_type(); ) for (uint i = 1; i < vlen; i++) { @@ -1546,7 +1560,7 @@ void SuperWord::insert_extracts(Node_List* p) { _igvn.hash_delete(def); int def_pos = alignment(def) / data_size(def); - Node* ex = ExtractNode::make(_phase->C, def, def_pos, velt_basic_type(def)); + Node* ex = ExtractNode::make(def, def_pos, velt_basic_type(def)); _igvn.register_new_node_with_optimizer(ex); _phase->set_ctrl(ex, _phase->get_ctrl(def)); _igvn.replace_input_of(use, idx, ex); diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index 39662643ac9..8a5eddf56b9 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -265,7 +265,7 @@ void Type::Initialize_shared(Compile* current) { // locking. Arena* save = current->type_arena(); - Arena* shared_type_arena = new (mtCompiler)Arena(); + Arena* shared_type_arena = new (mtCompiler)Arena(mtCompiler); current->set_type_arena(shared_type_arena); _shared_type_dict = @@ -5087,11 +5087,11 @@ int TypeFunc::hash(void) const { // Dump Function Type #ifndef PRODUCT void TypeFunc::dump2( Dict &d, uint depth, outputStream *st ) const { - if( _range->_cnt <= Parms ) + if( _range->cnt() <= Parms ) st->print("void"); else { uint i; - for (i = Parms; i < _range->_cnt-1; i++) { + for (i = Parms; i < _range->cnt()-1; i++) { _range->field_at(i)->dump2(d,depth,st); st->print("/"); } @@ -5104,9 +5104,9 @@ void TypeFunc::dump2( Dict &d, uint depth, outputStream *st ) const { return; } d.Insert((void*)this,(void*)this); // Stop recursion - if (Parms < _domain->_cnt) + if (Parms < _domain->cnt()) _domain->field_at(Parms)->dump2(d,depth-1,st); - for (uint i = Parms+1; i < _domain->_cnt; i++) { + for (uint i = Parms+1; i < _domain->cnt(); i++) { st->print(", "); _domain->field_at(i)->dump2(d,depth-1,st); } diff --git a/hotspot/src/share/vm/opto/type.hpp b/hotspot/src/share/vm/opto/type.hpp index e4340df4f9a..e0aeba1e91e 100644 --- a/hotspot/src/share/vm/opto/type.hpp +++ b/hotspot/src/share/vm/opto/type.hpp @@ -609,16 +609,16 @@ public: // signature types. class TypeTuple : public Type { TypeTuple( uint cnt, const Type **fields ) : Type(Tuple), _cnt(cnt), _fields(fields) { } + + const uint _cnt; // Count of fields + const Type ** const _fields; // Array of field types + public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous -public: - const uint _cnt; // Count of fields - const Type ** const _fields; // Array of field types - // Accessors: uint cnt() const { return _cnt; } const Type* field_at(uint i) const { @@ -1447,6 +1447,10 @@ class TypeFunc : public Type { virtual int hash() const; // Type specific hashing virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous + + const TypeTuple* const _domain; // Domain of inputs + const TypeTuple* const _range; // Range of results + public: // Constants are shared among ADLC and VM enum { Control = AdlcVMDeps::Control, @@ -1457,8 +1461,6 @@ public: Parms = AdlcVMDeps::Parms }; - const TypeTuple* const _domain; // Domain of inputs - const TypeTuple* const _range; // Range of results // Accessors: const TypeTuple* domain() const { return _domain; } diff --git a/hotspot/src/share/vm/opto/vectornode.cpp b/hotspot/src/share/vm/opto/vectornode.cpp index 21b51e5b524..b4a07799efb 100644 --- a/hotspot/src/share/vm/opto/vectornode.cpp +++ b/hotspot/src/share/vm/opto/vectornode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -245,7 +245,7 @@ void VectorNode::vector_operands(Node* n, uint* start, uint* end) { } // Return the vector version of a scalar operation node. -VectorNode* VectorNode::make(Compile* C, int opc, Node* n1, Node* n2, uint vlen, BasicType bt) { +VectorNode* VectorNode::make(int opc, Node* n1, Node* n2, uint vlen, BasicType bt) { const TypeVect* vt = TypeVect::make(bt, vlen); int vopc = VectorNode::opcode(opc, bt); // This method should not be called for unimplemented vectors. @@ -299,7 +299,7 @@ VectorNode* VectorNode::make(Compile* C, int opc, Node* n1, Node* n2, uint vlen, } // Scalar promotion -VectorNode* VectorNode::scalar2vector(Compile* C, Node* s, uint vlen, const Type* opd_t) { +VectorNode* VectorNode::scalar2vector(Node* s, uint vlen, const Type* opd_t) { BasicType bt = opd_t->array_element_basic_type(); const TypeVect* vt = opd_t->singleton() ? TypeVect::make(opd_t, vlen) : TypeVect::make(bt, vlen); @@ -323,7 +323,7 @@ VectorNode* VectorNode::scalar2vector(Compile* C, Node* s, uint vlen, const Type return NULL; } -VectorNode* VectorNode::shift_count(Compile* C, Node* shift, Node* cnt, uint vlen, BasicType bt) { +VectorNode* VectorNode::shift_count(Node* shift, Node* cnt, uint vlen, BasicType bt) { assert(VectorNode::is_shift(shift) && !cnt->is_Con(), "only variable shift count"); // Match shift count type with shift vector type. const TypeVect* vt = TypeVect::make(bt, vlen); @@ -342,7 +342,7 @@ VectorNode* VectorNode::shift_count(Compile* C, Node* shift, Node* cnt, uint vle } // Return initial Pack node. Additional operands added with add_opd() calls. -PackNode* PackNode::make(Compile* C, Node* s, uint vlen, BasicType bt) { +PackNode* PackNode::make(Node* s, uint vlen, BasicType bt) { const TypeVect* vt = TypeVect::make(bt, vlen); switch (bt) { case T_BOOLEAN: @@ -365,18 +365,18 @@ PackNode* PackNode::make(Compile* C, Node* s, uint vlen, BasicType bt) { } // Create a binary tree form for Packs. [lo, hi) (half-open) range -PackNode* PackNode::binary_tree_pack(Compile* C, int lo, int hi) { +PackNode* PackNode::binary_tree_pack(int lo, int hi) { int ct = hi - lo; assert(is_power_of_2(ct), "power of 2"); if (ct == 2) { - PackNode* pk = PackNode::make(C, in(lo), 2, vect_type()->element_basic_type()); + PackNode* pk = PackNode::make(in(lo), 2, vect_type()->element_basic_type()); pk->add_opd(in(lo+1)); return pk; } else { int mid = lo + ct/2; - PackNode* n1 = binary_tree_pack(C, lo, mid); - PackNode* n2 = binary_tree_pack(C, mid, hi ); + PackNode* n1 = binary_tree_pack(lo, mid); + PackNode* n2 = binary_tree_pack(mid, hi ); BasicType bt = n1->vect_type()->element_basic_type(); assert(bt == n2->vect_type()->element_basic_type(), "should be the same"); @@ -402,23 +402,23 @@ PackNode* PackNode::binary_tree_pack(Compile* C, int lo, int hi) { } // Return the vector version of a scalar load node. -LoadVectorNode* LoadVectorNode::make(Compile* C, int opc, Node* ctl, Node* mem, +LoadVectorNode* LoadVectorNode::make(int opc, Node* ctl, Node* mem, Node* adr, const TypePtr* atyp, uint vlen, BasicType bt) { const TypeVect* vt = TypeVect::make(bt, vlen); return new LoadVectorNode(ctl, mem, adr, atyp, vt); } // Return the vector version of a scalar store node. -StoreVectorNode* StoreVectorNode::make(Compile* C, int opc, Node* ctl, Node* mem, +StoreVectorNode* StoreVectorNode::make(int opc, Node* ctl, Node* mem, Node* adr, const TypePtr* atyp, Node* val, uint vlen) { return new StoreVectorNode(ctl, mem, adr, atyp, val); } // Extract a scalar element of vector. -Node* ExtractNode::make(Compile* C, Node* v, uint position, BasicType bt) { +Node* ExtractNode::make(Node* v, uint position, BasicType bt) { assert((int)position < Matcher::max_vector_size(bt), "pos in range"); - ConINode* pos = ConINode::make(C, (int)position); + ConINode* pos = ConINode::make((int)position); switch (bt) { case T_BOOLEAN: return new ExtractUBNode(v, pos); diff --git a/hotspot/src/share/vm/opto/vectornode.hpp b/hotspot/src/share/vm/opto/vectornode.hpp index 0b95a10d8a6..759d724335d 100644 --- a/hotspot/src/share/vm/opto/vectornode.hpp +++ b/hotspot/src/share/vm/opto/vectornode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -52,9 +52,9 @@ class VectorNode : public TypeNode { virtual uint ideal_reg() const { return Matcher::vector_ideal_reg(vect_type()->length_in_bytes()); } - static VectorNode* scalar2vector(Compile* C, Node* s, uint vlen, const Type* opd_t); - static VectorNode* shift_count(Compile* C, Node* shift, Node* cnt, uint vlen, BasicType bt); - static VectorNode* make(Compile* C, int opc, Node* n1, Node* n2, uint vlen, BasicType bt); + static VectorNode* scalar2vector(Node* s, uint vlen, const Type* opd_t); + static VectorNode* shift_count(Node* shift, Node* cnt, uint vlen, BasicType bt); + static VectorNode* make(int opc, Node* n1, Node* n2, uint vlen, BasicType bt); static int opcode(int opc, BasicType bt); static bool implemented(int opc, uint vlen, BasicType bt); @@ -371,7 +371,7 @@ class LoadVectorNode : public LoadNode { virtual int store_Opcode() const { return Op_StoreVector; } - static LoadVectorNode* make(Compile* C, int opc, Node* ctl, Node* mem, + static LoadVectorNode* make(int opc, Node* ctl, Node* mem, Node* adr, const TypePtr* atyp, uint vlen, BasicType bt); }; @@ -394,7 +394,7 @@ class StoreVectorNode : public StoreNode { virtual BasicType memory_type() const { return T_VOID; } virtual int memory_size() const { return vect_type()->length_in_bytes(); } - static StoreVectorNode* make(Compile* C, int opc, Node* ctl, Node* mem, + static StoreVectorNode* make(int opc, Node* ctl, Node* mem, Node* adr, const TypePtr* atyp, Node* val, uint vlen); }; @@ -465,9 +465,9 @@ class PackNode : public VectorNode { } // Create a binary tree form for Packs. [lo, hi) (half-open) range - PackNode* binary_tree_pack(Compile* C, int lo, int hi); + PackNode* binary_tree_pack(int lo, int hi); - static PackNode* make(Compile* C, Node* s, uint vlen, BasicType bt); + static PackNode* make(Node* s, uint vlen, BasicType bt); }; //------------------------------PackBNode-------------------------------------- @@ -552,7 +552,7 @@ class ExtractNode : public Node { virtual int Opcode() const; uint pos() const { return in(2)->get_int(); } - static Node* make(Compile* C, Node* v, uint position, BasicType bt); + static Node* make(Node* v, uint position, BasicType bt); }; //------------------------------ExtractBNode----------------------------------- diff --git a/hotspot/src/share/vm/precompiled/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp index be70cfffd6e..121c8aa14c6 100644 --- a/hotspot/src/share/vm/precompiled/precompiled.hpp +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -222,10 +222,17 @@ # include "runtime/vmThread.hpp" # include "runtime/vm_operations.hpp" # include "runtime/vm_version.hpp" +# include "services/allocationSite.hpp" # include "services/lowMemoryDetector.hpp" +# include "services/mallocTracker.hpp" +# include "services/memBaseline.hpp" # include "services/memoryPool.hpp" # include "services/memoryService.hpp" # include "services/memoryUsage.hpp" +# include "services/memReporter.hpp" +# include "services/memTracker.hpp" +# include "services/nmtCommon.hpp" +# include "services/virtualMemoryTracker.hpp" # include "utilities/accessFlags.hpp" # include "utilities/array.hpp" # include "utilities/bitMap.hpp" @@ -240,6 +247,7 @@ # include "utilities/hashtable.hpp" # include "utilities/histogram.hpp" # include "utilities/macros.hpp" +# include "utilities/nativeCallStack.hpp" # include "utilities/numberSeq.hpp" # include "utilities/ostream.hpp" # include "utilities/preserveException.hpp" diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 51548acdba3..c404b4c7de5 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -74,6 +74,7 @@ #include "runtime/signature.hpp" #include "runtime/thread.inline.hpp" #include "runtime/vm_operations.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "trace/tracing.hpp" #include "utilities/defaultStream.hpp" @@ -2697,6 +2698,7 @@ static char* get_bad_address() { if (bad_address != NULL) { os::protect_memory(bad_address, size, os::MEM_PROT_READ, /*is_committed*/false); + MemTracker::record_virtual_memory_type((void*)bad_address, mtInternal); } } return bad_address; @@ -3857,11 +3859,13 @@ void TestOldSize_test(); void TestKlass_test(); void TestBitMap_test(); void TestAsUtf8(); +void Test_linked_list(); #if INCLUDE_ALL_GCS void TestOldFreeSpaceCalculation_test(); void TestG1BiasedArray_test(); void TestBufferingOopClosure_test(); void TestCodeCacheRemSet_test(); +void FreeRegionList_test(); #endif void execute_internal_vm_tests() { @@ -3887,6 +3891,7 @@ void execute_internal_vm_tests() { run_unit_test(TestBitMap_test()); run_unit_test(TestAsUtf8()); run_unit_test(ObjectMonitor::sanity_checks()); + run_unit_test(Test_linked_list()); #if INCLUDE_VM_STRUCTS run_unit_test(VMStructs::test()); #endif @@ -3896,6 +3901,9 @@ void execute_internal_vm_tests() { run_unit_test(HeapRegionRemSet::test_prt()); run_unit_test(TestBufferingOopClosure_test()); run_unit_test(TestCodeCacheRemSet_test()); + if (UseG1GC) { + run_unit_test(FreeRegionList_test()); + } #endif tty->print_cr("All internal VM tests passed"); } diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 1970d715ebc..aa28aca328a 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -28,6 +28,10 @@ #include "classfile/javaClasses.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" +#if INCLUDE_CDS +#include "classfile/sharedClassUtil.hpp" +#include "classfile/systemDictionaryShared.hpp" +#endif #include "classfile/vmSymbols.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "interpreter/bytecode.hpp" @@ -993,7 +997,15 @@ JVM_ENTRY(jclass, JVM_FindLoadedClass(JNIEnv *env, jobject loader, jstring name) h_loader, Handle(), CHECK_NULL); - +#if INCLUDE_CDS + if (k == NULL) { + // If the class is not already loaded, try to see if it's in the shared + // archive for the current classloader (h_loader). + instanceKlassHandle ik = SystemDictionaryShared::find_or_load_shared_class( + klass_name, h_loader, CHECK_NULL); + k = ik(); + } +#endif return (k == NULL) ? NULL : (jclass) JNIHandles::make_local(env, k->java_mirror()); JVM_END diff --git a/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp b/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp index d2dab57a374..b614b5acea0 100644 --- a/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp +++ b/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -316,6 +316,7 @@ void JvmtiManageCapabilities::update() { avail.can_generate_frame_pop_events || avail.can_generate_method_entry_events || avail.can_generate_method_exit_events; +#ifdef ZERO bool enter_all_methods = interp_events || avail.can_generate_breakpoint_events; @@ -324,6 +325,7 @@ void JvmtiManageCapabilities::update() { UseFastEmptyMethods = false; UseFastAccessorMethods = false; } +#endif // ZERO if (avail.can_generate_breakpoint_events) { RewriteFrequentPairs = false; diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index e6805b12e5b..8cd30c31707 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -47,13 +47,16 @@ #include "utilities/exceptions.hpp" #if INCLUDE_ALL_GCS +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp" #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #endif // INCLUDE_ALL_GCS -#ifdef INCLUDE_NMT +#if INCLUDE_NMT +#include "services/mallocSiteTable.hpp" #include "services/memTracker.hpp" +#include "utilities/nativeCallStack.hpp" #endif // INCLUDE_NMT #include "compiler/compileBroker.hpp" @@ -225,6 +228,30 @@ WB_ENTRY(jint, WB_StressVirtualSpaceResize(JNIEnv* env, jobject o, (size_t) magnitude, (size_t) iterations); WB_END +WB_ENTRY(jboolean, WB_isObjectInOldGen(JNIEnv* env, jobject o, jobject obj)) + oop p = JNIHandles::resolve(obj); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + G1CollectedHeap* g1 = G1CollectedHeap::heap(); + const HeapRegion* hr = g1->heap_region_containing(p); + if (hr == NULL) { + return false; + } + return !(hr->is_young()); + } else if (UseParallelGC) { + ParallelScavengeHeap* psh = ParallelScavengeHeap::heap(); + return !psh->is_in_young(p); + } +#endif // INCLUDE_ALL_GCS + GenCollectedHeap* gch = GenCollectedHeap::heap(); + return !gch->is_in_young(p); +WB_END + +WB_ENTRY(jlong, WB_GetObjectSize(JNIEnv* env, jobject o, jobject obj)) + oop p = JNIHandles::resolve(obj); + return p->size() * HeapWordSize; +WB_END + #if INCLUDE_ALL_GCS WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj)) G1CollectedHeap* g1 = G1CollectedHeap::heap(); @@ -235,7 +262,7 @@ WB_END WB_ENTRY(jlong, WB_G1NumFreeRegions(JNIEnv* env, jobject o)) G1CollectedHeap* g1 = G1CollectedHeap::heap(); - size_t nr = g1->free_regions(); + size_t nr = g1->num_free_regions(); return (jlong)nr; WB_END @@ -255,14 +282,18 @@ WB_END // NMT picks it up correctly WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size)) jlong addr = 0; - - if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) { addr = (jlong)(uintptr_t)os::malloc(size, mtTest); - } - return addr; WB_END +// Alloc memory with pseudo call stack. The test can create psudo malloc +// allocation site to stress the malloc tracking. +WB_ENTRY(jlong, WB_NMTMallocWithPseudoStack(JNIEnv* env, jobject o, jlong size, jint pseudo_stack)) + address pc = (address)(size_t)pseudo_stack; + NativeCallStack stack(&pc, 1); + return (jlong)os::malloc(size, mtTest, stack); +WB_END + // Free the memory allocated by NMTAllocTest WB_ENTRY(void, WB_NMTFree(JNIEnv* env, jobject o, jlong mem)) os::free((void*)(uintptr_t)mem, mtTest); @@ -271,10 +302,8 @@ WB_END WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size)) jlong addr = 0; - if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) { addr = (jlong)(uintptr_t)os::reserve_memory(size); MemTracker::record_virtual_memory_type((address)addr, mtTest); - } return addr; WB_END @@ -293,20 +322,20 @@ WB_ENTRY(void, WB_NMTReleaseMemory(JNIEnv* env, jobject o, jlong addr, jlong siz os::release_memory((char *)(uintptr_t)addr, size); WB_END -// Block until the current generation of NMT data to be merged, used to reliably test the NMT feature -WB_ENTRY(jboolean, WB_NMTWaitForDataMerge(JNIEnv* env)) - - if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { - return false; - } - - return MemTracker::wbtest_wait_for_data_merge(); -WB_END - WB_ENTRY(jboolean, WB_NMTIsDetailSupported(JNIEnv* env)) - return MemTracker::tracking_level() == MemTracker::NMT_detail; + return MemTracker::tracking_level() == NMT_detail; WB_END +WB_ENTRY(void, WB_NMTOverflowHashBucket(JNIEnv* env, jobject o, jlong num)) + address pc = (address)1; + for (jlong index = 0; index < num; index ++) { + NativeCallStack stack(&pc, 1); + os::malloc(0, mtTest, stack); + pc += MallocSiteTable::hash_buckets(); + } +WB_END + + #endif // INCLUDE_NMT static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) { @@ -597,6 +626,15 @@ WB_ENTRY(jobject, WB_GetUint64VMFlag(JNIEnv* env, jobject o, jstring name)) return NULL; WB_END +WB_ENTRY(jobject, WB_GetSizeTVMFlag(JNIEnv* env, jobject o, jstring name)) + uintx result; + if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::size_tAt)) { + ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI + return longBox(thread, env, result); + } + return NULL; +WB_END + WB_ENTRY(jobject, WB_GetDoubleVMFlag(JNIEnv* env, jobject o, jstring name)) double result; if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::doubleAt)) { @@ -637,6 +675,11 @@ WB_ENTRY(void, WB_SetUint64VMFlag(JNIEnv* env, jobject o, jstring name, jlong va SetVMFlag (thread, env, name, &result, &CommandLineFlags::uint64_tAtPut); WB_END +WB_ENTRY(void, WB_SetSizeTVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) + size_t result = value; + SetVMFlag (thread, env, name, &result, &CommandLineFlags::size_tAtPut); +WB_END + WB_ENTRY(void, WB_SetDoubleVMFlag(JNIEnv* env, jobject o, jstring name, jdouble value)) double result = value; SetVMFlag (thread, env, name, &result, &CommandLineFlags::doubleAtPut); @@ -672,6 +715,9 @@ WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o)) Universe::heap()->collect(GCCause::_last_ditch_collection); WB_END +WB_ENTRY(void, WB_YoungGC(JNIEnv* env, jobject o)) + Universe::heap()->collect(GCCause::_wb_young_gc); +WB_END WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o)) // static+volatile in order to force the read to happen @@ -823,6 +869,8 @@ bool WhiteBox::lookup_bool(const char* field_name, oop object) { static JNINativeMethod methods[] = { {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, + {CC"getObjectSize", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize }, + {CC"isObjectInOldGen", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen }, {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, {CC"parseCommandLine", @@ -843,12 +891,13 @@ static JNINativeMethod methods[] = { #endif // INCLUDE_ALL_GCS #if INCLUDE_NMT {CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc }, + {CC"NMTMallocWithPseudoStack", CC"(JI)J", (void*)&WB_NMTMallocWithPseudoStack}, {CC"NMTFree", CC"(J)V", (void*)&WB_NMTFree }, {CC"NMTReserveMemory", CC"(J)J", (void*)&WB_NMTReserveMemory }, {CC"NMTCommitMemory", CC"(JJ)V", (void*)&WB_NMTCommitMemory }, {CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory }, {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory }, - {CC"NMTWaitForDataMerge", CC"()Z", (void*)&WB_NMTWaitForDataMerge}, + {CC"NMTOverflowHashBucket", CC"(J)V", (void*)&WB_NMTOverflowHashBucket}, {CC"NMTIsDetailSupported",CC"()Z", (void*)&WB_NMTIsDetailSupported}, #endif // INCLUDE_NMT {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, @@ -880,6 +929,7 @@ static JNINativeMethod methods[] = { {CC"setIntxVMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetIntxVMFlag}, {CC"setUintxVMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetUintxVMFlag}, {CC"setUint64VMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetUint64VMFlag}, + {CC"setSizeTVMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetSizeTVMFlag}, {CC"setDoubleVMFlag", CC"(Ljava/lang/String;D)V",(void*)&WB_SetDoubleVMFlag}, {CC"setStringVMFlag", CC"(Ljava/lang/String;Ljava/lang/String;)V", (void*)&WB_SetStringVMFlag}, @@ -891,12 +941,15 @@ static JNINativeMethod methods[] = { (void*)&WB_GetUintxVMFlag}, {CC"getUint64VMFlag", CC"(Ljava/lang/String;)Ljava/lang/Long;", (void*)&WB_GetUint64VMFlag}, + {CC"getSizeTVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Long;", + (void*)&WB_GetSizeTVMFlag}, {CC"getDoubleVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Double;", (void*)&WB_GetDoubleVMFlag}, {CC"getStringVMFlag", CC"(Ljava/lang/String;)Ljava/lang/String;", (void*)&WB_GetStringVMFlag}, {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable }, {CC"fullGC", CC"()V", (void*)&WB_FullGC }, + {CC"youngGC", CC"()V", (void*)&WB_YoungGC }, {CC"readReservedMemory", CC"()V", (void*)&WB_ReadReservedMemory }, {CC"allocateMetaspace", CC"(Ljava/lang/ClassLoader;J)J", (void*)&WB_AllocateMetaspace }, diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 3f0bff025ec..9ae78d32b06 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoader.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" @@ -43,6 +44,7 @@ #include "services/memTracker.hpp" #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" +#include "utilities/stringUtils.hpp" #include "utilities/taskqueue.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" @@ -300,6 +302,11 @@ static ObsoleteFlag obsolete_jvm_flags[] = { { "UseNewReflection", JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "ReflectionWrapResolutionErrors",JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "VerifyReflectionBytecodes", JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "AutoShutdownNMT", JDK_Version::jdk(9), JDK_Version::jdk(10) }, +#ifndef ZERO + { "UseFastAccessorMethods", JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "UseFastEmptyMethods", JDK_Version::jdk(9), JDK_Version::jdk(10) }, +#endif // ZERO { NULL, JDK_Version(0), JDK_Version(0) } }; @@ -686,6 +693,10 @@ static bool set_numeric_flag(char* name, char* value, Flag::Flags origin) { if (!is_neg && CommandLineFlags::uint64_tAtPut(name, &uint64_t_v, origin)) { return true; } + size_t size_t_v = (size_t) v; + if (!is_neg && CommandLineFlags::size_tAtPut(name, &size_t_v, origin)) { + return true; + } return false; } @@ -799,7 +810,7 @@ void Arguments::add_string(char*** bldarray, int* count, const char* arg) { } else { *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, new_count, mtInternal); } - (*bldarray)[*count] = strdup(arg); + (*bldarray)[*count] = os::strdup_check_oom(arg); *count = new_count; } @@ -1070,16 +1081,6 @@ void Arguments::set_mode_flags(Mode mode) { UseCompiler = true; UseLoopCounter = true; -#ifndef ZERO - // Turn these off for mixed and comp. Leave them on for Zero. - if (FLAG_IS_DEFAULT(UseFastAccessorMethods)) { - UseFastAccessorMethods = (mode == _int); - } - if (FLAG_IS_DEFAULT(UseFastEmptyMethods)) { - UseFastEmptyMethods = (mode == _int); - } -#endif - // Default values may be platform/compiler dependent - // use the saved values ClipInlining = Arguments::_ClipInlining; @@ -1120,11 +1121,11 @@ void Arguments::set_mode_flags(Mode mode) { // Conflict: required to use shared spaces (-Xshare:on), but // incompatible command line options were chosen. -static void no_shared_spaces() { +static void no_shared_spaces(const char* message) { if (RequireSharedSpaces) { jio_fprintf(defaultStream::error_stream(), "Class data sharing is inconsistent with other specified options.\n"); - vm_exit_during_initialization("Unable to use shared archive.", NULL); + vm_exit_during_initialization("Unable to use shared archive.", message); } else { FLAG_SET_DEFAULT(UseSharedSpaces, false); } @@ -1431,6 +1432,22 @@ bool verify_object_alignment() { (int)ObjectAlignmentInBytes, os::vm_page_size()); return false; } + if(SurvivorAlignmentInBytes == 0) { + SurvivorAlignmentInBytes = ObjectAlignmentInBytes; + } else { + if (!is_power_of_2(SurvivorAlignmentInBytes)) { + jio_fprintf(defaultStream::error_stream(), + "error: SurvivorAlignmentInBytes=%d must be power of 2\n", + (int)SurvivorAlignmentInBytes); + return false; + } + if (SurvivorAlignmentInBytes < ObjectAlignmentInBytes) { + jio_fprintf(defaultStream::error_stream(), + "error: SurvivorAlignmentInBytes=%d must be greater than ObjectAlignmentInBytes=%d \n", + (int)SurvivorAlignmentInBytes, (int)ObjectAlignmentInBytes); + return false; + } + } return true; } @@ -1570,7 +1587,7 @@ void Arguments::set_ergonomics_flags() { // at link time, or rewrite bytecodes in non-shared methods. if (!DumpSharedSpaces && !RequireSharedSpaces && (FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) { - no_shared_spaces(); + no_shared_spaces("COMPILER2 default: -Xshare:auto | off, have to manually setup to on."); } #endif @@ -1869,7 +1886,7 @@ void Arguments::process_java_compiler_argument(char* arg) { } void Arguments::process_java_launcher_argument(const char* launcher, void* extra_info) { - _sun_java_launcher = strdup(launcher); + _sun_java_launcher = os::strdup_check_oom(launcher); } bool Arguments::created_by_java_launcher() { @@ -2372,7 +2389,7 @@ bool Arguments::check_vm_args_consistency() { if (PrintNMTStatistics) { #if INCLUDE_NMT - if (MemTracker::tracking_level() == MemTracker::NMT_off) { + if (MemTracker::tracking_level() == NMT_off) { #endif // INCLUDE_NMT warning("PrintNMTStatistics is disabled, because native memory tracking is not enabled"); PrintNMTStatistics = false; @@ -2979,7 +2996,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // Redirect GC output to the file. -Xloggc: // ostream_init_log(), when called will use this filename // to initialize a fileStream. - _gc_log_filename = strdup(tail); + _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 " @@ -3291,6 +3308,15 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } } + // PrintSharedArchiveAndExit will turn on + // -Xshare:on + // -XX:+TraceClassPaths + if (PrintSharedArchiveAndExit) { + FLAG_SET_CMDLINE(bool, UseSharedSpaces, true); + FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true); + FLAG_SET_CMDLINE(bool, TraceClassPaths, true); + } + // Change the default value for flags which have different default values // when working with older JDKs. #ifdef LINUX @@ -3299,9 +3325,55 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, FLAG_SET_DEFAULT(UseLinuxPosixThreadCPUClocks, false); } #endif // LINUX + fix_appclasspath(); return JNI_OK; } +// Remove all empty paths from the app classpath (if IgnoreEmptyClassPaths is enabled) +// +// This is necessary because some apps like to specify classpath like -cp foo.jar:${XYZ}:bar.jar +// in their start-up scripts. If XYZ is empty, the classpath will look like "-cp foo.jar::bar.jar". +// Java treats such empty paths as if the user specified "-cp foo.jar:.:bar.jar". I.e., an empty +// path is treated as the current directory. +// +// This causes problems with CDS, which requires that all directories specified in the classpath +// must be empty. In most cases, applications do NOT want to load classes from the current +// directory anyway. Adding -XX:+IgnoreEmptyClassPaths will make these applications' start-up +// scripts compatible with CDS. +void Arguments::fix_appclasspath() { + if (IgnoreEmptyClassPaths) { + const char separator = *os::path_separator(); + const char* src = _java_class_path->value(); + + // skip over all the leading empty paths + while (*src == separator) { + src ++; + } + + char* copy = AllocateHeap(strlen(src) + 1, mtInternal); + strncpy(copy, src, strlen(src) + 1); + + // trim all trailing empty paths + for (char* tail = copy + strlen(copy) - 1; tail >= copy && *tail == separator; tail--) { + *tail = '\0'; + } + + char from[3] = {separator, separator, '\0'}; + char to [2] = {separator, '\0'}; + while (StringUtils::replace_no_expand(copy, from, to) > 0) { + // Keep replacing "::" -> ":" until we have no more "::" (non-windows) + // Keep replacing ";;" -> ";" until we have no more ";;" (windows) + } + + _java_class_path->set_value(copy); + FreeHeap(copy); // a copy was made by set_value, so don't need this anymore + } + + if (!PrintSharedArchiveAndExit) { + ClassLoader::trace_class_path("[classpath: ", _java_class_path->value()); + } +} + jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required) { // This must be done after all -D arguments have been processed. scp_p->expand_endorsed(); @@ -3472,9 +3544,8 @@ void Arguments::set_shared_spaces_flags() { "Cannot dump shared archive when UseCompressedOops or UseCompressedClassPointers is off.", NULL); } } else { - // UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces. if (!UseCompressedOops || !UseCompressedClassPointers) { - no_shared_spaces(); + no_shared_spaces("UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces."); } #endif } @@ -3582,15 +3653,24 @@ jint Arguments::parse(const JavaVMInitArgs* args) { CommandLineFlags::printFlags(tty, false); vm_exit(0); } - if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { #if INCLUDE_NMT - MemTracker::init_tracking_options(tail); -#else - jio_fprintf(defaultStream::error_stream(), - "Native Memory Tracking is not supported in this VM\n"); - return JNI_ERR; -#endif + if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { + // The launcher did not setup nmt environment variable properly. + if (!MemTracker::check_launcher_nmt_support(tail)) { + warning("Native Memory Tracking did not setup properly, using wrong launcher?"); + } + + // Verify if nmt option is valid. + if (MemTracker::verify_nmt_option()) { + // Late initialization, still in single-threaded mode. + if (MemTracker::tracking_level() >= NMT_summary) { + MemTracker::init(); + } + } else { + vm_exit_during_initialization("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]", NULL); + } } +#endif #ifndef PRODUCT @@ -3705,7 +3785,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { FLAG_SET_DEFAULT(UseSharedSpaces, false); FLAG_SET_DEFAULT(PrintSharedSpaces, false); } - no_shared_spaces(); + no_shared_spaces("CDS Disabled"); #endif // INCLUDE_CDS return JNI_OK; diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 64cdc5ca72d..28608e2ba1a 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -579,12 +579,15 @@ class Arguments : AllStatic { _meta_index_dir = meta_index_dir; } - static char *get_java_home() { return _java_home->value(); } - static char *get_dll_dir() { return _sun_boot_library_path->value(); } - static char *get_endorsed_dir() { return _java_endorsed_dirs->value(); } - static char *get_sysclasspath() { return _sun_boot_class_path->value(); } + static char* get_java_home() { return _java_home->value(); } + static char* get_dll_dir() { return _sun_boot_library_path->value(); } + static char* get_endorsed_dir() { return _java_endorsed_dirs->value(); } + static char* get_sysclasspath() { return _sun_boot_class_path->value(); } static char* get_meta_index_path() { return _meta_index_path; } static char* get_meta_index_dir() { return _meta_index_dir; } + static char* get_ext_dirs() { return _java_ext_dirs->value(); } + static char* get_appclasspath() { return _java_class_path->value(); } + static void fix_appclasspath(); // Operation modi static Mode mode() { return _mode; } diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index a7ad943cf7c..f630d5d35cc 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -661,7 +661,7 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m (iframe->interpreter_frame_expression_stack_size() == (next_mask_expression_stack_size - top_frame_expression_stack_adjustment))) || (is_top_frame && (exec_mode == Unpack_exception) && iframe->interpreter_frame_expression_stack_size() == 0) || - (is_top_frame && (exec_mode == Unpack_uncommon_trap || exec_mode == Unpack_reexecute) && + (is_top_frame && (exec_mode == Unpack_uncommon_trap || exec_mode == Unpack_reexecute || el->should_reexecute()) && (iframe->interpreter_frame_expression_stack_size() == mask.expression_stack_size() + cur_invoke_parameter_size)) )) { ttyLocker ttyl; diff --git a/hotspot/src/share/vm/runtime/fprofiler.cpp b/hotspot/src/share/vm/runtime/fprofiler.cpp index aec76268824..7f741fee561 100644 --- a/hotspot/src/share/vm/runtime/fprofiler.cpp +++ b/hotspot/src/share/vm/runtime/fprofiler.cpp @@ -629,10 +629,16 @@ class vmNode : public ProfilerNode { } vmNode(const char* name, const TickPosition where) : ProfilerNode() { - _name = name; + _name = os::strdup(name); update(where); } + ~vmNode() { + if (_name != NULL) { + os::free((void*)_name); + } + } + const char *name() const { return _name; } bool is_compiled() const { return true; } @@ -784,7 +790,7 @@ void ThreadProfiler::vm_update(const char* name, TickPosition where) { assert(index >= 0, "Must be positive"); // Note that we call strdup below since the symbol may be resource allocated if (!table[index]) { - table[index] = new (this) vmNode(os::strdup(name), where); + table[index] = new (this) vmNode(name, where); } else { ProfilerNode* prev = table[index]; for(ProfilerNode* node = prev; node; node = node->next()) { @@ -794,7 +800,7 @@ void ThreadProfiler::vm_update(const char* name, TickPosition where) { } prev = node; } - prev->set_next(new (this) vmNode(os::strdup(name), where)); + prev->set_next(new (this) vmNode(name, where)); } } diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index d076896f0aa..8701b9ccf63 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -407,7 +407,8 @@ jint frame::interpreter_frame_bci() const { address frame::interpreter_frame_bcp() const { assert(is_interpreted_frame(), "interpreted frame expected"); - return (address)*interpreter_frame_bcp_addr(); + address bcp = (address)*interpreter_frame_bcp_addr(); + return interpreter_frame_method()->bcp_from(bcp); } void frame::interpreter_frame_set_bcp(address bcp) { diff --git a/hotspot/src/share/vm/runtime/globals.cpp b/hotspot/src/share/vm/runtime/globals.cpp index 928f7134e14..b20ef79db13 100644 --- a/hotspot/src/share/vm/runtime/globals.cpp +++ b/hotspot/src/share/vm/runtime/globals.cpp @@ -131,6 +131,19 @@ void Flag::set_uint64_t(uint64_t value) { *((uint64_t*) _addr) = value; } +bool Flag::is_size_t() const { + return strcmp(_type, "size_t") == 0; +} + +size_t Flag::get_size_t() const { + return *((size_t*) _addr); +} + +void Flag::set_size_t(size_t value) { + check_writable(); + *((size_t*) _addr) = value; +} + bool Flag::is_double() const { return strcmp(_type, "double") == 0; } @@ -306,6 +319,9 @@ void Flag::print_on(outputStream* st, bool withComments) { if (is_uint64_t()) { st->print("%-16lu", get_uint64_t()); } + if (is_size_t()) { + st->print(SIZE_FORMAT_W(-16), get_size_t()); + } if (is_double()) { st->print("%-16f", get_double()); } @@ -395,6 +411,8 @@ void Flag::print_as_flag(outputStream* st) { st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx()); } else if (is_uint64_t()) { st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t()); + } else if (is_size_t()) { + st->print("-XX:%s=" SIZE_FORMAT, _name, get_size_t()); } else if (is_double()) { st->print("-XX:%s=%f", _name, get_double()); } else if (is_ccstr()) { @@ -723,6 +741,34 @@ void CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t va faddr->set_origin(origin); } +bool CommandLineFlags::size_tAt(const char* name, size_t len, size_t* value) { + Flag* result = Flag::find_flag(name, len); + if (result == NULL) return false; + if (!result->is_size_t()) return false; + *value = result->get_size_t(); + return true; +} + +bool CommandLineFlags::size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + if (result == NULL) return false; + if (!result->is_size_t()) return false; + size_t old_value = result->get_size_t(); + trace_flag_changed(name, old_value, *value, origin); + result->set_size_t(*value); + *value = old_value; + result->set_origin(origin); + return true; +} + +void CommandLineFlagsEx::size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type"); + trace_flag_changed(faddr->_name, faddr->get_size_t(), value, origin); + faddr->set_size_t(value); + faddr->set_origin(origin); +} + bool CommandLineFlags::doubleAt(const char* name, size_t len, double* value) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 2d1805e2fb6..372f6c720ab 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -275,6 +275,10 @@ struct Flag { uint64_t get_uint64_t() const; void set_uint64_t(uint64_t value); + bool is_size_t() const; + size_t get_size_t() const; + void set_size_t(size_t value); + bool is_double() const; double get_double() const; void set_double(double value); @@ -350,7 +354,6 @@ class UIntFlagSetting { ~UIntFlagSetting() { *flag = val; } }; - class DoubleFlagSetting { double val; double* flag; @@ -359,6 +362,14 @@ class DoubleFlagSetting { ~DoubleFlagSetting() { *flag = val; } }; +class SizeTFlagSetting { + size_t val; + size_t* flag; + public: + SizeTFlagSetting(size_t& fl, size_t newValue) { flag = &fl; val = fl; fl = newValue; } + ~SizeTFlagSetting() { *flag = val; } +}; + class CommandLineFlags { public: @@ -377,6 +388,11 @@ class CommandLineFlags { static bool uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin); static bool uintxAtPut(const char* name, uintx* value, Flag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); } + static bool size_tAt(const char* name, size_t len, size_t* value); + static bool size_tAt(const char* name, size_t* value) { return size_tAt(name, strlen(name), value); } + static bool size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin); + static bool size_tAtPut(const char* name, size_t* value, Flag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); } + static bool uint64_tAt(const char* name, size_t len, uint64_t* value); static bool uint64_tAt(const char* name, uint64_t* value) { return uint64_tAt(name, strlen(name), value); } static bool uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin); @@ -945,11 +961,6 @@ class CommandLineFlags { diagnostic(bool, PrintNMTStatistics, false, \ "Print native memory tracking summary data if it is on") \ \ - diagnostic(bool, AutoShutdownNMT, true, \ - "Automatically shutdown native memory tracking under stress " \ - "situations. When set to false, native memory tracking tries to " \ - "stay alive at the expense of JVM performance") \ - \ diagnostic(bool, LogCompilation, false, \ "Log compilation activity in detail to LogFile") \ \ @@ -1078,6 +1089,9 @@ class CommandLineFlags { product(bool, ClassUnloading, true, \ "Do unloading of classes") \ \ + product(bool, ClassUnloadingWithConcurrentMark, true, \ + "Do unloading of classes with a concurrent marking cycle") \ + \ develop(bool, DisableStartThread, false, \ "Disable starting of additional Java threads " \ "(for debugging only)") \ @@ -2331,6 +2345,12 @@ class CommandLineFlags { notproduct(bool, TraceScavenge, false, \ "Trace scavenge") \ \ + product(bool, IgnoreEmptyClassPaths, false, \ + "Ignore empty path elements in -classpath") \ + \ + product(bool, TraceClassPaths, false, \ + "Trace processing of class paths") \ + \ product_rw(bool, TraceClassLoading, false, \ "Trace all classes loaded") \ \ @@ -2786,12 +2806,6 @@ class CommandLineFlags { product(bool, UseLoopCounter, true, \ "Increment invocation counter on backward branch") \ \ - product(bool, UseFastEmptyMethods, true, \ - "Use fast method entry code for empty methods") \ - \ - product(bool, UseFastAccessorMethods, true, \ - "Use fast method entry code for accessor methods") \ - \ product_pd(bool, UseOnStackReplacement, \ "Use on stack replacement, calls runtime if invoc. counter " \ "overflows in loop") \ @@ -3771,6 +3785,13 @@ class CommandLineFlags { product(bool, PrintSharedSpaces, false, \ "Print usage of shared spaces") \ \ + product(bool, PrintSharedArchiveAndExit, false, \ + "Print shared archive file contents") \ + \ + product(bool, PrintSharedDictionary, false, \ + "If PrintSharedArchiveAndExit is true, also print the shared " \ + "dictionary") \ + \ product(uintx, SharedReadWriteSize, NOT_LP64(12*M) LP64_ONLY(16*M), \ "Size of read-write space for metadata (in bytes)") \ \ @@ -3787,6 +3808,10 @@ class CommandLineFlags { NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \ "Address to allocate shared memory region for class data") \ \ + diagnostic(bool, IgnoreUnverifiableClassesDuringDump, false, \ + "Do not quit -Xshare:dump even if we encounter unverifiable " \ + "classes. Just exclude them from the shared dictionary.") \ + \ diagnostic(bool, PrintMethodHandleStubs, false, \ "Print generated stub code for method handles") \ \ @@ -3871,14 +3896,27 @@ class CommandLineFlags { product(bool, PrintGCCause, true, \ "Include GC cause in GC logging") \ \ + experimental(intx, SurvivorAlignmentInBytes, 0, \ + "Default survivor space alignment in bytes") \ + \ product(bool , AllowNonVirtualCalls, false, \ "Obey the ACC_SUPER flag and allow invokenonvirtual calls") \ \ + product(ccstr, DumpLoadedClassList, NULL, \ + "Dump the names all loaded classes, that could be stored into " \ + "the CDS archive, in the specified file") \ + \ + product(ccstr, SharedClassListFile, NULL, \ + "Override the default CDS class list") \ + \ diagnostic(ccstr, SharedArchiveFile, NULL, \ "Override the default location of the CDS archive file") \ \ - experimental(uintx, ArrayAllocatorMallocLimit, \ - SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx), \ + product(ccstr, ExtraSharedClassListFile, NULL, \ + "Extra classlist for building the CDS archive file") \ + \ + experimental(size_t, ArrayAllocatorMallocLimit, \ + SOLARIS_ONLY(64*K) NOT_SOLARIS((size_t)-1), \ "Allocation less than this value will be allocated " \ "using malloc. Larger allocations will use mmap.") \ \ diff --git a/hotspot/src/share/vm/runtime/globals_extension.hpp b/hotspot/src/share/vm/runtime/globals_extension.hpp index 468d4bb87fa..99c19776fe3 100644 --- a/hotspot/src/share/vm/runtime/globals_extension.hpp +++ b/hotspot/src/share/vm/runtime/globals_extension.hpp @@ -200,6 +200,7 @@ class CommandLineFlagsEx : CommandLineFlags { static void intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin); static void uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin); static void uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin); + static void size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin); static void doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin); // Contract: Flag will make private copy of the incoming value static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin); diff --git a/hotspot/src/share/vm/runtime/handles.hpp b/hotspot/src/share/vm/runtime/handles.hpp index e7212214a14..3eef0adbc60 100644 --- a/hotspot/src/share/vm/runtime/handles.hpp +++ b/hotspot/src/share/vm/runtime/handles.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -227,7 +227,7 @@ class HandleArea: public Arena { HandleArea* _prev; // link to outer (older) area public: // Constructor - HandleArea(HandleArea* prev) : Arena(Chunk::tiny_size) { + HandleArea(HandleArea* prev) : Arena(mtThread, Chunk::tiny_size) { debug_only(_handle_mark_nesting = 0); debug_only(_no_handle_mark_nesting = 0); _prev = prev; diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp index 6c654d280e2..68c8845aaf7 100644 --- a/hotspot/src/share/vm/runtime/init.cpp +++ b/hotspot/src/share/vm/runtime/init.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -34,8 +34,10 @@ #include "runtime/init.hpp" #include "runtime/safepoint.hpp" #include "runtime/sharedRuntime.hpp" +#include "services/memTracker.hpp" #include "utilities/macros.hpp" + // Initialization done by VM thread in vm_init_globals() void check_ThreadShadow(); void eventlog_init(); @@ -131,6 +133,12 @@ jint init_globals() { javaClasses_init(); // must happen after vtable initialization stubRoutines_init2(); // note: StubRoutines need 2-phase init +#if INCLUDE_NMT + // Solaris stack is walkable only after stubRoutines are set up. + // On Other platforms, the stack is always walkable. + NMT_stack_walkable = true; +#endif // INCLUDE_NMT + // All the flags that get adjusted by VM_Version_init and os::init_2 // have been set so dump the flags now. if (PrintFlagsFinal) { diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index cfecf0a5d57..881d808cdf7 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -57,7 +57,6 @@ #include "runtime/thread.inline.hpp" #include "runtime/timer.hpp" #include "runtime/vm_operations.hpp" -#include "services/memReporter.hpp" #include "services/memTracker.hpp" #include "trace/tracing.hpp" #include "utilities/dtrace.hpp" @@ -349,12 +348,7 @@ void print_statistics() { #endif // ENABLE_ZAP_DEAD_LOCALS // Native memory tracking data if (PrintNMTStatistics) { - if (MemTracker::is_on()) { - BaselineTTYOutputer outputer(tty); - MemTracker::print_memory_usage(outputer, K, false); - } else { - tty->print_cr("%s", MemTracker::reason()); - } + MemTracker::final_report(tty); } } @@ -390,12 +384,7 @@ void print_statistics() { // Native memory tracking data if (PrintNMTStatistics) { - if (MemTracker::is_on()) { - BaselineTTYOutputer outputer(tty); - MemTracker::print_memory_usage(outputer, K, false); - } else { - tty->print_cr("%s", MemTracker::reason()); - } + MemTracker::final_report(tty); } } @@ -544,10 +533,6 @@ void before_exit(JavaThread * thread) { BeforeExit_lock->notify_all(); } - // Shutdown NMT before exit. Otherwise, - // it will run into trouble when system destroys static variables. - MemTracker::shutdown(MemTracker::NMT_normal); - if (VerifyStringTableAtExit) { int fail_cnt = 0; { diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 24f84978fe2..3cb4053f893 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -309,6 +309,10 @@ void JavaCalls::call(JavaValue* result, methodHandle method, JavaCallArguments* } void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArguments* args, TRAPS) { + // During dumping, Java execution environment is not fully initialized. Also, Java execution + // may cause undesirable side-effects in the class metadata. + assert(!DumpSharedSpaces, "must not execute Java bytecodes when dumping"); + methodHandle method = *m; JavaThread* thread = (JavaThread*)THREAD; assert(thread->is_Java_thread(), "must be called by a java thread"); diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 6c682a703cd..3b3bc44bec0 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -52,6 +52,7 @@ #include "runtime/thread.inline.hpp" #include "runtime/vm_version.hpp" #include "services/attachListener.hpp" +#include "services/nmtCommon.hpp" #include "services/memTracker.hpp" #include "services/threadService.hpp" #include "utilities/defaultStream.hpp" @@ -516,6 +517,14 @@ char *os::strdup(const char *str, MEMFLAGS flags) { return dup_str; } +char* os::strdup_check_oom(const char* str, MEMFLAGS flags) { + char* p = os::strdup(str, flags); + if (p == NULL) { + vm_exit_out_of_memory(strlen(str) + 1, OOM_MALLOC_ERROR, "os::strdup_check_oom"); + } + return p; +} + #define paranoid 0 /* only set to 1 if you suspect checking code has bug */ @@ -553,7 +562,11 @@ static u_char* testMalloc(size_t alloc_size) { return ptr; } -void* os::malloc(size_t size, MEMFLAGS memflags, address caller) { +void* os::malloc(size_t size, MEMFLAGS flags) { + return os::malloc(size, flags, CALLER_PC); +} + +void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) { NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); @@ -579,11 +592,15 @@ void* os::malloc(size_t size, MEMFLAGS memflags, address caller) { size = 1; } + // NMT support + NMT_TrackingLevel level = MemTracker::tracking_level(); + size_t nmt_header_size = MemTracker::malloc_header_size(level); + #ifndef ASSERT - const size_t alloc_size = size; + const size_t alloc_size = size + nmt_header_size; #else - const size_t alloc_size = GuardedMemory::get_total_size(size); - if (size > alloc_size) { // Check for rollover. + const size_t alloc_size = GuardedMemory::get_total_size(size + nmt_header_size); + if (size + nmt_header_size > alloc_size) { // Check for rollover. return NULL; } #endif @@ -602,7 +619,7 @@ void* os::malloc(size_t size, MEMFLAGS memflags, address caller) { return NULL; } // Wrap memory with guard - GuardedMemory guarded(ptr, size); + GuardedMemory guarded(ptr, size + nmt_header_size); ptr = guarded.get_user_ptr(); #endif if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) { @@ -615,48 +632,50 @@ void* os::malloc(size_t size, MEMFLAGS memflags, address caller) { } // we do not track guard memory - MemTracker::record_malloc((address)ptr, size, memflags, caller == 0 ? CALLER_PC : caller); - - return ptr; + return MemTracker::record_malloc((address)ptr, size, memflags, stack, level); } +void* os::realloc(void *memblock, size_t size, MEMFLAGS flags) { + return os::realloc(memblock, size, flags, CALLER_PC); +} -void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, address caller) { +void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) { #ifndef ASSERT NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); - MemTracker::Tracker tkr = MemTracker::get_realloc_tracker(); - void* ptr = ::realloc(memblock, size); - if (ptr != NULL) { - tkr.record((address)memblock, (address)ptr, size, memflags, - caller == 0 ? CALLER_PC : caller); - } else { - tkr.discard(); - } - return ptr; + // NMT support + void* membase = MemTracker::record_free(memblock); + NMT_TrackingLevel level = MemTracker::tracking_level(); + size_t nmt_header_size = MemTracker::malloc_header_size(level); + void* ptr = ::realloc(membase, size + nmt_header_size); + return MemTracker::record_malloc(ptr, size, memflags, stack, level); #else if (memblock == NULL) { - return os::malloc(size, memflags, (caller == 0 ? CALLER_PC : caller)); + return os::malloc(size, memflags, stack); } if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { tty->print_cr("os::realloc caught " PTR_FORMAT, memblock); breakpoint(); } - verify_memory(memblock); + // NMT support + void* membase = MemTracker::malloc_base(memblock); + verify_memory(membase); NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap()); if (size == 0) { return NULL; } // always move the block - void* ptr = os::malloc(size, memflags, caller == 0 ? CALLER_PC : caller); + void* ptr = os::malloc(size, memflags, stack); if (PrintMalloc) { tty->print_cr("os::remalloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr); } // Copy to new memory if malloc didn't fail if ( ptr != NULL ) { - GuardedMemory guarded(memblock); - memcpy(ptr, memblock, MIN2(size, guarded.get_user_size())); - if (paranoid) verify_memory(ptr); + GuardedMemory guarded(MemTracker::malloc_base(memblock)); + // Guard's user data contains NMT header + size_t memblock_size = guarded.get_user_size() - MemTracker::malloc_header_size(memblock); + memcpy(ptr, memblock, MIN2(size, memblock_size)); + if (paranoid) verify_memory(MemTracker::malloc_base(ptr)); if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) { tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr); breakpoint(); @@ -669,7 +688,6 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, address caller void os::free(void *memblock, MEMFLAGS memflags) { - address trackp = (address) memblock; NOT_PRODUCT(inc_stat_counter(&num_frees, 1)); #ifdef ASSERT if (memblock == NULL) return; @@ -677,20 +695,22 @@ void os::free(void *memblock, MEMFLAGS memflags) { if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, memblock); breakpoint(); } - verify_memory(memblock); + void* membase = MemTracker::record_free(memblock); + verify_memory(membase); NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap()); - GuardedMemory guarded(memblock); + GuardedMemory guarded(membase); size_t size = guarded.get_user_size(); inc_stat_counter(&free_bytes, size); - memblock = guarded.release_for_freeing(); + membase = guarded.release_for_freeing(); if (PrintMalloc && tty != NULL) { - fprintf(stderr, "os::free " SIZE_FORMAT " bytes --> " PTR_FORMAT "\n", size, (uintptr_t)memblock); + fprintf(stderr, "os::free " SIZE_FORMAT " bytes --> " PTR_FORMAT "\n", size, (uintptr_t)membase); } + ::free(membase); +#else + void* membase = MemTracker::record_free(memblock); + ::free(membase); #endif - MemTracker::record_free(trackp, memflags); - - ::free(memblock); } void os::init_random(long initval) { @@ -1478,7 +1498,7 @@ bool os::create_stack_guard_pages(char* addr, size_t bytes) { char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { char* result = pd_reserve_memory(bytes, addr, alignment_hint); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); } return result; @@ -1488,7 +1508,7 @@ char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint, MEMFLAGS flags) { char* result = pd_reserve_memory(bytes, addr, alignment_hint); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); MemTracker::record_virtual_memory_type((address)result, flags); } @@ -1498,7 +1518,7 @@ char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint, char* os::attempt_reserve_memory_at(size_t bytes, char* addr) { char* result = pd_attempt_reserve_memory_at(bytes, addr); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); } return result; } @@ -1538,23 +1558,29 @@ void os::commit_memory_or_exit(char* addr, size_t size, size_t alignment_hint, } bool os::uncommit_memory(char* addr, size_t bytes) { - MemTracker::Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker(); - bool res = pd_uncommit_memory(addr, bytes); - if (res) { - tkr.record((address)addr, bytes); + bool res; + if (MemTracker::tracking_level() > NMT_minimal) { + Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker(); + res = pd_uncommit_memory(addr, bytes); + if (res) { + tkr.record((address)addr, bytes); + } } else { - tkr.discard(); + res = pd_uncommit_memory(addr, bytes); } return res; } bool os::release_memory(char* addr, size_t bytes) { - MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); - bool res = pd_release_memory(addr, bytes); - if (res) { - tkr.record((address)addr, bytes); + bool res; + if (MemTracker::tracking_level() > NMT_minimal) { + Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + res = pd_release_memory(addr, bytes); + if (res) { + tkr.record((address)addr, bytes); + } } else { - tkr.discard(); + res = pd_release_memory(addr, bytes); } return res; } @@ -1565,7 +1591,7 @@ char* os::map_memory(int fd, const char* file_name, size_t file_offset, bool allow_exec) { char* result = pd_map_memory(fd, file_name, file_offset, addr, bytes, read_only, allow_exec); if (result != NULL) { - MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, mtNone, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC); } return result; } @@ -1578,12 +1604,15 @@ char* os::remap_memory(int fd, const char* file_name, size_t file_offset, } bool os::unmap_memory(char *addr, size_t bytes) { - MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); - bool result = pd_unmap_memory(addr, bytes); - if (result) { - tkr.record((address)addr, bytes); + bool result; + if (MemTracker::tracking_level() > NMT_minimal) { + Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + result = pd_unmap_memory(addr, bytes); + if (result) { + tkr.record((address)addr, bytes); + } } else { - tkr.discard(); + result = pd_unmap_memory(addr, bytes); } return result; } diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index b65e7ab44c5..5029a238a00 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -65,6 +65,8 @@ class JavaThread; class Event; class DLL; class FileHandle; +class NativeCallStack; + template class GrowableArray; // %%%%% Moved ThreadState, START_FN, OSThread to new osThread.hpp. -- Rose @@ -96,9 +98,11 @@ const bool ExecMem = true; // Typedef for structured exception handling support typedef void (*java_call_t)(JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread); +class MallocTracker; + class os: AllStatic { friend class VMStructs; - + friend class MallocTracker; public: enum { page_sizes_max = 9 }; // Size of _page_sizes array (8 plus a sentinel) @@ -160,7 +164,10 @@ class os: AllStatic { // Override me as needed static int file_name_strcmp(const char* s1, const char* s2); + // get/unset environment variable static bool getenv(const char* name, char* buffer, int len); + static bool unsetenv(const char* name); + static bool have_special_privileges(); static jlong javaTimeMillis(); @@ -207,8 +214,13 @@ class os: AllStatic { // Interface for detecting multiprocessor system static inline bool is_MP() { +#if !INCLUDE_NMT assert(_processor_count > 0, "invalid processor count"); return _processor_count > 1 || AssumeMP; +#else + // NMT needs atomic operations before this initialization. + return true; +#endif } static julong available_memory(); static julong physical_memory(); @@ -635,15 +647,25 @@ class os: AllStatic { static void* thread_local_storage_at(int index); static void free_thread_local_storage(int index); - // Stack walk - static address get_caller_pc(int n = 0); + // Retrieve native stack frames. + // Parameter: + // stack: an array to storage stack pointers. + // frames: size of above array. + // toSkip: number of stack frames to skip at the beginning. + // Return: number of stack frames captured. + static int get_native_stack(address* stack, int size, int toSkip = 0); // General allocation (must be MT-safe) - static void* malloc (size_t size, MEMFLAGS flags, address caller_pc = 0); - static void* realloc (void *memblock, size_t size, MEMFLAGS flags, address caller_pc = 0); + static void* malloc (size_t size, MEMFLAGS flags, const NativeCallStack& stack); + static void* malloc (size_t size, MEMFLAGS flags); + static void* realloc (void *memblock, size_t size, MEMFLAGS flag, const NativeCallStack& stack); + static void* realloc (void *memblock, size_t size, MEMFLAGS flag); + static void free (void *memblock, MEMFLAGS flags = mtNone); static bool check_heap(bool force = false); // verify C heap integrity static char* strdup(const char *, MEMFLAGS flags = mtInternal); // Like strdup + // Like strdup, but exit VM when strdup() returns NULL + static char* strdup_check_oom(const char*, MEMFLAGS flags = mtInternal); #ifndef PRODUCT static julong num_mallocs; // # of calls to malloc/realloc diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp index 4b16f6b04a8..05460b84dc0 100644 --- a/hotspot/src/share/vm/runtime/safepoint.cpp +++ b/hotspot/src/share/vm/runtime/safepoint.cpp @@ -52,7 +52,6 @@ #include "runtime/sweeper.hpp" #include "runtime/synchronizer.hpp" #include "runtime/thread.inline.hpp" -#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/events.hpp" #include "utilities/macros.hpp" @@ -527,10 +526,6 @@ void SafepointSynchronize::do_cleanup_tasks() { TraceTime t7("purging class loader data graph", TraceSafepointCleanupTime); ClassLoaderDataGraph::purge_if_needed(); } - - if (MemTracker::is_on()) { - MemTracker::sync(); - } } diff --git a/hotspot/src/share/vm/runtime/sharedRuntimeMath.hpp b/hotspot/src/share/vm/runtime/sharedRuntimeMath.hpp index 4259227c3b3..26c9147f8b1 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntimeMath.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntimeMath.hpp @@ -27,20 +27,51 @@ #include -// VM_LITTLE_ENDIAN is #defined appropriately in the Makefiles -// [jk] this is not 100% correct because the float word order may different -// from the byte order (e.g. on ARM FPA) +// Used to access the lower/higher 32 bits of a double +typedef union { + double d; + struct { #ifdef VM_LITTLE_ENDIAN -# define __HI(x) *(1+(int*)&x) -# define __LO(x) *(int*)&x + int lo; + int hi; #else -# define __HI(x) *(int*)&x -# define __LO(x) *(1+(int*)&x) + int hi; + int lo; #endif + } split; +} DoubleIntConv; + +static inline int high(double d) { + DoubleIntConv x; + x.d = d; + return x.split.hi; +} + +static inline int low(double d) { + DoubleIntConv x; + x.d = d; + return x.split.lo; +} + +static inline void set_high(double* d, int high) { + DoubleIntConv conv; + conv.d = *d; + conv.split.hi = high; + *d = conv.d; +} + +static inline void set_low(double* d, int low) { + DoubleIntConv conv; + conv.d = *d; + conv.split.lo = low; + *d = conv.d; +} static double copysignA(double x, double y) { - __HI(x) = (__HI(x)&0x7fffffff)|(__HI(y)&0x80000000); - return x; + DoubleIntConv convX; + convX.d = x; + convX.split.hi = (convX.split.hi & 0x7fffffff) | (high(y) & 0x80000000); + return convX.d; } /* @@ -67,30 +98,32 @@ twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ hugeX = 1.0e+300, tiny = 1.0e-300; -static double scalbnA (double x, int n) { +static double scalbnA(double x, int n) { int k,hx,lx; - hx = __HI(x); - lx = __LO(x); + hx = high(x); + lx = low(x); k = (hx&0x7ff00000)>>20; /* extract exponent */ if (k==0) { /* 0 or subnormal x */ if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ x *= two54; - hx = __HI(x); + hx = high(x); k = ((hx&0x7ff00000)>>20) - 54; if (n< -50000) return tiny*x; /*underflow*/ } if (k==0x7ff) return x+x; /* NaN or Inf */ k = k+n; - if (k > 0x7fe) return hugeX*copysignA(hugeX,x); /* overflow */ - if (k > 0) /* normal result */ - {__HI(x) = (hx&0x800fffff)|(k<<20); return x;} + if (k > 0x7fe) return hugeX*copysignA(hugeX,x); /* overflow */ + if (k > 0) { /* normal result */ + set_high(&x, (hx&0x800fffff)|(k<<20)); + return x; + } if (k <= -54) { if (n > 50000) /* in case integer overflow in n+k */ return hugeX*copysignA(hugeX,x); /*overflow*/ else return tiny*copysignA(tiny,x); /*underflow*/ } k += 54; /* subnormal result */ - __HI(x) = (hx&0x800fffff)|(k<<20); + set_high(&x, (hx&0x800fffff)|(k<<20)); return x*twom54; } diff --git a/hotspot/src/share/vm/runtime/sharedRuntimeTrans.cpp b/hotspot/src/share/vm/runtime/sharedRuntimeTrans.cpp index 69feb28bdfb..3b8c8a3010b 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntimeTrans.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntimeTrans.cpp @@ -40,6 +40,7 @@ // generated; can not figure out how to turn down optimization for one // file in the IDE on Windows #ifdef WIN32 +# pragma warning( disable: 4748 ) // /GS can not protect parameters and local variables from local buffer overrun because optimizations are disabled in function # pragma optimize ( "", off ) #endif @@ -114,8 +115,8 @@ static double __ieee754_log(double x) { int k,hx,i,j; unsigned lx; - hx = __HI(x); /* high word of x */ - lx = __LO(x); /* low word of x */ + hx = high(x); /* high word of x */ + lx = low(x); /* low word of x */ k=0; if (hx < 0x00100000) { /* x < 2**-1022 */ @@ -123,13 +124,13 @@ static double __ieee754_log(double x) { return -two54/zero; /* log(+-0)=-inf */ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ k -= 54; x *= two54; /* subnormal number, scale up x */ - hx = __HI(x); /* high word of x */ + hx = high(x); /* high word of x */ } if (hx >= 0x7ff00000) return x+x; k += (hx>>20)-1023; hx &= 0x000fffff; i = (hx+0x95f64)&0x100000; - __HI(x) = hx|(i^0x3ff00000); /* normalize x or x/2 */ + set_high(&x, hx|(i^0x3ff00000)); /* normalize x or x/2 */ k += (i>>20); f = x-1.0; if((0x000fffff&(2+hx))<3) { /* |f| < 2**-20 */ @@ -208,8 +209,8 @@ static double __ieee754_log10(double x) { int i,k,hx; unsigned lx; - hx = __HI(x); /* high word of x */ - lx = __LO(x); /* low word of x */ + hx = high(x); /* high word of x */ + lx = low(x); /* low word of x */ k=0; if (hx < 0x00100000) { /* x < 2**-1022 */ @@ -217,14 +218,14 @@ static double __ieee754_log10(double x) { return -two54/zero; /* log(+-0)=-inf */ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ k -= 54; x *= two54; /* subnormal number, scale up x */ - hx = __HI(x); /* high word of x */ + hx = high(x); /* high word of x */ } if (hx >= 0x7ff00000) return x+x; k += (hx>>20)-1023; i = ((unsigned)k&0x80000000)>>31; hx = (hx&0x000fffff)|((0x3ff-i)<<20); y = (double)(k+i); - __HI(x) = hx; + set_high(&x, hx); z = y*log10_2lo + ivln10*__ieee754_log(x); return z+y*log10_2hi; } @@ -319,14 +320,14 @@ static double __ieee754_exp(double x) { int k=0,xsb; unsigned hx; - hx = __HI(x); /* high word of x */ + hx = high(x); /* high word of x */ xsb = (hx>>31)&1; /* sign bit of x */ hx &= 0x7fffffff; /* high word of |x| */ /* filter out non-finite argument */ if(hx >= 0x40862E42) { /* if |x|>=709.78... */ if(hx>=0x7ff00000) { - if(((hx&0xfffff)|__LO(x))!=0) + if(((hx&0xfffff)|low(x))!=0) return x+x; /* NaN */ else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */ } @@ -357,10 +358,10 @@ static double __ieee754_exp(double x) { if(k==0) return one-((x*c)/(c-2.0)-x); else y = one-((lo-(x*c)/(2.0-c))-hi); if(k >= -1021) { - __HI(y) += (k<<20); /* add k to y's exponent */ + set_high(&y, high(y) + (k<<20)); /* add k to y's exponent */ return y; } else { - __HI(y) += ((k+1000)<<20);/* add k to y's exponent */ + set_high(&y, high(y) + ((k+1000)<<20)); /* add k to y's exponent */ return y*twom1000; } } @@ -447,8 +448,8 @@ double __ieee754_pow(double x, double y) { unsigned lx,ly; i0 = ((*(int*)&one)>>29)^1; i1=1-i0; - hx = __HI(x); lx = __LO(x); - hy = __HI(y); ly = __LO(y); + hx = high(x); lx = low(x); + hy = high(y); ly = low(y); ix = hx&0x7fffffff; iy = hy&0x7fffffff; /* y==zero: x**0 = 1 */ @@ -548,14 +549,14 @@ double __ieee754_pow(double x, double y) { u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ v = t*ivln2_l-w*ivln2; t1 = u+v; - __LO(t1) = 0; + set_low(&t1, 0); t2 = v-(t1-u); } else { double ss,s2,s_h,s_l,t_h,t_l; n = 0; /* take care subnormal number */ if(ix<0x00100000) - {ax *= two53; n -= 53; ix = __HI(ax); } + {ax *= two53; n -= 53; ix = high(ax); } n += ((ix)>>20)-0x3ff; j = ix&0x000fffff; /* determine interval */ @@ -563,17 +564,17 @@ double __ieee754_pow(double x, double y) { if(j<=0x3988E) k=0; /* |x|>1)|0x20000000)+0x00080000+(k<<18); + set_high(&t_h, ((ix>>1)|0x20000000)+0x00080000+(k<<18)); t_l = ax - (t_h-bp[k]); s_l = v*((u-s_h*t_h)-s_h*t_l); /* compute log(ax) */ @@ -582,32 +583,32 @@ double __ieee754_pow(double x, double y) { r += s_l*(s_h+ss); s2 = s_h*s_h; t_h = 3.0+s2+r; - __LO(t_h) = 0; + set_low(&t_h, 0); t_l = r-((t_h-3.0)-s2); /* u+v = ss*(1+...) */ u = s_h*t_h; v = s_l*t_h+t_l*ss; /* 2/(3log2)*(ss+...) */ p_h = u+v; - __LO(p_h) = 0; + set_low(&p_h, 0); p_l = v-(p_h-u); z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ z_l = cp_l*p_h+p_l*cp+dp_l[k]; /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ t = (double)n; t1 = (((z_h+z_l)+dp_h[k])+t); - __LO(t1) = 0; + set_low(&t1, 0); t2 = z_l-(((t1-t)-dp_h[k])-z_h); } /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ y1 = y; - __LO(y1) = 0; + set_low(&y1, 0); p_l = (y-y1)*t1+y*t2; p_h = y1*t1; z = p_l+p_h; - j = __HI(z); - i = __LO(z); + j = high(z); + i = low(z); if (j>=0x40900000) { /* z >= 1024 */ if(((j-0x40900000)|i)!=0) /* if z > 1024 */ return s*hugeX*hugeX; /* overflow */ @@ -631,13 +632,13 @@ double __ieee754_pow(double x, double y) { n = j+(0x00100000>>(k+1)); k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ t = zeroX; - __HI(t) = (n&~(0x000fffff>>k)); + set_high(&t, (n&~(0x000fffff>>k))); n = ((n&0x000fffff)|0x00100000)>>(20-k); if(j<0) n = -n; p_h -= t; } t = p_l+p_h; - __LO(t) = 0; + set_low(&t, 0); u = t*lg2_h; v = (p_l-(t-p_h))*lg2+t*lg2_l; z = u+v; @@ -646,10 +647,10 @@ double __ieee754_pow(double x, double y) { t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); r = (z*t1)/(t1-two)-(w+z*w); z = one-(r-z); - j = __HI(z); + j = high(z); j += (n<<20); if((j>>20)<=0) z = scalbnA(z,n); /* subnormal output */ - else __HI(z) += (n<<20); + else set_high(&z, high(z) + (n<<20)); return s*z; } diff --git a/hotspot/src/share/vm/runtime/sharedRuntimeTrig.cpp b/hotspot/src/share/vm/runtime/sharedRuntimeTrig.cpp index 84f35aa9317..8acd7401585 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntimeTrig.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntimeTrig.cpp @@ -519,7 +519,7 @@ static double __kernel_sin(double x, double y, int iy) { double z,r,v; int ix; - ix = __HI(x)&0x7fffffff; /* high word of x */ + ix = high(x)&0x7fffffff; /* high word of x */ if(ix<0x3e400000) /* |x| < 2**-27 */ {if((int)x==0) return x;} /* generate inexact */ z = x*x; @@ -574,9 +574,9 @@ C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ static double __kernel_cos(double x, double y) { - double a,h,z,r,qx; + double a,h,z,r,qx=0; int ix; - ix = __HI(x)&0x7fffffff; /* ix = |x|'s high word*/ + ix = high(x)&0x7fffffff; /* ix = |x|'s high word*/ if(ix<0x3e400000) { /* if x < 2**27 */ if(((int)x)==0) return one; /* generate inexact */ } @@ -588,8 +588,8 @@ static double __kernel_cos(double x, double y) if(ix > 0x3fe90000) { /* x > 0.78125 */ qx = 0.28125; } else { - __HI(qx) = ix-0x00200000; /* x/4 */ - __LO(qx) = 0; + set_high(&qx, ix-0x00200000); /* x/4 */ + set_low(&qx, 0); } h = 0.5*z-qx; a = one-qx; @@ -654,11 +654,11 @@ static double __kernel_tan(double x, double y, int iy) { double z,r,v,w,s; int ix,hx; - hx = __HI(x); /* high word of x */ + hx = high(x); /* high word of x */ ix = hx&0x7fffffff; /* high word of |x| */ if(ix<0x3e300000) { /* x < 2**-28 */ if((int)x==0) { /* generate inexact */ - if (((ix | __LO(x)) | (iy + 1)) == 0) + if (((ix | low(x)) | (iy + 1)) == 0) return one / fabsd(x); else { if (iy == 1) @@ -667,10 +667,10 @@ static double __kernel_tan(double x, double y, int iy) double a, t; z = w = x + y; - __LO(z) = 0; + set_low(&z, 0); v = y - (z - x); t = a = -one / w; - __LO(t) = 0; + set_low(&t, 0); s = one + t * z; return t + a * (s + t * v); } @@ -705,10 +705,10 @@ static double __kernel_tan(double x, double y, int iy) /* compute -1.0/(x+r) accurately */ double a,t; z = w; - __LO(z) = 0; + set_low(&z, 0); v = r-(z - x); /* z+v = r+x */ t = a = -1.0/w; /* a = -1.0/w */ - __LO(t) = 0; + set_low(&t, 0); s = 1.0+t*z; return t+a*(s+t*v); } @@ -757,7 +757,7 @@ JRT_LEAF(jdouble, SharedRuntime::dsin(jdouble x)) int n, ix; /* High word of x. */ - ix = __HI(x); + ix = high(x); /* |x| ~< pi/4 */ ix &= 0x7fffffff; @@ -815,7 +815,7 @@ JRT_LEAF(jdouble, SharedRuntime::dcos(jdouble x)) int n, ix; /* High word of x. */ - ix = __HI(x); + ix = high(x); /* |x| ~< pi/4 */ ix &= 0x7fffffff; @@ -872,7 +872,7 @@ JRT_LEAF(jdouble, SharedRuntime::dtan(jdouble x)) int n, ix; /* High word of x. */ - ix = __HI(x); + ix = high(x); /* |x| ~< pi/4 */ ix &= 0x7fffffff; diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 08785805729..9956ed28846 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -297,8 +297,7 @@ void Thread::record_stack_base_and_size() { #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(), this, - CURRENT_PC); + MemTracker::record_thread_stack(stack_low_addr, stack_size()); #endif // INCLUDE_NMT } @@ -316,7 +315,7 @@ Thread::~Thread() { #if INCLUDE_NMT if (_stack_base != NULL) { address low_stack_addr = stack_base() - stack_size(); - MemTracker::release_thread_stack(low_stack_addr, stack_size(), this); + MemTracker::release_thread_stack(low_stack_addr, stack_size()); #ifdef ASSERT set_stack_base(NULL); #endif @@ -1425,9 +1424,6 @@ void JavaThread::initialize() { set_monitor_chunks(NULL); set_next(NULL); set_thread_state(_thread_new); -#if INCLUDE_NMT - set_recorder(NULL); -#endif _terminated = _not_terminated; _privileged_stack_top = NULL; _array_for_gc = NULL; @@ -1503,7 +1499,6 @@ JavaThread::JavaThread(bool is_attaching_via_jni) : _jni_attach_state = _not_attaching_via_jni; } assert(deferred_card_mark().is_empty(), "Default MemRegion ctor"); - _safepoint_visible = false; } bool JavaThread::reguard_stack(address cur_sp) { @@ -1566,7 +1561,6 @@ JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread : os::java_thread; os::create_thread(this, thr_type, stack_sz); - _safepoint_visible = false; // The _osthread may be NULL here because we ran out of memory (too many threads active). // We need to throw and OutOfMemoryError - however we cannot do this here because the caller // may hold a lock and all locks must be unlocked before throwing the exception (throwing @@ -1584,13 +1578,6 @@ JavaThread::~JavaThread() { tty->print_cr("terminate thread %p", this); } - // By now, this thread should already be invisible to safepoint, - // and its per-thread recorder also collected. - assert(!is_safepoint_visible(), "wrong state"); -#if INCLUDE_NMT - assert(get_recorder() == NULL, "Already collected"); -#endif // INCLUDE_NMT - // JSR166 -- return the parker to the free list Parker::Release(_parker); _parker = NULL; @@ -3359,11 +3346,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // initialize TLS ThreadLocalStorage::init(); - // Bootstrap native memory tracking, so it can start recording memory - // activities before worker thread is started. This is the first phase - // of bootstrapping, VM is currently running in single-thread mode. - MemTracker::bootstrap_single_thread(); - // Initialize output stream logging ostream_init_log(); @@ -3414,9 +3396,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Initialize Java-Level synchronization subsystem ObjectMonitor::Initialize(); - // Second phase of bootstrapping, VM is about entering multi-thread mode - MemTracker::bootstrap_multi_thread(); - // Initialize global modules jint status = init_globals(); if (status != JNI_OK) { @@ -3438,9 +3417,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // real raw monitor. VM is setup enough here for raw monitor enter. JvmtiExport::transition_pending_onload_raw_monitors(); - // Fully start NMT - MemTracker::start(); - // Create the VMThread { TraceTime timer("Start VMThread", TraceStartupTime); VMThread::create(); @@ -3995,8 +3971,6 @@ void Threads::add(JavaThread* p, bool force_daemon) { daemon = false; } - p->set_safepoint_visible(true); - ThreadService::add_thread(p, daemon); // Possible GC point. @@ -4042,13 +4016,6 @@ void Threads::remove(JavaThread* p) { // to do callbacks into the safepoint code. However, the safepoint code is not aware // of this thread since it is removed from the queue. p->set_terminated_value(); - - // Now, this thread is not visible to safepoint - p->set_safepoint_visible(false); - // once the thread becomes safepoint invisible, we can not use its per-thread - // recorder. And Threads::do_threads() no longer walks this thread, so we have - // to release its per-thread recorder here. - MemTracker::thread_exiting(p); } // unlock Threads_lock // Since Events::log uses a lock, we grab it outside the Threads_lock diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 7df1c0f3cbc..332fd8666f8 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -43,10 +43,6 @@ #include "runtime/unhandledOops.hpp" #include "utilities/macros.hpp" -#if INCLUDE_NMT -#include "services/memRecorder.hpp" -#endif // INCLUDE_NMT - #include "trace/traceBackend.hpp" #include "trace/traceMacros.hpp" #include "utilities/exceptions.hpp" @@ -1036,16 +1032,6 @@ class JavaThread: public Thread { bool do_not_unlock_if_synchronized() { return _do_not_unlock_if_synchronized; } void set_do_not_unlock_if_synchronized(bool val) { _do_not_unlock_if_synchronized = val; } -#if INCLUDE_NMT - // native memory tracking - inline MemRecorder* get_recorder() const { return (MemRecorder*)_recorder; } - inline void set_recorder(MemRecorder* rc) { _recorder = rc; } - - private: - // per-thread memory recorder - MemRecorder* volatile _recorder; -#endif // INCLUDE_NMT - // Suspend/resume support for JavaThread private: inline void set_ext_suspended(); @@ -1485,19 +1471,6 @@ public: return result; } - // NMT (Native memory tracking) support. - // This flag helps NMT to determine if this JavaThread will be blocked - // at safepoint. If not, ThreadCritical is needed for writing memory records. - // JavaThread is only safepoint visible when it is in Threads' thread list, - // it is not visible until it is added to the list and becomes invisible - // once it is removed from the list. - public: - bool is_safepoint_visible() const { return _safepoint_visible; } - void set_safepoint_visible(bool visible) { _safepoint_visible = visible; } - private: - bool _safepoint_visible; - - // Static operations public: // Returns the running thread as a JavaThread static inline JavaThread* current(); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 3ff41705843..aa6d5558f51 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -52,6 +52,7 @@ #include "interpreter/bytecodes.hpp" #include "interpreter/interpreter.hpp" #include "memory/allocation.hpp" +#include "memory/allocation.inline.hpp" #include "memory/cardTableRS.hpp" #include "memory/defNewGeneration.hpp" #include "memory/freeBlockDictionary.hpp" @@ -93,6 +94,7 @@ #include "runtime/globals.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" +#include "runtime/os.hpp" #include "runtime/perfMemory.hpp" #include "runtime/serviceThread.hpp" #include "runtime/sharedRuntime.hpp" @@ -312,7 +314,7 @@ typedef TwoOopHashtable SymbolTwoOopHashtable; nonstatic_field(InstanceKlass, _jni_ids, JNIid*) \ nonstatic_field(InstanceKlass, _osr_nmethods_head, nmethod*) \ nonstatic_field(InstanceKlass, _breakpoints, BreakpointInfo*) \ - nonstatic_field(InstanceKlass, _generic_signature_index, u2) \ + nonstatic_field(InstanceKlass, _generic_signature_index, u2) \ nonstatic_field(InstanceKlass, _methods_jmethod_ids, jmethodID*) \ volatile_nonstatic_field(InstanceKlass, _idnum_allocated_count, u2) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ @@ -660,6 +662,7 @@ typedef TwoOopHashtable SymbolTwoOopHashtable; static_field(SystemDictionary, WK_KLASS(StackOverflowError_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(ProtectionDomain_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(AccessControlContext_klass), Klass*) \ + static_field(SystemDictionary, WK_KLASS(SecureClassLoader_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(Reference_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(SoftReference_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(WeakReference_klass), Klass*) \ @@ -3296,14 +3299,14 @@ static int recursiveFindType(VMTypeEntry* origtypes, const char* typeName, bool } } if (strstr(typeName, " const") == typeName + len - 6) { - char * s = strdup(typeName); + char * s = os::strdup_check_oom(typeName); s[len - 6] = '\0'; // tty->print_cr("checking \"%s\" for \"%s\"", s, typeName); if (recursiveFindType(origtypes, s, true) == 1) { - free(s); + os::free(s); return 1; } - free(s); + os::free(s); } if (!isRecurse) { tty->print_cr("type \"%s\" not found", typeName); diff --git a/hotspot/src/share/vm/services/allocationSite.hpp b/hotspot/src/share/vm/services/allocationSite.hpp new file mode 100644 index 00000000000..07f8595f815 --- /dev/null +++ b/hotspot/src/share/vm/services/allocationSite.hpp @@ -0,0 +1,57 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_SERVICES_ALLOCATION_SITE_HPP +#define SHARE_VM_SERVICES_ALLOCATION_SITE_HPP + +#include "memory/allocation.hpp" +#include "utilities/nativeCallStack.hpp" + +// Allocation site represents a code path that makes a memory +// allocation +template class AllocationSite VALUE_OBJ_CLASS_SPEC { + private: + NativeCallStack _call_stack; + E e; + public: + AllocationSite(const NativeCallStack& stack) : _call_stack(stack) { } + int hash() const { return _call_stack.hash(); } + bool equals(const NativeCallStack& stack) const { + return _call_stack.equals(stack); + } + + bool equals(const AllocationSite& other) const { + return other.equals(_call_stack); + } + + const NativeCallStack* call_stack() const { + return &_call_stack; + } + + // Information regarding this allocation + E* data() { return &e; } + const E* peek() const { return &e; } +}; + +#endif // SHARE_VM_SERVICES_ALLOCATION_SITE_HPP diff --git a/hotspot/src/share/vm/services/attachListener.cpp b/hotspot/src/share/vm/services/attachListener.cpp index 2321f084dc5..ecd59d4c11d 100644 --- a/hotspot/src/share/vm/services/attachListener.cpp +++ b/hotspot/src/share/vm/services/attachListener.cpp @@ -320,6 +320,25 @@ static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStrea return res? JNI_OK : JNI_ERR; } +// set a size_t global flag using value from AttachOperation +static jint set_size_t_flag(const char* name, AttachOperation* op, outputStream* out) { + size_t value; + const char* arg1; + if ((arg1 = op->arg(1)) != NULL) { + int n = sscanf(arg1, SIZE_FORMAT, &value); + if (n != 1) { + out->print_cr("flag value must be an unsigned integer"); + return JNI_ERR; + } + } + bool res = CommandLineFlags::size_tAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); + if (! res) { + out->print_cr("setting flag %s failed", name); + } + + return res? JNI_OK : JNI_ERR; +} + // set a string global flag using value from AttachOperation static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) { const char* value; @@ -356,6 +375,8 @@ static jint set_flag(AttachOperation* op, outputStream* out) { return set_uintx_flag(name, op, out); } else if (f->is_uint64_t()) { return set_uint64_t_flag(name, op, out); + } else if (f->is_size_t()) { + return set_size_t_flag(name, op, out); } else if (f->is_ccstr()) { return set_ccstr_flag(name, op, out); } else { diff --git a/hotspot/src/share/vm/services/mallocSiteTable.cpp b/hotspot/src/share/vm/services/mallocSiteTable.cpp new file mode 100644 index 00000000000..ec11cfabe69 --- /dev/null +++ b/hotspot/src/share/vm/services/mallocSiteTable.cpp @@ -0,0 +1,261 @@ +/* + * 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. + * + */ +#include "precompiled.hpp" + + +#include "memory/allocation.inline.hpp" +#include "runtime/atomic.hpp" +#include "services/mallocSiteTable.hpp" + +/* + * Early os::malloc() calls come from initializations of static variables, long before entering any + * VM code. Upon the arrival of the first os::malloc() call, malloc site hashtable has to be + * initialized, along with the allocation site for the hashtable entries. + * To ensure that malloc site hashtable can be initialized without triggering any additional os::malloc() + * call, the hashtable bucket array and hashtable entry allocation site have to be static. + * It is not a problem for hashtable bucket, since it is an array of pointer type, C runtime just + * allocates a block memory and zero the memory for it. + * But for hashtable entry allocation site object, things get tricky. C runtime not only allocates + * memory for it, but also calls its constructor at some later time. If we initialize the allocation site + * at the first os::malloc() call, the object will be reinitialized when its constructor is called + * by C runtime. + * To workaround above issue, we declare a static size_t array with the size of the CallsiteHashtableEntry, + * the memory is used to instantiate CallsiteHashtableEntry for the hashtable entry allocation site. + * Given it is a primitive type array, C runtime will do nothing other than assign the memory block for the variable, + * which is exactly what we want. + * The same trick is also applied to create NativeCallStack object for CallsiteHashtableEntry memory allocation. + * + * Note: C++ object usually aligns to particular alignment, depends on compiler implementation, we declare + * the memory as size_t arrays, to ensure the memory is aligned to native machine word alignment. + */ + +// Reserve enough memory for NativeCallStack and MallocSiteHashtableEntry objects +size_t MallocSiteTable::_hash_entry_allocation_stack[CALC_OBJ_SIZE_IN_TYPE(NativeCallStack, size_t)]; +size_t MallocSiteTable::_hash_entry_allocation_site[CALC_OBJ_SIZE_IN_TYPE(MallocSiteHashtableEntry, size_t)]; + +// Malloc site hashtable buckets +MallocSiteHashtableEntry* MallocSiteTable::_table[MallocSiteTable::table_size]; + +// concurrent access counter +volatile int MallocSiteTable::_access_count = 0; + +// Tracking hashtable contention +NOT_PRODUCT(int MallocSiteTable::_peak_count = 0;) + + +/* + * Initialize malloc site table. + * Hashtable entry is malloc'd, so it can cause infinite recursion. + * To avoid above problem, we pre-initialize a hash entry for + * this allocation site. + * The method is called during C runtime static variable initialization + * time, it is in single-threaded mode from JVM perspective. + */ +bool MallocSiteTable::initialize() { + assert(sizeof(_hash_entry_allocation_stack) >= sizeof(NativeCallStack), "Sanity Check"); + assert(sizeof(_hash_entry_allocation_site) >= sizeof(MallocSiteHashtableEntry), + "Sanity Check"); + assert((size_t)table_size <= MAX_MALLOCSITE_TABLE_SIZE, "Hashtable overflow"); + + // Fake the call stack for hashtable entry allocation + assert(NMT_TrackingStackDepth > 1, "At least one tracking stack"); + + // Create pseudo call stack for hashtable entry allocation + address pc[3]; + if (NMT_TrackingStackDepth >= 3) { + pc[2] = (address)MallocSiteTable::allocation_at; + } + if (NMT_TrackingStackDepth >= 2) { + pc[1] = (address)MallocSiteTable::lookup_or_add; + } + pc[0] = (address)MallocSiteTable::new_entry; + + // Instantiate NativeCallStack object, have to use placement new operator. (see comments above) + NativeCallStack* stack = ::new ((void*)_hash_entry_allocation_stack) + NativeCallStack(pc, MIN2(((int)(sizeof(pc) / sizeof(address))), ((int)NMT_TrackingStackDepth))); + + // Instantiate hash entry for hashtable entry allocation callsite + MallocSiteHashtableEntry* entry = ::new ((void*)_hash_entry_allocation_site) + MallocSiteHashtableEntry(*stack); + + // Add the allocation site to hashtable. + int index = hash_to_index(stack->hash()); + _table[index] = entry; + + return true; +} + +// Walks entries in the hashtable. +// It stops walk if the walker returns false. +bool MallocSiteTable::walk(MallocSiteWalker* walker) { + MallocSiteHashtableEntry* head; + for (int index = 0; index < table_size; index ++) { + head = _table[index]; + while (head != NULL) { + if (!walker->do_malloc_site(head->peek())) { + return false; + } + head = (MallocSiteHashtableEntry*)head->next(); + } + } + return true; +} + +/* + * The hashtable does not have deletion policy on individual entry, + * and each linked list node is inserted via compare-and-swap, + * so each linked list is stable, the contention only happens + * at the end of linked list. + * This method should not return NULL under normal circumstance. + * If NULL is returned, it indicates: + * 1. Out of memory, it cannot allocate new hash entry. + * 2. Overflow hash bucket. + * Under any of above circumstances, caller should handle the situation. + */ +MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, + size_t* pos_idx) { + int index = hash_to_index(key.hash()); + assert(index >= 0, "Negative index"); + *bucket_idx = (size_t)index; + *pos_idx = 0; + + // First entry for this hash bucket + if (_table[index] == NULL) { + MallocSiteHashtableEntry* entry = new_entry(key); + // OOM check + if (entry == NULL) return NULL; + + // swap in the head + if (Atomic::cmpxchg_ptr((void*)entry, (volatile void *)&_table[index], NULL) == NULL) { + return entry->data(); + } + + delete entry; + } + + MallocSiteHashtableEntry* head = _table[index]; + while (head != NULL && (*pos_idx) <= MAX_BUCKET_LENGTH) { + MallocSite* site = head->data(); + if (site->equals(key)) { + // found matched entry + return head->data(); + } + + if (head->next() == NULL && (*pos_idx) < MAX_BUCKET_LENGTH) { + MallocSiteHashtableEntry* entry = new_entry(key); + // OOM check + if (entry == NULL) return NULL; + if (head->atomic_insert(entry)) { + (*pos_idx) ++; + return entry->data(); + } + // contended, other thread won + delete entry; + } + head = (MallocSiteHashtableEntry*)head->next(); + (*pos_idx) ++; + } + return NULL; +} + +// Access malloc site +MallocSite* MallocSiteTable::malloc_site(size_t bucket_idx, size_t pos_idx) { + assert(bucket_idx < table_size, "Invalid bucket index"); + MallocSiteHashtableEntry* head = _table[bucket_idx]; + for (size_t index = 0; index < pos_idx && head != NULL; + index ++, head = (MallocSiteHashtableEntry*)head->next()); + assert(head != NULL, "Invalid position index"); + return head->data(); +} + +// Allocates MallocSiteHashtableEntry object. Special call stack +// (pre-installed allocation site) has to be used to avoid infinite +// recursion. +MallocSiteHashtableEntry* MallocSiteTable::new_entry(const NativeCallStack& key) { + void* p = AllocateHeap(sizeof(MallocSiteHashtableEntry), mtNMT, + *hash_entry_allocation_stack(), AllocFailStrategy::RETURN_NULL); + return ::new (p) MallocSiteHashtableEntry(key); +} + +void MallocSiteTable::reset() { + for (int index = 0; index < table_size; index ++) { + MallocSiteHashtableEntry* head = _table[index]; + _table[index] = NULL; + delete_linked_list(head); + } +} + +void MallocSiteTable::delete_linked_list(MallocSiteHashtableEntry* head) { + MallocSiteHashtableEntry* p; + while (head != NULL) { + p = head; + head = (MallocSiteHashtableEntry*)head->next(); + if (p != (MallocSiteHashtableEntry*)_hash_entry_allocation_site) { + delete p; + } + } +} + +void MallocSiteTable::shutdown() { + AccessLock locker(&_access_count); + locker.exclusiveLock(); + reset(); +} + +bool MallocSiteTable::walk_malloc_site(MallocSiteWalker* walker) { + assert(walker != NULL, "NuLL walker"); + AccessLock locker(&_access_count); + if (locker.sharedLock()) { + NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) + return walk(walker); + } + return false; +} + + +void MallocSiteTable::AccessLock::exclusiveLock() { + jint target; + jint val; + + assert(_lock_state != ExclusiveLock, "Can only call once"); + assert(*_lock >= 0, "Can not content exclusive lock"); + + // make counter negative to block out shared locks + do { + val = *_lock; + target = _MAGIC_ + *_lock; + } while (Atomic::cmpxchg(target, _lock, val) != val); + + // wait for all readers to exit + while (*_lock != _MAGIC_) { +#ifdef _WINDOWS + os::naked_short_sleep(1); +#else + os::naked_yield(); +#endif + } + _lock_state = ExclusiveLock; +} + + diff --git a/hotspot/src/share/vm/services/mallocSiteTable.hpp b/hotspot/src/share/vm/services/mallocSiteTable.hpp new file mode 100644 index 00000000000..cff98161449 --- /dev/null +++ b/hotspot/src/share/vm/services/mallocSiteTable.hpp @@ -0,0 +1,269 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP +#define SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP + +#if INCLUDE_NMT + +#include "memory/allocation.hpp" +#include "runtime/atomic.hpp" +#include "services/allocationSite.hpp" +#include "services/mallocTracker.hpp" +#include "services/nmtCommon.hpp" +#include "utilities/nativeCallStack.hpp" + +// MallocSite represents a code path that eventually calls +// os::malloc() to allocate memory +class MallocSite : public AllocationSite { + public: + MallocSite() : + AllocationSite(NativeCallStack::EMPTY_STACK) { } + + MallocSite(const NativeCallStack& stack) : + AllocationSite(stack) { } + + void allocate(size_t size) { data()->allocate(size); } + void deallocate(size_t size) { data()->deallocate(size); } + + // Memory allocated from this code path + size_t size() const { return peek()->size(); } + // The number of calls were made + size_t count() const { return peek()->count(); } +}; + +// Malloc site hashtable entry +class MallocSiteHashtableEntry : public CHeapObj { + private: + MallocSite _malloc_site; + MallocSiteHashtableEntry* _next; + + public: + MallocSiteHashtableEntry() : _next(NULL) { } + + MallocSiteHashtableEntry(NativeCallStack stack): + _malloc_site(stack), _next(NULL) { } + + inline const MallocSiteHashtableEntry* next() const { + return _next; + } + + // Insert an entry atomically. + // Return true if the entry is inserted successfully. + // The operation can be failed due to contention from other thread. + bool atomic_insert(const MallocSiteHashtableEntry* entry) { + return (Atomic::cmpxchg_ptr((void*)entry, (volatile void*)&_next, + NULL) == NULL); + } + + void set_callsite(const MallocSite& site) { + _malloc_site = site; + } + + inline const MallocSite* peek() const { return &_malloc_site; } + inline MallocSite* data() { return &_malloc_site; } + + inline long hash() const { return _malloc_site.hash(); } + inline bool equals(const NativeCallStack& stack) const { + return _malloc_site.equals(stack); + } + // Allocation/deallocation on this allocation site + inline void allocate(size_t size) { _malloc_site.allocate(size); } + inline void deallocate(size_t size) { _malloc_site.deallocate(size); } + // Memory counters + inline size_t size() const { return _malloc_site.size(); } + inline size_t count() const { return _malloc_site.count(); } +}; + +// The walker walks every entry on MallocSiteTable +class MallocSiteWalker : public StackObj { + public: + virtual bool do_malloc_site(const MallocSite* e) { return false; } +}; + +/* + * Native memory tracking call site table. + * The table is only needed when detail tracking is enabled. + */ +class MallocSiteTable : AllStatic { + private: + // The number of hash bucket in this hashtable. The number should + // be tuned if malloc activities changed significantly. + // The statistics data can be obtained via Jcmd + // jcmd VM.native_memory statistics. + + // Currently, (number of buckets / number of entires) ratio is + // about 1 / 6 + enum { + table_base_size = 128, // The base size is calculated from statistics to give + // table ratio around 1:6 + table_size = (table_base_size * NMT_TrackingStackDepth - 1) + }; + + + // This is a very special lock, that allows multiple shared accesses (sharedLock), but + // once exclusive access (exclusiveLock) is requested, all shared accesses are + // rejected forever. + class AccessLock : public StackObj { + enum LockState { + NoLock, + SharedLock, + ExclusiveLock + }; + + private: + // A very large negative number. The only possibility to "overflow" + // this number is when there are more than -min_jint threads in + // this process, which is not going to happen in foreseeable future. + const static int _MAGIC_ = min_jint; + + LockState _lock_state; + volatile int* _lock; + public: + AccessLock(volatile int* lock) : + _lock(lock), _lock_state(NoLock) { + } + + ~AccessLock() { + if (_lock_state == SharedLock) { + Atomic::dec((volatile jint*)_lock); + } + } + // Acquire shared lock. + // Return true if shared access is granted. + inline bool sharedLock() { + jint res = Atomic::add(1, _lock); + if (res < 0) { + Atomic::add(-1, _lock); + return false; + } + _lock_state = SharedLock; + return true; + } + // Acquire exclusive lock + void exclusiveLock(); + }; + + public: + static bool initialize(); + static void shutdown(); + + NOT_PRODUCT(static int access_peak_count() { return _peak_count; }) + + // Number of hash buckets + static inline int hash_buckets() { return (int)table_size; } + + // Access and copy a call stack from this table. Shared lock should be + // acquired before access the entry. + static inline bool access_stack(NativeCallStack& stack, size_t bucket_idx, + size_t pos_idx) { + AccessLock locker(&_access_count); + if (locker.sharedLock()) { + NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) + MallocSite* site = malloc_site(bucket_idx, pos_idx); + if (site != NULL) { + stack = *site->call_stack(); + return true; + } + } + return false; + } + + // Record a new allocation from specified call path. + // Return true if the allocation is recorded successfully, bucket_idx + // and pos_idx are also updated to indicate the entry where the allocation + // information was recorded. + // Return false only occurs under rare scenarios: + // 1. out of memory + // 2. overflow hash bucket + static inline bool allocation_at(const NativeCallStack& stack, size_t size, + size_t* bucket_idx, size_t* pos_idx) { + AccessLock locker(&_access_count); + if (locker.sharedLock()) { + NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) + MallocSite* site = lookup_or_add(stack, bucket_idx, pos_idx); + if (site != NULL) site->allocate(size); + return site != NULL; + } + return false; + } + + // Record memory deallocation. bucket_idx and pos_idx indicate where the allocation + // information was recorded. + static inline bool deallocation_at(size_t size, size_t bucket_idx, size_t pos_idx) { + AccessLock locker(&_access_count); + if (locker.sharedLock()) { + NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) + MallocSite* site = malloc_site(bucket_idx, pos_idx); + if (site != NULL) { + site->deallocate(size); + return true; + } + } + return false; + } + + // Walk this table. + static bool walk_malloc_site(MallocSiteWalker* walker); + + private: + static MallocSiteHashtableEntry* new_entry(const NativeCallStack& key); + static void reset(); + + // Delete a bucket linked list + static void delete_linked_list(MallocSiteHashtableEntry* head); + + static MallocSite* lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, size_t* pos_idx); + static MallocSite* malloc_site(size_t bucket_idx, size_t pos_idx); + static bool walk(MallocSiteWalker* walker); + + static inline int hash_to_index(int hash) { + hash = (hash > 0) ? hash : (-hash); + return (hash % table_size); + } + + static inline const NativeCallStack* hash_entry_allocation_stack() { + return (NativeCallStack*)_hash_entry_allocation_stack; + } + + private: + // Counter for counting concurrent access + static volatile int _access_count; + + // The callsite hashtable. It has to be a static table, + // since malloc call can come from C runtime linker. + static MallocSiteHashtableEntry* _table[table_size]; + + + // Reserve enough memory for placing the objects + + // The memory for hashtable entry allocation stack object + static size_t _hash_entry_allocation_stack[CALC_OBJ_SIZE_IN_TYPE(NativeCallStack, size_t)]; + // The memory for hashtable entry allocation callsite object + static size_t _hash_entry_allocation_site[CALC_OBJ_SIZE_IN_TYPE(MallocSiteHashtableEntry, size_t)]; + NOT_PRODUCT(static int _peak_count;) +}; + +#endif // INCLUDE_NMT +#endif // SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP diff --git a/hotspot/src/share/vm/services/mallocTracker.cpp b/hotspot/src/share/vm/services/mallocTracker.cpp new file mode 100644 index 00000000000..d60dd383576 --- /dev/null +++ b/hotspot/src/share/vm/services/mallocTracker.cpp @@ -0,0 +1,200 @@ +/* + * 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. + * + */ +#include "precompiled.hpp" + +#include "runtime/atomic.hpp" +#include "runtime/atomic.inline.hpp" +#include "services/mallocSiteTable.hpp" +#include "services/mallocTracker.hpp" +#include "services/mallocTracker.inline.hpp" +#include "services/memTracker.hpp" + +size_t MallocMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)]; + +// Total malloc'd memory amount +size_t MallocMemorySnapshot::total() const { + size_t amount = 0; + for (int index = 0; index < mt_number_of_types; index ++) { + amount += _malloc[index].malloc_size(); + } + amount += _tracking_header.size() + total_arena(); + return amount; +} + +// Total malloc'd memory used by arenas +size_t MallocMemorySnapshot::total_arena() const { + size_t amount = 0; + for (int index = 0; index < mt_number_of_types; index ++) { + amount += _malloc[index].arena_size(); + } + return amount; +} + + +void MallocMemorySnapshot::reset() { + _tracking_header.reset(); + for (int index = 0; index < mt_number_of_types; index ++) { + _malloc[index].reset(); + } +} + +// Make adjustment by subtracting chunks used by arenas +// from total chunks to get total free chunck size +void MallocMemorySnapshot::make_adjustment() { + size_t arena_size = total_arena(); + int chunk_idx = NMTUtil::flag_to_index(mtChunk); + _malloc[chunk_idx].record_free(arena_size); +} + + +void MallocMemorySummary::initialize() { + assert(sizeof(_snapshot) >= sizeof(MallocMemorySnapshot), "Sanity Check"); + // Uses placement new operator to initialize static area. + ::new ((void*)_snapshot)MallocMemorySnapshot(); +} + +void MallocHeader::release() const { + // Tracking already shutdown, no housekeeping is needed anymore + if (MemTracker::tracking_level() <= NMT_minimal) return; + + MallocMemorySummary::record_free(size(), flags()); + MallocMemorySummary::record_free_malloc_header(sizeof(MallocHeader)); + if (tracking_level() == NMT_detail) { + MallocSiteTable::deallocation_at(size(), _bucket_idx, _pos_idx); + } +} + +bool MallocHeader::record_malloc_site(const NativeCallStack& stack, size_t size, + size_t* bucket_idx, size_t* pos_idx) const { + bool ret = MallocSiteTable::allocation_at(stack, size, bucket_idx, pos_idx); + + // Something went wrong, could be OOM or overflow malloc site table. + // We want to keep tracking data under OOM circumstance, so transition to + // summary tracking. + if (!ret) { + MemTracker::transition_to(NMT_summary); + } + return ret; +} + +bool MallocHeader::get_stack(NativeCallStack& stack) const { + return MallocSiteTable::access_stack(stack, _bucket_idx, _pos_idx); +} + +bool MallocTracker::initialize(NMT_TrackingLevel level) { + if (level >= NMT_summary) { + MallocMemorySummary::initialize(); + } + + if (level == NMT_detail) { + return MallocSiteTable::initialize(); + } + return true; +} + +bool MallocTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) { + assert(from != NMT_off, "Can not transition from off state"); + assert(to != NMT_off, "Can not transition to off state"); + if (from == NMT_minimal) { + MallocMemorySummary::reset(); + } + + if (to == NMT_detail) { + assert(from == NMT_minimal || from == NMT_summary, "Just check"); + return MallocSiteTable::initialize(); + } else if (from == NMT_detail) { + assert(to == NMT_minimal || to == NMT_summary, "Just check"); + MallocSiteTable::shutdown(); + } + return true; +} + +// Record a malloc memory allocation +void* MallocTracker::record_malloc(void* malloc_base, size_t size, MEMFLAGS flags, + const NativeCallStack& stack, NMT_TrackingLevel level) { + void* memblock; // the address for user data + MallocHeader* header = NULL; + + if (malloc_base == NULL) { + return NULL; + } + + // Check malloc size, size has to <= MAX_MALLOC_SIZE. This is only possible on 32-bit + // systems, when malloc size >= 1GB, but is is safe to assume it won't happen. + if (size > MAX_MALLOC_SIZE) { + fatal("Should not use malloc for big memory block, use virtual memory instead"); + } + // Uses placement global new operator to initialize malloc header + switch(level) { + case NMT_off: + return malloc_base; + case NMT_minimal: { + MallocHeader* hdr = ::new (malloc_base) MallocHeader(); + break; + } + case NMT_summary: { + header = ::new (malloc_base) MallocHeader(size, flags); + break; + } + case NMT_detail: { + header = ::new (malloc_base) MallocHeader(size, flags, stack); + break; + } + default: + ShouldNotReachHere(); + } + memblock = (void*)((char*)malloc_base + sizeof(MallocHeader)); + + // The alignment check: 8 bytes alignment for 32 bit systems. + // 16 bytes alignment for 64-bit systems. + assert(((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0, "Alignment check"); + + // Sanity check + assert(get_memory_tracking_level(memblock) == level, + "Wrong tracking level"); + +#ifdef ASSERT + if (level > NMT_minimal) { + // Read back + assert(get_size(memblock) == size, "Wrong size"); + assert(get_flags(memblock) == flags, "Wrong flags"); + } +#endif + + return memblock; +} + +void* MallocTracker::record_free(void* memblock) { + // Never turned on + if (MemTracker::tracking_level() == NMT_off || + memblock == NULL) { + return memblock; + } + MallocHeader* header = malloc_header(memblock); + header->release(); + + return (void*)header; +} + + diff --git a/hotspot/src/share/vm/services/mallocTracker.hpp b/hotspot/src/share/vm/services/mallocTracker.hpp new file mode 100644 index 00000000000..3b84270477b --- /dev/null +++ b/hotspot/src/share/vm/services/mallocTracker.hpp @@ -0,0 +1,424 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_HPP +#define SHARE_VM_SERVICES_MALLOC_TRACKER_HPP + +#if INCLUDE_NMT + +#include "memory/allocation.hpp" +#include "runtime/atomic.hpp" +#include "services/nmtCommon.hpp" +#include "utilities/nativeCallStack.hpp" + +/* + * This counter class counts memory allocation and deallocation, + * records total memory allocation size and number of allocations. + * The counters are updated atomically. + */ +class MemoryCounter VALUE_OBJ_CLASS_SPEC { + private: + size_t _count; + size_t _size; + + DEBUG_ONLY(size_t _peak_count;) + DEBUG_ONLY(size_t _peak_size; ) + + public: + MemoryCounter() : _count(0), _size(0) { + DEBUG_ONLY(_peak_count = 0;) + DEBUG_ONLY(_peak_size = 0;) + } + + // Reset counters + void reset() { + _size = 0; + _count = 0; + DEBUG_ONLY(_peak_size = 0;) + DEBUG_ONLY(_peak_count = 0;) + } + + inline void allocate(size_t sz) { + Atomic::add(1, (volatile MemoryCounterType*)&_count); + if (sz > 0) { + Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size); + DEBUG_ONLY(_peak_size = MAX2(_peak_size, _size)); + } + DEBUG_ONLY(_peak_count = MAX2(_peak_count, _count);) + } + + inline void deallocate(size_t sz) { + assert(_count > 0, "Negative counter"); + assert(_size >= sz, "Negative size"); + Atomic::add(-1, (volatile MemoryCounterType*)&_count); + if (sz > 0) { + Atomic::add(-(MemoryCounterType)sz, (volatile MemoryCounterType*)&_size); + } + } + + inline void resize(long sz) { + if (sz != 0) { + Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size); + DEBUG_ONLY(_peak_size = MAX2(_size, _peak_size);) + } + } + + inline size_t count() const { return _count; } + inline size_t size() const { return _size; } + DEBUG_ONLY(inline size_t peak_count() const { return _peak_count; }) + DEBUG_ONLY(inline size_t peak_size() const { return _peak_size; }) + +}; + +/* + * Malloc memory used by a particular subsystem. + * It includes the memory acquired through os::malloc() + * call and arena's backing memory. + */ +class MallocMemory VALUE_OBJ_CLASS_SPEC { + private: + MemoryCounter _malloc; + MemoryCounter _arena; + + public: + MallocMemory() { } + + inline void record_malloc(size_t sz) { + _malloc.allocate(sz); + } + + inline void record_free(size_t sz) { + _malloc.deallocate(sz); + } + + inline void record_new_arena() { + _arena.allocate(0); + } + + inline void record_arena_free() { + _arena.deallocate(0); + } + + inline void record_arena_size_change(long sz) { + _arena.resize(sz); + } + + void reset() { + _malloc.reset(); + _arena.reset(); + } + + inline size_t malloc_size() const { return _malloc.size(); } + inline size_t malloc_count() const { return _malloc.count();} + inline size_t arena_size() const { return _arena.size(); } + inline size_t arena_count() const { return _arena.count(); } + + DEBUG_ONLY(inline const MemoryCounter& malloc_counter() const { return _malloc; }) + DEBUG_ONLY(inline const MemoryCounter& arena_counter() const { return _arena; }) +}; + +class MallocMemorySummary; + +// A snapshot of malloc'd memory, includes malloc memory +// usage by types and memory used by tracking itself. +class MallocMemorySnapshot : public ResourceObj { + friend class MallocMemorySummary; + + private: + MallocMemory _malloc[mt_number_of_types]; + MemoryCounter _tracking_header; + + + public: + inline MallocMemory* by_type(MEMFLAGS flags) { + int index = NMTUtil::flag_to_index(flags); + return &_malloc[index]; + } + + inline MallocMemory* by_index(int index) { + assert(index >= 0, "Index out of bound"); + assert(index < mt_number_of_types, "Index out of bound"); + return &_malloc[index]; + } + + inline MemoryCounter* malloc_overhead() { + return &_tracking_header; + } + + // Total malloc'd memory amount + size_t total() const; + // Total malloc'd memory used by arenas + size_t total_arena() const; + + inline size_t thread_count() { + return by_type(mtThreadStack)->malloc_count(); + } + + void reset(); + + void copy_to(MallocMemorySnapshot* s) { + s->_tracking_header = _tracking_header; + for (int index = 0; index < mt_number_of_types; index ++) { + s->_malloc[index] = _malloc[index]; + } + } + + // Make adjustment by subtracting chunks used by arenas + // from total chunks to get total free chunk size + void make_adjustment(); +}; + +/* + * This class is for collecting malloc statistics at summary level + */ +class MallocMemorySummary : AllStatic { + private: + // Reserve memory for placement of MallocMemorySnapshot object + static size_t _snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)]; + + public: + static void initialize(); + + static inline void record_malloc(size_t size, MEMFLAGS flag) { + as_snapshot()->by_type(flag)->record_malloc(size); + } + + static inline void record_free(size_t size, MEMFLAGS flag) { + as_snapshot()->by_type(flag)->record_free(size); + } + + static inline void record_new_arena(MEMFLAGS flag) { + as_snapshot()->by_type(flag)->record_new_arena(); + } + + static inline void record_arena_free(MEMFLAGS flag) { + as_snapshot()->by_type(flag)->record_arena_free(); + } + + static inline void record_arena_size_change(long size, MEMFLAGS flag) { + as_snapshot()->by_type(flag)->record_arena_size_change(size); + } + + static void snapshot(MallocMemorySnapshot* s) { + as_snapshot()->copy_to(s); + s->make_adjustment(); + } + + // Record memory used by malloc tracking header + static inline void record_new_malloc_header(size_t sz) { + as_snapshot()->malloc_overhead()->allocate(sz); + } + + static inline void record_free_malloc_header(size_t sz) { + as_snapshot()->malloc_overhead()->deallocate(sz); + } + + // The memory used by malloc tracking headers + static inline size_t tracking_overhead() { + return as_snapshot()->malloc_overhead()->size(); + } + + // Reset all counters to zero + static void reset() { + as_snapshot()->reset(); + } + + static MallocMemorySnapshot* as_snapshot() { + return (MallocMemorySnapshot*)_snapshot; + } +}; + + +/* + * Malloc tracking header. + * To satisfy malloc alignment requirement, NMT uses 2 machine words for tracking purpose, + * which ensures 8-bytes alignment on 32-bit systems and 16-bytes on 64-bit systems (Product build). + */ + +class MallocHeader VALUE_OBJ_CLASS_SPEC { +#ifdef _LP64 + size_t _size : 62; + size_t _level : 2; + size_t _flags : 8; + size_t _pos_idx : 16; + size_t _bucket_idx: 40; +#define MAX_MALLOCSITE_TABLE_SIZE ((size_t)1 << 40) +#define MAX_BUCKET_LENGTH ((size_t)(1 << 16)) +#define MAX_MALLOC_SIZE (((size_t)1 << 62) - 1) +#else + size_t _size : 30; + size_t _level : 2; + size_t _flags : 8; + size_t _pos_idx : 8; + size_t _bucket_idx: 16; +#define MAX_MALLOCSITE_TABLE_SIZE ((size_t)(1 << 16)) +#define MAX_BUCKET_LENGTH ((size_t)(1 << 8)) +// Max malloc size = 1GB - 1 on 32 bit system, such has total 4GB memory +#define MAX_MALLOC_SIZE ((size_t)(1 << 30) - 1) +#endif // _LP64 + + public: + // Summary tracking header + MallocHeader(size_t size, MEMFLAGS flags) { + assert(sizeof(MallocHeader) == sizeof(void*) * 2, + "Wrong header size"); + + _level = NMT_summary; + _flags = flags; + set_size(size); + MallocMemorySummary::record_malloc(size, flags); + MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); + } + // Detail tracking header + MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack) { + assert(sizeof(MallocHeader) == sizeof(void*) * 2, + "Wrong header size"); + + _level = NMT_detail; + _flags = flags; + set_size(size); + size_t bucket_idx; + size_t pos_idx; + if (record_malloc_site(stack, size, &bucket_idx, &pos_idx)) { + assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index"); + assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index"); + _bucket_idx = bucket_idx; + _pos_idx = pos_idx; + } + MallocMemorySummary::record_malloc(size, flags); + MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); + } + // Minimal tracking header + MallocHeader() { + assert(sizeof(MallocHeader) == sizeof(void*) * 2, + "Wrong header size"); + + _level = (unsigned short)NMT_minimal; + } + + inline NMT_TrackingLevel tracking_level() const { + return (NMT_TrackingLevel)_level; + } + + inline size_t size() const { return _size; } + inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; } + bool get_stack(NativeCallStack& stack) const; + + // Cleanup tracking information before the memory is released. + void release() const; + + private: + inline void set_size(size_t size) { + assert(size <= MAX_MALLOC_SIZE, "Malloc size too large, should use virtual memory?"); + _size = size; + } + bool record_malloc_site(const NativeCallStack& stack, size_t size, + size_t* bucket_idx, size_t* pos_idx) const; +}; + + +// Main class called from MemTracker to track malloc activities +class MallocTracker : AllStatic { + public: + // Initialize malloc tracker for specific tracking level + static bool initialize(NMT_TrackingLevel level); + + static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to); + + // malloc tracking header size for specific tracking level + static inline size_t malloc_header_size(NMT_TrackingLevel level) { + return (level == NMT_off) ? 0 : sizeof(MallocHeader); + } + + // Parameter name convention: + // memblock : the beginning address for user data + // malloc_base: the beginning address that includes malloc tracking header + // + // The relationship: + // memblock = (char*)malloc_base + sizeof(nmt header) + // + + // Record malloc on specified memory block + static void* record_malloc(void* malloc_base, size_t size, MEMFLAGS flags, + const NativeCallStack& stack, NMT_TrackingLevel level); + + // Record free on specified memory block + static void* record_free(void* memblock); + + // Get tracking level of specified memory block + static inline NMT_TrackingLevel get_memory_tracking_level(void* memblock); + + + // Offset memory address to header address + static inline void* get_base(void* memblock); + static inline void* get_base(void* memblock, NMT_TrackingLevel level) { + if (memblock == NULL || level == NMT_off) return memblock; + return (char*)memblock - malloc_header_size(level); + } + + // Get memory size + static inline size_t get_size(void* memblock) { + MallocHeader* header = malloc_header(memblock); + assert(header->tracking_level() >= NMT_summary, + "Wrong tracking level"); + return header->size(); + } + + // Get memory type + static inline MEMFLAGS get_flags(void* memblock) { + MallocHeader* header = malloc_header(memblock); + assert(header->tracking_level() >= NMT_summary, + "Wrong tracking level"); + return header->flags(); + } + + // Get header size + static inline size_t get_header_size(void* memblock) { + return (memblock == NULL) ? 0 : sizeof(MallocHeader); + } + + static inline void record_new_arena(MEMFLAGS flags) { + MallocMemorySummary::record_new_arena(flags); + } + + static inline void record_arena_free(MEMFLAGS flags) { + MallocMemorySummary::record_arena_free(flags); + } + + static inline void record_arena_size_change(int size, MEMFLAGS flags) { + MallocMemorySummary::record_arena_size_change(size, flags); + } + private: + static inline MallocHeader* malloc_header(void *memblock) { + assert(memblock != NULL, "NULL pointer"); + MallocHeader* header = (MallocHeader*)((char*)memblock - sizeof(MallocHeader)); + assert(header->tracking_level() >= NMT_minimal, "Bad header"); + return header; + } +}; + +#endif // INCLUDE_NMT + + +#endif //SHARE_VM_SERVICES_MALLOC_TRACKER_HPP diff --git a/hotspot/src/share/vm/services/mallocTracker.inline.hpp b/hotspot/src/share/vm/services/mallocTracker.inline.hpp new file mode 100644 index 00000000000..338295b6566 --- /dev/null +++ b/hotspot/src/share/vm/services/mallocTracker.inline.hpp @@ -0,0 +1,43 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP +#define SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP + +#include "services/mallocTracker.hpp" +#include "services/memTracker.hpp" + +inline NMT_TrackingLevel MallocTracker::get_memory_tracking_level(void* memblock) { + assert(memblock != NULL, "Sanity check"); + if (MemTracker::tracking_level() == NMT_off) return NMT_off; + MallocHeader* header = malloc_header(memblock); + return header->tracking_level(); +} + +inline void* MallocTracker::get_base(void* memblock){ + return get_base(memblock, MemTracker::tracking_level()); +} + +#endif // SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP + diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index 2d6f2ff1d23..53096acc584 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -1696,6 +1696,9 @@ bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, } else if (flag->is_uint64_t()) { global->value.j = (jlong)flag->get_uint64_t(); global->type = JMM_VMGLOBAL_TYPE_JLONG; + } else if (flag->is_size_t()) { + global->value.j = (jlong)flag->get_size_t(); + global->type = JMM_VMGLOBAL_TYPE_JLONG; } else if (flag->is_ccstr()) { Handle str = java_lang_String::create_from_str(flag->get_ccstr(), CHECK_false); global->value.l = (jobject)JNIHandles::make_local(env, str()); @@ -1851,6 +1854,9 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value } else if (flag->is_uint64_t()) { uint64_t uvalue = (uint64_t)new_value.j; succeed = CommandLineFlags::uint64_tAtPut(name, &uvalue, Flag::MANAGEMENT); + } else if (flag->is_size_t()) { + size_t svalue = (size_t)new_value.j; + succeed = CommandLineFlags::size_tAtPut(name, &svalue, Flag::MANAGEMENT); } else if (flag->is_ccstr()) { oop str = JNIHandles::resolve_external_guard(new_value.l); if (str == NULL) { @@ -1914,7 +1920,7 @@ void ThreadTimesClosure::do_thread(Thread* thread) { ResourceMark rm(THREAD); // thread->name() uses ResourceArea assert(thread->name() != NULL, "All threads should have a name"); - _names_chars[_count] = strdup(thread->name()); + _names_chars[_count] = os::strdup(thread->name()); _times->long_at_put(_count, os::is_thread_cpu_time_supported() ? os::thread_cpu_time(thread) : -1); _count++; @@ -1932,7 +1938,7 @@ void ThreadTimesClosure::do_unlocked() { ThreadTimesClosure::~ThreadTimesClosure() { for (int i = 0; i < _count; i++) { - free(_names_chars[i]); + os::free(_names_chars[i]); } FREE_C_HEAP_ARRAY(char *, _names_chars, mtInternal); } diff --git a/hotspot/src/share/vm/services/memBaseline.cpp b/hotspot/src/share/vm/services/memBaseline.cpp index 62e51873c7b..26cef4ceebb 100644 --- a/hotspot/src/share/vm/services/memBaseline.cpp +++ b/hotspot/src/share/vm/services/memBaseline.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -22,471 +22,301 @@ * */ #include "precompiled.hpp" + #include "memory/allocation.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.inline.hpp" #include "services/memBaseline.hpp" #include "services/memTracker.hpp" +/* + * Sizes are sorted in descenting order for reporting + */ +int compare_malloc_size(const MallocSite& s1, const MallocSite& s2) { + if (s1.size() == s2.size()) { + return 0; + } else if (s1.size() > s2.size()) { + return -1; + } else { + return 1; + } +} -MemType2Name MemBaseline::MemType2NameMap[NUMBER_OF_MEMORY_TYPE] = { - {mtJavaHeap, "Java Heap"}, - {mtClass, "Class"}, - {mtThreadStack,"Thread Stack"}, - {mtThread, "Thread"}, - {mtCode, "Code"}, - {mtGC, "GC"}, - {mtCompiler, "Compiler"}, - {mtInternal, "Internal"}, - {mtOther, "Other"}, - {mtSymbol, "Symbol"}, - {mtNMT, "Memory Tracking"}, - {mtTracing, "Tracing"}, - {mtChunk, "Pooled Free Chunks"}, - {mtClassShared,"Shared spaces for classes"}, - {mtTest, "Test"}, - {mtNone, "Unknown"} // It can happen when type tagging records are lagging - // behind + +int compare_virtual_memory_size(const VirtualMemoryAllocationSite& s1, + const VirtualMemoryAllocationSite& s2) { + if (s1.reserved() == s2.reserved()) { + return 0; + } else if (s1.reserved() > s2.reserved()) { + return -1; + } else { + return 1; + } +} + +// Sort into allocation site addresses order for baseline comparison +int compare_malloc_site(const MallocSite& s1, const MallocSite& s2) { + return s1.call_stack()->compare(*s2.call_stack()); +} + + +int compare_virtual_memory_site(const VirtualMemoryAllocationSite& s1, + const VirtualMemoryAllocationSite& s2) { + return s1.call_stack()->compare(*s2.call_stack()); +} + +/* + * Walker to walk malloc allocation site table + */ +class MallocAllocationSiteWalker : public MallocSiteWalker { + private: + SortedLinkedList + _malloc_sites; + size_t _count; + + // Entries in MallocSiteTable with size = 0 and count = 0, + // when the malloc site is not longer there. + public: + MallocAllocationSiteWalker(Arena* arena) : _count(0), _malloc_sites(arena) { + } + + inline size_t count() const { return _count; } + + LinkedList* malloc_sites() { + return &_malloc_sites; + } + + bool do_malloc_site(const MallocSite* site) { + if (site->size() >= MemBaseline::SIZE_THRESHOLD) { + if (_malloc_sites.add(*site) != NULL) { + _count++; + return true; + } else { + return false; // OOM + } + } else { + // malloc site does not meet threshold, ignore and continue + return true; + } + } }; -MemBaseline::MemBaseline() { - _baselined = false; - - for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { - _malloc_data[index].set_type(MemType2NameMap[index]._flag); - _vm_data[index].set_type(MemType2NameMap[index]._flag); - _arena_data[index].set_type(MemType2NameMap[index]._flag); - } - - _malloc_cs = NULL; - _vm_cs = NULL; - _vm_map = NULL; - - _number_of_classes = 0; - _number_of_threads = 0; +// Compare virtual memory region's base address +int compare_virtual_memory_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2) { + return r1.compare(r2); } +// Walk all virtual memory regions for baselining +class VirtualMemoryAllocationWalker : public VirtualMemoryWalker { + private: + SortedLinkedList + _virtual_memory_regions; + size_t _count; -void MemBaseline::clear() { - if (_malloc_cs != NULL) { - delete _malloc_cs; - _malloc_cs = NULL; + public: + VirtualMemoryAllocationWalker(Arena* a) : _count(0), _virtual_memory_regions(a) { } - if (_vm_cs != NULL) { - delete _vm_cs; - _vm_cs = NULL; - } - - if (_vm_map != NULL) { - delete _vm_map; - _vm_map = NULL; - } - - reset(); -} - - -void MemBaseline::reset() { - _baselined = false; - _total_vm_reserved = 0; - _total_vm_committed = 0; - _total_malloced = 0; - _number_of_classes = 0; - - if (_malloc_cs != NULL) _malloc_cs->clear(); - if (_vm_cs != NULL) _vm_cs->clear(); - if (_vm_map != NULL) _vm_map->clear(); - - for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { - _malloc_data[index].clear(); - _vm_data[index].clear(); - _arena_data[index].clear(); - } -} - -MemBaseline::~MemBaseline() { - clear(); -} - -// baseline malloc'd memory records, generate overall summary and summaries by -// memory types -bool MemBaseline::baseline_malloc_summary(const MemPointerArray* malloc_records) { - MemPointerArrayIteratorImpl malloc_itr((MemPointerArray*)malloc_records); - MemPointerRecord* malloc_ptr = (MemPointerRecord*)malloc_itr.current(); - size_t used_arena_size = 0; - int index; - while (malloc_ptr != NULL) { - index = flag2index(FLAGS_TO_MEMORY_TYPE(malloc_ptr->flags())); - size_t size = malloc_ptr->size(); - if (malloc_ptr->is_arena_memory_record()) { - // We do have anonymous arenas, they are either used as value objects, - // which are embedded inside other objects, or used as stack objects. - _arena_data[index].inc(size); - used_arena_size += size; - } else { - _total_malloced += size; - _malloc_data[index].inc(size); - if (malloc_ptr->is_arena_record()) { - // see if arena memory record present - MemPointerRecord* next_malloc_ptr = (MemPointerRecordEx*)malloc_itr.peek_next(); - if (next_malloc_ptr != NULL && next_malloc_ptr->is_arena_memory_record()) { - assert(next_malloc_ptr->is_memory_record_of_arena(malloc_ptr), - "Arena records do not match"); - size = next_malloc_ptr->size(); - _arena_data[index].inc(size); - used_arena_size += size; - malloc_itr.next(); - } - } - } - malloc_ptr = (MemPointerRecordEx*)malloc_itr.next(); - } - - // substract used arena size to get size of arena chunk in free list - index = flag2index(mtChunk); - _malloc_data[index].reduce(used_arena_size); - // we really don't know how many chunks in free list, so just set to - // 0 - _malloc_data[index].overwrite_counter(0); - - return true; -} - -// check if there is a safepoint in progress, if so, block the thread -// for the safepoint -void MemBaseline::check_safepoint(JavaThread* thr) { - if (SafepointSynchronize::is_synchronizing()) { - // grab and drop the SR_lock to honor the safepoint protocol - MutexLocker ml(thr->SR_lock()); - } -} - -// baseline mmap'd memory records, generate overall summary and summaries by -// memory types -bool MemBaseline::baseline_vm_summary(const MemPointerArray* vm_records) { - MemPointerArrayIteratorImpl vm_itr((MemPointerArray*)vm_records); - VMMemRegion* vm_ptr = (VMMemRegion*)vm_itr.current(); - int index; - while (vm_ptr != NULL) { - if (vm_ptr->is_reserved_region()) { - index = flag2index(FLAGS_TO_MEMORY_TYPE(vm_ptr->flags())); - // we use the number of thread stack to count threads - if (IS_MEMORY_TYPE(vm_ptr->flags(), mtThreadStack)) { - _number_of_threads ++; - } - _total_vm_reserved += vm_ptr->size(); - _vm_data[index].inc(vm_ptr->size(), 0); - } else { - _total_vm_committed += vm_ptr->size(); - _vm_data[index].inc(0, vm_ptr->size()); - } - vm_ptr = (VMMemRegion*)vm_itr.next(); - } - return true; -} - -// baseline malloc'd memory by callsites, but only the callsites with memory allocation -// over 1KB are stored. -bool MemBaseline::baseline_malloc_details(const MemPointerArray* malloc_records) { - assert(MemTracker::track_callsite(), "detail tracking is off"); - - MemPointerArrayIteratorImpl malloc_itr(const_cast(malloc_records)); - MemPointerRecordEx* malloc_ptr = (MemPointerRecordEx*)malloc_itr.current(); - MallocCallsitePointer malloc_callsite; - - // initailize malloc callsite array - if (_malloc_cs == NULL) { - _malloc_cs = new (std::nothrow) MemPointerArrayImpl(64); - // out of native memory - if (_malloc_cs == NULL || _malloc_cs->out_of_memory()) { - return false; - } - } else { - _malloc_cs->clear(); - } - - MemPointerArray* malloc_data = const_cast(malloc_records); - - // sort into callsite pc order. Details are aggregated by callsites - malloc_data->sort((FN_SORT)malloc_sort_by_pc); - bool ret = true; - - // baseline memory that is totaled over 1 KB - while (malloc_ptr != NULL) { - if (!MemPointerRecord::is_arena_memory_record(malloc_ptr->flags())) { - // skip thread stacks - if (!IS_MEMORY_TYPE(malloc_ptr->flags(), mtThreadStack)) { - if (malloc_callsite.addr() != malloc_ptr->pc()) { - if ((malloc_callsite.amount()/K) > 0) { - if (!_malloc_cs->append(&malloc_callsite)) { - ret = false; - break; - } - } - malloc_callsite = MallocCallsitePointer(malloc_ptr->pc()); - } - malloc_callsite.inc(malloc_ptr->size()); - } - } - malloc_ptr = (MemPointerRecordEx*)malloc_itr.next(); - } - - // restore to address order. Snapshot malloc data is maintained in memory - // address order. - malloc_data->sort((FN_SORT)malloc_sort_by_addr); - - if (!ret) { - return false; - } - // deal with last record - if (malloc_callsite.addr() != 0 && (malloc_callsite.amount()/K) > 0) { - if (!_malloc_cs->append(&malloc_callsite)) { - return false; - } - } - return true; -} - -// baseline mmap'd memory by callsites -bool MemBaseline::baseline_vm_details(const MemPointerArray* vm_records) { - assert(MemTracker::track_callsite(), "detail tracking is off"); - - VMCallsitePointer vm_callsite; - VMCallsitePointer* cur_callsite = NULL; - MemPointerArrayIteratorImpl vm_itr((MemPointerArray*)vm_records); - VMMemRegionEx* vm_ptr = (VMMemRegionEx*)vm_itr.current(); - - // initialize virtual memory map array - if (_vm_map == NULL) { - _vm_map = new (std::nothrow) MemPointerArrayImpl(vm_records->length()); - if (_vm_map == NULL || _vm_map->out_of_memory()) { - return false; - } - } else { - _vm_map->clear(); - } - - // initialize virtual memory callsite array - if (_vm_cs == NULL) { - _vm_cs = new (std::nothrow) MemPointerArrayImpl(64); - if (_vm_cs == NULL || _vm_cs->out_of_memory()) { - return false; - } - } else { - _vm_cs->clear(); - } - - // consolidate virtual memory data - VMMemRegionEx* reserved_rec = NULL; - VMMemRegionEx* committed_rec = NULL; - - // vm_ptr is coming in increasing base address order - while (vm_ptr != NULL) { - if (vm_ptr->is_reserved_region()) { - // consolidate reserved memory regions for virtual memory map. - // The criteria for consolidation is: - // 1. two adjacent reserved memory regions - // 2. belong to the same memory type - // 3. reserved from the same callsite - if (reserved_rec == NULL || - reserved_rec->base() + reserved_rec->size() != vm_ptr->addr() || - FLAGS_TO_MEMORY_TYPE(reserved_rec->flags()) != FLAGS_TO_MEMORY_TYPE(vm_ptr->flags()) || - reserved_rec->pc() != vm_ptr->pc()) { - if (!_vm_map->append(vm_ptr)) { + bool do_allocation_site(const ReservedMemoryRegion* rgn) { + if (rgn->size() >= MemBaseline::SIZE_THRESHOLD) { + if (_virtual_memory_regions.add(*rgn) != NULL) { + _count ++; + return true; + } else { return false; } - // inserted reserved region, we need the pointer to the element in virtual - // memory map array. - reserved_rec = (VMMemRegionEx*)_vm_map->at(_vm_map->length() - 1); - } else { - reserved_rec->expand_region(vm_ptr->addr(), vm_ptr->size()); } - - if (cur_callsite != NULL && !_vm_cs->append(cur_callsite)) { - return false; - } - vm_callsite = VMCallsitePointer(vm_ptr->pc()); - cur_callsite = &vm_callsite; - vm_callsite.inc(vm_ptr->size(), 0); - } else { - // consolidate committed memory regions for virtual memory map - // The criterial is: - // 1. two adjacent committed memory regions - // 2. committed from the same callsite - if (committed_rec == NULL || - committed_rec->base() + committed_rec->size() != vm_ptr->addr() || - committed_rec->pc() != vm_ptr->pc()) { - if (!_vm_map->append(vm_ptr)) { - return false; - } - committed_rec = (VMMemRegionEx*)_vm_map->at(_vm_map->length() - 1); - } else { - committed_rec->expand_region(vm_ptr->addr(), vm_ptr->size()); - } - vm_callsite.inc(0, vm_ptr->size()); - } - vm_ptr = (VMMemRegionEx*)vm_itr.next(); + return true; } - // deal with last record - if (cur_callsite != NULL && !_vm_cs->append(cur_callsite)) { + + LinkedList* virtual_memory_allocations() { + return &_virtual_memory_regions; + } +}; + + +bool MemBaseline::baseline_summary() { + assert(_malloc_memory_snapshot == NULL, "Malloc baseline not yet reset"); + assert(_virtual_memory_snapshot == NULL, "Virtual baseline not yet reset"); + + _malloc_memory_snapshot = new (arena()) MallocMemorySnapshot(); + _virtual_memory_snapshot = new (arena()) VirtualMemorySnapshot(); + if (_malloc_memory_snapshot == NULL || _virtual_memory_snapshot == NULL) { + return false; + } + MallocMemorySummary::snapshot(_malloc_memory_snapshot); + VirtualMemorySummary::snapshot(_virtual_memory_snapshot); + return true; +} + +bool MemBaseline::baseline_allocation_sites() { + assert(arena() != NULL, "Just check"); + // Malloc allocation sites + MallocAllocationSiteWalker malloc_walker(arena()); + if (!MallocSiteTable::walk_malloc_site(&malloc_walker)) { return false; } - // sort it into callsite pc order. Details are aggregated by callsites - _vm_cs->sort((FN_SORT)bl_vm_sort_by_pc); + _malloc_sites.set_head(malloc_walker.malloc_sites()->head()); + // The malloc sites are collected in size order + _malloc_sites_order = by_size; - // walk the array to consolidate record by pc - MemPointerArrayIteratorImpl itr(_vm_cs); - VMCallsitePointer* callsite_rec = (VMCallsitePointer*)itr.current(); - VMCallsitePointer* next_rec = (VMCallsitePointer*)itr.next(); - while (next_rec != NULL) { - assert(callsite_rec != NULL, "Sanity check"); - if (next_rec->addr() == callsite_rec->addr()) { - callsite_rec->inc(next_rec->reserved_amount(), next_rec->committed_amount()); - itr.remove(); - next_rec = (VMCallsitePointer*)itr.current(); - } else { - callsite_rec = next_rec; - next_rec = (VMCallsitePointer*)itr.next(); - } + // Virtual memory allocation sites + VirtualMemoryAllocationWalker virtual_memory_walker(arena()); + if (!VirtualMemoryTracker::walk_virtual_memory(&virtual_memory_walker)) { + return false; + } + + // Virtual memory allocations are collected in call stack order + _virtual_memory_allocations.set_head(virtual_memory_walker.virtual_memory_allocations()->head()); + + if (!aggregate_virtual_memory_allocation_sites()) { + return false; + } + // Virtual memory allocation sites are aggregrated in call stack order + _virtual_memory_sites_order = by_address; + + return true; +} + +bool MemBaseline::baseline(bool summaryOnly) { + if (arena() == NULL) { + _arena = new (std::nothrow, mtNMT) Arena(mtNMT); + if (arena() == NULL) return false; + } + + reset(); + + _class_count = InstanceKlass::number_of_instance_classes(); + + if (!baseline_summary()) { + return false; + } + + _baseline_type = Summary_baselined; + + // baseline details + if (!summaryOnly && + MemTracker::tracking_level() == NMT_detail) { + baseline_allocation_sites(); + _baseline_type = Detail_baselined; } return true; } -// baseline a snapshot. If summary_only = false, memory usages aggregated by -// callsites are also baselined. -// The method call can be lengthy, especially when detail tracking info is -// requested. So the method checks for safepoint explicitly. -bool MemBaseline::baseline(MemSnapshot& snapshot, bool summary_only) { - Thread* THREAD = Thread::current(); - assert(THREAD->is_Java_thread(), "must be a JavaThread"); - MutexLocker snapshot_locker(snapshot._lock); - reset(); - _baselined = baseline_malloc_summary(snapshot._alloc_ptrs); - if (_baselined) { - check_safepoint((JavaThread*)THREAD); - _baselined = baseline_vm_summary(snapshot._vm_ptrs); - } - _number_of_classes = snapshot.number_of_classes(); +int compare_allocation_site(const VirtualMemoryAllocationSite& s1, + const VirtualMemoryAllocationSite& s2) { + return s1.call_stack()->compare(*s2.call_stack()); +} - if (!summary_only && MemTracker::track_callsite() && _baselined) { - check_safepoint((JavaThread*)THREAD); - _baselined = baseline_malloc_details(snapshot._alloc_ptrs); - if (_baselined) { - check_safepoint((JavaThread*)THREAD); - _baselined = baseline_vm_details(snapshot._vm_ptrs); +bool MemBaseline::aggregate_virtual_memory_allocation_sites() { + SortedLinkedList + allocation_sites(arena()); + + VirtualMemoryAllocationIterator itr = virtual_memory_allocations(); + const ReservedMemoryRegion* rgn; + VirtualMemoryAllocationSite* site; + while ((rgn = itr.next()) != NULL) { + VirtualMemoryAllocationSite tmp(*rgn->call_stack()); + site = allocation_sites.find(tmp); + if (site == NULL) { + LinkedListNode* node = + allocation_sites.add(tmp); + if (node == NULL) return false; + site = node->data(); } - } - return _baselined; -} - - -int MemBaseline::flag2index(MEMFLAGS flag) const { - for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { - if (MemType2NameMap[index]._flag == flag) { - return index; - } - } - assert(false, "no type"); - return -1; -} - -const char* MemBaseline::type2name(MEMFLAGS type) { - for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { - if (MemType2NameMap[index]._flag == type) { - return MemType2NameMap[index]._name; - } - } - assert(false, err_msg("bad type %x", type)); - return NULL; -} - - -MemBaseline& MemBaseline::operator=(const MemBaseline& other) { - _total_malloced = other._total_malloced; - _total_vm_reserved = other._total_vm_reserved; - _total_vm_committed = other._total_vm_committed; - - _baselined = other._baselined; - _number_of_classes = other._number_of_classes; - - for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { - _malloc_data[index] = other._malloc_data[index]; - _vm_data[index] = other._vm_data[index]; - _arena_data[index] = other._arena_data[index]; + site->reserve_memory(rgn->size()); + site->commit_memory(rgn->committed_size()); } - if (MemTracker::track_callsite()) { - assert(_malloc_cs != NULL && _vm_cs != NULL, "out of memory"); - assert(other._malloc_cs != NULL && other._vm_cs != NULL, - "not properly baselined"); - _malloc_cs->clear(); - _vm_cs->clear(); - int index; - for (index = 0; index < other._malloc_cs->length(); index ++) { - _malloc_cs->append(other._malloc_cs->at(index)); - } + _virtual_memory_sites.set_head(allocation_sites.head()); + return true; +} - for (index = 0; index < other._vm_cs->length(); index ++) { - _vm_cs->append(other._vm_cs->at(index)); - } +MallocSiteIterator MemBaseline::malloc_sites(SortingOrder order) { + assert(!_malloc_sites.is_empty(), "Detail baseline?"); + switch(order) { + case by_size: + malloc_sites_to_size_order(); + break; + case by_site: + malloc_sites_to_allocation_site_order(); + break; + case by_address: + default: + ShouldNotReachHere(); } - return *this; + return MallocSiteIterator(_malloc_sites.head()); } -/* compare functions for sorting */ - -// sort snapshot malloc'd records in callsite pc order -int MemBaseline::malloc_sort_by_pc(const void* p1, const void* p2) { - assert(MemTracker::track_callsite(),"Just check"); - const MemPointerRecordEx* mp1 = (const MemPointerRecordEx*)p1; - const MemPointerRecordEx* mp2 = (const MemPointerRecordEx*)p2; - return UNSIGNED_COMPARE(mp1->pc(), mp2->pc()); -} - -// sort baselined malloc'd records in size order -int MemBaseline::bl_malloc_sort_by_size(const void* p1, const void* p2) { - assert(MemTracker::is_on(), "Just check"); - const MallocCallsitePointer* mp1 = (const MallocCallsitePointer*)p1; - const MallocCallsitePointer* mp2 = (const MallocCallsitePointer*)p2; - return UNSIGNED_COMPARE(mp2->amount(), mp1->amount()); -} - -// sort baselined malloc'd records in callsite pc order -int MemBaseline::bl_malloc_sort_by_pc(const void* p1, const void* p2) { - assert(MemTracker::is_on(), "Just check"); - const MallocCallsitePointer* mp1 = (const MallocCallsitePointer*)p1; - const MallocCallsitePointer* mp2 = (const MallocCallsitePointer*)p2; - return UNSIGNED_COMPARE(mp1->addr(), mp2->addr()); +VirtualMemorySiteIterator MemBaseline::virtual_memory_sites(SortingOrder order) { + assert(!_virtual_memory_sites.is_empty(), "Detail baseline?"); + switch(order) { + case by_size: + virtual_memory_sites_to_size_order(); + break; + case by_site: + virtual_memory_sites_to_reservation_site_order(); + break; + case by_address: + default: + ShouldNotReachHere(); + } + return VirtualMemorySiteIterator(_virtual_memory_sites.head()); } -// sort baselined mmap'd records in size (reserved size) order -int MemBaseline::bl_vm_sort_by_size(const void* p1, const void* p2) { - assert(MemTracker::is_on(), "Just check"); - const VMCallsitePointer* mp1 = (const VMCallsitePointer*)p1; - const VMCallsitePointer* mp2 = (const VMCallsitePointer*)p2; - return UNSIGNED_COMPARE(mp2->reserved_amount(), mp1->reserved_amount()); +// Sorting allocations sites in different orders +void MemBaseline::malloc_sites_to_size_order() { + if (_malloc_sites_order != by_size) { + SortedLinkedList + tmp(arena()); + + // Add malloc sites to sorted linked list to sort into size order + tmp.move(&_malloc_sites); + _malloc_sites.set_head(tmp.head()); + tmp.set_head(NULL); + _malloc_sites_order = by_size; + } } -// sort baselined mmap'd records in callsite pc order -int MemBaseline::bl_vm_sort_by_pc(const void* p1, const void* p2) { - assert(MemTracker::is_on(), "Just check"); - const VMCallsitePointer* mp1 = (const VMCallsitePointer*)p1; - const VMCallsitePointer* mp2 = (const VMCallsitePointer*)p2; - return UNSIGNED_COMPARE(mp1->addr(), mp2->addr()); +void MemBaseline::malloc_sites_to_allocation_site_order() { + if (_malloc_sites_order != by_site) { + SortedLinkedList + tmp(arena()); + // Add malloc sites to sorted linked list to sort into site (address) order + tmp.move(&_malloc_sites); + _malloc_sites.set_head(tmp.head()); + tmp.set_head(NULL); + _malloc_sites_order = by_site; + } } +void MemBaseline::virtual_memory_sites_to_size_order() { + if (_virtual_memory_sites_order != by_size) { + SortedLinkedList + tmp(arena()); -// sort snapshot malloc'd records in memory block address order -int MemBaseline::malloc_sort_by_addr(const void* p1, const void* p2) { - assert(MemTracker::is_on(), "Just check"); - const MemPointerRecord* mp1 = (const MemPointerRecord*)p1; - const MemPointerRecord* mp2 = (const MemPointerRecord*)p2; - int delta = UNSIGNED_COMPARE(mp1->addr(), mp2->addr()); - assert(p1 == p2 || delta != 0, "dup pointer"); - return delta; + tmp.move(&_virtual_memory_sites); + + _virtual_memory_sites.set_head(tmp.head()); + tmp.set_head(NULL); + _virtual_memory_sites_order = by_size; + } +} + +void MemBaseline::virtual_memory_sites_to_reservation_site_order() { + if (_virtual_memory_sites_order != by_size) { + SortedLinkedList + tmp(arena()); + + tmp.add(&_virtual_memory_sites); + + _virtual_memory_sites.set_head(tmp.head()); + tmp.set_head(NULL); + + _virtual_memory_sites_order = by_size; + } } diff --git a/hotspot/src/share/vm/services/memBaseline.hpp b/hotspot/src/share/vm/services/memBaseline.hpp index 864c6cc5724..bf742f8d56a 100644 --- a/hotspot/src/share/vm/services/memBaseline.hpp +++ b/hotspot/src/share/vm/services/memBaseline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -25,425 +25,205 @@ #ifndef SHARE_VM_SERVICES_MEM_BASELINE_HPP #define SHARE_VM_SERVICES_MEM_BASELINE_HPP +#if INCLUDE_NMT + #include "memory/allocation.hpp" #include "runtime/mutex.hpp" -#include "services/memPtr.hpp" -#include "services/memSnapshot.hpp" +#include "services/mallocSiteTable.hpp" +#include "services/mallocTracker.hpp" +#include "services/nmtCommon.hpp" +#include "services/virtualMemoryTracker.hpp" +#include "utilities/linkedlist.hpp" -// compare unsigned number -#define UNSIGNED_COMPARE(a, b) ((a > b) ? 1 : ((a == b) ? 0 : -1)) +typedef LinkedListIterator MallocSiteIterator; +typedef LinkedListIterator VirtualMemorySiteIterator; +typedef LinkedListIterator VirtualMemoryAllocationIterator; /* - * MallocCallsitePointer and VMCallsitePointer are used - * to baseline memory blocks with their callsite information. - * They are only available when detail tracking is turned - * on. - */ - -/* baselined malloc record aggregated by callsite */ -class MallocCallsitePointer : public MemPointer { - private: - size_t _count; // number of malloc invocation from this callsite - size_t _amount; // total amount of memory malloc-ed from this callsite - - public: - MallocCallsitePointer() { - _count = 0; - _amount = 0; - } - - MallocCallsitePointer(address pc) : MemPointer(pc) { - _count = 0; - _amount = 0; - } - - MallocCallsitePointer& operator=(const MallocCallsitePointer& p) { - MemPointer::operator=(p); - _count = p.count(); - _amount = p.amount(); - return *this; - } - - inline void inc(size_t size) { - _count ++; - _amount += size; - }; - - inline size_t count() const { - return _count; - } - - inline size_t amount() const { - return _amount; - } -}; - -// baselined virtual memory record aggregated by callsite -class VMCallsitePointer : public MemPointer { - private: - size_t _count; // number of invocation from this callsite - size_t _reserved_amount; // total reserved amount - size_t _committed_amount; // total committed amount - - public: - VMCallsitePointer() { - _count = 0; - _reserved_amount = 0; - _committed_amount = 0; - } - - VMCallsitePointer(address pc) : MemPointer(pc) { - _count = 0; - _reserved_amount = 0; - _committed_amount = 0; - } - - VMCallsitePointer& operator=(const VMCallsitePointer& p) { - MemPointer::operator=(p); - _count = p.count(); - _reserved_amount = p.reserved_amount(); - _committed_amount = p.committed_amount(); - return *this; - } - - inline void inc(size_t reserved, size_t committed) { - _count ++; - _reserved_amount += reserved; - _committed_amount += committed; - } - - inline size_t count() const { - return _count; - } - - inline size_t reserved_amount() const { - return _reserved_amount; - } - - inline size_t committed_amount() const { - return _committed_amount; - } -}; - -// maps a memory type flag to readable name -typedef struct _memType2Name { - MEMFLAGS _flag; - const char* _name; -} MemType2Name; - - -// This class aggregates malloc'd records by memory type -class MallocMem VALUE_OBJ_CLASS_SPEC { - private: - MEMFLAGS _type; - - size_t _count; - size_t _amount; - - public: - MallocMem() { - _type = mtNone; - _count = 0; - _amount = 0; - } - - MallocMem(MEMFLAGS flags) { - assert(HAS_VALID_MEMORY_TYPE(flags), "no type"); - _type = FLAGS_TO_MEMORY_TYPE(flags); - _count = 0; - _amount = 0; - } - - inline void set_type(MEMFLAGS flag) { - _type = flag; - } - - inline void clear() { - _count = 0; - _amount = 0; - _type = mtNone; - } - - MallocMem& operator=(const MallocMem& m) { - assert(_type == m.type(), "different type"); - _count = m.count(); - _amount = m.amount(); - return *this; - } - - inline void inc(size_t amt) { - _amount += amt; - _count ++; - } - - inline void reduce(size_t amt) { - assert(_amount >= amt, "Just check"); - _amount -= amt; - } - - inline void overwrite_counter(size_t count) { - _count = count; - } - - inline MEMFLAGS type() const { - return _type; - } - - inline bool is_type(MEMFLAGS flags) const { - return FLAGS_TO_MEMORY_TYPE(flags) == _type; - } - - inline size_t count() const { - return _count; - } - - inline size_t amount() const { - return _amount; - } -}; - -// This class records live arena's memory usage -class ArenaMem : public MallocMem { - public: - ArenaMem(MEMFLAGS typeflag): MallocMem(typeflag) { - } - ArenaMem() { } -}; - -// This class aggregates virtual memory by its memory type -class VMMem VALUE_OBJ_CLASS_SPEC { - private: - MEMFLAGS _type; - - size_t _count; - size_t _reserved_amount; - size_t _committed_amount; - - public: - VMMem() { - _type = mtNone; - _count = 0; - _reserved_amount = 0; - _committed_amount = 0; - } - - VMMem(MEMFLAGS flags) { - assert(HAS_VALID_MEMORY_TYPE(flags), "no type"); - _type = FLAGS_TO_MEMORY_TYPE(flags); - _count = 0; - _reserved_amount = 0; - _committed_amount = 0; - } - - inline void clear() { - _type = mtNone; - _count = 0; - _reserved_amount = 0; - _committed_amount = 0; - } - - inline void set_type(MEMFLAGS flags) { - _type = FLAGS_TO_MEMORY_TYPE(flags); - } - - VMMem& operator=(const VMMem& m) { - assert(_type == m.type(), "different type"); - - _count = m.count(); - _reserved_amount = m.reserved_amount(); - _committed_amount = m.committed_amount(); - return *this; - } - - - inline MEMFLAGS type() const { - return _type; - } - - inline bool is_type(MEMFLAGS flags) const { - return FLAGS_TO_MEMORY_TYPE(flags) == _type; - } - - inline void inc(size_t reserved_amt, size_t committed_amt) { - _reserved_amount += reserved_amt; - _committed_amount += committed_amt; - _count ++; - } - - inline size_t count() const { - return _count; - } - - inline size_t reserved_amount() const { - return _reserved_amount; - } - - inline size_t committed_amount() const { - return _committed_amount; - } -}; - - - -#define NUMBER_OF_MEMORY_TYPE (mt_number_of_types + 1) - -class BaselineReporter; -class BaselineComparisonReporter; - -/* - * This class baselines current memory snapshot. - * A memory baseline summarizes memory usage by memory type, - * aggregates memory usage by callsites when detail tracking - * is on. + * Baseline a memory snapshot */ class MemBaseline VALUE_OBJ_CLASS_SPEC { - friend class BaselineReporter; - friend class BaselineComparisonReporter; + public: + enum BaselineThreshold { + SIZE_THRESHOLD = K // Only allocation size over this threshold will be baselined. + }; + + enum BaselineType { + Not_baselined, + Summary_baselined, + Detail_baselined + }; + + enum SortingOrder { + by_address, // by memory address + by_size, // by memory size + by_site // by call site where the memory is allocated from + }; private: - // overall summaries - size_t _total_malloced; - size_t _total_vm_reserved; - size_t _total_vm_committed; - size_t _number_of_classes; - size_t _number_of_threads; + // All baseline data is stored in this arena + Arena* _arena; - // if it has properly baselined - bool _baselined; + // Summary information + MallocMemorySnapshot* _malloc_memory_snapshot; + VirtualMemorySnapshot* _virtual_memory_snapshot; - // we categorize memory into three categories within the memory type - MallocMem _malloc_data[NUMBER_OF_MEMORY_TYPE]; - VMMem _vm_data[NUMBER_OF_MEMORY_TYPE]; - ArenaMem _arena_data[NUMBER_OF_MEMORY_TYPE]; + size_t _class_count; - // memory records that aggregate memory usage by callsites. - // only available when detail tracking is on. - MemPointerArray* _malloc_cs; - MemPointerArray* _vm_cs; - // virtual memory map - MemPointerArray* _vm_map; + // Allocation sites information + // Malloc allocation sites + LinkedListImpl + _malloc_sites; - private: - static MemType2Name MemType2NameMap[NUMBER_OF_MEMORY_TYPE]; + // All virtual memory allocations + LinkedListImpl + _virtual_memory_allocations; - private: - // should not use copy constructor - MemBaseline(MemBaseline& copy) { ShouldNotReachHere(); } + // Virtual memory allocations by allocation sites, always in by_address + // order + LinkedListImpl + _virtual_memory_sites; - // check and block at a safepoint - static inline void check_safepoint(JavaThread* thr); + SortingOrder _malloc_sites_order; + SortingOrder _virtual_memory_sites_order; + + BaselineType _baseline_type; public: // create a memory baseline - MemBaseline(); - - ~MemBaseline(); - - inline bool baselined() const { - return _baselined; + MemBaseline(): + _baseline_type(Not_baselined), + _class_count(0), + _arena(NULL), + _malloc_memory_snapshot(NULL), + _virtual_memory_snapshot(NULL), + _malloc_sites(NULL) { } - MemBaseline& operator=(const MemBaseline& other); + ~MemBaseline() { + reset(); + if (_arena != NULL) { + delete _arena; + } + } + + bool baseline(bool summaryOnly = true); + + BaselineType baseline_type() const { return _baseline_type; } + + MallocMemorySnapshot* malloc_memory_snapshot() const { + return _malloc_memory_snapshot; + } + + VirtualMemorySnapshot* virtual_memory_snapshot() const { + return _virtual_memory_snapshot; + } + + MallocSiteIterator malloc_sites(SortingOrder order); + VirtualMemorySiteIterator virtual_memory_sites(SortingOrder order); + + // Virtual memory allocation iterator always returns in virtual memory + // base address order. + VirtualMemoryAllocationIterator virtual_memory_allocations() { + assert(!_virtual_memory_allocations.is_empty(), "Not detail baseline"); + return VirtualMemoryAllocationIterator(_virtual_memory_allocations.head()); + } + + // Total reserved memory = total malloc'd memory + total reserved virtual + // memory + size_t total_reserved_memory() const { + assert(baseline_type() != Not_baselined, "Not yet baselined"); + assert(_virtual_memory_snapshot != NULL, "No virtual memory snapshot"); + assert(_malloc_memory_snapshot != NULL, "No malloc memory snapshot"); + size_t amount = _malloc_memory_snapshot->total() + + _virtual_memory_snapshot->total_reserved(); + return amount; + } + + // Total committed memory = total malloc'd memory + total committed + // virtual memory + size_t total_committed_memory() const { + assert(baseline_type() != Not_baselined, "Not yet baselined"); + assert(_virtual_memory_snapshot != NULL, + "Not a snapshot"); + size_t amount = _malloc_memory_snapshot->total() + + _virtual_memory_snapshot->total_committed(); + return amount; + } + + size_t total_arena_memory() const { + assert(baseline_type() != Not_baselined, "Not yet baselined"); + assert(_malloc_memory_snapshot != NULL, "Not yet baselined"); + return _malloc_memory_snapshot->total_arena(); + } + + size_t malloc_tracking_overhead() const { + assert(baseline_type() != Not_baselined, "Not yet baselined"); + return _malloc_memory_snapshot->malloc_overhead()->size(); + } + + const MallocMemory* malloc_memory(MEMFLAGS flag) const { + assert(_malloc_memory_snapshot != NULL, "Not a snapshot"); + return _malloc_memory_snapshot->by_type(flag); + } + + const VirtualMemory* virtual_memory(MEMFLAGS flag) const { + assert(_virtual_memory_snapshot != NULL, "Not a snapshot"); + return _virtual_memory_snapshot->by_type(flag); + } + + + size_t class_count() const { + assert(baseline_type() != Not_baselined, "Not yet baselined"); + return _class_count; + } + + size_t thread_count() const { + assert(baseline_type() != Not_baselined, "Not yet baselined"); + assert(_malloc_memory_snapshot != NULL, "Baselined?"); + return _malloc_memory_snapshot->thread_count(); + } // reset the baseline for reuse - void clear(); + void reset() { + _baseline_type = Not_baselined; + _malloc_memory_snapshot = NULL; + _virtual_memory_snapshot = NULL; + _class_count = 0; - // baseline the snapshot - bool baseline(MemSnapshot& snapshot, bool summary_only = true); + _malloc_sites = NULL; + _virtual_memory_sites = NULL; + _virtual_memory_allocations = NULL; - bool baseline(const MemPointerArray* malloc_records, - const MemPointerArray* vm_records, - bool summary_only = true); - - // total malloc'd memory of specified memory type - inline size_t malloc_amount(MEMFLAGS flag) const { - return _malloc_data[flag2index(flag)].amount(); + if (_arena != NULL) { + _arena->destruct_contents(); + } } - // number of malloc'd memory blocks of specified memory type - inline size_t malloc_count(MEMFLAGS flag) const { - return _malloc_data[flag2index(flag)].count(); - } - // total memory used by arenas of specified memory type - inline size_t arena_amount(MEMFLAGS flag) const { - return _arena_data[flag2index(flag)].amount(); - } - // number of arenas of specified memory type - inline size_t arena_count(MEMFLAGS flag) const { - return _arena_data[flag2index(flag)].count(); - } - // total reserved memory of specified memory type - inline size_t reserved_amount(MEMFLAGS flag) const { - return _vm_data[flag2index(flag)].reserved_amount(); - } - // total committed memory of specified memory type - inline size_t committed_amount(MEMFLAGS flag) const { - return _vm_data[flag2index(flag)].committed_amount(); - } - // total memory (malloc'd + mmap'd + arena) of specified - // memory type - inline size_t total_amount(MEMFLAGS flag) const { - int index = flag2index(flag); - return _malloc_data[index].amount() + - _vm_data[index].reserved_amount() + - _arena_data[index].amount(); - } - - /* overall summaries */ - - // total malloc'd memory in snapshot - inline size_t total_malloc_amount() const { - return _total_malloced; - } - // total mmap'd memory in snapshot - inline size_t total_reserved_amount() const { - return _total_vm_reserved; - } - // total committed memory in snapshot - inline size_t total_committed_amount() const { - return _total_vm_committed; - } - // number of loaded classes - inline size_t number_of_classes() const { - return _number_of_classes; - } - // number of running threads - inline size_t number_of_threads() const { - return _number_of_threads; - } - // lookup human readable name of a memory type - static const char* type2name(MEMFLAGS type); private: - // convert memory flag to the index to mapping table - int flag2index(MEMFLAGS flag) const; + // Baseline summary information + bool baseline_summary(); - // reset baseline values - void reset(); + // Baseline allocation sites (detail tracking only) + bool baseline_allocation_sites(); - // summarize the records in global snapshot - bool baseline_malloc_summary(const MemPointerArray* malloc_records); - bool baseline_vm_summary(const MemPointerArray* vm_records); - bool baseline_malloc_details(const MemPointerArray* malloc_records); - bool baseline_vm_details(const MemPointerArray* vm_records); + // Aggregate virtual memory allocation by allocation sites + bool aggregate_virtual_memory_allocation_sites(); - // print a line of malloc'd memory aggregated by callsite - void print_malloc_callsite(outputStream* st, address pc, size_t size, - size_t count, int diff_amt, int diff_count) const; - // print a line of mmap'd memory aggregated by callsite - void print_vm_callsite(outputStream* st, address pc, size_t rsz, - size_t csz, int diff_rsz, int diff_csz) const; + Arena* arena() { return _arena; } - // sorting functions for raw records - static int malloc_sort_by_pc(const void* p1, const void* p2); - static int malloc_sort_by_addr(const void* p1, const void* p2); + // Sorting allocation sites in different orders + // Sort allocation sites in size order + void malloc_sites_to_size_order(); + // Sort allocation sites in call site address order + void malloc_sites_to_allocation_site_order(); - private: - // sorting functions for baselined records - static int bl_malloc_sort_by_size(const void* p1, const void* p2); - static int bl_vm_sort_by_size(const void* p1, const void* p2); - static int bl_malloc_sort_by_pc(const void* p1, const void* p2); - static int bl_vm_sort_by_pc(const void* p1, const void* p2); + // Sort allocation sites in reserved size order + void virtual_memory_sites_to_size_order(); + // Sort allocation sites in call site address order + void virtual_memory_sites_to_reservation_site_order(); }; +#endif // INCLUDE_NMT #endif // SHARE_VM_SERVICES_MEM_BASELINE_HPP diff --git a/hotspot/src/share/vm/services/memPtr.hpp b/hotspot/src/share/vm/services/memPtr.hpp deleted file mode 100644 index cae454cc318..00000000000 --- a/hotspot/src/share/vm/services/memPtr.hpp +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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_SERVICES_MEM_PTR_HPP -#define SHARE_VM_SERVICES_MEM_PTR_HPP - -#include "memory/allocation.hpp" -#include "runtime/os.hpp" -#include "runtime/safepoint.hpp" - -/* - * global sequence generator that generates sequence numbers to serialize - * memory records. - */ -class SequenceGenerator : AllStatic { - public: - static jint next(); - - // peek last sequence number - static jint peek() { - return _seq_number; - } - - // reset sequence number - static void reset() { - assert(SafepointSynchronize::is_at_safepoint(), "Safepoint required"); - _seq_number = 1; - _generation ++; - }; - - static unsigned long current_generation() { return _generation; } - NOT_PRODUCT(static jint max_seq_num() { return _max_seq_number; }) - - private: - static volatile jint _seq_number; - static volatile unsigned long _generation; - NOT_PRODUCT(static jint _max_seq_number; ) -}; - -/* - * followings are the classes that are used to hold memory activity records in different stages. - * MemPointer - * |--------MemPointerRecord - * | - * |----MemPointerRecordEx - * | | - * | |-------SeqMemPointerRecordEx - * | - * |----SeqMemPointerRecord - * | - * |----VMMemRegion - * | - * |-----VMMemRegionEx - * - * - * prefix 'Seq' - sequenced, the record contains a sequence number - * surfix 'Ex' - extension, the record contains a caller's pc - * - * per-thread recorder : SeqMemPointerRecord(Ex) - * snapshot staging : SeqMemPointerRecord(Ex) - * snapshot : MemPointerRecord(Ex) and VMMemRegion(Ex) - * - */ - -/* - * class that wraps an address to a memory block, - * the memory pointer either points to a malloc'd - * memory block, or a mmap'd memory block - */ -class MemPointer VALUE_OBJ_CLASS_SPEC { - public: - MemPointer(): _addr(0) { } - MemPointer(address addr): _addr(addr) { } - - MemPointer(const MemPointer& copy_from) { - _addr = copy_from.addr(); - } - - inline address addr() const { - return _addr; - } - - inline operator address() const { - return addr(); - } - - inline bool operator == (const MemPointer& other) const { - return addr() == other.addr(); - } - - inline MemPointer& operator = (const MemPointer& other) { - _addr = other.addr(); - return *this; - } - - protected: - inline void set_addr(address addr) { _addr = addr; } - - protected: - // memory address - address _addr; -}; - -/* MemPointerRecord records an activityand associated - * attributes on a memory block. - */ -class MemPointerRecord : public MemPointer { - private: - MEMFLAGS _flags; - size_t _size; - -public: - /* extension of MemoryType enum - * see share/vm/memory/allocation.hpp for details. - * - * The tag values are associated to sorting orders, so be - * careful if changes are needed. - * The allocation records should be sorted ahead of tagging - * records, which in turn ahead of deallocation records - */ - enum MemPointerTags { - tag_alloc = 0x0001, // malloc or reserve record - tag_commit = 0x0002, // commit record - tag_type = 0x0003, // tag virtual memory to a memory type - tag_uncommit = 0x0004, // uncommit record - tag_release = 0x0005, // free or release record - tag_size = 0x0006, // arena size - tag_masks = 0x0007, // all tag bits - vmBit = 0x0008 - }; - - /* helper functions to interpret the tagging flags */ - - inline static bool is_allocation_record(MEMFLAGS flags) { - return (flags & tag_masks) == tag_alloc; - } - - inline static bool is_deallocation_record(MEMFLAGS flags) { - return (flags & tag_masks) == tag_release; - } - - inline static bool is_arena_record(MEMFLAGS flags) { - return (flags & (otArena | tag_size)) == otArena; - } - - inline static bool is_arena_memory_record(MEMFLAGS flags) { - return (flags & (otArena | tag_size)) == (otArena | tag_size); - } - - inline static bool is_virtual_memory_record(MEMFLAGS flags) { - return (flags & vmBit) != 0; - } - - inline static bool is_virtual_memory_reserve_record(MEMFLAGS flags) { - return (flags & 0x0F) == (tag_alloc | vmBit); - } - - inline static bool is_virtual_memory_commit_record(MEMFLAGS flags) { - return (flags & 0x0F) == (tag_commit | vmBit); - } - - inline static bool is_virtual_memory_uncommit_record(MEMFLAGS flags) { - return (flags & 0x0F) == (tag_uncommit | vmBit); - } - - inline static bool is_virtual_memory_release_record(MEMFLAGS flags) { - return (flags & 0x0F) == (tag_release | vmBit); - } - - inline static bool is_virtual_memory_type_record(MEMFLAGS flags) { - return (flags & 0x0F) == (tag_type | vmBit); - } - - /* tagging flags */ - inline static MEMFLAGS malloc_tag() { return tag_alloc; } - inline static MEMFLAGS free_tag() { return tag_release; } - inline static MEMFLAGS arena_size_tag() { return tag_size | otArena; } - inline static MEMFLAGS virtual_memory_tag() { return vmBit; } - inline static MEMFLAGS virtual_memory_reserve_tag() { return (tag_alloc | vmBit); } - inline static MEMFLAGS virtual_memory_commit_tag() { return (tag_commit | vmBit); } - inline static MEMFLAGS virtual_memory_uncommit_tag(){ return (tag_uncommit | vmBit); } - inline static MEMFLAGS virtual_memory_release_tag() { return (tag_release | vmBit); } - inline static MEMFLAGS virtual_memory_type_tag() { return (tag_type | vmBit); } - - public: - MemPointerRecord(): _size(0), _flags(mtNone) { } - - MemPointerRecord(address addr, MEMFLAGS memflags, size_t size = 0): - MemPointer(addr), _flags(memflags), _size(size) { } - - MemPointerRecord(const MemPointerRecord& copy_from): - MemPointer(copy_from), _flags(copy_from.flags()), - _size(copy_from.size()) { - } - - /* MemPointerRecord is not sequenced, it always return - * 0 to indicate non-sequenced - */ - virtual jint seq() const { return 0; } - - inline size_t size() const { return _size; } - inline void set_size(size_t size) { _size = size; } - - inline MEMFLAGS flags() const { return _flags; } - inline void set_flags(MEMFLAGS flags) { _flags = flags; } - - MemPointerRecord& operator= (const MemPointerRecord& ptr) { - MemPointer::operator=(ptr); - _flags = ptr.flags(); -#ifdef ASSERT - if (IS_ARENA_OBJ(_flags)) { - assert(!is_vm_pointer(), "wrong flags"); - assert((_flags & ot_masks) == otArena, "wrong flags"); - } -#endif - _size = ptr.size(); - return *this; - } - - // if the pointer represents a malloc-ed memory address - inline bool is_malloced_pointer() const { - return !is_vm_pointer(); - } - - // if the pointer represents a virtual memory address - inline bool is_vm_pointer() const { - return is_virtual_memory_record(_flags); - } - - // if this record records a 'malloc' or virtual memory - // 'reserve' call - inline bool is_allocation_record() const { - return is_allocation_record(_flags); - } - - // if this record records a size information of an arena - inline bool is_arena_memory_record() const { - return is_arena_memory_record(_flags); - } - - // if this pointer represents an address to an arena object - inline bool is_arena_record() const { - return is_arena_record(_flags); - } - - // if this record represents a size information of specific arena - inline bool is_memory_record_of_arena(const MemPointerRecord* arena_rc) { - assert(is_arena_memory_record(), "not size record"); - assert(arena_rc->is_arena_record(), "not arena record"); - return (arena_rc->addr() + sizeof(void*)) == addr(); - } - - // if this record records a 'free' or virtual memory 'free' call - inline bool is_deallocation_record() const { - return is_deallocation_record(_flags); - } - - // if this record records a virtual memory 'commit' call - inline bool is_commit_record() const { - return is_virtual_memory_commit_record(_flags); - } - - // if this record records a virtual memory 'uncommit' call - inline bool is_uncommit_record() const { - return is_virtual_memory_uncommit_record(_flags); - } - - // if this record is a tagging record of a virtual memory block - inline bool is_type_tagging_record() const { - return is_virtual_memory_type_record(_flags); - } - - // if the two memory pointer records actually represent the same - // memory block - inline bool is_same_region(const MemPointerRecord* other) const { - return (addr() == other->addr() && size() == other->size()); - } - - // if this memory region fully contains another one - inline bool contains_region(const MemPointerRecord* other) const { - return contains_region(other->addr(), other->size()); - } - - // if this memory region fully contains specified memory range - inline bool contains_region(address add, size_t sz) const { - return (addr() <= add && addr() + size() >= add + sz); - } - - inline bool contains_address(address add) const { - return (addr() <= add && addr() + size() > add); - } - - // if this memory region overlaps another region - inline bool overlaps_region(const MemPointerRecord* other) const { - assert(other != NULL, "Just check"); - assert(size() > 0 && other->size() > 0, "empty range"); - return contains_address(other->addr()) || - contains_address(other->addr() + other->size() - 1) || // exclude end address - other->contains_address(addr()) || - other->contains_address(addr() + size() - 1); // exclude end address - } - -}; - -// MemPointerRecordEx also records callsite pc, from where -// the memory block is allocated -class MemPointerRecordEx : public MemPointerRecord { - private: - address _pc; // callsite pc - - public: - MemPointerRecordEx(): _pc(0) { } - - MemPointerRecordEx(address addr, MEMFLAGS memflags, size_t size = 0, address pc = 0): - MemPointerRecord(addr, memflags, size), _pc(pc) {} - - MemPointerRecordEx(const MemPointerRecordEx& copy_from): - MemPointerRecord(copy_from), _pc(copy_from.pc()) {} - - inline address pc() const { return _pc; } - - void init(const MemPointerRecordEx* mpe) { - MemPointerRecord::operator=(*mpe); - _pc = mpe->pc(); - } - - void init(const MemPointerRecord* mp) { - MemPointerRecord::operator=(*mp); - _pc = 0; - } -}; - -// a virtual memory region. The region can represent a reserved -// virtual memory region or a committed memory region -class VMMemRegion : public MemPointerRecord { -public: - VMMemRegion() { } - - void init(const MemPointerRecord* mp) { - assert(mp->is_vm_pointer(), "Sanity check"); - _addr = mp->addr(); - set_size(mp->size()); - set_flags(mp->flags()); - } - - VMMemRegion& operator=(const VMMemRegion& other) { - MemPointerRecord::operator=(other); - return *this; - } - - inline bool is_reserved_region() const { - return is_allocation_record(); - } - - inline bool is_committed_region() const { - return is_commit_record(); - } - - /* base address of this virtual memory range */ - inline address base() const { - return addr(); - } - - /* tag this virtual memory range to the specified memory type */ - inline void tag(MEMFLAGS f) { - set_flags(flags() | (f & mt_masks)); - } - - // expand this region to also cover specified range. - // The range has to be on either end of the memory region. - void expand_region(address addr, size_t sz) { - if (addr < base()) { - assert(addr + sz == base(), "Sanity check"); - _addr = addr; - set_size(size() + sz); - } else { - assert(base() + size() == addr, "Sanity check"); - set_size(size() + sz); - } - } - - // exclude the specified address range from this region. - // The excluded memory range has to be on either end of this memory - // region. - inline void exclude_region(address add, size_t sz) { - assert(is_reserved_region() || is_committed_region(), "Sanity check"); - assert(addr() != NULL && size() != 0, "Sanity check"); - assert(add >= addr() && add < addr() + size(), "Sanity check"); - assert(add == addr() || (add + sz) == (addr() + size()), - "exclude in the middle"); - if (add == addr()) { - set_addr(add + sz); - set_size(size() - sz); - } else { - set_size(size() - sz); - } - } -}; - -class VMMemRegionEx : public VMMemRegion { - private: - jint _seq; // sequence number - - public: - VMMemRegionEx(): _pc(0) { } - - void init(const MemPointerRecordEx* mpe) { - VMMemRegion::init(mpe); - _pc = mpe->pc(); - } - - void init(const MemPointerRecord* mpe) { - VMMemRegion::init(mpe); - _pc = 0; - } - - VMMemRegionEx& operator=(const VMMemRegionEx& other) { - VMMemRegion::operator=(other); - _pc = other.pc(); - return *this; - } - - inline address pc() const { return _pc; } - private: - address _pc; -}; - -/* - * Sequenced memory record - */ -class SeqMemPointerRecord : public MemPointerRecord { - private: - jint _seq; // sequence number - - public: - SeqMemPointerRecord(): _seq(0){ } - - SeqMemPointerRecord(address addr, MEMFLAGS flags, size_t size, jint seq) - : MemPointerRecord(addr, flags, size), _seq(seq) { - } - - SeqMemPointerRecord(const SeqMemPointerRecord& copy_from) - : MemPointerRecord(copy_from) { - _seq = copy_from.seq(); - } - - SeqMemPointerRecord& operator= (const SeqMemPointerRecord& ptr) { - MemPointerRecord::operator=(ptr); - _seq = ptr.seq(); - return *this; - } - - inline jint seq() const { - return _seq; - } -}; - - - -class SeqMemPointerRecordEx : public MemPointerRecordEx { - private: - jint _seq; // sequence number - - public: - SeqMemPointerRecordEx(): _seq(0) { } - - SeqMemPointerRecordEx(address addr, MEMFLAGS flags, size_t size, - jint seq, address pc): - MemPointerRecordEx(addr, flags, size, pc), _seq(seq) { - } - - SeqMemPointerRecordEx(const SeqMemPointerRecordEx& copy_from) - : MemPointerRecordEx(copy_from) { - _seq = copy_from.seq(); - } - - SeqMemPointerRecordEx& operator= (const SeqMemPointerRecordEx& ptr) { - MemPointerRecordEx::operator=(ptr); - _seq = ptr.seq(); - return *this; - } - - inline jint seq() const { - return _seq; - } -}; - -#endif // SHARE_VM_SERVICES_MEM_PTR_HPP diff --git a/hotspot/src/share/vm/services/memPtrArray.hpp b/hotspot/src/share/vm/services/memPtrArray.hpp deleted file mode 100644 index b3e48f6868e..00000000000 --- a/hotspot/src/share/vm/services/memPtrArray.hpp +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (c) 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. - * - */ -#ifndef SHARE_VM_UTILITIES_MEM_PTR_ARRAY_HPP -#define SHARE_VM_UTILITIES_MEM_PTR_ARRAY_HPP - -#include "memory/allocation.hpp" -#include "services/memPtr.hpp" - -class MemPtr; -class MemRecorder; -class ArenaInfo; -class MemSnapshot; - -extern "C" { - typedef int (*FN_SORT)(const void *, const void *); -} - - -// Memory pointer array interface. This array is used by NMT to hold -// various memory block information. -// The memory pointer arrays are usually walked with their iterators. - -class MemPointerArray : public CHeapObj { - public: - virtual ~MemPointerArray() { } - - // return true if it can not allocate storage for the data - virtual bool out_of_memory() const = 0; - virtual bool is_empty() const = 0; - virtual bool is_full() = 0; - virtual int length() const = 0; - virtual void clear() = 0; - virtual bool append(MemPointer* ptr) = 0; - virtual bool insert_at(MemPointer* ptr, int pos) = 0; - virtual bool remove_at(int pos) = 0; - virtual MemPointer* at(int index) const = 0; - virtual void sort(FN_SORT fn) = 0; - virtual size_t instance_size() const = 0; - virtual bool shrink() = 0; - - NOT_PRODUCT(virtual int capacity() const = 0;) -}; - -// Iterator interface -class MemPointerArrayIterator VALUE_OBJ_CLASS_SPEC { - public: - // return the pointer at current position - virtual MemPointer* current() const = 0; - // return the next pointer and advance current position - virtual MemPointer* next() = 0; - // return next pointer without advancing current position - virtual MemPointer* peek_next() const = 0; - // return previous pointer without changing current position - virtual MemPointer* peek_prev() const = 0; - // remove the pointer at current position - virtual void remove() = 0; - // insert the pointer at current position - virtual bool insert(MemPointer* ptr) = 0; - // insert specified element after current position and - // move current position to newly inserted position - virtual bool insert_after(MemPointer* ptr) = 0; -}; - -// implementation class -class MemPointerArrayIteratorImpl : public MemPointerArrayIterator { - protected: - MemPointerArray* _array; - int _pos; - - public: - MemPointerArrayIteratorImpl(MemPointerArray* arr) { - assert(arr != NULL, "Parameter check"); - _array = arr; - _pos = 0; - } - - virtual MemPointer* current() const { - if (_pos < _array->length()) { - return _array->at(_pos); - } - return NULL; - } - - virtual MemPointer* next() { - if (_pos + 1 < _array->length()) { - return _array->at(++_pos); - } - _pos = _array->length(); - return NULL; - } - - virtual MemPointer* peek_next() const { - if (_pos + 1 < _array->length()) { - return _array->at(_pos + 1); - } - return NULL; - } - - virtual MemPointer* peek_prev() const { - if (_pos > 0) { - return _array->at(_pos - 1); - } - return NULL; - } - - virtual void remove() { - if (_pos < _array->length()) { - _array->remove_at(_pos); - } - } - - virtual bool insert(MemPointer* ptr) { - return _array->insert_at(ptr, _pos); - } - - virtual bool insert_after(MemPointer* ptr) { - if (_array->insert_at(ptr, _pos + 1)) { - _pos ++; - return true; - } - return false; - } -}; - - - -// Memory pointer array implementation. -// This implementation implements expandable array -#define DEFAULT_PTR_ARRAY_SIZE 1024 - -template class MemPointerArrayImpl : public MemPointerArray { - private: - int _max_size; - int _size; - bool _init_elements; - E* _data; - - public: - MemPointerArrayImpl(int initial_size = DEFAULT_PTR_ARRAY_SIZE, bool init_elements = true): - _max_size(initial_size), _size(0), _init_elements(init_elements) { - _data = (E*)raw_allocate(sizeof(E), initial_size); - if (_init_elements) { - for (int index = 0; index < _max_size; index ++) { - ::new ((void*)&_data[index]) E(); - } - } - } - - virtual ~MemPointerArrayImpl() { - if (_data != NULL) { - raw_free(_data); - } - } - - public: - bool out_of_memory() const { - return (_data == NULL); - } - - size_t instance_size() const { - return sizeof(MemPointerArrayImpl) + _max_size * sizeof(E); - } - - bool is_empty() const { - assert(_data != NULL, "Just check"); - return _size == 0; - } - - bool is_full() { - assert(_data != NULL, "Just check"); - if (_size < _max_size) { - return false; - } else { - return !expand_array(); - } - } - - int length() const { - assert(_data != NULL, "Just check"); - return _size; - } - - NOT_PRODUCT(int capacity() const { return _max_size; }) - - void clear() { - assert(_data != NULL, "Just check"); - _size = 0; - } - - bool append(MemPointer* ptr) { - assert(_data != NULL, "Just check"); - if (is_full()) { - return false; - } - _data[_size ++] = *(E*)ptr; - return true; - } - - bool insert_at(MemPointer* ptr, int pos) { - assert(_data != NULL, "Just check"); - if (is_full()) { - return false; - } - for (int index = _size; index > pos; index --) { - _data[index] = _data[index - 1]; - } - _data[pos] = *(E*)ptr; - _size ++; - return true; - } - - bool remove_at(int pos) { - assert(_data != NULL, "Just check"); - if (_size <= pos && pos >= 0) { - return false; - } - -- _size; - - for (int index = pos; index < _size; index ++) { - _data[index] = _data[index + 1]; - } - return true; - } - - MemPointer* at(int index) const { - assert(_data != NULL, "Just check"); - assert(index >= 0 && index < _size, "illegal index"); - return &_data[index]; - } - - bool shrink() { - float used = ((float)_size) / ((float)_max_size); - if (used < 0.40) { - E* old_ptr = _data; - int new_size = ((_max_size) / (2 * DEFAULT_PTR_ARRAY_SIZE) + 1) * DEFAULT_PTR_ARRAY_SIZE; - _data = (E*)raw_reallocate(_data, sizeof(E), new_size); - if (_data == NULL) { - _data = old_ptr; - return false; - } else { - _max_size = new_size; - return true; - } - } - return false; - } - - void sort(FN_SORT fn) { - assert(_data != NULL, "Just check"); - qsort((void*)_data, _size, sizeof(E), fn); - } - - private: - bool expand_array() { - assert(_data != NULL, "Not yet allocated"); - E* old_ptr = _data; - if ((_data = (E*)raw_reallocate((void*)_data, sizeof(E), - _max_size + DEFAULT_PTR_ARRAY_SIZE)) == NULL) { - _data = old_ptr; - return false; - } else { - _max_size += DEFAULT_PTR_ARRAY_SIZE; - if (_init_elements) { - for (int index = _size; index < _max_size; index ++) { - ::new ((void*)&_data[index]) E(); - } - } - return true; - } - } - - void* raw_allocate(size_t elementSize, int items) { - return os::malloc(elementSize * items, mtNMT); - } - - void* raw_reallocate(void* ptr, size_t elementSize, int items) { - return os::realloc(ptr, elementSize * items, mtNMT); - } - - void raw_free(void* ptr) { - os::free(ptr, mtNMT); - } -}; - -#endif // SHARE_VM_UTILITIES_MEM_PTR_ARRAY_HPP diff --git a/hotspot/src/share/vm/services/memRecorder.cpp b/hotspot/src/share/vm/services/memRecorder.cpp deleted file mode 100644 index b8707f58360..00000000000 --- a/hotspot/src/share/vm/services/memRecorder.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 "runtime/atomic.inline.hpp" -#include "services/memBaseline.hpp" -#include "services/memRecorder.hpp" -#include "services/memPtr.hpp" -#include "services/memTracker.hpp" - -MemPointer* SequencedRecordIterator::next_record() { - MemPointerRecord* itr_cur = (MemPointerRecord*)_itr.current(); - if (itr_cur == NULL) { - return itr_cur; - } - - MemPointerRecord* itr_next = (MemPointerRecord*)_itr.next(); - - // don't collapse virtual memory records - while (itr_next != NULL && !itr_cur->is_vm_pointer() && - !itr_next->is_vm_pointer() && - same_kind(itr_cur, itr_next)) { - itr_cur = itr_next; - itr_next = (MemPointerRecord*)_itr.next(); - } - - return itr_cur; -} - - -volatile jint MemRecorder::_instance_count = 0; - -MemRecorder::MemRecorder() { - assert(MemTracker::is_on(), "Native memory tracking is off"); - Atomic::inc(&_instance_count); - set_generation(); - - if (MemTracker::track_callsite()) { - _pointer_records = new (std::nothrow)FixedSizeMemPointerArray(); - } else { - _pointer_records = new (std::nothrow)FixedSizeMemPointerArray(); - } - _next = NULL; - - - if (_pointer_records != NULL) { - // recode itself - address pc = CURRENT_PC; - record((address)this, (MemPointerRecord::malloc_tag()|mtNMT|otNMTRecorder), - sizeof(MemRecorder), SequenceGenerator::next(), pc); - record((address)_pointer_records, (MemPointerRecord::malloc_tag()|mtNMT|otNMTRecorder), - _pointer_records->instance_size(), SequenceGenerator::next(), pc); - } -} - -MemRecorder::~MemRecorder() { - if (_pointer_records != NULL) { - if (MemTracker::is_on()) { - MemTracker::record_free((address)_pointer_records, mtNMT); - MemTracker::record_free((address)this, mtNMT); - } - delete _pointer_records; - } - // delete all linked recorders - while (_next != NULL) { - MemRecorder* tmp = _next; - _next = _next->next(); - tmp->set_next(NULL); - delete tmp; - } - Atomic::dec(&_instance_count); -} - -// Sorting order: -// 1. memory block address -// 2. mem pointer record tags -// 3. sequence number -int MemRecorder::sort_record_fn(const void* e1, const void* e2) { - const MemPointerRecord* p1 = (const MemPointerRecord*)e1; - const MemPointerRecord* p2 = (const MemPointerRecord*)e2; - int delta = UNSIGNED_COMPARE(p1->addr(), p2->addr()); - if (delta == 0) { - int df = UNSIGNED_COMPARE((p1->flags() & MemPointerRecord::tag_masks), - (p2->flags() & MemPointerRecord::tag_masks)); - if (df == 0) { - assert(p1->seq() != p2->seq(), "dup seq"); - return p1->seq() - p2->seq(); - } else { - return df; - } - } else { - return delta; - } -} - -bool MemRecorder::record(address p, MEMFLAGS flags, size_t size, jint seq, address pc) { - assert(seq > 0, "No sequence number"); -#ifdef ASSERT - if (MemPointerRecord::is_virtual_memory_record(flags)) { - assert((flags & MemPointerRecord::tag_masks) != 0, "bad virtual memory record"); - } else { - assert((flags & MemPointerRecord::tag_masks) == MemPointerRecord::malloc_tag() || - (flags & MemPointerRecord::tag_masks) == MemPointerRecord::free_tag() || - IS_ARENA_OBJ(flags), - "bad malloc record"); - } - // a recorder should only hold records within the same generation - unsigned long cur_generation = SequenceGenerator::current_generation(); - assert(cur_generation == _generation, - "this thread did not enter sync point"); -#endif - - if (MemTracker::track_callsite()) { - SeqMemPointerRecordEx ap(p, flags, size, seq, pc); - debug_only(check_dup_seq(ap.seq());) - return _pointer_records->append(&ap); - } else { - SeqMemPointerRecord ap(p, flags, size, seq); - debug_only(check_dup_seq(ap.seq());) - return _pointer_records->append(&ap); - } -} - - // iterator for alloc pointers -SequencedRecordIterator MemRecorder::pointer_itr() { - assert(_pointer_records != NULL, "just check"); - _pointer_records->sort((FN_SORT)sort_record_fn); - return SequencedRecordIterator(_pointer_records); -} - - -void MemRecorder::set_generation() { - _generation = SequenceGenerator::current_generation(); -} - -#ifdef ASSERT - -void MemRecorder::check_dup_seq(jint seq) const { - MemPointerArrayIteratorImpl itr(_pointer_records); - MemPointerRecord* rc = (MemPointerRecord*)itr.current(); - while (rc != NULL) { - assert(rc->seq() != seq, "dup seq"); - rc = (MemPointerRecord*)itr.next(); - } -} - -#endif diff --git a/hotspot/src/share/vm/services/memRecorder.hpp b/hotspot/src/share/vm/services/memRecorder.hpp deleted file mode 100644 index 4329dad0267..00000000000 --- a/hotspot/src/share/vm/services/memRecorder.hpp +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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_SERVICES_MEM_RECORDER_HPP -#define SHARE_VM_SERVICES_MEM_RECORDER_HPP - -#include "memory/allocation.hpp" -#include "runtime/os.hpp" -#include "services/memPtrArray.hpp" - -class MemSnapshot; -class MemTracker; -class MemTrackWorker; - -// Fixed size memory pointer array implementation -template class FixedSizeMemPointerArray : - public MemPointerArray { - // This implementation is for memory recorder only - friend class MemRecorder; - - private: - E _data[SIZE]; - int _size; - - protected: - FixedSizeMemPointerArray(bool init_elements = false): - _size(0){ - if (init_elements) { - for (int index = 0; index < SIZE; index ++) { - ::new ((void*)&_data[index]) E(); - } - } - } - - void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() { - // the instance is part of memRecorder, needs to be tagged with 'otNMTRecorder' - // to avoid recursion - return os::malloc(size, (mtNMT | otNMTRecorder)); - } - - void* operator new(size_t size) throw() { - assert(false, "use nothrow version"); - return NULL; - } - - void operator delete(void* p) { - os::free(p, (mtNMT | otNMTRecorder)); - } - - // instance size - inline size_t instance_size() const { - return sizeof(FixedSizeMemPointerArray); - } - - NOT_PRODUCT(int capacity() const { return SIZE; }) - - public: - // implementation of public interface - bool out_of_memory() const { return false; } - bool is_empty() const { return _size == 0; } - bool is_full() { return length() >= SIZE; } - int length() const { return _size; } - - void clear() { - _size = 0; - } - - bool append(MemPointer* ptr) { - if (is_full()) return false; - _data[_size ++] = *(E*)ptr; - return true; - } - - virtual bool insert_at(MemPointer* p, int pos) { - assert(false, "append only"); - return false; - } - - virtual bool remove_at(int pos) { - assert(false, "not supported"); - return false; - } - - MemPointer* at(int index) const { - assert(index >= 0 && index < length(), - "parameter check"); - return ((E*)&_data[index]); - } - - void sort(FN_SORT fn) { - qsort((void*)_data, _size, sizeof(E), fn); - } - - bool shrink() { - return false; - } -}; - - -// This iterator requires pre-sorted MemPointerArray, which is sorted by: -// 1. address -// 2. allocation type -// 3. sequence number -// During the array walking, iterator collapses pointers with the same -// address and allocation type, and only returns the one with highest -// sequence number. -// -// This is read-only iterator, update methods are asserted. -class SequencedRecordIterator : public MemPointerArrayIterator { - private: - MemPointerArrayIteratorImpl _itr; - MemPointer* _cur; - - public: - SequencedRecordIterator(const MemPointerArray* arr): - _itr(const_cast(arr)) { - _cur = next_record(); - } - - SequencedRecordIterator(const SequencedRecordIterator& itr): - _itr(itr._itr) { - _cur = next_record(); - } - - // return the pointer at current position - virtual MemPointer* current() const { - return _cur; - }; - - // return the next pointer and advance current position - virtual MemPointer* next() { - _cur = next_record(); - return _cur; - } - - // return the next pointer without advancing current position - virtual MemPointer* peek_next() const { - assert(false, "not implemented"); - return NULL; - - } - // return the previous pointer without changing current position - virtual MemPointer* peek_prev() const { - assert(false, "not implemented"); - return NULL; - } - - // remove the pointer at current position - virtual void remove() { - assert(false, "read-only iterator"); - }; - // insert the pointer at current position - virtual bool insert(MemPointer* ptr) { - assert(false, "read-only iterator"); - return false; - } - - virtual bool insert_after(MemPointer* ptr) { - assert(false, "read-only iterator"); - return false; - } - private: - // collapse the 'same kind' of records, and return this 'kind' of - // record with highest sequence number - MemPointer* next_record(); - - // Test if the two records are the same kind: the same memory block and allocation - // type. - inline bool same_kind(const MemPointerRecord* p1, const MemPointerRecord* p2) const { - assert(!p1->is_vm_pointer() && !p2->is_vm_pointer(), "malloc pointer only"); - return (p1->addr() == p2->addr() && - (p1->flags() &MemPointerRecord::tag_masks) == - (p2->flags() & MemPointerRecord::tag_masks)); - } -}; - - - -#define DEFAULT_RECORDER_PTR_ARRAY_SIZE 512 - -class MemRecorder : public CHeapObj { - friend class MemSnapshot; - friend class MemTracker; - friend class MemTrackWorker; - friend class GenerationData; - - protected: - // the array that holds memory records - MemPointerArray* _pointer_records; - - private: - // used for linked list - MemRecorder* _next; - // active recorder can only record a certain generation data - unsigned long _generation; - - protected: - _NOINLINE_ MemRecorder(); - ~MemRecorder(); - - // record a memory operation - bool record(address addr, MEMFLAGS flags, size_t size, jint seq, address caller_pc = 0); - - // linked list support - inline void set_next(MemRecorder* rec) { - _next = rec; - } - - inline MemRecorder* next() const { - return _next; - } - - // if the recorder is full - inline bool is_full() const { - assert(_pointer_records != NULL, "just check"); - return _pointer_records->is_full(); - } - - // if running out of memory when initializing recorder's internal - // data - inline bool out_of_memory() const { - return (_pointer_records == NULL || - _pointer_records->out_of_memory()); - } - - inline void clear() { - assert(_pointer_records != NULL, "Just check"); - _pointer_records->clear(); - } - - SequencedRecordIterator pointer_itr(); - - // return the generation of this recorder which it belongs to - unsigned long get_generation() const { return _generation; } - protected: - // number of MemRecorder instance - static volatile jint _instance_count; - - private: - // sorting function, sort records into following order - // 1. memory address - // 2. allocation type - // 3. sequence number - static int sort_record_fn(const void* e1, const void* e2); - - debug_only(void check_dup_seq(jint seq) const;) - void set_generation(); -}; - -#endif // SHARE_VM_SERVICES_MEM_RECORDER_HPP diff --git a/hotspot/src/share/vm/services/memReporter.cpp b/hotspot/src/share/vm/services/memReporter.cpp index 305693dad08..0269619178f 100644 --- a/hotspot/src/share/vm/services/memReporter.cpp +++ b/hotspot/src/share/vm/services/memReporter.cpp @@ -22,618 +22,595 @@ * */ #include "precompiled.hpp" -#include "classfile/systemDictionary.hpp" -#include "runtime/os.hpp" + +#include "memory/allocation.hpp" +#include "services/mallocTracker.hpp" #include "services/memReporter.hpp" -#include "services/memPtrArray.hpp" -#include "services/memTracker.hpp" +#include "services/virtualMemoryTracker.hpp" +#include "utilities/globalDefinitions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +size_t MemReporterBase::reserved_total(const MallocMemory* malloc, const VirtualMemory* vm) const { + return malloc->malloc_size() + malloc->arena_size() + vm->reserved(); +} -const char* BaselineOutputer::memory_unit(size_t scale) { - switch(scale) { - case K: return "KB"; - case M: return "MB"; - case G: return "GB"; +size_t MemReporterBase::committed_total(const MallocMemory* malloc, const VirtualMemory* vm) const { + return malloc->malloc_size() + malloc->arena_size() + vm->committed(); +} + +void MemReporterBase::print_total(size_t reserved, size_t committed) const { + const char* scale = current_scale(); + output()->print("reserved=" SIZE_FORMAT "%s, committed=" SIZE_FORMAT "%s", + amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale); +} + +void MemReporterBase::print_malloc(size_t amount, size_t count) const { + const char* scale = current_scale(); + outputStream* out = output(); + out->print("(malloc=" SIZE_FORMAT "%s", + amount_in_current_scale(amount), scale); + + if (count > 0) { + out->print(" #" SIZE_FORMAT "", count); } - ShouldNotReachHere(); - return NULL; + + out->print(")"); +} + +void MemReporterBase::print_virtual_memory(size_t reserved, size_t committed) const { + const char* scale = current_scale(); + output()->print("(mmap: reserved=" SIZE_FORMAT "%s, committed=" SIZE_FORMAT "%s)", + amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale); +} + +void MemReporterBase::print_malloc_line(size_t amount, size_t count) const { + output()->print("%28s", " "); + print_malloc(amount, count); + output()->print_cr(" "); +} + +void MemReporterBase::print_virtual_memory_line(size_t reserved, size_t committed) const { + output()->print("%28s", " "); + print_virtual_memory(reserved, committed); + output()->print_cr(" "); +} + +void MemReporterBase::print_arena_line(size_t amount, size_t count) const { + const char* scale = current_scale(); + output()->print_cr("%27s (arena=" SIZE_FORMAT "%s #" SIZE_FORMAT ")", " ", + amount_in_current_scale(amount), scale, count); +} + +void MemReporterBase::print_virtual_memory_region(const char* type, address base, size_t size) const { + const char* scale = current_scale(); + output()->print("[" PTR_FORMAT " - " PTR_FORMAT "] %s " SIZE_FORMAT "%s", + p2i(base), p2i(base + size), type, amount_in_current_scale(size), scale); } -void BaselineReporter::report_baseline(const MemBaseline& baseline, bool summary_only) { - assert(MemTracker::is_on(), "Native memory tracking is off"); - _outputer.start(scale()); - _outputer.total_usage( - amount_in_current_scale(baseline.total_malloc_amount() + baseline.total_reserved_amount()), - amount_in_current_scale(baseline.total_malloc_amount() + baseline.total_committed_amount())); +void MemSummaryReporter::report() { + const char* scale = current_scale(); + outputStream* out = output(); + size_t total_reserved_amount = _malloc_snapshot->total() + + _vm_snapshot->total_reserved(); + size_t total_committed_amount = _malloc_snapshot->total() + + _vm_snapshot->total_committed(); - _outputer.num_of_classes(baseline.number_of_classes()); - _outputer.num_of_threads(baseline.number_of_threads()); + // Overall total + out->print_cr("\nNative Memory Tracking:\n"); + out->print("Total: "); + print_total(total_reserved_amount, total_committed_amount); + out->print("\n"); - report_summaries(baseline); - if (!summary_only && MemTracker::track_callsite()) { - report_virtual_memory_map(baseline); - report_callsites(baseline); + // Summary by memory type + for (int index = 0; index < mt_number_of_types; index ++) { + MEMFLAGS flag = NMTUtil::index_to_flag(index); + // thread stack is reported as part of thread category + if (flag == mtThreadStack) continue; + MallocMemory* malloc_memory = _malloc_snapshot->by_type(flag); + VirtualMemory* virtual_memory = _vm_snapshot->by_type(flag); + + report_summary_of_type(flag, malloc_memory, virtual_memory); } - _outputer.done(); } -void BaselineReporter::report_summaries(const MemBaseline& baseline) { - _outputer.start_category_summary(); - MEMFLAGS type; +void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag, + MallocMemory* malloc_memory, VirtualMemory* virtual_memory) { - for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { - type = MemBaseline::MemType2NameMap[index]._flag; - _outputer.category_summary(type, - amount_in_current_scale(baseline.reserved_amount(type)), - amount_in_current_scale(baseline.committed_amount(type)), - amount_in_current_scale(baseline.malloc_amount(type)), - baseline.malloc_count(type), - amount_in_current_scale(baseline.arena_amount(type)), - baseline.arena_count(type)); + size_t reserved_amount = reserved_total (malloc_memory, virtual_memory); + size_t committed_amount = committed_total(malloc_memory, virtual_memory); + + // Count thread's native stack in "Thread" category + if (flag == mtThread) { + const VirtualMemory* thread_stack_usage = + (const VirtualMemory*)_vm_snapshot->by_type(mtThreadStack); + reserved_amount += thread_stack_usage->reserved(); + committed_amount += thread_stack_usage->committed(); + } else if (flag == mtNMT) { + // Count malloc headers in "NMT" category + reserved_amount += _malloc_snapshot->malloc_overhead()->size(); + committed_amount += _malloc_snapshot->malloc_overhead()->size(); } - _outputer.done_category_summary(); -} + if (amount_in_current_scale(reserved_amount) > 0) { + outputStream* out = output(); + const char* scale = current_scale(); + out->print("-%26s (", NMTUtil::flag_to_name(flag)); + print_total(reserved_amount, committed_amount); + out->print_cr(")"); -void BaselineReporter::report_virtual_memory_map(const MemBaseline& baseline) { - _outputer.start_virtual_memory_map(); - MemBaseline* pBL = const_cast(&baseline); - MemPointerArrayIteratorImpl itr = MemPointerArrayIteratorImpl(pBL->_vm_map); - VMMemRegionEx* rgn = (VMMemRegionEx*)itr.current(); - while (rgn != NULL) { - if (rgn->is_reserved_region()) { - _outputer.reserved_memory_region(FLAGS_TO_MEMORY_TYPE(rgn->flags()), - rgn->base(), rgn->base() + rgn->size(), amount_in_current_scale(rgn->size()), rgn->pc()); - } else { - _outputer.committed_memory_region(rgn->base(), rgn->base() + rgn->size(), - amount_in_current_scale(rgn->size()), rgn->pc()); + if (flag == mtClass) { + // report class count + out->print_cr("%27s (classes #" SIZE_FORMAT ")", " ", _class_count); + } else if (flag == mtThread) { + // report thread count + out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", _malloc_snapshot->thread_count()); + const VirtualMemory* thread_stack_usage = + _vm_snapshot->by_type(mtThreadStack); + out->print("%27s (stack: ", " "); + print_total(thread_stack_usage->reserved(), thread_stack_usage->committed()); + out->print_cr(")"); } - rgn = (VMMemRegionEx*)itr.next(); - } - _outputer.done_virtual_memory_map(); + // report malloc'd memory + if (amount_in_current_scale(malloc_memory->malloc_size()) > 0) { + // We don't know how many arena chunks are in used, so don't report the count + size_t count = (flag == mtChunk) ? 0 : malloc_memory->malloc_count(); + print_malloc_line(malloc_memory->malloc_size(), count); + } + + if (amount_in_current_scale(virtual_memory->reserved()) > 0) { + print_virtual_memory_line(virtual_memory->reserved(), virtual_memory->committed()); + } + + if (amount_in_current_scale(malloc_memory->arena_size()) > 0) { + print_arena_line(malloc_memory->arena_size(), malloc_memory->arena_count()); + } + + if (flag == mtNMT && + amount_in_current_scale(_malloc_snapshot->malloc_overhead()->size()) > 0) { + out->print_cr("%27s (tracking overhead=" SIZE_FORMAT "%s)", " ", + amount_in_current_scale(_malloc_snapshot->malloc_overhead()->size()), scale); + } + + out->print_cr(" "); + } } -void BaselineReporter::report_callsites(const MemBaseline& baseline) { - _outputer.start_callsite(); - MemBaseline* pBL = const_cast(&baseline); +void MemDetailReporter::report_detail() { + // Start detail report + outputStream* out = output(); + out->print_cr("Details:\n"); - pBL->_malloc_cs->sort((FN_SORT)MemBaseline::bl_malloc_sort_by_size); - pBL->_vm_cs->sort((FN_SORT)MemBaseline::bl_vm_sort_by_size); - - // walk malloc callsites - MemPointerArrayIteratorImpl malloc_itr(pBL->_malloc_cs); - MallocCallsitePointer* malloc_callsite = - (MallocCallsitePointer*)malloc_itr.current(); - while (malloc_callsite != NULL) { - _outputer.malloc_callsite(malloc_callsite->addr(), - amount_in_current_scale(malloc_callsite->amount()), malloc_callsite->count()); - malloc_callsite = (MallocCallsitePointer*)malloc_itr.next(); - } - - // walk virtual memory callsite - MemPointerArrayIteratorImpl vm_itr(pBL->_vm_cs); - VMCallsitePointer* vm_callsite = (VMCallsitePointer*)vm_itr.current(); - while (vm_callsite != NULL) { - _outputer.virtual_memory_callsite(vm_callsite->addr(), - amount_in_current_scale(vm_callsite->reserved_amount()), - amount_in_current_scale(vm_callsite->committed_amount())); - vm_callsite = (VMCallsitePointer*)vm_itr.next(); - } - pBL->_malloc_cs->sort((FN_SORT)MemBaseline::bl_malloc_sort_by_pc); - pBL->_vm_cs->sort((FN_SORT)MemBaseline::bl_vm_sort_by_pc); - _outputer.done_callsite(); + report_malloc_sites(); + report_virtual_memory_allocation_sites(); } -void BaselineReporter::diff_baselines(const MemBaseline& cur, const MemBaseline& prev, - bool summary_only) { - assert(MemTracker::is_on(), "Native memory tracking is off"); - _outputer.start(scale()); - size_t total_reserved = cur.total_malloc_amount() + cur.total_reserved_amount(); - size_t total_committed = cur.total_malloc_amount() + cur.total_committed_amount(); +void MemDetailReporter::report_malloc_sites() { + MallocSiteIterator malloc_itr = _baseline.malloc_sites(MemBaseline::by_size); + if (malloc_itr.is_empty()) return; - _outputer.diff_total_usage( - amount_in_current_scale(total_reserved), amount_in_current_scale(total_committed), - diff_in_current_scale(total_reserved, (prev.total_malloc_amount() + prev.total_reserved_amount())), - diff_in_current_scale(total_committed, (prev.total_committed_amount() + prev.total_malloc_amount()))); + outputStream* out = output(); - _outputer.diff_num_of_classes(cur.number_of_classes(), - diff(cur.number_of_classes(), prev.number_of_classes())); - _outputer.diff_num_of_threads(cur.number_of_threads(), - diff(cur.number_of_threads(), prev.number_of_threads())); + const MallocSite* malloc_site; + while ((malloc_site = malloc_itr.next()) != NULL) { + // Don't report if size is too small + if (amount_in_current_scale(malloc_site->size()) == 0) + continue; - diff_summaries(cur, prev); - if (!summary_only && MemTracker::track_callsite()) { - diff_callsites(cur, prev); + const NativeCallStack* stack = malloc_site->call_stack(); + stack->print_on(out); + out->print("%29s", " "); + print_malloc(malloc_site->size(), malloc_site->count()); + out->print_cr("\n"); } - _outputer.done(); } -void BaselineReporter::diff_summaries(const MemBaseline& cur, const MemBaseline& prev) { - _outputer.start_category_summary(); - MEMFLAGS type; +void MemDetailReporter::report_virtual_memory_allocation_sites() { + VirtualMemorySiteIterator virtual_memory_itr = + _baseline.virtual_memory_sites(MemBaseline::by_size); - for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { - type = MemBaseline::MemType2NameMap[index]._flag; - _outputer.diff_category_summary(type, - amount_in_current_scale(cur.reserved_amount(type)), - amount_in_current_scale(cur.committed_amount(type)), - amount_in_current_scale(cur.malloc_amount(type)), - cur.malloc_count(type), - amount_in_current_scale(cur.arena_amount(type)), - cur.arena_count(type), - diff_in_current_scale(cur.reserved_amount(type), prev.reserved_amount(type)), - diff_in_current_scale(cur.committed_amount(type), prev.committed_amount(type)), - diff_in_current_scale(cur.malloc_amount(type), prev.malloc_amount(type)), - diff(cur.malloc_count(type), prev.malloc_count(type)), - diff_in_current_scale(cur.arena_amount(type), prev.arena_amount(type)), - diff(cur.arena_count(type), prev.arena_count(type))); + if (virtual_memory_itr.is_empty()) return; + + outputStream* out = output(); + const VirtualMemoryAllocationSite* virtual_memory_site; + + while ((virtual_memory_site = virtual_memory_itr.next()) != NULL) { + // Don't report if size is too small + if (amount_in_current_scale(virtual_memory_site->reserved()) == 0) + continue; + + const NativeCallStack* stack = virtual_memory_site->call_stack(); + stack->print_on(out); + out->print("%28s (", " "); + print_total(virtual_memory_site->reserved(), virtual_memory_site->committed()); + out->print_cr(")\n"); } - - _outputer.done_category_summary(); } -void BaselineReporter::diff_callsites(const MemBaseline& cur, const MemBaseline& prev) { - _outputer.start_callsite(); - MemBaseline* pBL_cur = const_cast(&cur); - MemBaseline* pBL_prev = const_cast(&prev); - // walk malloc callsites - MemPointerArrayIteratorImpl cur_malloc_itr(pBL_cur->_malloc_cs); - MemPointerArrayIteratorImpl prev_malloc_itr(pBL_prev->_malloc_cs); +void MemDetailReporter::report_virtual_memory_map() { + // Virtual memory map always in base address order + VirtualMemoryAllocationIterator itr = _baseline.virtual_memory_allocations(); + const ReservedMemoryRegion* rgn; - MallocCallsitePointer* cur_malloc_callsite = - (MallocCallsitePointer*)cur_malloc_itr.current(); - MallocCallsitePointer* prev_malloc_callsite = - (MallocCallsitePointer*)prev_malloc_itr.current(); + output()->print_cr("Virtual memory map:"); + while ((rgn = itr.next()) != NULL) { + report_virtual_memory_region(rgn); + } +} - while (cur_malloc_callsite != NULL || prev_malloc_callsite != NULL) { - if (prev_malloc_callsite == NULL) { - assert(cur_malloc_callsite != NULL, "sanity check"); - // this is a new callsite - _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(), - amount_in_current_scale(cur_malloc_callsite->amount()), - cur_malloc_callsite->count(), - diff_in_current_scale(cur_malloc_callsite->amount(), 0), - diff(cur_malloc_callsite->count(), 0)); - cur_malloc_callsite = (MallocCallsitePointer*)cur_malloc_itr.next(); - } else if (cur_malloc_callsite == NULL) { - assert(prev_malloc_callsite != NULL, "Sanity check"); - // this callsite is already gone - _outputer.diff_malloc_callsite(prev_malloc_callsite->addr(), - 0, 0, - diff_in_current_scale(0, prev_malloc_callsite->amount()), - diff(0, prev_malloc_callsite->count())); - prev_malloc_callsite = (MallocCallsitePointer*)prev_malloc_itr.next(); +void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* reserved_rgn) { + assert(reserved_rgn != NULL, "NULL pointer"); + + // Don't report if size is too small + if (amount_in_current_scale(reserved_rgn->size()) == 0) return; + + outputStream* out = output(); + const char* scale = current_scale(); + const NativeCallStack* stack = reserved_rgn->call_stack(); + bool all_committed = reserved_rgn->all_committed(); + const char* region_type = (all_committed ? "reserved and committed" : "reserved"); + out->print_cr(" "); + print_virtual_memory_region(region_type, reserved_rgn->base(), reserved_rgn->size()); + out->print(" for %s", NMTUtil::flag_to_name(reserved_rgn->flag())); + if (stack->is_empty()) { + out->print_cr(" "); + } else { + out->print_cr(" from"); + stack->print_on(out, 4); + } + + if (all_committed) return; + + CommittedRegionIterator itr = reserved_rgn->iterate_committed_regions(); + const CommittedMemoryRegion* committed_rgn; + while ((committed_rgn = itr.next()) != NULL) { + // Don't report if size is too small + if (amount_in_current_scale(committed_rgn->size()) == 0) continue; + stack = committed_rgn->call_stack(); + out->print("\n\t"); + print_virtual_memory_region("committed", committed_rgn->base(), committed_rgn->size()); + if (stack->is_empty()) { + out->print_cr(" "); } else { - assert(cur_malloc_callsite != NULL, "Sanity check"); - assert(prev_malloc_callsite != NULL, "Sanity check"); - if (cur_malloc_callsite->addr() < prev_malloc_callsite->addr()) { - // this is a new callsite - _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(), - amount_in_current_scale(cur_malloc_callsite->amount()), - cur_malloc_callsite->count(), - diff_in_current_scale(cur_malloc_callsite->amount(), 0), - diff(cur_malloc_callsite->count(), 0)); - cur_malloc_callsite = (MallocCallsitePointer*)cur_malloc_itr.next(); - } else if (cur_malloc_callsite->addr() > prev_malloc_callsite->addr()) { - // this callsite is already gone - _outputer.diff_malloc_callsite(prev_malloc_callsite->addr(), - 0, 0, - diff_in_current_scale(0, prev_malloc_callsite->amount()), - diff(0, prev_malloc_callsite->count())); - prev_malloc_callsite = (MallocCallsitePointer*)prev_malloc_itr.next(); + out->print_cr(" from"); + stack->print_on(out, 12); + } + } +} + +void MemSummaryDiffReporter::report_diff() { + const char* scale = current_scale(); + outputStream* out = output(); + out->print_cr("\nNative Memory Tracking:\n"); + + // Overall diff + out->print("Total: "); + print_virtual_memory_diff(_current_baseline.total_reserved_memory(), + _current_baseline.total_committed_memory(), _early_baseline.total_reserved_memory(), + _early_baseline.total_committed_memory()); + + out->print_cr("\n"); + + // Summary diff by memory type + for (int index = 0; index < mt_number_of_types; index ++) { + MEMFLAGS flag = NMTUtil::index_to_flag(index); + // thread stack is reported as part of thread category + if (flag == mtThreadStack) continue; + diff_summary_of_type(flag, _early_baseline.malloc_memory(flag), + _early_baseline.virtual_memory(flag), _current_baseline.malloc_memory(flag), + _current_baseline.virtual_memory(flag)); + } +} + +void MemSummaryDiffReporter::print_malloc_diff(size_t current_amount, size_t current_count, + size_t early_amount, size_t early_count) const { + const char* scale = current_scale(); + outputStream* out = output(); + + out->print("malloc=" SIZE_FORMAT "%s", amount_in_current_scale(current_amount), scale); + long amount_diff = diff_in_current_scale(current_amount, early_amount); + if (amount_diff != 0) { + out->print(" %+ld%s", amount_diff, scale); + } + if (current_count > 0) { + out->print(" #" SIZE_FORMAT "", current_count); + if (current_count != early_count) { + out->print(" %+d", (int)(current_count - early_count)); + } + } +} + +void MemSummaryDiffReporter::print_arena_diff(size_t current_amount, size_t current_count, + size_t early_amount, size_t early_count) const { + const char* scale = current_scale(); + outputStream* out = output(); + out->print("arena=" SIZE_FORMAT "%s", amount_in_current_scale(current_amount), scale); + if (diff_in_current_scale(current_amount, early_amount) != 0) { + out->print(" %+ld", diff_in_current_scale(current_amount, early_amount)); + } + + out->print(" #" SIZE_FORMAT "", current_count); + if (current_count != early_count) { + out->print(" %+d", (int)(current_count - early_count)); + } +} + +void MemSummaryDiffReporter::print_virtual_memory_diff(size_t current_reserved, size_t current_committed, + size_t early_reserved, size_t early_committed) const { + const char* scale = current_scale(); + outputStream* out = output(); + out->print("reserved=" SIZE_FORMAT "%s", amount_in_current_scale(current_reserved), scale); + long reserved_diff = diff_in_current_scale(current_reserved, early_reserved); + if (reserved_diff != 0) { + out->print(" %+ld%s", reserved_diff, scale); + } + + out->print(", committed=" SIZE_FORMAT "%s", amount_in_current_scale(current_committed), scale); + long committed_diff = diff_in_current_scale(current_committed, early_committed); + if (committed_diff != 0) { + out->print(" %+ld%s", committed_diff, scale); + } +} + + +void MemSummaryDiffReporter::diff_summary_of_type(MEMFLAGS flag, const MallocMemory* early_malloc, + const VirtualMemory* early_vm, const MallocMemory* current_malloc, + const VirtualMemory* current_vm) const { + + outputStream* out = output(); + const char* scale = current_scale(); + + // Total reserved and committed memory in current baseline + size_t current_reserved_amount = reserved_total (current_malloc, current_vm); + size_t current_committed_amount = committed_total(current_malloc, current_vm); + + // Total reserved and committed memory in early baseline + size_t early_reserved_amount = reserved_total(early_malloc, early_vm); + size_t early_committed_amount = committed_total(early_malloc, early_vm); + + // Adjust virtual memory total + if (flag == mtThread) { + const VirtualMemory* early_thread_stack_usage = + _early_baseline.virtual_memory(mtThreadStack); + const VirtualMemory* current_thread_stack_usage = + _current_baseline.virtual_memory(mtThreadStack); + + early_reserved_amount += early_thread_stack_usage->reserved(); + early_committed_amount += early_thread_stack_usage->committed(); + + current_reserved_amount += current_thread_stack_usage->reserved(); + current_committed_amount += current_thread_stack_usage->committed(); + } else if (flag == mtNMT) { + early_reserved_amount += _early_baseline.malloc_tracking_overhead(); + early_committed_amount += _early_baseline.malloc_tracking_overhead(); + + current_reserved_amount += _current_baseline.malloc_tracking_overhead(); + current_committed_amount += _current_baseline.malloc_tracking_overhead(); + } + + if (amount_in_current_scale(current_reserved_amount) > 0 || + diff_in_current_scale(current_reserved_amount, early_reserved_amount) != 0) { + + // print summary line + out->print("-%26s (", NMTUtil::flag_to_name(flag)); + print_virtual_memory_diff(current_reserved_amount, current_committed_amount, + early_reserved_amount, early_committed_amount); + out->print_cr(")"); + + // detail lines + if (flag == mtClass) { + // report class count + out->print("%27s (classes #" SIZE_FORMAT "", " ", _current_baseline.class_count()); + int class_count_diff = (int)(_current_baseline.class_count() - + _early_baseline.class_count()); + if (_current_baseline.class_count() != _early_baseline.class_count()) { + out->print(" %+d", (int)(_current_baseline.class_count() - _early_baseline.class_count())); + } + out->print_cr(")"); + } else if (flag == mtThread) { + // report thread count + out->print("%27s (thread #" SIZE_FORMAT "", " ", _current_baseline.thread_count()); + int thread_count_diff = (int)(_current_baseline.thread_count() - + _early_baseline.thread_count()); + if (thread_count_diff != 0) { + out->print(" %+d", thread_count_diff); + } + out->print_cr(")"); + + // report thread stack + const VirtualMemory* current_thread_stack = + _current_baseline.virtual_memory(mtThreadStack); + const VirtualMemory* early_thread_stack = + _early_baseline.virtual_memory(mtThreadStack); + + out->print("%27s (stack: ", " "); + print_virtual_memory_diff(current_thread_stack->reserved(), current_thread_stack->committed(), + early_thread_stack->reserved(), early_thread_stack->committed()); + out->print_cr(")"); + } + + // Report malloc'd memory + size_t current_malloc_amount = current_malloc->malloc_size(); + size_t early_malloc_amount = early_malloc->malloc_size(); + if (amount_in_current_scale(current_malloc_amount) > 0 || + diff_in_current_scale(current_malloc_amount, early_malloc_amount) != 0) { + out->print("%28s(", " "); + print_malloc_diff(current_malloc_amount, (flag == mtChunk) ? 0 : current_malloc->malloc_count(), + early_malloc_amount, early_malloc->malloc_count()); + out->print_cr(")"); + } + + // Report virtual memory + if (amount_in_current_scale(current_vm->reserved()) > 0 || + diff_in_current_scale(current_vm->reserved(), early_vm->reserved()) != 0) { + out->print("%27s (mmap: ", " "); + print_virtual_memory_diff(current_vm->reserved(), current_vm->committed(), + early_vm->reserved(), early_vm->committed()); + out->print_cr(")"); + } + + // Report arena memory + if (amount_in_current_scale(current_malloc->arena_size()) > 0 || + diff_in_current_scale(current_malloc->arena_size(), early_malloc->arena_size()) != 0) { + out->print("%28s(", " "); + print_arena_diff(current_malloc->arena_size(), current_malloc->arena_count(), + early_malloc->arena_size(), early_malloc->arena_count()); + out->print_cr(")"); + } + + // Report native memory tracking overhead + if (flag == mtNMT) { + size_t current_tracking_overhead = amount_in_current_scale(_current_baseline.malloc_tracking_overhead()); + size_t early_tracking_overhead = amount_in_current_scale(_early_baseline.malloc_tracking_overhead()); + + out->print("%27s (tracking overhead=" SIZE_FORMAT "%s", " ", + amount_in_current_scale(_current_baseline.malloc_tracking_overhead()), scale); + + long overhead_diff = diff_in_current_scale(_current_baseline.malloc_tracking_overhead(), + _early_baseline.malloc_tracking_overhead()); + if (overhead_diff != 0) { + out->print(" %+ld%s", overhead_diff, scale); + } + out->print_cr(")"); + } + out->print_cr(" "); + } +} + +void MemDetailDiffReporter::report_diff() { + MemSummaryDiffReporter::report_diff(); + diff_malloc_sites(); + diff_virtual_memory_sites(); +} + +void MemDetailDiffReporter::diff_malloc_sites() const { + MallocSiteIterator early_itr = _early_baseline.malloc_sites(MemBaseline::by_site); + MallocSiteIterator current_itr = _current_baseline.malloc_sites(MemBaseline::by_site); + + const MallocSite* early_site = early_itr.next(); + const MallocSite* current_site = current_itr.next(); + + while (early_site != NULL || current_site != NULL) { + if (early_site == NULL) { + new_malloc_site(current_site); + current_site = current_itr.next(); + } else if (current_site == NULL) { + old_malloc_site(early_site); + early_site = early_itr.next(); + } else { + int compVal = current_site->call_stack()->compare(*early_site->call_stack()); + if (compVal < 0) { + new_malloc_site(current_site); + current_site = current_itr.next(); + } else if (compVal > 0) { + old_malloc_site(early_site); + early_site = early_itr.next(); } else { - // the same callsite - _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(), - amount_in_current_scale(cur_malloc_callsite->amount()), - cur_malloc_callsite->count(), - diff_in_current_scale(cur_malloc_callsite->amount(), prev_malloc_callsite->amount()), - diff(cur_malloc_callsite->count(), prev_malloc_callsite->count())); - cur_malloc_callsite = (MallocCallsitePointer*)cur_malloc_itr.next(); - prev_malloc_callsite = (MallocCallsitePointer*)prev_malloc_itr.next(); + diff_malloc_site(early_site, current_site); + early_site = early_itr.next(); + current_site = current_itr.next(); } } } - - // walk virtual memory callsite - MemPointerArrayIteratorImpl cur_vm_itr(pBL_cur->_vm_cs); - MemPointerArrayIteratorImpl prev_vm_itr(pBL_prev->_vm_cs); - VMCallsitePointer* cur_vm_callsite = (VMCallsitePointer*)cur_vm_itr.current(); - VMCallsitePointer* prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.current(); - while (cur_vm_callsite != NULL || prev_vm_callsite != NULL) { - if (prev_vm_callsite == NULL || cur_vm_callsite->addr() < prev_vm_callsite->addr()) { - // this is a new callsite - _outputer.diff_virtual_memory_callsite(cur_vm_callsite->addr(), - amount_in_current_scale(cur_vm_callsite->reserved_amount()), - amount_in_current_scale(cur_vm_callsite->committed_amount()), - diff_in_current_scale(cur_vm_callsite->reserved_amount(), 0), - diff_in_current_scale(cur_vm_callsite->committed_amount(), 0)); - cur_vm_callsite = (VMCallsitePointer*)cur_vm_itr.next(); - } else if (cur_vm_callsite == NULL || cur_vm_callsite->addr() > prev_vm_callsite->addr()) { - // this callsite is already gone - _outputer.diff_virtual_memory_callsite(prev_vm_callsite->addr(), - amount_in_current_scale(0), - amount_in_current_scale(0), - diff_in_current_scale(0, prev_vm_callsite->reserved_amount()), - diff_in_current_scale(0, prev_vm_callsite->committed_amount())); - prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.next(); - } else { // the same callsite - _outputer.diff_virtual_memory_callsite(cur_vm_callsite->addr(), - amount_in_current_scale(cur_vm_callsite->reserved_amount()), - amount_in_current_scale(cur_vm_callsite->committed_amount()), - diff_in_current_scale(cur_vm_callsite->reserved_amount(), prev_vm_callsite->reserved_amount()), - diff_in_current_scale(cur_vm_callsite->committed_amount(), prev_vm_callsite->committed_amount())); - cur_vm_callsite = (VMCallsitePointer*)cur_vm_itr.next(); - prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.next(); - } - } - - _outputer.done_callsite(); } -size_t BaselineReporter::amount_in_current_scale(size_t amt) const { - return (size_t)(((float)amt/(float)_scale) + 0.5); -} +void MemDetailDiffReporter::diff_virtual_memory_sites() const { + VirtualMemorySiteIterator early_itr = _early_baseline.virtual_memory_sites(MemBaseline::by_site); + VirtualMemorySiteIterator current_itr = _current_baseline.virtual_memory_sites(MemBaseline::by_site); -int BaselineReporter::diff_in_current_scale(size_t value1, size_t value2) const { - return (int)(((float)value1 - (float)value2)/((float)_scale) + 0.5); -} + const VirtualMemoryAllocationSite* early_site = early_itr.next(); + const VirtualMemoryAllocationSite* current_site = current_itr.next(); -int BaselineReporter::diff(size_t value1, size_t value2) const { - return ((int)value1 - (int)value2); -} - -void BaselineTTYOutputer::start(size_t scale, bool report_diff) { - _scale = scale; - _output->print_cr(" "); - _output->print_cr("Native Memory Tracking:"); - _output->print_cr(" "); -} - -void BaselineTTYOutputer::done() { - -} - -void BaselineTTYOutputer::total_usage(size_t total_reserved, size_t total_committed) { - const char* unit = memory_unit(_scale); - _output->print_cr("Total: reserved=%d%s, committed=%d%s", - total_reserved, unit, total_committed, unit); -} - -void BaselineTTYOutputer::start_category_summary() { - _output->print_cr(" "); -} - -/** - * report a summary of memory type - */ -void BaselineTTYOutputer::category_summary(MEMFLAGS type, - size_t reserved_amt, size_t committed_amt, size_t malloc_amt, - size_t malloc_count, size_t arena_amt, size_t arena_count) { - - // we report mtThreadStack under mtThread category - if (type == mtThreadStack) { - assert(malloc_amt == 0 && malloc_count == 0 && arena_amt == 0, - "Just check"); - _thread_stack_reserved = reserved_amt; - _thread_stack_committed = committed_amt; - } else { - const char* unit = memory_unit(_scale); - size_t total_reserved = (reserved_amt + malloc_amt + arena_amt); - size_t total_committed = (committed_amt + malloc_amt + arena_amt); - if (type == mtThread) { - total_reserved += _thread_stack_reserved; - total_committed += _thread_stack_committed; - } - - if (total_reserved > 0) { - _output->print_cr("-%26s (reserved=%d%s, committed=%d%s)", - MemBaseline::type2name(type), total_reserved, unit, - total_committed, unit); - - if (type == mtClass) { - _output->print_cr("%27s (classes #%d)", " ", _num_of_classes); - } else if (type == mtThread) { - _output->print_cr("%27s (thread #%d)", " ", _num_of_threads); - _output->print_cr("%27s (stack: reserved=%d%s, committed=%d%s)", " ", - _thread_stack_reserved, unit, _thread_stack_committed, unit); - } - - if (malloc_amt > 0) { - if (type != mtChunk) { - _output->print_cr("%27s (malloc=%d%s, #%d)", " ", malloc_amt, unit, - malloc_count); - } else { - _output->print_cr("%27s (malloc=%d%s)", " ", malloc_amt, unit); - } - } - - if (reserved_amt > 0) { - _output->print_cr("%27s (mmap: reserved=%d%s, committed=%d%s)", - " ", reserved_amt, unit, committed_amt, unit); - } - - if (arena_amt > 0) { - _output->print_cr("%27s (arena=%d%s, #%d)", " ", arena_amt, unit, arena_count); - } - - _output->print_cr(" "); - } - } -} - -void BaselineTTYOutputer::done_category_summary() { - _output->print_cr(" "); -} - - -void BaselineTTYOutputer::start_virtual_memory_map() { - _output->print_cr("Virtual memory map:"); -} - -void BaselineTTYOutputer::reserved_memory_region(MEMFLAGS type, address base, address end, - size_t size, address pc) { - const char* unit = memory_unit(_scale); - char buf[128]; - int offset; - _output->print_cr(" "); - _output->print_cr("[" PTR_FORMAT " - " PTR_FORMAT "] reserved %d%s for %s", base, end, size, unit, - MemBaseline::type2name(type)); - if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { - _output->print_cr("\t\tfrom [%s+0x%x]", buf, offset); - } -} - -void BaselineTTYOutputer::committed_memory_region(address base, address end, size_t size, address pc) { - const char* unit = memory_unit(_scale); - char buf[128]; - int offset; - _output->print("\t[" PTR_FORMAT " - " PTR_FORMAT "] committed %d%s", base, end, size, unit); - if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { - _output->print_cr(" from [%s+0x%x]", buf, offset); - } -} - -void BaselineTTYOutputer::done_virtual_memory_map() { - _output->print_cr(" "); -} - - - -void BaselineTTYOutputer::start_callsite() { - _output->print_cr("Details:"); - _output->print_cr(" "); -} - -void BaselineTTYOutputer::done_callsite() { - _output->print_cr(" "); -} - -void BaselineTTYOutputer::malloc_callsite(address pc, size_t malloc_amt, - size_t malloc_count) { - if (malloc_amt > 0) { - const char* unit = memory_unit(_scale); - char buf[128]; - int offset; - if (pc == 0) { - _output->print("[BOOTSTRAP]%18s", " "); - } else if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { - _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset); - _output->print("%28s", " "); + while (early_site != NULL || current_site != NULL) { + if (early_site == NULL) { + new_virtual_memory_site(current_site); + current_site = current_itr.next(); + } else if (current_site == NULL) { + old_virtual_memory_site(early_site); + early_site = early_itr.next(); } else { - _output->print("[" PTR_FORMAT "]%18s", pc, " "); + int compVal = current_site->call_stack()->compare(*early_site->call_stack()); + if (compVal < 0) { + new_virtual_memory_site(current_site); + current_site = current_itr.next(); + } else if (compVal > 0) { + old_virtual_memory_site(early_site); + early_site = early_itr.next(); + } else { + diff_virtual_memory_site(early_site, current_site); + early_site = early_itr.next(); + current_site = current_itr.next(); + } } - - _output->print_cr("(malloc=%d%s #%d)", malloc_amt, unit, malloc_count); - _output->print_cr(" "); } } -void BaselineTTYOutputer::virtual_memory_callsite(address pc, size_t reserved_amt, - size_t committed_amt) { - if (reserved_amt > 0) { - const char* unit = memory_unit(_scale); - char buf[128]; - int offset; - if (pc == 0) { - _output->print("[BOOTSTRAP]%18s", " "); - } else if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { - _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset); - _output->print("%28s", " "); - } else { - _output->print("[" PTR_FORMAT "]%18s", pc, " "); - } - _output->print_cr("(mmap: reserved=%d%s, committed=%d%s)", - reserved_amt, unit, committed_amt, unit); - _output->print_cr(" "); - } +void MemDetailDiffReporter::new_malloc_site(const MallocSite* malloc_site) const { + diff_malloc_site(malloc_site->call_stack(), malloc_site->size(), malloc_site->count(), + 0, 0); } -void BaselineTTYOutputer::diff_total_usage(size_t total_reserved, - size_t total_committed, int reserved_diff, int committed_diff) { - const char* unit = memory_unit(_scale); - _output->print_cr("Total: reserved=%d%s %+d%s, committed=%d%s %+d%s", - total_reserved, unit, reserved_diff, unit, total_committed, unit, - committed_diff, unit); +void MemDetailDiffReporter::old_malloc_site(const MallocSite* malloc_site) const { + diff_malloc_site(malloc_site->call_stack(), 0, 0, malloc_site->size(), + malloc_site->count()); } -void BaselineTTYOutputer::diff_category_summary(MEMFLAGS type, - size_t cur_reserved_amt, size_t cur_committed_amt, - size_t cur_malloc_amt, size_t cur_malloc_count, - size_t cur_arena_amt, size_t cur_arena_count, - int reserved_diff, int committed_diff, int malloc_diff, - int malloc_count_diff, int arena_diff, int arena_count_diff) { +void MemDetailDiffReporter::diff_malloc_site(const MallocSite* early, + const MallocSite* current) const { + diff_malloc_site(current->call_stack(), current->size(), current->count(), + early->size(), early->count()); +} - if (type == mtThreadStack) { - assert(cur_malloc_amt == 0 && cur_malloc_count == 0 && - cur_arena_amt == 0, "Just check"); - _thread_stack_reserved = cur_reserved_amt; - _thread_stack_committed = cur_committed_amt; - _thread_stack_reserved_diff = reserved_diff; - _thread_stack_committed_diff = committed_diff; - } else { - const char* unit = memory_unit(_scale); - size_t total_reserved = (cur_reserved_amt + cur_malloc_amt + cur_arena_amt); - // nothing to report in this category - if (total_reserved == 0) { +void MemDetailDiffReporter::diff_malloc_site(const NativeCallStack* stack, size_t current_size, + size_t current_count, size_t early_size, size_t early_count) const { + outputStream* out = output(); + + assert(stack != NULL, "NULL stack"); + + if (diff_in_current_scale(current_size, early_size) == 0) { return; - } - int diff_reserved = (reserved_diff + malloc_diff + arena_diff); - - // category summary - _output->print("-%26s (reserved=%d%s", MemBaseline::type2name(type), - total_reserved, unit); - - if (diff_reserved != 0) { - _output->print(" %+d%s", diff_reserved, unit); - } - - size_t total_committed = cur_committed_amt + cur_malloc_amt + cur_arena_amt; - _output->print(", committed=%d%s", total_committed, unit); - - int total_committed_diff = committed_diff + malloc_diff + arena_diff; - if (total_committed_diff != 0) { - _output->print(" %+d%s", total_committed_diff, unit); - } - - _output->print_cr(")"); - - // special cases - if (type == mtClass) { - _output->print("%27s (classes #%d", " ", _num_of_classes); - if (_num_of_classes_diff != 0) { - _output->print(" %+d", _num_of_classes_diff); - } - _output->print_cr(")"); - } else if (type == mtThread) { - // thread count - _output->print("%27s (thread #%d", " ", _num_of_threads); - if (_num_of_threads_diff != 0) { - _output->print_cr(" %+d)", _num_of_threads_diff); - } else { - _output->print_cr(")"); - } - _output->print("%27s (stack: reserved=%d%s", " ", _thread_stack_reserved, unit); - if (_thread_stack_reserved_diff != 0) { - _output->print(" %+d%s", _thread_stack_reserved_diff, unit); - } - - _output->print(", committed=%d%s", _thread_stack_committed, unit); - if (_thread_stack_committed_diff != 0) { - _output->print(" %+d%s",_thread_stack_committed_diff, unit); - } - - _output->print_cr(")"); - } - - // malloc'd memory - if (cur_malloc_amt > 0) { - _output->print("%27s (malloc=%d%s", " ", cur_malloc_amt, unit); - if (malloc_diff != 0) { - _output->print(" %+d%s", malloc_diff, unit); - } - if (type != mtChunk) { - _output->print(", #%d", cur_malloc_count); - if (malloc_count_diff) { - _output->print(" %+d", malloc_count_diff); - } - } - _output->print_cr(")"); - } - - // mmap'd memory - if (cur_reserved_amt > 0) { - _output->print("%27s (mmap: reserved=%d%s", " ", cur_reserved_amt, unit); - if (reserved_diff != 0) { - _output->print(" %+d%s", reserved_diff, unit); - } - - _output->print(", committed=%d%s", cur_committed_amt, unit); - if (committed_diff != 0) { - _output->print(" %+d%s", committed_diff, unit); - } - _output->print_cr(")"); - } - - // arena memory - if (cur_arena_amt > 0) { - _output->print("%27s (arena=%d%s", " ", cur_arena_amt, unit); - if (arena_diff != 0) { - _output->print(" %+d%s", arena_diff, unit); - } - _output->print(", #%d", cur_arena_count); - if (arena_count_diff != 0) { - _output->print(" %+d", arena_count_diff); - } - _output->print_cr(")"); - } - - _output->print_cr(" "); } + + stack->print_on(out); + out->print("%28s (", " "); + print_malloc_diff(current_size, current_count, + early_size, early_count); + + out->print_cr(")\n"); } -void BaselineTTYOutputer::diff_malloc_callsite(address pc, - size_t cur_malloc_amt, size_t cur_malloc_count, - int malloc_diff, int malloc_count_diff) { - if (malloc_diff != 0) { - const char* unit = memory_unit(_scale); - char buf[128]; - int offset; - if (pc == 0) { - _output->print_cr("[BOOTSTRAP]%18s", " "); - } else { - if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { - _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset); - _output->print("%28s", " "); - } else { - _output->print("[" PTR_FORMAT "]%18s", pc, " "); - } - } - _output->print("(malloc=%d%s", cur_malloc_amt, unit); - if (malloc_diff != 0) { - _output->print(" %+d%s", malloc_diff, unit); - } - _output->print(", #%d", cur_malloc_count); - if (malloc_count_diff != 0) { - _output->print(" %+d", malloc_count_diff); - } - _output->print_cr(")"); - _output->print_cr(" "); - } +void MemDetailDiffReporter::new_virtual_memory_site(const VirtualMemoryAllocationSite* site) const { + diff_virtual_memory_site(site->call_stack(), site->reserved(), site->committed(), 0, 0); } -void BaselineTTYOutputer::diff_virtual_memory_callsite(address pc, - size_t cur_reserved_amt, size_t cur_committed_amt, - int reserved_diff, int committed_diff) { - if (reserved_diff != 0 || committed_diff != 0) { - const char* unit = memory_unit(_scale); - char buf[64]; - int offset; - if (pc == 0) { - _output->print_cr("[BOOSTRAP]%18s", " "); - } else { - if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { - _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset); - _output->print("%28s", " "); - } else { - _output->print("[" PTR_FORMAT "]%18s", pc, " "); - } - } - - _output->print("(mmap: reserved=%d%s", cur_reserved_amt, unit); - if (reserved_diff != 0) { - _output->print(" %+d%s", reserved_diff, unit); - } - _output->print(", committed=%d%s", cur_committed_amt, unit); - if (committed_diff != 0) { - _output->print(" %+d%s", committed_diff, unit); - } - _output->print_cr(")"); - _output->print_cr(" "); - } +void MemDetailDiffReporter::old_virtual_memory_site(const VirtualMemoryAllocationSite* site) const { + diff_virtual_memory_site(site->call_stack(), 0, 0, site->reserved(), site->committed()); } + +void MemDetailDiffReporter::diff_virtual_memory_site(const VirtualMemoryAllocationSite* early, + const VirtualMemoryAllocationSite* current) const { + diff_virtual_memory_site(current->call_stack(), current->reserved(), current->committed(), + early->reserved(), early->committed()); +} + +void MemDetailDiffReporter::diff_virtual_memory_site(const NativeCallStack* stack, size_t current_reserved, + size_t current_committed, size_t early_reserved, size_t early_committed) const { + outputStream* out = output(); + + // no change + if (diff_in_current_scale(current_reserved, early_reserved) == 0 && + diff_in_current_scale(current_committed, early_committed) == 0) { + return; + } + + stack->print_on(out); + out->print("%28s (mmap: ", " "); + print_virtual_memory_diff(current_reserved, current_committed, + early_reserved, early_committed); + + out->print_cr(")\n"); + } + diff --git a/hotspot/src/share/vm/services/memReporter.hpp b/hotspot/src/share/vm/services/memReporter.hpp index 805559b6fba..239fb945b33 100644 --- a/hotspot/src/share/vm/services/memReporter.hpp +++ b/hotspot/src/share/vm/services/memReporter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -25,262 +25,217 @@ #ifndef SHARE_VM_SERVICES_MEM_REPORTER_HPP #define SHARE_VM_SERVICES_MEM_REPORTER_HPP -#include "runtime/mutexLocker.hpp" -#include "services/memBaseline.hpp" -#include "services/memTracker.hpp" -#include "utilities/ostream.hpp" -#include "utilities/macros.hpp" - #if INCLUDE_NMT +#include "oops/instanceKlass.hpp" +#include "services/memBaseline.hpp" +#include "services/nmtCommon.hpp" +#include "services/mallocTracker.hpp" +#include "services/virtualMemoryTracker.hpp" + /* - * MemBaselineReporter reports data to this outputer class, - * ReportOutputer is responsible for format, store and redirect - * the data to the final destination. - */ -class BaselineOutputer : public StackObj { + * Base class that provides helpers +*/ +class MemReporterBase : public StackObj { + private: + size_t _scale; // report in this scale + outputStream* _output; // destination + public: - // start to report memory usage in specified scale. - // if report_diff = true, the reporter reports baseline comparison - // information. + MemReporterBase(outputStream* out = NULL, size_t scale = K) + : _scale(scale) { + _output = (out == NULL) ? tty : out; + } - virtual void start(size_t scale, bool report_diff = false) = 0; - // Done reporting - virtual void done() = 0; + protected: + inline outputStream* output() const { + return _output; + } + // Current reporting scale + inline const char* current_scale() const { + return NMTUtil::scale_name(_scale); + } + // Convert memory amount in bytes to current reporting scale + inline size_t amount_in_current_scale(size_t amount) const { + return NMTUtil::amount_in_scale(amount, _scale); + } - /* report baseline summary information */ - virtual void total_usage(size_t total_reserved, - size_t total_committed) = 0; - virtual void num_of_classes(size_t classes) = 0; - virtual void num_of_threads(size_t threads) = 0; + // Convert diff amount in bytes to current reporting scale + inline long diff_in_current_scale(size_t s1, size_t s2) const { + long amount = (long)(s1 - s2); + long scale = (long)_scale; + amount = (amount > 0) ? (amount + scale / 2) : (amount - scale / 2); + return amount / scale; + } - virtual void thread_info(size_t stack_reserved_amt, size_t stack_committed_amt) = 0; - - /* report baseline summary comparison */ - virtual void diff_total_usage(size_t total_reserved, - size_t total_committed, - int reserved_diff, - int committed_diff) = 0; - virtual void diff_num_of_classes(size_t classes, int diff) = 0; - virtual void diff_num_of_threads(size_t threads, int diff) = 0; - - virtual void diff_thread_info(size_t stack_reserved, size_t stack_committed, - int stack_reserved_diff, int stack_committed_diff) = 0; + // Helper functions + // Calculate total reserved and committed amount + size_t reserved_total(const MallocMemory* malloc, const VirtualMemory* vm) const; + size_t committed_total(const MallocMemory* malloc, const VirtualMemory* vm) const; - /* - * memory summary by memory types. - * for each memory type, following summaries are reported: - * - reserved amount, committed amount - * - malloc'd amount, malloc count - * - arena amount, arena count - */ + // Print summary total, malloc and virtual memory + void print_total(size_t reserved, size_t committed) const; + void print_malloc(size_t amount, size_t count) const; + void print_virtual_memory(size_t reserved, size_t committed) const; - // start reporting memory summary by memory type - virtual void start_category_summary() = 0; + void print_malloc_line(size_t amount, size_t count) const; + void print_virtual_memory_line(size_t reserved, size_t committed) const; + void print_arena_line(size_t amount, size_t count) const; - virtual void category_summary(MEMFLAGS type, size_t reserved_amt, - size_t committed_amt, - size_t malloc_amt, size_t malloc_count, - size_t arena_amt, size_t arena_count) = 0; - - virtual void diff_category_summary(MEMFLAGS type, size_t cur_reserved_amt, - size_t cur_committed_amt, - size_t cur_malloc_amt, size_t cur_malloc_count, - size_t cur_arena_amt, size_t cur_arena_count, - int reserved_diff, int committed_diff, int malloc_diff, - int malloc_count_diff, int arena_diff, - int arena_count_diff) = 0; - - virtual void done_category_summary() = 0; - - virtual void start_virtual_memory_map() = 0; - virtual void reserved_memory_region(MEMFLAGS type, address base, address end, size_t size, address pc) = 0; - virtual void committed_memory_region(address base, address end, size_t size, address pc) = 0; - virtual void done_virtual_memory_map() = 0; - - /* - * Report callsite information - */ - virtual void start_callsite() = 0; - virtual void malloc_callsite(address pc, size_t malloc_amt, size_t malloc_count) = 0; - virtual void virtual_memory_callsite(address pc, size_t reserved_amt, size_t committed_amt) = 0; - - virtual void diff_malloc_callsite(address pc, size_t cur_malloc_amt, size_t cur_malloc_count, - int malloc_diff, int malloc_count_diff) = 0; - virtual void diff_virtual_memory_callsite(address pc, size_t cur_reserved_amt, size_t cur_committed_amt, - int reserved_diff, int committed_diff) = 0; - - virtual void done_callsite() = 0; - - // return current scale in "KB", "MB" or "GB" - static const char* memory_unit(size_t scale); + void print_virtual_memory_region(const char* type, address base, size_t size) const; }; /* - * This class reports processed data from a baseline or - * the changes between the two baseline. + * The class is for generating summary tracking report. */ -class BaselineReporter : public StackObj { +class MemSummaryReporter : public MemReporterBase { private: - BaselineOutputer& _outputer; - size_t _scale; + MallocMemorySnapshot* _malloc_snapshot; + VirtualMemorySnapshot* _vm_snapshot; + size_t _class_count; public: - // construct a reporter that reports memory usage - // in specified scale - BaselineReporter(BaselineOutputer& outputer, size_t scale = K): - _outputer(outputer) { - _scale = scale; + // Report summary tracking data from global snapshots directly. + // This constructor is used for final reporting and hs_err reporting. + MemSummaryReporter(MallocMemorySnapshot* malloc_snapshot, + VirtualMemorySnapshot* vm_snapshot, outputStream* output, + size_t class_count = 0, size_t scale = K) : + MemReporterBase(output, scale), + _malloc_snapshot(malloc_snapshot), + _vm_snapshot(vm_snapshot) { + if (class_count == 0) { + _class_count = InstanceKlass::number_of_instance_classes(); + } else { + _class_count = class_count; + } } - virtual void report_baseline(const MemBaseline& baseline, bool summary_only = false); - virtual void diff_baselines(const MemBaseline& cur, const MemBaseline& prev, - bool summary_only = false); + // This constructor is for normal reporting from a recent baseline. + MemSummaryReporter(MemBaseline& baseline, outputStream* output, + size_t scale = K) : MemReporterBase(output, scale), + _malloc_snapshot(baseline.malloc_memory_snapshot()), + _vm_snapshot(baseline.virtual_memory_snapshot()), + _class_count(baseline.class_count()) { } - void set_scale(size_t scale); - size_t scale() const { return _scale; } + // Generate summary report + virtual void report(); private: - void report_summaries(const MemBaseline& baseline); - void report_virtual_memory_map(const MemBaseline& baseline); - void report_callsites(const MemBaseline& baseline); - - void diff_summaries(const MemBaseline& cur, const MemBaseline& prev); - void diff_callsites(const MemBaseline& cur, const MemBaseline& prev); - - // calculate memory size in current memory scale - size_t amount_in_current_scale(size_t amt) const; - // diff two unsigned values in current memory scale - int diff_in_current_scale(size_t value1, size_t value2) const; - // diff two unsigned value - int diff(size_t value1, size_t value2) const; + // Report summary for each memory type + void report_summary_of_type(MEMFLAGS type, MallocMemory* malloc_memory, + VirtualMemory* virtual_memory); }; /* - * tty output implementation. Native memory tracking - * DCmd uses this outputer. + * The class is for generating detail tracking report. */ -class BaselineTTYOutputer : public BaselineOutputer { +class MemDetailReporter : public MemSummaryReporter { private: - size_t _scale; - - size_t _num_of_classes; - size_t _num_of_threads; - size_t _thread_stack_reserved; - size_t _thread_stack_committed; - - int _num_of_classes_diff; - int _num_of_threads_diff; - int _thread_stack_reserved_diff; - int _thread_stack_committed_diff; - - outputStream* _output; + MemBaseline& _baseline; public: - BaselineTTYOutputer(outputStream* st) { - _scale = K; - _num_of_classes = 0; - _num_of_threads = 0; - _thread_stack_reserved = 0; - _thread_stack_committed = 0; - _num_of_classes_diff = 0; - _num_of_threads_diff = 0; - _thread_stack_reserved_diff = 0; - _thread_stack_committed_diff = 0; - _output = st; + MemDetailReporter(MemBaseline& baseline, outputStream* output, size_t scale = K) : + MemSummaryReporter(baseline, output, scale), + _baseline(baseline) { } + + // Generate detail report. + // The report contains summary and detail sections. + virtual void report() { + MemSummaryReporter::report(); + report_virtual_memory_map(); + report_detail(); } - // begin reporting memory usage in specified scale - void start(size_t scale, bool report_diff = false); - // done reporting - void done(); + private: + // Report detail tracking data. + void report_detail(); + // Report virtual memory map + void report_virtual_memory_map(); + // Report malloc allocation sites + void report_malloc_sites(); + // Report virtual memory reservation sites + void report_virtual_memory_allocation_sites(); - // total memory usage - void total_usage(size_t total_reserved, - size_t total_committed); - // report total loaded classes - void num_of_classes(size_t classes) { - _num_of_classes = classes; - } - - void num_of_threads(size_t threads) { - _num_of_threads = threads; - } - - void thread_info(size_t stack_reserved_amt, size_t stack_committed_amt) { - _thread_stack_reserved = stack_reserved_amt; - _thread_stack_committed = stack_committed_amt; - } - - void diff_total_usage(size_t total_reserved, - size_t total_committed, - int reserved_diff, - int committed_diff); - - void diff_num_of_classes(size_t classes, int diff) { - _num_of_classes = classes; - _num_of_classes_diff = diff; - } - - void diff_num_of_threads(size_t threads, int diff) { - _num_of_threads = threads; - _num_of_threads_diff = diff; - } - - void diff_thread_info(size_t stack_reserved_amt, size_t stack_committed_amt, - int stack_reserved_diff, int stack_committed_diff) { - _thread_stack_reserved = stack_reserved_amt; - _thread_stack_committed = stack_committed_amt; - _thread_stack_reserved_diff = stack_reserved_diff; - _thread_stack_committed_diff = stack_committed_diff; - } - - /* - * Report memory summary categoriuzed by memory types. - * For each memory type, following summaries are reported: - * - reserved amount, committed amount - * - malloc-ed amount, malloc count - * - arena amount, arena count - */ - // start reporting memory summary by memory type - void start_category_summary(); - void category_summary(MEMFLAGS type, size_t reserved_amt, size_t committed_amt, - size_t malloc_amt, size_t malloc_count, - size_t arena_amt, size_t arena_count); - - void diff_category_summary(MEMFLAGS type, size_t cur_reserved_amt, - size_t cur_committed_amt, - size_t cur_malloc_amt, size_t cur_malloc_count, - size_t cur_arena_amt, size_t cur_arena_count, - int reserved_diff, int committed_diff, int malloc_diff, - int malloc_count_diff, int arena_diff, - int arena_count_diff); - - void done_category_summary(); - - // virtual memory map - void start_virtual_memory_map(); - void reserved_memory_region(MEMFLAGS type, address base, address end, size_t size, address pc); - void committed_memory_region(address base, address end, size_t size, address pc); - void done_virtual_memory_map(); - - - /* - * Report callsite information - */ - void start_callsite(); - void malloc_callsite(address pc, size_t malloc_amt, size_t malloc_count); - void virtual_memory_callsite(address pc, size_t reserved_amt, size_t committed_amt); - - void diff_malloc_callsite(address pc, size_t cur_malloc_amt, size_t cur_malloc_count, - int malloc_diff, int malloc_count_diff); - void diff_virtual_memory_callsite(address pc, size_t cur_reserved_amt, size_t cur_committed_amt, - int reserved_diff, int committed_diff); - - void done_callsite(); + // Report a virtual memory region + void report_virtual_memory_region(const ReservedMemoryRegion* rgn); }; +/* + * The class is for generating summary comparison report. + * It compares current memory baseline against an early baseline. + */ +class MemSummaryDiffReporter : public MemReporterBase { + protected: + MemBaseline& _early_baseline; + MemBaseline& _current_baseline; + + public: + MemSummaryDiffReporter(MemBaseline& early_baseline, MemBaseline& current_baseline, + outputStream* output, size_t scale = K) : MemReporterBase(output, scale), + _early_baseline(early_baseline), _current_baseline(current_baseline) { + assert(early_baseline.baseline_type() != MemBaseline::Not_baselined, "Not baselined"); + assert(current_baseline.baseline_type() != MemBaseline::Not_baselined, "Not baselined"); + } + + // Generate summary comparison report + virtual void report_diff(); + + private: + // report the comparison of each memory type + void diff_summary_of_type(MEMFLAGS type, + const MallocMemory* early_malloc, const VirtualMemory* early_vm, + const MallocMemory* current_malloc, const VirtualMemory* current_vm) const; + + protected: + void print_malloc_diff(size_t current_amount, size_t current_count, + size_t early_amount, size_t early_count) const; + void print_virtual_memory_diff(size_t current_reserved, size_t current_committed, + size_t early_reserved, size_t early_committed) const; + void print_arena_diff(size_t current_amount, size_t current_count, + size_t early_amount, size_t early_count) const; +}; + +/* + * The class is for generating detail comparison report. + * It compares current memory baseline against an early baseline, + * both baselines have to be detail baseline. + */ +class MemDetailDiffReporter : public MemSummaryDiffReporter { + public: + MemDetailDiffReporter(MemBaseline& early_baseline, MemBaseline& current_baseline, + outputStream* output, size_t scale = K) : + MemSummaryDiffReporter(early_baseline, current_baseline, output, scale) { } + + // Generate detail comparison report + virtual void report_diff(); + + // Malloc allocation site comparison + void diff_malloc_sites() const; + // Virutal memory reservation site comparison + void diff_virtual_memory_sites() const; + + // New malloc allocation site in recent baseline + void new_malloc_site (const MallocSite* site) const; + // The malloc allocation site is not in recent baseline + void old_malloc_site (const MallocSite* site) const; + // Compare malloc allocation site, it is in both baselines + void diff_malloc_site(const MallocSite* early, const MallocSite* current) const; + + // New virtual memory allocation site in recent baseline + void new_virtual_memory_site (const VirtualMemoryAllocationSite* callsite) const; + // The virtual memory allocation site is not in recent baseline + void old_virtual_memory_site (const VirtualMemoryAllocationSite* callsite) const; + // Compare virtual memory allocation site, it is in both baseline + void diff_virtual_memory_site(const VirtualMemoryAllocationSite* early, + const VirtualMemoryAllocationSite* current) const; + + void diff_malloc_site(const NativeCallStack* stack, size_t current_size, + size_t currrent_count, size_t early_size, size_t early_count) const; + void diff_virtual_memory_site(const NativeCallStack* stack, size_t current_reserved, + size_t current_committed, size_t early_reserved, size_t early_committed) const; +}; #endif // INCLUDE_NMT -#endif // SHARE_VM_SERVICES_MEM_REPORTER_HPP +#endif + diff --git a/hotspot/src/share/vm/services/memSnapshot.cpp b/hotspot/src/share/vm/services/memSnapshot.cpp deleted file mode 100644 index 8f5ca4f4195..00000000000 --- a/hotspot/src/share/vm/services/memSnapshot.cpp +++ /dev/null @@ -1,748 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 "runtime/mutexLocker.hpp" -#include "utilities/decoder.hpp" -#include "services/memBaseline.hpp" -#include "services/memPtr.hpp" -#include "services/memPtrArray.hpp" -#include "services/memSnapshot.hpp" -#include "services/memTracker.hpp" - -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - -#ifdef ASSERT - -void decode_pointer_record(MemPointerRecord* rec) { - tty->print("Pointer: [" PTR_FORMAT " - " PTR_FORMAT "] size = %d bytes", rec->addr(), - rec->addr() + rec->size(), (int)rec->size()); - tty->print(" type = %s", MemBaseline::type2name(FLAGS_TO_MEMORY_TYPE(rec->flags()))); - if (rec->is_vm_pointer()) { - if (rec->is_allocation_record()) { - tty->print_cr(" (reserve)"); - } else if (rec->is_commit_record()) { - tty->print_cr(" (commit)"); - } else if (rec->is_uncommit_record()) { - tty->print_cr(" (uncommit)"); - } else if (rec->is_deallocation_record()) { - tty->print_cr(" (release)"); - } else { - tty->print_cr(" (tag)"); - } - } else { - if (rec->is_arena_memory_record()) { - tty->print_cr(" (arena size)"); - } else if (rec->is_allocation_record()) { - tty->print_cr(" (malloc)"); - } else { - tty->print_cr(" (free)"); - } - } - if (MemTracker::track_callsite()) { - char buf[1024]; - address pc = ((MemPointerRecordEx*)rec)->pc(); - if (pc != NULL && os::dll_address_to_function_name(pc, buf, sizeof(buf), NULL)) { - tty->print_cr("\tfrom %s", buf); - } else { - tty->print_cr("\tcould not decode pc = " PTR_FORMAT "", pc); - } - } -} - -void decode_vm_region_record(VMMemRegion* rec) { - tty->print("VM Region [" PTR_FORMAT " - " PTR_FORMAT "]", rec->addr(), - rec->addr() + rec->size()); - tty->print(" type = %s", MemBaseline::type2name(FLAGS_TO_MEMORY_TYPE(rec->flags()))); - if (rec->is_allocation_record()) { - tty->print_cr(" (reserved)"); - } else if (rec->is_commit_record()) { - tty->print_cr(" (committed)"); - } else { - ShouldNotReachHere(); - } - if (MemTracker::track_callsite()) { - char buf[1024]; - address pc = ((VMMemRegionEx*)rec)->pc(); - if (pc != NULL && os::dll_address_to_function_name(pc, buf, sizeof(buf), NULL)) { - tty->print_cr("\tfrom %s", buf); - } else { - tty->print_cr("\tcould not decode pc = " PTR_FORMAT "", pc); - } - - } -} - -#endif - - -bool VMMemPointerIterator::insert_record(MemPointerRecord* rec) { - VMMemRegionEx new_rec; - assert(rec->is_allocation_record() || rec->is_commit_record(), - "Sanity check"); - if (MemTracker::track_callsite()) { - new_rec.init((MemPointerRecordEx*)rec); - } else { - new_rec.init(rec); - } - return insert(&new_rec); -} - -bool VMMemPointerIterator::insert_record_after(MemPointerRecord* rec) { - VMMemRegionEx new_rec; - assert(rec->is_allocation_record() || rec->is_commit_record(), - "Sanity check"); - if (MemTracker::track_callsite()) { - new_rec.init((MemPointerRecordEx*)rec); - } else { - new_rec.init(rec); - } - return insert_after(&new_rec); -} - -// we don't consolidate reserved regions, since they may be categorized -// in different types. -bool VMMemPointerIterator::add_reserved_region(MemPointerRecord* rec) { - assert(rec->is_allocation_record(), "Sanity check"); - VMMemRegion* reserved_region = (VMMemRegion*)current(); - - // we don't have anything yet - if (reserved_region == NULL) { - return insert_record(rec); - } - - assert(reserved_region->is_reserved_region(), "Sanity check"); - // duplicated records - if (reserved_region->is_same_region(rec)) { - return true; - } - // Overlapping stack regions indicate that a JNI thread failed to - // detach from the VM before exiting. This leaks the JavaThread object. - if (CheckJNICalls) { - guarantee(FLAGS_TO_MEMORY_TYPE(reserved_region->flags()) != mtThreadStack || - !reserved_region->overlaps_region(rec), - "Attached JNI thread exited without being detached"); - } - // otherwise, we should not have overlapping reserved regions - assert(FLAGS_TO_MEMORY_TYPE(reserved_region->flags()) == mtThreadStack || - reserved_region->base() > rec->addr(), "Just check: locate()"); - assert(FLAGS_TO_MEMORY_TYPE(reserved_region->flags()) == mtThreadStack || - !reserved_region->overlaps_region(rec), "overlapping reserved regions"); - - return insert_record(rec); -} - -// we do consolidate committed regions -bool VMMemPointerIterator::add_committed_region(MemPointerRecord* rec) { - assert(rec->is_commit_record(), "Sanity check"); - VMMemRegion* reserved_rgn = (VMMemRegion*)current(); - assert(reserved_rgn->is_reserved_region() && reserved_rgn->contains_region(rec), - "Sanity check"); - - // thread's native stack is always marked as "committed", ignore - // the "commit" operation for creating stack guard pages - if (FLAGS_TO_MEMORY_TYPE(reserved_rgn->flags()) == mtThreadStack && - FLAGS_TO_MEMORY_TYPE(rec->flags()) != mtThreadStack) { - return true; - } - - // if the reserved region has any committed regions - VMMemRegion* committed_rgn = (VMMemRegion*)next(); - while (committed_rgn != NULL && committed_rgn->is_committed_region()) { - // duplicated commit records - if(committed_rgn->contains_region(rec)) { - return true; - } else if (committed_rgn->overlaps_region(rec)) { - // overlaps front part - if (rec->addr() < committed_rgn->addr()) { - committed_rgn->expand_region(rec->addr(), - committed_rgn->addr() - rec->addr()); - } else { - // overlaps tail part - address committed_rgn_end = committed_rgn->addr() + - committed_rgn->size(); - assert(committed_rgn_end < rec->addr() + rec->size(), - "overlap tail part"); - committed_rgn->expand_region(committed_rgn_end, - (rec->addr() + rec->size()) - committed_rgn_end); - } - } else if (committed_rgn->base() + committed_rgn->size() == rec->addr()) { - // adjunct each other - committed_rgn->expand_region(rec->addr(), rec->size()); - VMMemRegion* next_reg = (VMMemRegion*)next(); - // see if we can consolidate next committed region - if (next_reg != NULL && next_reg->is_committed_region() && - next_reg->base() == committed_rgn->base() + committed_rgn->size()) { - committed_rgn->expand_region(next_reg->base(), next_reg->size()); - // delete merged region - remove(); - } - return true; - } else if (committed_rgn->base() > rec->addr()) { - // found the location, insert this committed region - return insert_record(rec); - } - committed_rgn = (VMMemRegion*)next(); - } - return insert_record(rec); -} - -bool VMMemPointerIterator::remove_uncommitted_region(MemPointerRecord* rec) { - assert(rec->is_uncommit_record(), "sanity check"); - VMMemRegion* cur; - cur = (VMMemRegion*)current(); - assert(cur->is_reserved_region() && cur->contains_region(rec), - "Sanity check"); - // thread's native stack is always marked as "committed", ignore - // the "commit" operation for creating stack guard pages - if (FLAGS_TO_MEMORY_TYPE(cur->flags()) == mtThreadStack && - FLAGS_TO_MEMORY_TYPE(rec->flags()) != mtThreadStack) { - return true; - } - - cur = (VMMemRegion*)next(); - while (cur != NULL && cur->is_committed_region()) { - // region already uncommitted, must be due to duplicated record - if (cur->addr() >= rec->addr() + rec->size()) { - break; - } else if (cur->contains_region(rec)) { - // uncommit whole region - if (cur->is_same_region(rec)) { - remove(); - break; - } else if (rec->addr() == cur->addr() || - rec->addr() + rec->size() == cur->addr() + cur->size()) { - // uncommitted from either end of current memory region. - cur->exclude_region(rec->addr(), rec->size()); - break; - } else { // split the committed region and release the middle - address high_addr = cur->addr() + cur->size(); - size_t sz = high_addr - rec->addr(); - cur->exclude_region(rec->addr(), sz); - sz = high_addr - (rec->addr() + rec->size()); - if (MemTracker::track_callsite()) { - MemPointerRecordEx tmp(rec->addr() + rec->size(), cur->flags(), sz, - ((VMMemRegionEx*)cur)->pc()); - return insert_record_after(&tmp); - } else { - MemPointerRecord tmp(rec->addr() + rec->size(), cur->flags(), sz); - return insert_record_after(&tmp); - } - } - } - cur = (VMMemRegion*)next(); - } - - // we may not find committed record due to duplicated records - return true; -} - -bool VMMemPointerIterator::remove_released_region(MemPointerRecord* rec) { - assert(rec->is_deallocation_record(), "Sanity check"); - VMMemRegion* cur = (VMMemRegion*)current(); - assert(cur->is_reserved_region() && cur->contains_region(rec), - "Sanity check"); - if (rec->is_same_region(cur)) { - - // In snapshot, the virtual memory records are sorted in following orders: - // 1. virtual memory's base address - // 2. virtual memory reservation record, followed by commit records within this reservation. - // The commit records are also in base address order. - // When a reserved region is released, we want to remove the reservation record and all - // commit records following it. -#ifdef ASSERT - address low_addr = cur->addr(); - address high_addr = low_addr + cur->size(); -#endif - // remove virtual memory reservation record - remove(); - // remove committed regions within above reservation - VMMemRegion* next_region = (VMMemRegion*)current(); - while (next_region != NULL && next_region->is_committed_region()) { - assert(next_region->addr() >= low_addr && - next_region->addr() + next_region->size() <= high_addr, - "Range check"); - remove(); - next_region = (VMMemRegion*)current(); - } - } else if (rec->addr() == cur->addr() || - rec->addr() + rec->size() == cur->addr() + cur->size()) { - // released region is at either end of this region - cur->exclude_region(rec->addr(), rec->size()); - assert(check_reserved_region(), "Integrity check"); - } else { // split the reserved region and release the middle - address high_addr = cur->addr() + cur->size(); - size_t sz = high_addr - rec->addr(); - cur->exclude_region(rec->addr(), sz); - sz = high_addr - rec->addr() - rec->size(); - if (MemTracker::track_callsite()) { - MemPointerRecordEx tmp(rec->addr() + rec->size(), cur->flags(), sz, - ((VMMemRegionEx*)cur)->pc()); - bool ret = insert_reserved_region(&tmp); - assert(!ret || check_reserved_region(), "Integrity check"); - return ret; - } else { - MemPointerRecord tmp(rec->addr() + rec->size(), cur->flags(), sz); - bool ret = insert_reserved_region(&tmp); - assert(!ret || check_reserved_region(), "Integrity check"); - return ret; - } - } - return true; -} - -bool VMMemPointerIterator::insert_reserved_region(MemPointerRecord* rec) { - // skip all 'commit' records associated with previous reserved region - VMMemRegion* p = (VMMemRegion*)next(); - while (p != NULL && p->is_committed_region() && - p->base() + p->size() < rec->addr()) { - p = (VMMemRegion*)next(); - } - return insert_record(rec); -} - -bool VMMemPointerIterator::split_reserved_region(VMMemRegion* rgn, address new_rgn_addr, size_t new_rgn_size) { - assert(rgn->contains_region(new_rgn_addr, new_rgn_size), "Not fully contained"); - address pc = (MemTracker::track_callsite() ? ((VMMemRegionEx*)rgn)->pc() : NULL); - if (rgn->base() == new_rgn_addr) { // new region is at the beginning of the region - size_t sz = rgn->size() - new_rgn_size; - // the original region becomes 'new' region - rgn->exclude_region(new_rgn_addr + new_rgn_size, sz); - // remaining becomes next region - MemPointerRecordEx next_rgn(new_rgn_addr + new_rgn_size, rgn->flags(), sz, pc); - return insert_reserved_region(&next_rgn); - } else if (rgn->base() + rgn->size() == new_rgn_addr + new_rgn_size) { - rgn->exclude_region(new_rgn_addr, new_rgn_size); - MemPointerRecordEx next_rgn(new_rgn_addr, rgn->flags(), new_rgn_size, pc); - return insert_reserved_region(&next_rgn); - } else { - // the orginal region will be split into three - address rgn_high_addr = rgn->base() + rgn->size(); - // first region - rgn->exclude_region(new_rgn_addr, (rgn_high_addr - new_rgn_addr)); - // the second region is the new region - MemPointerRecordEx new_rgn(new_rgn_addr, rgn->flags(), new_rgn_size, pc); - if (!insert_reserved_region(&new_rgn)) return false; - // the remaining region - MemPointerRecordEx rem_rgn(new_rgn_addr + new_rgn_size, rgn->flags(), - rgn_high_addr - (new_rgn_addr + new_rgn_size), pc); - return insert_reserved_region(&rem_rgn); - } -} - -static int sort_in_seq_order(const void* p1, const void* p2) { - assert(p1 != NULL && p2 != NULL, "Sanity check"); - const MemPointerRecord* mp1 = (MemPointerRecord*)p1; - const MemPointerRecord* mp2 = (MemPointerRecord*)p2; - return (mp1->seq() - mp2->seq()); -} - -bool StagingArea::init() { - if (MemTracker::track_callsite()) { - _malloc_data = new (std::nothrow)MemPointerArrayImpl(); - _vm_data = new (std::nothrow)MemPointerArrayImpl(); - } else { - _malloc_data = new (std::nothrow)MemPointerArrayImpl(); - _vm_data = new (std::nothrow)MemPointerArrayImpl(); - } - - if (_malloc_data != NULL && _vm_data != NULL && - !_malloc_data->out_of_memory() && - !_vm_data->out_of_memory()) { - return true; - } else { - if (_malloc_data != NULL) delete _malloc_data; - if (_vm_data != NULL) delete _vm_data; - _malloc_data = NULL; - _vm_data = NULL; - return false; - } -} - - -VMRecordIterator StagingArea::virtual_memory_record_walker() { - MemPointerArray* arr = vm_data(); - // sort into seq number order - arr->sort((FN_SORT)sort_in_seq_order); - return VMRecordIterator(arr); -} - - -MemSnapshot::MemSnapshot() { - if (MemTracker::track_callsite()) { - _alloc_ptrs = new (std::nothrow) MemPointerArrayImpl(); - _vm_ptrs = new (std::nothrow)MemPointerArrayImpl(64, true); - } else { - _alloc_ptrs = new (std::nothrow) MemPointerArrayImpl(); - _vm_ptrs = new (std::nothrow)MemPointerArrayImpl(64, true); - } - - _staging_area.init(); - _lock = new (std::nothrow) Mutex(Monitor::max_nonleaf - 1, "memSnapshotLock"); - NOT_PRODUCT(_untracked_count = 0;) - _number_of_classes = 0; -} - -MemSnapshot::~MemSnapshot() { - assert(MemTracker::shutdown_in_progress(), "native memory tracking still on"); - { - MutexLockerEx locker(_lock); - if (_alloc_ptrs != NULL) { - delete _alloc_ptrs; - _alloc_ptrs = NULL; - } - - if (_vm_ptrs != NULL) { - delete _vm_ptrs; - _vm_ptrs = NULL; - } - } - - if (_lock != NULL) { - delete _lock; - _lock = NULL; - } -} - - -void MemSnapshot::copy_seq_pointer(MemPointerRecord* dest, const MemPointerRecord* src) { - assert(dest != NULL && src != NULL, "Just check"); - assert(dest->addr() == src->addr(), "Just check"); - assert(dest->seq() > 0 && src->seq() > 0, "not sequenced"); - - if (MemTracker::track_callsite()) { - *(SeqMemPointerRecordEx*)dest = *(SeqMemPointerRecordEx*)src; - } else { - *(SeqMemPointerRecord*)dest = *(SeqMemPointerRecord*)src; - } -} - -void MemSnapshot::assign_pointer(MemPointerRecord*dest, const MemPointerRecord* src) { - assert(src != NULL && dest != NULL, "Just check"); - assert(dest->seq() == 0 && src->seq() >0, "cast away sequence"); - - if (MemTracker::track_callsite()) { - *(MemPointerRecordEx*)dest = *(MemPointerRecordEx*)src; - } else { - *(MemPointerRecord*)dest = *(MemPointerRecord*)src; - } -} - -// merge a recorder to the staging area -bool MemSnapshot::merge(MemRecorder* rec) { - assert(rec != NULL && !rec->out_of_memory(), "Just check"); - - SequencedRecordIterator itr(rec->pointer_itr()); - - MutexLockerEx lock(_lock, true); - MemPointerIterator malloc_staging_itr(_staging_area.malloc_data()); - MemPointerRecord* incoming_rec = (MemPointerRecord*) itr.current(); - MemPointerRecord* matched_rec; - - while (incoming_rec != NULL) { - if (incoming_rec->is_vm_pointer()) { - // we don't do anything with virtual memory records during merge - if (!_staging_area.vm_data()->append(incoming_rec)) { - return false; - } - } else { - // locate matched record and/or also position the iterator to proper - // location for this incoming record. - matched_rec = (MemPointerRecord*)malloc_staging_itr.locate(incoming_rec->addr()); - // we have not seen this memory block in this generation, - // so just add to staging area - if (matched_rec == NULL) { - if (!malloc_staging_itr.insert(incoming_rec)) { - return false; - } - } else if (incoming_rec->addr() == matched_rec->addr()) { - // whoever has higher sequence number wins - if (incoming_rec->seq() > matched_rec->seq()) { - copy_seq_pointer(matched_rec, incoming_rec); - } - } else if (incoming_rec->addr() < matched_rec->addr()) { - if (!malloc_staging_itr.insert(incoming_rec)) { - return false; - } - } else { - ShouldNotReachHere(); - } - } - incoming_rec = (MemPointerRecord*)itr.next(); - } - NOT_PRODUCT(void check_staging_data();) - return true; -} - - -// promote data to next generation -bool MemSnapshot::promote(int number_of_classes) { - assert(_alloc_ptrs != NULL && _vm_ptrs != NULL, "Just check"); - assert(_staging_area.malloc_data() != NULL && _staging_area.vm_data() != NULL, - "Just check"); - MutexLockerEx lock(_lock, true); - - MallocRecordIterator malloc_itr = _staging_area.malloc_record_walker(); - bool promoted = false; - if (promote_malloc_records(&malloc_itr)) { - VMRecordIterator vm_itr = _staging_area.virtual_memory_record_walker(); - if (promote_virtual_memory_records(&vm_itr)) { - promoted = true; - } - } - - NOT_PRODUCT(check_malloc_pointers();) - _staging_area.clear(); - _number_of_classes = number_of_classes; - return promoted; -} - -bool MemSnapshot::promote_malloc_records(MemPointerArrayIterator* itr) { - MemPointerIterator malloc_snapshot_itr(_alloc_ptrs); - MemPointerRecord* new_rec = (MemPointerRecord*)itr->current(); - MemPointerRecord* matched_rec; - while (new_rec != NULL) { - matched_rec = (MemPointerRecord*)malloc_snapshot_itr.locate(new_rec->addr()); - // found matched memory block - if (matched_rec != NULL && new_rec->addr() == matched_rec->addr()) { - // snapshot already contains 'live' records - assert(matched_rec->is_allocation_record() || matched_rec->is_arena_memory_record(), - "Sanity check"); - // update block states - if (new_rec->is_allocation_record()) { - assign_pointer(matched_rec, new_rec); - } else if (new_rec->is_arena_memory_record()) { - if (new_rec->size() == 0) { - // remove size record once size drops to 0 - malloc_snapshot_itr.remove(); - } else { - assign_pointer(matched_rec, new_rec); - } - } else { - // a deallocation record - assert(new_rec->is_deallocation_record(), "Sanity check"); - // an arena record can be followed by a size record, we need to remove both - if (matched_rec->is_arena_record()) { - MemPointerRecord* next = (MemPointerRecord*)malloc_snapshot_itr.peek_next(); - if (next != NULL && next->is_arena_memory_record() && - next->is_memory_record_of_arena(matched_rec)) { - malloc_snapshot_itr.remove(); - } - } - // the memory is deallocated, remove related record(s) - malloc_snapshot_itr.remove(); - } - } else { - // don't insert size 0 record - if (new_rec->is_arena_memory_record() && new_rec->size() == 0) { - new_rec = NULL; - } - - if (new_rec != NULL) { - if (new_rec->is_allocation_record() || new_rec->is_arena_memory_record()) { - if (matched_rec != NULL && new_rec->addr() > matched_rec->addr()) { - if (!malloc_snapshot_itr.insert_after(new_rec)) { - return false; - } - } else { - if (!malloc_snapshot_itr.insert(new_rec)) { - return false; - } - } - } -#ifndef PRODUCT - else if (!has_allocation_record(new_rec->addr())) { - // NMT can not track some startup memory, which is allocated before NMT is on - _untracked_count ++; - } -#endif - } - } - new_rec = (MemPointerRecord*)itr->next(); - } - return true; -} - -bool MemSnapshot::promote_virtual_memory_records(MemPointerArrayIterator* itr) { - VMMemPointerIterator vm_snapshot_itr(_vm_ptrs); - MemPointerRecord* new_rec = (MemPointerRecord*)itr->current(); - VMMemRegion* reserved_rec; - while (new_rec != NULL) { - assert(new_rec->is_vm_pointer(), "Sanity check"); - - // locate a reserved region that contains the specified address, or - // the nearest reserved region has base address just above the specified - // address - reserved_rec = (VMMemRegion*)vm_snapshot_itr.locate(new_rec->addr()); - if (reserved_rec != NULL && reserved_rec->contains_region(new_rec)) { - // snapshot can only have 'live' records - assert(reserved_rec->is_reserved_region(), "Sanity check"); - if (new_rec->is_allocation_record()) { - if (!reserved_rec->is_same_region(new_rec)) { - // only deal with split a bigger reserved region into smaller regions. - // So far, CDS is the only use case. - if (!vm_snapshot_itr.split_reserved_region(reserved_rec, new_rec->addr(), new_rec->size())) { - return false; - } - } - } else if (new_rec->is_uncommit_record()) { - if (!vm_snapshot_itr.remove_uncommitted_region(new_rec)) { - return false; - } - } else if (new_rec->is_commit_record()) { - // insert or expand existing committed region to cover this - // newly committed region - if (!vm_snapshot_itr.add_committed_region(new_rec)) { - return false; - } - } else if (new_rec->is_deallocation_record()) { - // release part or all memory region - if (!vm_snapshot_itr.remove_released_region(new_rec)) { - return false; - } - } else if (new_rec->is_type_tagging_record()) { - // tag this reserved virtual memory range to a memory type. Can not re-tag a memory range - // to different type. - assert(FLAGS_TO_MEMORY_TYPE(reserved_rec->flags()) == mtNone || - FLAGS_TO_MEMORY_TYPE(reserved_rec->flags()) == FLAGS_TO_MEMORY_TYPE(new_rec->flags()), - "Sanity check"); - reserved_rec->tag(new_rec->flags()); - } else { - ShouldNotReachHere(); - } - } else { - /* - * The assertion failure indicates mis-matched virtual memory records. The likely - * scenario is, that some virtual memory operations are not going through os::xxxx_memory() - * api, which have to be tracked manually. (perfMemory is an example). - */ - assert(new_rec->is_allocation_record(), "Sanity check"); - if (!vm_snapshot_itr.add_reserved_region(new_rec)) { - return false; - } - } - new_rec = (MemPointerRecord*)itr->next(); - } - return true; -} - -#ifndef PRODUCT -void MemSnapshot::print_snapshot_stats(outputStream* st) { - st->print_cr("Snapshot:"); - st->print_cr("\tMalloced: %d/%d [%5.2f%%] %dKB", _alloc_ptrs->length(), _alloc_ptrs->capacity(), - (100.0 * (float)_alloc_ptrs->length()) / (float)_alloc_ptrs->capacity(), _alloc_ptrs->instance_size()/K); - - st->print_cr("\tVM: %d/%d [%5.2f%%] %dKB", _vm_ptrs->length(), _vm_ptrs->capacity(), - (100.0 * (float)_vm_ptrs->length()) / (float)_vm_ptrs->capacity(), _vm_ptrs->instance_size()/K); - - st->print_cr("\tMalloc staging Area: %d/%d [%5.2f%%] %dKB", _staging_area.malloc_data()->length(), - _staging_area.malloc_data()->capacity(), - (100.0 * (float)_staging_area.malloc_data()->length()) / (float)_staging_area.malloc_data()->capacity(), - _staging_area.malloc_data()->instance_size()/K); - - st->print_cr("\tVirtual memory staging Area: %d/%d [%5.2f%%] %dKB", _staging_area.vm_data()->length(), - _staging_area.vm_data()->capacity(), - (100.0 * (float)_staging_area.vm_data()->length()) / (float)_staging_area.vm_data()->capacity(), - _staging_area.vm_data()->instance_size()/K); - - st->print_cr("\tUntracked allocation: %d", _untracked_count); -} - -void MemSnapshot::check_malloc_pointers() { - MemPointerArrayIteratorImpl mItr(_alloc_ptrs); - MemPointerRecord* p = (MemPointerRecord*)mItr.current(); - MemPointerRecord* prev = NULL; - while (p != NULL) { - if (prev != NULL) { - assert(p->addr() >= prev->addr(), "sorting order"); - } - prev = p; - p = (MemPointerRecord*)mItr.next(); - } -} - -bool MemSnapshot::has_allocation_record(address addr) { - MemPointerArrayIteratorImpl itr(_staging_area.malloc_data()); - MemPointerRecord* cur = (MemPointerRecord*)itr.current(); - while (cur != NULL) { - if (cur->addr() == addr && cur->is_allocation_record()) { - return true; - } - cur = (MemPointerRecord*)itr.next(); - } - return false; -} -#endif // PRODUCT - -#ifdef ASSERT -void MemSnapshot::check_staging_data() { - MemPointerArrayIteratorImpl itr(_staging_area.malloc_data()); - MemPointerRecord* cur = (MemPointerRecord*)itr.current(); - MemPointerRecord* next = (MemPointerRecord*)itr.next(); - while (next != NULL) { - assert((next->addr() > cur->addr()) || - ((next->flags() & MemPointerRecord::tag_masks) > - (cur->flags() & MemPointerRecord::tag_masks)), - "sorting order"); - cur = next; - next = (MemPointerRecord*)itr.next(); - } - - MemPointerArrayIteratorImpl vm_itr(_staging_area.vm_data()); - cur = (MemPointerRecord*)vm_itr.current(); - while (cur != NULL) { - assert(cur->is_vm_pointer(), "virtual memory pointer only"); - cur = (MemPointerRecord*)vm_itr.next(); - } -} - -void MemSnapshot::dump_all_vm_pointers() { - MemPointerArrayIteratorImpl itr(_vm_ptrs); - VMMemRegion* ptr = (VMMemRegion*)itr.current(); - tty->print_cr("dump virtual memory pointers:"); - while (ptr != NULL) { - if (ptr->is_committed_region()) { - tty->print("\t"); - } - tty->print("[" PTR_FORMAT " - " PTR_FORMAT "] [%x]", ptr->addr(), - (ptr->addr() + ptr->size()), ptr->flags()); - - if (MemTracker::track_callsite()) { - VMMemRegionEx* ex = (VMMemRegionEx*)ptr; - if (ex->pc() != NULL) { - char buf[1024]; - if (os::dll_address_to_function_name(ex->pc(), buf, sizeof(buf), NULL)) { - tty->print_cr("\t%s", buf); - } else { - tty->cr(); - } - } - } - - ptr = (VMMemRegion*)itr.next(); - } - tty->flush(); -} -#endif // ASSERT - diff --git a/hotspot/src/share/vm/services/memSnapshot.hpp b/hotspot/src/share/vm/services/memSnapshot.hpp deleted file mode 100644 index f7d07568c6d..00000000000 --- a/hotspot/src/share/vm/services/memSnapshot.hpp +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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_SERVICES_MEM_SNAPSHOT_HPP -#define SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP - -#include "memory/allocation.hpp" -#include "runtime/mutex.hpp" -#include "runtime/mutexLocker.hpp" -#include "services/memBaseline.hpp" -#include "services/memPtrArray.hpp" - -// Snapshot pointer array iterator - -// The pointer array contains malloc-ed pointers -class MemPointerIterator : public MemPointerArrayIteratorImpl { - public: - MemPointerIterator(MemPointerArray* arr): - MemPointerArrayIteratorImpl(arr) { - assert(arr != NULL, "null array"); - } - -#ifdef ASSERT - virtual bool is_dup_pointer(const MemPointer* ptr1, - const MemPointer* ptr2) const { - MemPointerRecord* p1 = (MemPointerRecord*)ptr1; - MemPointerRecord* p2 = (MemPointerRecord*)ptr2; - - if (p1->addr() != p2->addr()) return false; - if ((p1->flags() & MemPointerRecord::tag_masks) != - (p2->flags() & MemPointerRecord::tag_masks)) { - return false; - } - // we do see multiple commit/uncommit on the same memory, it is ok - return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc || - (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release; - } - - virtual bool insert(MemPointer* ptr) { - if (_pos > 0) { - MemPointer* p1 = (MemPointer*)ptr; - MemPointer* p2 = (MemPointer*)_array->at(_pos - 1); - assert(!is_dup_pointer(p1, p2), - err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags())); - } - if (_pos < _array->length() -1) { - MemPointer* p1 = (MemPointer*)ptr; - MemPointer* p2 = (MemPointer*)_array->at(_pos + 1); - assert(!is_dup_pointer(p1, p2), - err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags())); - } - return _array->insert_at(ptr, _pos); - } - - virtual bool insert_after(MemPointer* ptr) { - if (_pos > 0) { - MemPointer* p1 = (MemPointer*)ptr; - MemPointer* p2 = (MemPointer*)_array->at(_pos - 1); - assert(!is_dup_pointer(p1, p2), - err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags())); - } - if (_pos < _array->length() - 1) { - MemPointer* p1 = (MemPointer*)ptr; - MemPointer* p2 = (MemPointer*)_array->at(_pos + 1); - - assert(!is_dup_pointer(p1, p2), - err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags())); - } - if (_array->insert_at(ptr, _pos + 1)) { - _pos ++; - return true; - } - return false; - } -#endif - - virtual MemPointer* locate(address addr) { - MemPointer* cur = current(); - while (cur != NULL && cur->addr() < addr) { - cur = next(); - } - return cur; - } -}; - -class VMMemPointerIterator : public MemPointerIterator { - public: - VMMemPointerIterator(MemPointerArray* arr): - MemPointerIterator(arr) { - } - - // locate an existing reserved memory region that contains specified address, - // or the reserved region just above this address, where the incoming - // reserved region should be inserted. - virtual MemPointer* locate(address addr) { - reset(); - VMMemRegion* reg = (VMMemRegion*)current(); - while (reg != NULL) { - if (reg->is_reserved_region()) { - if (reg->contains_address(addr) || addr < reg->base()) { - return reg; - } - } - reg = (VMMemRegion*)next(); - } - return NULL; - } - - // following methods update virtual memory in the context - // of 'current' position, which is properly positioned by - // callers via locate method. - bool add_reserved_region(MemPointerRecord* rec); - bool add_committed_region(MemPointerRecord* rec); - bool remove_uncommitted_region(MemPointerRecord* rec); - bool remove_released_region(MemPointerRecord* rec); - - // split a reserved region to create a new memory region with specified base and size - bool split_reserved_region(VMMemRegion* rgn, address new_rgn_addr, size_t new_rgn_size); - private: - bool insert_record(MemPointerRecord* rec); - bool insert_record_after(MemPointerRecord* rec); - - bool insert_reserved_region(MemPointerRecord* rec); - - // reset current position - inline void reset() { _pos = 0; } -#ifdef ASSERT - // check integrity of records on current reserved memory region. - bool check_reserved_region() { - VMMemRegion* reserved_region = (VMMemRegion*)current(); - assert(reserved_region != NULL && reserved_region->is_reserved_region(), - "Sanity check"); - // all committed regions that follow current reserved region, should all - // belong to the reserved region. - VMMemRegion* next_region = (VMMemRegion*)next(); - for (; next_region != NULL && next_region->is_committed_region(); - next_region = (VMMemRegion*)next() ) { - if(!reserved_region->contains_region(next_region)) { - return false; - } - } - return true; - } - - virtual bool is_dup_pointer(const MemPointer* ptr1, - const MemPointer* ptr2) const { - VMMemRegion* p1 = (VMMemRegion*)ptr1; - VMMemRegion* p2 = (VMMemRegion*)ptr2; - - if (p1->addr() != p2->addr()) return false; - if ((p1->flags() & MemPointerRecord::tag_masks) != - (p2->flags() & MemPointerRecord::tag_masks)) { - return false; - } - // we do see multiple commit/uncommit on the same memory, it is ok - return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc || - (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release; - } -#endif -}; - -class MallocRecordIterator : public MemPointerArrayIterator { - private: - MemPointerArrayIteratorImpl _itr; - - - - public: - MallocRecordIterator(MemPointerArray* arr) : _itr(arr) { - } - - virtual MemPointer* current() const { -#ifdef ASSERT - MemPointer* cur_rec = _itr.current(); - if (cur_rec != NULL) { - MemPointer* prev_rec = _itr.peek_prev(); - MemPointer* next_rec = _itr.peek_next(); - assert(prev_rec == NULL || prev_rec->addr() < cur_rec->addr(), "Sorting order"); - assert(next_rec == NULL || next_rec->addr() > cur_rec->addr(), "Sorting order"); - } -#endif - return _itr.current(); - } - virtual MemPointer* next() { - MemPointerRecord* next_rec = (MemPointerRecord*)_itr.next(); - // arena memory record is a special case, which we have to compare - // sequence number against its associated arena record. - if (next_rec != NULL && next_rec->is_arena_memory_record()) { - MemPointerRecord* prev_rec = (MemPointerRecord*)_itr.peek_prev(); - // if there is an associated arena record, it has to be previous - // record because of sorting order (by address) - NMT generates a pseudo address - // for arena's size record by offsetting arena's address, that guarantees - // the order of arena record and it's size record. - if (prev_rec != NULL && prev_rec->is_arena_record() && - next_rec->is_memory_record_of_arena(prev_rec)) { - if (prev_rec->seq() > next_rec->seq()) { - // Skip this arena memory record - // Two scenarios: - // - if the arena record is an allocation record, this early - // size record must be leftover by previous arena, - // and the last size record should have size = 0. - // - if the arena record is a deallocation record, this - // size record should be its cleanup record, which should - // also have size = 0. In other world, arena alway reset - // its size before gone (see Arena's destructor) - assert(next_rec->size() == 0, "size not reset"); - return _itr.next(); - } else { - assert(prev_rec->is_allocation_record(), - "Arena size record ahead of allocation record"); - } - } - } - return next_rec; - } - - MemPointer* peek_next() const { ShouldNotReachHere(); return NULL; } - MemPointer* peek_prev() const { ShouldNotReachHere(); return NULL; } - void remove() { ShouldNotReachHere(); } - bool insert(MemPointer* ptr) { ShouldNotReachHere(); return false; } - bool insert_after(MemPointer* ptr) { ShouldNotReachHere(); return false; } -}; - -// collapse duplicated records. Eliminating duplicated records here, is much -// cheaper than during promotion phase. However, it does have limitation - it -// can only eliminate duplicated records within the generation, there are -// still chances seeing duplicated records during promotion. -// We want to use the record with higher sequence number, because it has -// more accurate callsite pc. -class VMRecordIterator : public MemPointerArrayIterator { - private: - MemPointerArrayIteratorImpl _itr; - - public: - VMRecordIterator(MemPointerArray* arr) : _itr(arr) { - MemPointerRecord* cur = (MemPointerRecord*)_itr.current(); - MemPointerRecord* next = (MemPointerRecord*)_itr.peek_next(); - while (next != NULL) { - assert(cur != NULL, "Sanity check"); - assert(((SeqMemPointerRecord*)next)->seq() > ((SeqMemPointerRecord*)cur)->seq(), - "pre-sort order"); - - if (is_duplicated_record(cur, next)) { - _itr.next(); - next = (MemPointerRecord*)_itr.peek_next(); - } else { - break; - } - } - } - - virtual MemPointer* current() const { - return _itr.current(); - } - - // get next record, but skip the duplicated records - virtual MemPointer* next() { - MemPointerRecord* cur = (MemPointerRecord*)_itr.next(); - MemPointerRecord* next = (MemPointerRecord*)_itr.peek_next(); - while (next != NULL) { - assert(cur != NULL, "Sanity check"); - assert(((SeqMemPointerRecord*)next)->seq() > ((SeqMemPointerRecord*)cur)->seq(), - "pre-sort order"); - - if (is_duplicated_record(cur, next)) { - _itr.next(); - cur = next; - next = (MemPointerRecord*)_itr.peek_next(); - } else { - break; - } - } - return cur; - } - - MemPointer* peek_next() const { ShouldNotReachHere(); return NULL; } - MemPointer* peek_prev() const { ShouldNotReachHere(); return NULL; } - void remove() { ShouldNotReachHere(); } - bool insert(MemPointer* ptr) { ShouldNotReachHere(); return false; } - bool insert_after(MemPointer* ptr) { ShouldNotReachHere(); return false; } - - private: - bool is_duplicated_record(MemPointerRecord* p1, MemPointerRecord* p2) const { - bool ret = (p1->addr() == p2->addr() && p1->size() == p2->size() && p1->flags() == p2->flags()); - assert(!(ret && FLAGS_TO_MEMORY_TYPE(p1->flags()) == mtThreadStack), "dup on stack record"); - return ret; - } -}; - -class StagingArea VALUE_OBJ_CLASS_SPEC { - private: - MemPointerArray* _malloc_data; - MemPointerArray* _vm_data; - - public: - StagingArea() : _malloc_data(NULL), _vm_data(NULL) { - init(); - } - - ~StagingArea() { - if (_malloc_data != NULL) delete _malloc_data; - if (_vm_data != NULL) delete _vm_data; - } - - MallocRecordIterator malloc_record_walker() { - return MallocRecordIterator(malloc_data()); - } - - VMRecordIterator virtual_memory_record_walker(); - - bool init(); - void clear() { - assert(_malloc_data != NULL && _vm_data != NULL, "Just check"); - _malloc_data->shrink(); - _malloc_data->clear(); - _vm_data->clear(); - } - - inline MemPointerArray* malloc_data() { return _malloc_data; } - inline MemPointerArray* vm_data() { return _vm_data; } -}; - -class MemBaseline; -class MemSnapshot : public CHeapObj { - private: - // the following two arrays contain records of all known lived memory blocks - // live malloc-ed memory pointers - MemPointerArray* _alloc_ptrs; - // live virtual memory pointers - MemPointerArray* _vm_ptrs; - - StagingArea _staging_area; - - // the lock to protect this snapshot - Monitor* _lock; - - // the number of instance classes - int _number_of_classes; - - NOT_PRODUCT(size_t _untracked_count;) - friend class MemBaseline; - - public: - MemSnapshot(); - virtual ~MemSnapshot(); - - // if we are running out of native memory - bool out_of_memory() { - return (_alloc_ptrs == NULL || - _staging_area.malloc_data() == NULL || - _staging_area.vm_data() == NULL || - _vm_ptrs == NULL || _lock == NULL || - _alloc_ptrs->out_of_memory() || - _vm_ptrs->out_of_memory()); - } - - // merge a per-thread memory recorder into staging area - bool merge(MemRecorder* rec); - // promote staged data to snapshot - bool promote(int number_of_classes); - - int number_of_classes() const { return _number_of_classes; } - - void wait(long timeout) { - assert(_lock != NULL, "Just check"); - MonitorLockerEx locker(_lock); - locker.wait(true, timeout); - } - - NOT_PRODUCT(void print_snapshot_stats(outputStream* st);) - NOT_PRODUCT(void check_staging_data();) - NOT_PRODUCT(void check_malloc_pointers();) - NOT_PRODUCT(bool has_allocation_record(address addr);) - // dump all virtual memory pointers in snapshot - DEBUG_ONLY( void dump_all_vm_pointers();) - - private: - // copy sequenced pointer from src to dest - void copy_seq_pointer(MemPointerRecord* dest, const MemPointerRecord* src); - // assign a sequenced pointer to non-sequenced pointer - void assign_pointer(MemPointerRecord*dest, const MemPointerRecord* src); - - bool promote_malloc_records(MemPointerArrayIterator* itr); - bool promote_virtual_memory_records(MemPointerArrayIterator* itr); -}; - -#endif // SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP diff --git a/hotspot/src/share/vm/services/memTrackWorker.cpp b/hotspot/src/share/vm/services/memTrackWorker.cpp deleted file mode 100644 index 7bf18eb273c..00000000000 --- a/hotspot/src/share/vm/services/memTrackWorker.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2013, 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 "runtime/threadCritical.hpp" -#include "services/memTracker.hpp" -#include "services/memTrackWorker.hpp" -#include "utilities/decoder.hpp" -#include "utilities/vmError.hpp" - - -void GenerationData::reset() { - _number_of_classes = 0; - while (_recorder_list != NULL) { - MemRecorder* tmp = _recorder_list; - _recorder_list = _recorder_list->next(); - MemTracker::release_thread_recorder(tmp); - } -} - -MemTrackWorker::MemTrackWorker(MemSnapshot* snapshot): _snapshot(snapshot) { - // create thread uses cgc thread type for now. We should revisit - // the option, or create new thread type. - _has_error = !os::create_thread(this, os::cgc_thread); - set_name("MemTrackWorker"); - - // initial generation circuit buffer - if (!has_error()) { - _head = _tail = 0; - for(int index = 0; index < MAX_GENERATIONS; index ++) { - ::new ((void*)&_gen[index]) GenerationData(); - } - } - NOT_PRODUCT(_sync_point_count = 0;) - NOT_PRODUCT(_merge_count = 0;) - NOT_PRODUCT(_last_gen_in_use = 0;) -} - -MemTrackWorker::~MemTrackWorker() { - for (int index = 0; index < MAX_GENERATIONS; index ++) { - _gen[index].reset(); - } -} - -void* MemTrackWorker::operator new(size_t size) throw() { - assert(false, "use nothrow version"); - return NULL; -} - -void* MemTrackWorker::operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() { - return allocate(size, false, mtNMT); -} - -void MemTrackWorker::start() { - os::start_thread(this); -} - -/* - * Native memory tracking worker thread loop: - * 1. merge one generation of memory recorders to staging area - * 2. promote staging data to memory snapshot - * - * This thread can run through safepoint. - */ - -void MemTrackWorker::run() { - assert(MemTracker::is_on(), "native memory tracking is off"); - this->initialize_thread_local_storage(); - this->record_stack_base_and_size(); - assert(_snapshot != NULL, "Worker should not be started"); - MemRecorder* rec; - unsigned long processing_generation = 0; - bool worker_idle = false; - - while (!MemTracker::shutdown_in_progress()) { - NOT_PRODUCT(_last_gen_in_use = generations_in_use();) - { - // take a recorder from earliest generation in buffer - ThreadCritical tc; - rec = _gen[_head].next_recorder(); - } - if (rec != NULL) { - if (rec->get_generation() != processing_generation || worker_idle) { - processing_generation = rec->get_generation(); - worker_idle = false; - MemTracker::set_current_processing_generation(processing_generation); - } - - // merge the recorder into staging area - if (!_snapshot->merge(rec)) { - MemTracker::shutdown(MemTracker::NMT_out_of_memory); - } else { - NOT_PRODUCT(_merge_count ++;) - } - MemTracker::release_thread_recorder(rec); - } else { - // no more recorder to merge, promote staging area - // to snapshot - if (_head != _tail) { - long number_of_classes; - { - ThreadCritical tc; - if (_gen[_head].has_more_recorder() || _head == _tail) { - continue; - } - number_of_classes = _gen[_head].number_of_classes(); - _gen[_head].reset(); - - // done with this generation, increment _head pointer - _head = (_head + 1) % MAX_GENERATIONS; - } - // promote this generation data to snapshot - if (!_snapshot->promote(number_of_classes)) { - // failed to promote, means out of memory - MemTracker::shutdown(MemTracker::NMT_out_of_memory); - } - } else { - // worker thread is idle - worker_idle = true; - MemTracker::report_worker_idle(); - _snapshot->wait(1000); - ThreadCritical tc; - // check if more data arrived - if (!_gen[_head].has_more_recorder()) { - _gen[_head].add_recorders(MemTracker::get_pending_recorders()); - } - } - } - } - assert(MemTracker::shutdown_in_progress(), "just check"); - - // transits to final shutdown - MemTracker::final_shutdown(); -} - -// at synchronization point, where 'safepoint visible' Java threads are blocked -// at a safepoint, and the rest of threads are blocked on ThreadCritical lock. -// The caller MemTracker::sync() already takes ThreadCritical before calling this -// method. -// -// Following tasks are performed: -// 1. add all recorders in pending queue to current generation -// 2. increase generation - -void MemTrackWorker::at_sync_point(MemRecorder* rec, int number_of_classes) { - NOT_PRODUCT(_sync_point_count ++;) - assert(count_recorder(rec) <= MemRecorder::_instance_count, - "pending queue has infinite loop"); - - bool out_of_generation_buffer = false; - // check shutdown state inside ThreadCritical - if (MemTracker::shutdown_in_progress()) return; - - _gen[_tail].set_number_of_classes(number_of_classes); - // append the recorders to the end of the generation - _gen[_tail].add_recorders(rec); - assert(count_recorder(_gen[_tail].peek()) <= MemRecorder::_instance_count, - "after add to current generation has infinite loop"); - // we have collected all recorders for this generation. If there is data, - // we need to increment _tail to start a new generation. - if (_gen[_tail].has_more_recorder() || _head == _tail) { - _tail = (_tail + 1) % MAX_GENERATIONS; - out_of_generation_buffer = (_tail == _head); - } - - if (out_of_generation_buffer) { - MemTracker::shutdown(MemTracker::NMT_out_of_generation); - } -} - -#ifndef PRODUCT -int MemTrackWorker::count_recorder(const MemRecorder* head) { - int count = 0; - while(head != NULL) { - count ++; - head = head->next(); - } - return count; -} - -int MemTrackWorker::count_pending_recorders() const { - int count = 0; - for (int index = 0; index < MAX_GENERATIONS; index ++) { - MemRecorder* head = _gen[index].peek(); - if (head != NULL) { - count += count_recorder(head); - } - } - return count; -} -#endif diff --git a/hotspot/src/share/vm/services/memTrackWorker.hpp b/hotspot/src/share/vm/services/memTrackWorker.hpp deleted file mode 100644 index ee45244e324..00000000000 --- a/hotspot/src/share/vm/services/memTrackWorker.hpp +++ /dev/null @@ -1,118 +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. - * - */ - -#ifndef SHARE_VM_SERVICES_MEM_TRACK_WORKER_HPP -#define SHARE_VM_SERVICES_MEM_TRACK_WORKER_HPP - -#include "memory/allocation.hpp" -#include "runtime/thread.hpp" -#include "services/memRecorder.hpp" - -// Maximum MAX_GENERATIONS generation data can be tracked. -#define MAX_GENERATIONS 512 - -class GenerationData VALUE_OBJ_CLASS_SPEC { - private: - int _number_of_classes; - MemRecorder* _recorder_list; - - public: - GenerationData(): _number_of_classes(0), _recorder_list(NULL) { } - - inline int number_of_classes() const { return _number_of_classes; } - inline void set_number_of_classes(long num) { _number_of_classes = num; } - - inline MemRecorder* next_recorder() { - if (_recorder_list == NULL) { - return NULL; - } else { - MemRecorder* tmp = _recorder_list; - _recorder_list = _recorder_list->next(); - return tmp; - } - } - - inline bool has_more_recorder() const { - return (_recorder_list != NULL); - } - - // add recorders to this generation - void add_recorders(MemRecorder* head) { - if (head != NULL) { - if (_recorder_list == NULL) { - _recorder_list = head; - } else { - MemRecorder* tmp = _recorder_list; - for (; tmp->next() != NULL; tmp = tmp->next()); - tmp->set_next(head); - } - } - } - - void reset(); - - NOT_PRODUCT(MemRecorder* peek() const { return _recorder_list; }) -}; - -class MemTrackWorker : public NamedThread { - private: - // circular buffer. This buffer contains generation data to be merged into global - // snaphsot. - // Each slot holds a generation - GenerationData _gen[MAX_GENERATIONS]; - int _head, _tail; // head and tail pointers to above circular buffer - - bool _has_error; - - MemSnapshot* _snapshot; - - public: - MemTrackWorker(MemSnapshot* snapshot); - ~MemTrackWorker(); - _NOINLINE_ void* operator new(size_t size) throw(); - _NOINLINE_ void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw(); - - void start(); - void run(); - - inline bool has_error() const { return _has_error; } - - // task at synchronization point - void at_sync_point(MemRecorder* pending_recorders, int number_of_classes); - - // for debugging purpose, they are not thread safe. - NOT_PRODUCT(static int count_recorder(const MemRecorder* head);) - NOT_PRODUCT(int count_pending_recorders() const;) - - NOT_PRODUCT(int _sync_point_count;) - NOT_PRODUCT(int _merge_count;) - NOT_PRODUCT(int _last_gen_in_use;) - - // how many generations are queued - inline int generations_in_use() const { - return (_tail >= _head ? (_tail - _head + 1) : (MAX_GENERATIONS - (_head - _tail) + 1)); - } -}; - -#endif // SHARE_VM_SERVICES_MEM_TRACK_WORKER_HPP diff --git a/hotspot/src/share/vm/services/memTracker.cpp b/hotspot/src/share/vm/services/memTracker.cpp index 190c004b374..24644c8cc67 100644 --- a/hotspot/src/share/vm/services/memTracker.cpp +++ b/hotspot/src/share/vm/services/memTracker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -23,862 +23,315 @@ */ #include "precompiled.hpp" -#include "oops/instanceKlass.hpp" -#include "runtime/atomic.inline.hpp" -#include "runtime/interfaceSupport.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/safepoint.hpp" -#include "runtime/threadCritical.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/vm_operations.hpp" -#include "services/memPtr.hpp" +#include "runtime/mutex.hpp" +#include "services/memBaseline.hpp" #include "services/memReporter.hpp" +#include "services/mallocTracker.inline.hpp" #include "services/memTracker.hpp" -#include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" -#include "utilities/globalDefinitions.hpp" -bool NMT_track_callsite = false; +#ifdef SOLARIS + volatile bool NMT_stack_walkable = false; +#else + volatile bool NMT_stack_walkable = true; +#endif -// walk all 'known' threads at NMT sync point, and collect their recorders -void SyncThreadRecorderClosure::do_thread(Thread* thread) { - assert(SafepointSynchronize::is_at_safepoint(), "Safepoint required"); - if (thread->is_Java_thread()) { - JavaThread* javaThread = (JavaThread*)thread; - MemRecorder* recorder = javaThread->get_recorder(); - if (recorder != NULL) { - MemTracker::enqueue_pending_recorder(recorder); - javaThread->set_recorder(NULL); +volatile NMT_TrackingLevel MemTracker::_tracking_level = NMT_unknown; +NMT_TrackingLevel MemTracker::_cmdline_tracking_level = NMT_unknown; + +MemBaseline MemTracker::_baseline; +Mutex* MemTracker::_query_lock = NULL; +bool MemTracker::_is_nmt_env_valid = true; + + +NMT_TrackingLevel MemTracker::init_tracking_level() { + NMT_TrackingLevel level = NMT_off; + char buf[64]; + char nmt_option[64]; + jio_snprintf(buf, sizeof(buf), "NMT_LEVEL_%d", os::current_process_id()); + if (os::getenv(buf, nmt_option, sizeof(nmt_option))) { + if (strcmp(nmt_option, "summary") == 0) { + level = NMT_summary; + } else if (strcmp(nmt_option, "detail") == 0) { +#if PLATFORM_NATIVE_STACK_WALKING_SUPPORTED + level = NMT_detail; +#else + level = NMT_summary; +#endif // PLATFORM_NATIVE_STACK_WALKING_SUPPORTED + } else if (strcmp(nmt_option, "off") != 0) { + // The option value is invalid + _is_nmt_env_valid = false; } + + // Remove the environment variable to avoid leaking to child processes + os::unsetenv(buf); } - _thread_count ++; + + // Construct NativeCallStack::EMPTY_STACK. It may get constructed twice, + // but it is benign, the results are the same. + ::new ((void*)&NativeCallStack::EMPTY_STACK) NativeCallStack(0, false); + + if (!MallocTracker::initialize(level) || + !VirtualMemoryTracker::initialize(level)) { + level = NMT_off; + } + return level; } +void MemTracker::init() { + NMT_TrackingLevel level = tracking_level(); + if (level >= NMT_summary) { + if (!VirtualMemoryTracker::late_initialize(level)) { + shutdown(); + return; + } + _query_lock = new (std::nothrow) Mutex(Monitor::max_nonleaf, "NMT_queryLock"); + // Already OOM. It is unlikely, but still have to handle it. + if (_query_lock == NULL) { + shutdown(); + } + } +} -MemRecorder* volatile MemTracker::_global_recorder = NULL; -MemSnapshot* MemTracker::_snapshot = NULL; -MemBaseline MemTracker::_baseline; -Mutex* MemTracker::_query_lock = NULL; -MemRecorder* volatile MemTracker::_merge_pending_queue = NULL; -MemRecorder* volatile MemTracker::_pooled_recorders = NULL; -MemTrackWorker* MemTracker::_worker_thread = NULL; -int MemTracker::_sync_point_skip_count = 0; -MemTracker::NMTLevel MemTracker::_tracking_level = MemTracker::NMT_off; -volatile MemTracker::NMTStates MemTracker::_state = NMT_uninited; -MemTracker::ShutdownReason MemTracker::_reason = NMT_shutdown_none; -int MemTracker::_thread_count = 255; -volatile jint MemTracker::_pooled_recorder_count = 0; -volatile unsigned long MemTracker::_processing_generation = 0; -volatile bool MemTracker::_worker_thread_idle = false; -volatile jint MemTracker::_pending_op_count = 0; -volatile bool MemTracker::_slowdown_calling_thread = false; -debug_only(intx MemTracker::_main_thread_tid = 0;) -NOT_PRODUCT(volatile jint MemTracker::_pending_recorder_count = 0;) - -void MemTracker::init_tracking_options(const char* option_line) { - _tracking_level = NMT_off; - if (strcmp(option_line, "=summary") == 0) { - _tracking_level = NMT_summary; - } else if (strcmp(option_line, "=detail") == 0) { - // detail relies on a stack-walking ability that may not - // be available depending on platform and/or compiler flags -#if PLATFORM_NATIVE_STACK_WALKING_SUPPORTED - _tracking_level = NMT_detail; -#else +bool MemTracker::check_launcher_nmt_support(const char* value) { + if (strcmp(value, "=detail") == 0) { +#if !PLATFORM_NATIVE_STACK_WALKING_SUPPORTED jio_fprintf(defaultStream::error_stream(), "NMT detail is not supported on this platform. Using NMT summary instead.\n"); - _tracking_level = NMT_summary; + if (MemTracker::tracking_level() != NMT_summary) { + return false; + } +#else + if (MemTracker::tracking_level() != NMT_detail) { + return false; + } #endif - } else if (strcmp(option_line, "=off") != 0) { - vm_exit_during_initialization("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]", NULL); - } -} - -// first phase of bootstrapping, when VM is still in single-threaded mode. -void MemTracker::bootstrap_single_thread() { - if (_tracking_level > NMT_off) { - assert(_state == NMT_uninited, "wrong state"); - - // NMT is not supported with UseMallocOnly is on. NMT can NOT - // handle the amount of malloc data without significantly impacting - // runtime performance when this flag is on. - if (UseMallocOnly) { - shutdown(NMT_use_malloc_only); - return; + } else if (strcmp(value, "=summary") == 0) { + if (MemTracker::tracking_level() != NMT_summary) { + return false; } - - _query_lock = new (std::nothrow) Mutex(Monitor::max_nonleaf, "NMT_queryLock"); - if (_query_lock == NULL) { - shutdown(NMT_out_of_memory); - return; + } else if (strcmp(value, "=off") == 0) { + if (MemTracker::tracking_level() != NMT_off) { + return false; } - - debug_only(_main_thread_tid = os::current_thread_id();) - _state = NMT_bootstrapping_single_thread; - NMT_track_callsite = (_tracking_level == NMT_detail && can_walk_stack()); - } -} - -// second phase of bootstrapping, when VM is about to or already entered multi-theaded mode. -void MemTracker::bootstrap_multi_thread() { - if (_tracking_level > NMT_off && _state == NMT_bootstrapping_single_thread) { - // create nmt lock for multi-thread execution - assert(_main_thread_tid == os::current_thread_id(), "wrong thread"); - _state = NMT_bootstrapping_multi_thread; - NMT_track_callsite = (_tracking_level == NMT_detail && can_walk_stack()); - } -} - -// fully start nmt -void MemTracker::start() { - // Native memory tracking is off from command line option - if (_tracking_level == NMT_off || shutdown_in_progress()) return; - - assert(_main_thread_tid == os::current_thread_id(), "wrong thread"); - assert(_state == NMT_bootstrapping_multi_thread, "wrong state"); - - _snapshot = new (std::nothrow)MemSnapshot(); - if (_snapshot != NULL) { - if (!_snapshot->out_of_memory() && start_worker(_snapshot)) { - _state = NMT_started; - NMT_track_callsite = (_tracking_level == NMT_detail && can_walk_stack()); - return; - } - - delete _snapshot; - _snapshot = NULL; - } - - // fail to start native memory tracking, shut it down - shutdown(NMT_initialization); -} - -/** - * Shutting down native memory tracking. - * We can not shutdown native memory tracking immediately, so we just - * setup shutdown pending flag, every native memory tracking component - * should orderly shut itself down. - * - * The shutdown sequences: - * 1. MemTracker::shutdown() sets MemTracker to shutdown pending state - * 2. Worker thread calls MemTracker::final_shutdown(), which transites - * MemTracker to final shutdown state. - * 3. At sync point, MemTracker does final cleanup, before sets memory - * tracking level to off to complete shutdown. - */ -void MemTracker::shutdown(ShutdownReason reason) { - if (_tracking_level == NMT_off) return; - - if (_state <= NMT_bootstrapping_single_thread) { - // we still in single thread mode, there is not contention - _state = NMT_shutdown_pending; - _reason = reason; } else { - // we want to know who initialized shutdown - if ((jint)NMT_started == Atomic::cmpxchg((jint)NMT_shutdown_pending, - (jint*)&_state, (jint)NMT_started)) { - _reason = reason; - } - } -} - -// final phase of shutdown -void MemTracker::final_shutdown() { - // delete all pending recorders and pooled recorders - delete_all_pending_recorders(); - delete_all_pooled_recorders(); - - { - // shared baseline and snapshot are the only objects needed to - // create query results - MutexLockerEx locker(_query_lock, true); - // cleanup baseline data and snapshot - _baseline.clear(); - delete _snapshot; - _snapshot = NULL; + _is_nmt_env_valid = false; } - // shutdown shared decoder instance, since it is only - // used by native memory tracking so far. - Decoder::shutdown(); - - MemTrackWorker* worker = NULL; - { - ThreadCritical tc; - // can not delete worker inside the thread critical - if (_worker_thread != NULL && Thread::current() == _worker_thread) { - worker = _worker_thread; - _worker_thread = NULL; - } - } - if (worker != NULL) { - delete worker; - } - _state = NMT_final_shutdown; -} - -// delete all pooled recorders -void MemTracker::delete_all_pooled_recorders() { - // free all pooled recorders - MemRecorder* volatile cur_head = _pooled_recorders; - if (cur_head != NULL) { - MemRecorder* null_ptr = NULL; - while (cur_head != NULL && (void*)cur_head != Atomic::cmpxchg_ptr((void*)null_ptr, - (void*)&_pooled_recorders, (void*)cur_head)) { - cur_head = _pooled_recorders; - } - if (cur_head != NULL) { - delete cur_head; - _pooled_recorder_count = 0; - } - } -} - -// delete all recorders in pending queue -void MemTracker::delete_all_pending_recorders() { - // free all pending recorders - MemRecorder* pending_head = get_pending_recorders(); - if (pending_head != NULL) { - delete pending_head; - } -} - -/* - * retrieve per-thread recorder of specified thread. - * if thread == NULL, it means global recorder - */ -MemRecorder* MemTracker::get_thread_recorder(JavaThread* thread) { - if (shutdown_in_progress()) return NULL; - - MemRecorder* rc; - if (thread == NULL) { - rc = _global_recorder; - } else { - rc = thread->get_recorder(); - } - - if (rc != NULL && rc->is_full()) { - enqueue_pending_recorder(rc); - rc = NULL; - } - - if (rc == NULL) { - rc = get_new_or_pooled_instance(); - if (thread == NULL) { - _global_recorder = rc; - } else { - thread->set_recorder(rc); - } - } - return rc; -} - -/* - * get a per-thread recorder from pool, or create a new one if - * there is not one available. - */ -MemRecorder* MemTracker::get_new_or_pooled_instance() { - MemRecorder* cur_head = const_cast (_pooled_recorders); - if (cur_head == NULL) { - MemRecorder* rec = new (std::nothrow)MemRecorder(); - if (rec == NULL || rec->out_of_memory()) { - shutdown(NMT_out_of_memory); - if (rec != NULL) { - delete rec; - rec = NULL; - } - } - return rec; - } else { - MemRecorder* next_head = cur_head->next(); - if ((void*)cur_head != Atomic::cmpxchg_ptr((void*)next_head, (void*)&_pooled_recorders, - (void*)cur_head)) { - return get_new_or_pooled_instance(); - } - cur_head->set_next(NULL); - Atomic::dec(&_pooled_recorder_count); - cur_head->set_generation(); - return cur_head; - } -} - -/* - * retrieve all recorders in pending queue, and empty the queue - */ -MemRecorder* MemTracker::get_pending_recorders() { - MemRecorder* cur_head = const_cast(_merge_pending_queue); - MemRecorder* null_ptr = NULL; - while ((void*)cur_head != Atomic::cmpxchg_ptr((void*)null_ptr, (void*)&_merge_pending_queue, - (void*)cur_head)) { - cur_head = const_cast(_merge_pending_queue); - } - NOT_PRODUCT(Atomic::store(0, &_pending_recorder_count)); - return cur_head; -} - -/* - * release a recorder to recorder pool. - */ -void MemTracker::release_thread_recorder(MemRecorder* rec) { - assert(rec != NULL, "null recorder"); - // we don't want to pool too many recorders - rec->set_next(NULL); - if (shutdown_in_progress() || _pooled_recorder_count > _thread_count * 2) { - delete rec; - return; - } - - rec->clear(); - MemRecorder* cur_head = const_cast(_pooled_recorders); - rec->set_next(cur_head); - while ((void*)cur_head != Atomic::cmpxchg_ptr((void*)rec, (void*)&_pooled_recorders, - (void*)cur_head)) { - cur_head = const_cast(_pooled_recorders); - rec->set_next(cur_head); - } - Atomic::inc(&_pooled_recorder_count); -} - -// write a record to proper recorder. No lock can be taken from this method -// down. -void MemTracker::write_tracking_record(address addr, MEMFLAGS flags, - size_t size, jint seq, address pc, JavaThread* thread) { - - MemRecorder* rc = get_thread_recorder(thread); - if (rc != NULL) { - rc->record(addr, flags, size, seq, pc); - } -} - -/** - * enqueue a recorder to pending queue - */ -void MemTracker::enqueue_pending_recorder(MemRecorder* rec) { - assert(rec != NULL, "null recorder"); - - // we are shutting down, so just delete it - if (shutdown_in_progress()) { - rec->set_next(NULL); - delete rec; - return; - } - - MemRecorder* cur_head = const_cast(_merge_pending_queue); - rec->set_next(cur_head); - while ((void*)cur_head != Atomic::cmpxchg_ptr((void*)rec, (void*)&_merge_pending_queue, - (void*)cur_head)) { - cur_head = const_cast(_merge_pending_queue); - rec->set_next(cur_head); - } - NOT_PRODUCT(Atomic::inc(&_pending_recorder_count);) -} - -/* - * The method is called at global safepoint - * during it synchronization process. - * 1. enqueue all JavaThreads' per-thread recorders - * 2. enqueue global recorder - * 3. retrieve all pending recorders - * 4. reset global sequence number generator - * 5. call worker's sync - */ -#define MAX_SAFEPOINTS_TO_SKIP 128 -#define SAFE_SEQUENCE_THRESHOLD 30 -#define HIGH_GENERATION_THRESHOLD 60 -#define MAX_RECORDER_THREAD_RATIO 30 -#define MAX_RECORDER_PER_THREAD 100 - -void MemTracker::sync() { - assert(_tracking_level > NMT_off, "NMT is not enabled"); - assert(SafepointSynchronize::is_at_safepoint(), "Safepoint required"); - - // Some GC tests hit large number of safepoints in short period of time - // without meaningful activities. We should prevent going to - // sync point in these cases, which can potentially exhaust generation buffer. - // Here is the factots to determine if we should go into sync point: - // 1. not to overflow sequence number - // 2. if we are in danger to overflow generation buffer - // 3. how many safepoints we already skipped sync point - if (_state == NMT_started) { - // worker thread is not ready, no one can manage generation - // buffer, so skip this safepoint - if (_worker_thread == NULL) return; - - if (_sync_point_skip_count < MAX_SAFEPOINTS_TO_SKIP) { - int per_seq_in_use = SequenceGenerator::peek() * 100 / max_jint; - int per_gen_in_use = _worker_thread->generations_in_use() * 100 / MAX_GENERATIONS; - if (per_seq_in_use < SAFE_SEQUENCE_THRESHOLD && per_gen_in_use >= HIGH_GENERATION_THRESHOLD) { - _sync_point_skip_count ++; - return; - } - } - { - // This method is running at safepoint, with ThreadCritical lock, - // it should guarantee that NMT is fully sync-ed. - ThreadCritical tc; - - // We can NOT execute NMT sync-point if there are pending tracking ops. - if (_pending_op_count == 0) { - SequenceGenerator::reset(); - _sync_point_skip_count = 0; - - // walk all JavaThreads to collect recorders - SyncThreadRecorderClosure stc; - Threads::threads_do(&stc); - - _thread_count = stc.get_thread_count(); - MemRecorder* pending_recorders = get_pending_recorders(); - - if (_global_recorder != NULL) { - _global_recorder->set_next(pending_recorders); - pending_recorders = _global_recorder; - _global_recorder = NULL; - } - - // see if NMT has too many outstanding recorder instances, it usually - // means that worker thread is lagging behind in processing them. - if (!AutoShutdownNMT) { - _slowdown_calling_thread = (MemRecorder::_instance_count > MAX_RECORDER_THREAD_RATIO * _thread_count); - } else { - // If auto shutdown is on, enforce MAX_RECORDER_PER_THREAD threshold to prevent OOM - if (MemRecorder::_instance_count >= _thread_count * MAX_RECORDER_PER_THREAD) { - shutdown(NMT_out_of_memory); - } - } - - // check _worker_thread with lock to avoid racing condition - if (_worker_thread != NULL) { - _worker_thread->at_sync_point(pending_recorders, InstanceKlass::number_of_instance_classes()); - } - assert(SequenceGenerator::peek() == 1, "Should not have memory activities during sync-point"); - } else { - _sync_point_skip_count ++; - } - } - } - - // now, it is the time to shut whole things off - if (_state == NMT_final_shutdown) { - // walk all JavaThreads to delete all recorders - SyncThreadRecorderClosure stc; - Threads::threads_do(&stc); - // delete global recorder - { - ThreadCritical tc; - if (_global_recorder != NULL) { - delete _global_recorder; - _global_recorder = NULL; - } - } - MemRecorder* pending_recorders = get_pending_recorders(); - if (pending_recorders != NULL) { - delete pending_recorders; - } - // try at a later sync point to ensure MemRecorder instance drops to zero to - // completely shutdown NMT - if (MemRecorder::_instance_count == 0) { - _state = NMT_shutdown; - _tracking_level = NMT_off; - } - } -} - -/* - * Start worker thread. - */ -bool MemTracker::start_worker(MemSnapshot* snapshot) { - assert(_worker_thread == NULL && _snapshot != NULL, "Just Check"); - _worker_thread = new (std::nothrow) MemTrackWorker(snapshot); - if (_worker_thread == NULL) { - return false; - } else if (_worker_thread->has_error()) { - delete _worker_thread; - _worker_thread = NULL; - return false; - } - _worker_thread->start(); return true; } -/* - * We need to collect a JavaThread's per-thread recorder - * before it exits. - */ -void MemTracker::thread_exiting(JavaThread* thread) { - if (is_on()) { - MemRecorder* rec = thread->get_recorder(); - if (rec != NULL) { - enqueue_pending_recorder(rec); - thread->set_recorder(NULL); +bool MemTracker::verify_nmt_option() { + return _is_nmt_env_valid; +} + +void* MemTracker::malloc_base(void* memblock) { + return MallocTracker::get_base(memblock); +} + +void Tracker::record(address addr, size_t size) { + if (MemTracker::tracking_level() < NMT_summary) return; + switch(_type) { + case uncommit: + VirtualMemoryTracker::remove_uncommitted_region(addr, size); + break; + case release: + VirtualMemoryTracker::remove_released_region(addr, size); + break; + default: + ShouldNotReachHere(); + } +} + + +// Shutdown can only be issued via JCmd, and NMT JCmd is serialized +// by lock +void MemTracker::shutdown() { + // We can only shutdown NMT to minimal tracking level if it is + // ever on. + if (tracking_level () > NMT_minimal) { + transition_to(NMT_minimal); + } +} + +bool MemTracker::transition_to(NMT_TrackingLevel level) { + NMT_TrackingLevel current_level = tracking_level(); + + if (current_level == level) { + return true; + } else if (current_level > level) { + // Downgrade tracking level, we want to lower the tracking + // level first + _tracking_level = level; + // Make _tracking_level visible immediately. + OrderAccess::fence(); + VirtualMemoryTracker::transition(current_level, level); + MallocTracker::transition(current_level, level); + + if (level == NMT_minimal) _baseline.reset(); + } else { + VirtualMemoryTracker::transition(current_level, level); + MallocTracker::transition(current_level, level); + + _tracking_level = level; + // Make _tracking_level visible immediately. + OrderAccess::fence(); + } + + return true; +} + +void MemTracker::final_report(outputStream* output) { + assert(output != NULL, "No output stream"); + if (tracking_level() >= NMT_summary) { + MallocMemorySnapshot* malloc_memory_snapshot = + MallocMemorySummary::as_snapshot(); + malloc_memory_snapshot->make_adjustment(); + + VirtualMemorySnapshot* virtual_memory_snapshot = + VirtualMemorySummary::as_snapshot(); + + MemSummaryReporter rptr(malloc_memory_snapshot, + virtual_memory_snapshot, output); + rptr.report(); + // shutdown NMT, the data no longer accurate + shutdown(); + } +} + +// This is a walker to gather malloc site hashtable statistics, +// the result is used for tuning. +class StatisticsWalker : public MallocSiteWalker { + private: + enum Threshold { + // aggregates statistics over this threshold into one + // line item. + report_threshold = 20 + }; + + private: + // Number of allocation sites that have all memory freed + int _empty_entries; + // Total number of allocation sites, include empty sites + int _total_entries; + // Number of captured call stack distribution + int _stack_depth_distribution[NMT_TrackingStackDepth]; + // Hash distribution + int _hash_distribution[report_threshold]; + // Number of hash buckets that have entries over the threshold + int _bucket_over_threshold; + + // The hash bucket that walker is currently walking + int _current_hash_bucket; + // The length of current hash bucket + int _current_bucket_length; + // Number of hash buckets that are not empty + int _used_buckets; + // Longest hash bucket length + int _longest_bucket_length; + + public: + StatisticsWalker() : _empty_entries(0), _total_entries(0) { + int index = 0; + for (index = 0; index < NMT_TrackingStackDepth; index ++) { + _stack_depth_distribution[index] = 0; } + for (index = 0; index < report_threshold; index ++) { + _hash_distribution[index] = 0; + } + _bucket_over_threshold = 0; + _longest_bucket_length = 0; + _current_hash_bucket = -1; + _current_bucket_length = 0; + _used_buckets = 0; } -} -// baseline current memory snapshot -bool MemTracker::baseline() { - MutexLocker lock(_query_lock); - MemSnapshot* snapshot = get_snapshot(); - if (snapshot != NULL) { - return _baseline.baseline(*snapshot, false); - } - return false; -} + virtual bool do_malloc_site(const MallocSite* e) { + if (e->size() == 0) _empty_entries ++; + _total_entries ++; -// print memory usage from current snapshot -bool MemTracker::print_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) { - MemBaseline baseline; - MutexLocker lock(_query_lock); - MemSnapshot* snapshot = get_snapshot(); - if (snapshot != NULL && baseline.baseline(*snapshot, summary_only)) { - BaselineReporter reporter(out, unit); - reporter.report_baseline(baseline, summary_only); + // stack depth distrubution + int frames = e->call_stack()->frames(); + _stack_depth_distribution[frames - 1] ++; + + // hash distribution + int hash_bucket = e->hash() % MallocSiteTable::hash_buckets(); + if (_current_hash_bucket == -1) { + _current_hash_bucket = hash_bucket; + _current_bucket_length = 1; + } else if (_current_hash_bucket == hash_bucket) { + _current_bucket_length ++; + } else { + record_bucket_length(_current_bucket_length); + _current_hash_bucket = hash_bucket; + _current_bucket_length = 1; + } return true; } - return false; -} -// Whitebox API for blocking until the current generation of NMT data has been merged -bool MemTracker::wbtest_wait_for_data_merge() { - // NMT can't be shutdown while we're holding _query_lock - MutexLocker lock(_query_lock); - assert(_worker_thread != NULL, "Invalid query"); - // the generation at query time, so NMT will spin till this generation is processed - unsigned long generation_at_query_time = SequenceGenerator::current_generation(); - unsigned long current_processing_generation = _processing_generation; - // if generation counter overflown - bool generation_overflown = (generation_at_query_time < current_processing_generation); - long generations_to_wrap = MAX_UNSIGNED_LONG - current_processing_generation; - // spin - while (!shutdown_in_progress()) { - if (!generation_overflown) { - if (current_processing_generation > generation_at_query_time) { - return true; + // walk completed + void completed() { + record_bucket_length(_current_bucket_length); + } + + void report_statistics(outputStream* out) { + int index; + out->print_cr("Malloc allocation site table:"); + out->print_cr("\tTotal entries: %d", _total_entries); + out->print_cr("\tEmpty entries: %d (%2.2f%%)", _empty_entries, ((float)_empty_entries * 100) / _total_entries); + out->print_cr(" "); + out->print_cr("Hash distribution:"); + if (_used_buckets < MallocSiteTable::hash_buckets()) { + out->print_cr("empty bucket: %d", (MallocSiteTable::hash_buckets() - _used_buckets)); + } + for (index = 0; index < report_threshold; index ++) { + if (_hash_distribution[index] != 0) { + if (index == 0) { + out->print_cr(" %d entry: %d", 1, _hash_distribution[0]); + } else if (index < 9) { // single digit + out->print_cr(" %d entries: %d", (index + 1), _hash_distribution[index]); + } else { + out->print_cr(" %d entries: %d", (index + 1), _hash_distribution[index]); + } } + } + if (_bucket_over_threshold > 0) { + out->print_cr(" >%d entries: %d", report_threshold, _bucket_over_threshold); + } + out->print_cr("most entries: %d", _longest_bucket_length); + out->print_cr(" "); + out->print_cr("Call stack depth distribution:"); + for (index = 0; index < NMT_TrackingStackDepth; index ++) { + if (_stack_depth_distribution[index] > 0) { + out->print_cr("\t%d: %d", index + 1, _stack_depth_distribution[index]); + } + } + } + + private: + void record_bucket_length(int length) { + _used_buckets ++; + if (length <= report_threshold) { + _hash_distribution[length - 1] ++; } else { - assert(generations_to_wrap >= 0, "Sanity check"); - long current_generations_to_wrap = MAX_UNSIGNED_LONG - current_processing_generation; - assert(current_generations_to_wrap >= 0, "Sanity check"); - // to overflow an unsigned long should take long time, so to_wrap check should be sufficient - if (current_generations_to_wrap > generations_to_wrap && - current_processing_generation > generation_at_query_time) { - return true; - } + _bucket_over_threshold ++; } - - // if worker thread is idle, but generation is not advancing, that means - // there is not safepoint to let NMT advance generation, force one. - if (_worker_thread_idle) { - VM_ForceSafepoint vfs; - VMThread::execute(&vfs); - } - MemSnapshot* snapshot = get_snapshot(); - if (snapshot == NULL) { - return false; - } - snapshot->wait(1000); - current_processing_generation = _processing_generation; - } - // We end up here if NMT is shutting down before our data has been merged - return false; -} - -// compare memory usage between current snapshot and baseline -bool MemTracker::compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) { - MutexLocker lock(_query_lock); - if (_baseline.baselined()) { - MemBaseline baseline; - MemSnapshot* snapshot = get_snapshot(); - if (snapshot != NULL && baseline.baseline(*snapshot, summary_only)) { - BaselineReporter reporter(out, unit); - reporter.diff_baselines(baseline, _baseline, summary_only); - return true; - } - } - return false; -} - -#ifndef PRODUCT -void MemTracker::walk_stack(int toSkip, char* buf, int len) { - int cur_len = 0; - char tmp[1024]; - address pc; - - while (cur_len < len) { - pc = os::get_caller_pc(toSkip + 1); - if (pc != NULL && os::dll_address_to_function_name(pc, tmp, sizeof(tmp), NULL)) { - jio_snprintf(&buf[cur_len], (len - cur_len), "%s\n", tmp); - cur_len = (int)strlen(buf); - } else { - buf[cur_len] = '\0'; - break; - } - toSkip ++; - } -} - -void MemTracker::print_tracker_stats(outputStream* st) { - st->print_cr("\nMemory Tracker Stats:"); - st->print_cr("\tMax sequence number = %d", SequenceGenerator::max_seq_num()); - st->print_cr("\tthead count = %d", _thread_count); - st->print_cr("\tArena instance = %d", Arena::_instance_count); - st->print_cr("\tpooled recorder count = %d", _pooled_recorder_count); - st->print_cr("\tqueued recorder count = %d", _pending_recorder_count); - st->print_cr("\tmemory recorder instance count = %d", MemRecorder::_instance_count); - if (_worker_thread != NULL) { - st->print_cr("\tWorker thread:"); - st->print_cr("\t\tSync point count = %d", _worker_thread->_sync_point_count); - st->print_cr("\t\tpending recorder count = %d", _worker_thread->count_pending_recorders()); - st->print_cr("\t\tmerge count = %d", _worker_thread->_merge_count); - } else { - st->print_cr("\tWorker thread is not started"); - } - st->print_cr(" "); - - if (_snapshot != NULL) { - _snapshot->print_snapshot_stats(st); - } else { - st->print_cr("No snapshot"); - } -} -#endif - - -// Tracker Implementation - -/* - * Create a tracker. - * This is a fairly complicated constructor, as it has to make two important decisions: - * 1) Does it need to take ThreadCritical lock to write tracking record - * 2) Does it need to pre-reserve a sequence number for the tracking record - * - * The rules to determine if ThreadCritical is needed: - * 1. When nmt is in single-threaded bootstrapping mode, no lock is needed as VM - * still in single thread mode. - * 2. For all threads other than JavaThread, ThreadCritical is needed - * to write to recorders to global recorder. - * 3. For JavaThreads that are no longer visible by safepoint, also - * need to take ThreadCritical and records are written to global - * recorders, since these threads are NOT walked by Threads.do_thread(). - * 4. JavaThreads that are running in safepoint-safe states do not stop - * for safepoints, ThreadCritical lock should be taken to write - * memory records. - * 5. JavaThreads that are running in VM state do not need any lock and - * records are written to per-thread recorders. - * 6. For a thread has yet to attach VM 'Thread', they need to take - * ThreadCritical to write to global recorder. - * - * The memory operations that need pre-reserve sequence numbers: - * The memory operations that "release" memory blocks and the - * operations can fail, need to pre-reserve sequence number. They - * are realloc, uncommit and release. - * - * The reason for pre-reserve sequence number, is to prevent race condition: - * Thread 1 Thread 2 - * - * - * - * - * if Thread 2 happens to obtain the memory address Thread 1 just released, - * then NMT can mistakenly report the memory is free. - * - * Noticeably, free() does not need pre-reserve sequence number, because the call - * does not fail, so we can alway write "release" record before the memory is actaully - * freed. - * - * For realloc, uncommit and release, following coding pattern should be used: - * - * MemTracker::Tracker tkr = MemTracker::get_realloc_tracker(); - * ptr = ::realloc(...); - * if (ptr == NULL) { - * tkr.record(...) - * } else { - * tkr.discard(); - * } - * - * MemTracker::Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker(); - * if (uncommit(...)) { - * tkr.record(...); - * } else { - * tkr.discard(); - * } - * - * MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); - * if (release(...)) { - * tkr.record(...); - * } else { - * tkr.discard(); - * } - * - * Since pre-reserved sequence number is only good for the generation that it is acquired, - * when there is pending Tracker that reserved sequence number, NMT sync-point has - * to be skipped to prevent from advancing generation. This is done by inc and dec - * MemTracker::_pending_op_count, when MemTracker::_pending_op_count > 0, NMT sync-point is skipped. - * Not all pre-reservation of sequence number will increment pending op count. For JavaThreads - * that honor safepoints, safepoint can not occur during the memory operations, so the - * pre-reserved sequence number won't cross the generation boundry. - */ -MemTracker::Tracker::Tracker(MemoryOperation op, Thread* thr) { - _op = NoOp; - _seq = 0; - if (MemTracker::is_on()) { - _java_thread = NULL; - _op = op; - - // figure out if ThreadCritical lock is needed to write this operation - // to MemTracker - if (MemTracker::is_single_threaded_bootstrap()) { - thr = NULL; - } else if (thr == NULL) { - // don't use Thread::current(), since it is possible that - // the calling thread has yet to attach to VM 'Thread', - // which will result assertion failure - thr = ThreadLocalStorage::thread(); - } - - if (thr != NULL) { - // Check NMT load - MemTracker::check_NMT_load(thr); - - if (thr->is_Java_thread() && ((JavaThread*)thr)->is_safepoint_visible()) { - _java_thread = (JavaThread*)thr; - JavaThreadState state = _java_thread->thread_state(); - // JavaThreads that are safepoint safe, can run through safepoint, - // so ThreadCritical is needed to ensure no threads at safepoint create - // new records while the records are being gathered and the sequence number is changing - _need_thread_critical_lock = - SafepointSynchronize::safepoint_safe(_java_thread, state); - } else { - _need_thread_critical_lock = true; - } - } else { - _need_thread_critical_lock - = !MemTracker::is_single_threaded_bootstrap(); - } - - // see if we need to pre-reserve sequence number for this operation - if (_op == Realloc || _op == Uncommit || _op == Release) { - if (_need_thread_critical_lock) { - ThreadCritical tc; - MemTracker::inc_pending_op_count(); - _seq = SequenceGenerator::next(); - } else { - // for the threads that honor safepoints, no safepoint can occur - // during the lifespan of tracker, so we don't need to increase - // pending op count. - _seq = SequenceGenerator::next(); - } - } - } -} - -void MemTracker::Tracker::discard() { - if (MemTracker::is_on() && _seq != 0) { - if (_need_thread_critical_lock) { - ThreadCritical tc; - MemTracker::dec_pending_op_count(); - } - _seq = 0; - } -} - - -void MemTracker::Tracker::record(address old_addr, address new_addr, size_t size, - MEMFLAGS flags, address pc) { - assert(old_addr != NULL && new_addr != NULL, "Sanity check"); - assert(_op == Realloc || _op == NoOp, "Wrong call"); - if (MemTracker::is_on() && NMT_CAN_TRACK(flags) && _op != NoOp && !MemTracker::shutdown_in_progress()) { - assert(_seq > 0, "Need pre-reserve sequence number"); - if (_need_thread_critical_lock) { - ThreadCritical tc; - // free old address, use pre-reserved sequence number - MemTracker::write_tracking_record(old_addr, MemPointerRecord::free_tag(), - 0, _seq, pc, _java_thread); - MemTracker::write_tracking_record(new_addr, flags | MemPointerRecord::malloc_tag(), - size, SequenceGenerator::next(), pc, _java_thread); - // decrement MemTracker pending_op_count - MemTracker::dec_pending_op_count(); - } else { - // free old address, use pre-reserved sequence number - MemTracker::write_tracking_record(old_addr, MemPointerRecord::free_tag(), - 0, _seq, pc, _java_thread); - MemTracker::write_tracking_record(new_addr, flags | MemPointerRecord::malloc_tag(), - size, SequenceGenerator::next(), pc, _java_thread); - } - _seq = 0; - } -} - -void MemTracker::Tracker::record(address addr, size_t size, MEMFLAGS flags, address pc) { - // OOM already? - if (addr == NULL) return; - - if (MemTracker::is_on() && NMT_CAN_TRACK(flags) && _op != NoOp && !MemTracker::shutdown_in_progress()) { - bool pre_reserved_seq = (_seq != 0); - address pc = CALLER_CALLER_PC; - MEMFLAGS orig_flags = flags; - - // or the tagging flags - switch(_op) { - case Malloc: - flags |= MemPointerRecord::malloc_tag(); - break; - case Free: - flags = MemPointerRecord::free_tag(); - break; - case Realloc: - fatal("Use the other Tracker::record()"); - break; - case Reserve: - case ReserveAndCommit: - flags |= MemPointerRecord::virtual_memory_reserve_tag(); - break; - case Commit: - flags = MemPointerRecord::virtual_memory_commit_tag(); - break; - case Type: - flags |= MemPointerRecord::virtual_memory_type_tag(); - break; - case Uncommit: - assert(pre_reserved_seq, "Need pre-reserve sequence number"); - flags = MemPointerRecord::virtual_memory_uncommit_tag(); - break; - case Release: - assert(pre_reserved_seq, "Need pre-reserve sequence number"); - flags = MemPointerRecord::virtual_memory_release_tag(); - break; - case ArenaSize: - // a bit of hack here, add a small postive offset to arena - // address for its size record, so the size record is sorted - // right after arena record. - flags = MemPointerRecord::arena_size_tag(); - addr += sizeof(void*); - break; - case StackRelease: - flags = MemPointerRecord::virtual_memory_release_tag(); - break; - default: - ShouldNotReachHere(); - } - - // write memory tracking record - if (_need_thread_critical_lock) { - ThreadCritical tc; - if (_seq == 0) _seq = SequenceGenerator::next(); - MemTracker::write_tracking_record(addr, flags, size, _seq, pc, _java_thread); - if (_op == ReserveAndCommit) { - MemTracker::write_tracking_record(addr, orig_flags | MemPointerRecord::virtual_memory_commit_tag(), - size, SequenceGenerator::next(), pc, _java_thread); - } - if (pre_reserved_seq) MemTracker::dec_pending_op_count(); - } else { - if (_seq == 0) _seq = SequenceGenerator::next(); - MemTracker::write_tracking_record(addr, flags, size, _seq, pc, _java_thread); - if (_op == ReserveAndCommit) { - MemTracker::write_tracking_record(addr, orig_flags | MemPointerRecord::virtual_memory_commit_tag(), - size, SequenceGenerator::next(), pc, _java_thread); - } - } - _seq = 0; + _longest_bucket_length = MAX2(_longest_bucket_length, length); } +}; + + +void MemTracker::tuning_statistics(outputStream* out) { + // NMT statistics + StatisticsWalker walker; + MallocSiteTable::walk_malloc_site(&walker); + walker.completed(); + + out->print_cr("Native Memory Tracking Statistics:"); + out->print_cr("Malloc allocation site table size: %d", MallocSiteTable::hash_buckets()); + out->print_cr(" Tracking stack depth: %d", NMT_TrackingStackDepth); + NOT_PRODUCT(out->print_cr("Peak concurrent access: %d", MallocSiteTable::access_peak_count());) + out->print_cr(" "); + walker.report_statistics(out); } diff --git a/hotspot/src/share/vm/services/memTracker.hpp b/hotspot/src/share/vm/services/memTracker.hpp index 8573c1f6530..de43b9f2b0e 100644 --- a/hotspot/src/share/vm/services/memTracker.hpp +++ b/hotspot/src/share/vm/services/memTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -25,566 +25,288 @@ #ifndef SHARE_VM_SERVICES_MEM_TRACKER_HPP #define SHARE_VM_SERVICES_MEM_TRACKER_HPP -#include "utilities/macros.hpp" +#include "services/nmtCommon.hpp" +#include "utilities/nativeCallStack.hpp" + #if !INCLUDE_NMT -#include "utilities/ostream.hpp" +#define CURRENT_PC NativeCallStack::EMPTY_STACK +#define CALLER_PC NativeCallStack::EMPTY_STACK -class BaselineOutputer : public StackObj { - -}; - -class BaselineTTYOutputer : public BaselineOutputer { - public: - BaselineTTYOutputer(outputStream* st) { } +class Tracker : public StackObj { + public: + Tracker() { } + void record(address addr, size_t size) { } }; class MemTracker : AllStatic { - public: - enum ShutdownReason { - NMT_shutdown_none, // no shutdown requested - NMT_shutdown_user, // user requested shutdown - NMT_normal, // normal shutdown, process exit - NMT_out_of_memory, // shutdown due to out of memory - NMT_initialization, // shutdown due to initialization failure - NMT_use_malloc_only, // can not combine NMT with UseMallocOnly flag - NMT_error_reporting, // shutdown by vmError::report_and_die() - NMT_out_of_generation, // running out of generation queue - NMT_sequence_overflow // overflow the sequence number - }; + public: + static inline NMT_TrackingLevel tracking_level() { return NMT_off; } + static inline void shutdown() { } + static inline void init() { } + static bool check_launcher_nmt_support(const char* value) { return true; } + static bool verify_nmt_option() { return true; } - class Tracker { - public: - void discard() { } + static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag, + const NativeCallStack& stack, NMT_TrackingLevel level) { return mem_base; } + static inline size_t malloc_header_size(NMT_TrackingLevel level) { return 0; } + static inline size_t malloc_header_size(void* memblock) { return 0; } + static inline void* malloc_base(void* memblock) { return memblock; } + static inline void* record_free(void* memblock) { return memblock; } - void record(address addr, size_t size = 0, MEMFLAGS flags = mtNone, address pc = NULL) { } - void record(address old_addr, address new_addr, size_t size, - MEMFLAGS flags, address pc = NULL) { } - }; + static inline void record_new_arena(MEMFLAGS flag) { } + static inline void record_arena_free(MEMFLAGS flag) { } + static inline void record_arena_size_change(int diff, MEMFLAGS flag) { } + static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack, + MEMFLAGS flag = mtNone) { } + static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size, + const NativeCallStack& stack, MEMFLAGS flag = mtNone) { } + static inline void record_virtual_memory_commit(void* addr, size_t size, const NativeCallStack& stack) { } + static inline Tracker get_virtual_memory_uncommit_tracker() { return Tracker(); } + static inline Tracker get_virtual_memory_release_tracker() { } + static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { } + static inline void record_thread_stack(void* addr, size_t size) { } + static inline void release_thread_stack(void* addr, size_t size) { } - private: - static Tracker _tkr; - - - public: - static inline void init_tracking_options(const char* option_line) { } - static inline bool is_on() { return false; } - static const char* reason() { return "Native memory tracking is not implemented"; } - static inline bool can_walk_stack() { return false; } - - static inline void bootstrap_single_thread() { } - static inline void bootstrap_multi_thread() { } - static inline void start() { } - - static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, - address pc = 0, Thread* thread = NULL) { } - static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { } - static inline void record_arena_size(address addr, size_t size) { } - static inline void record_virtual_memory_reserve(address addr, size_t size, - MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { } - static inline void record_virtual_memory_reserve_and_commit(address addr, size_t size, - MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { } - static inline void record_virtual_memory_commit(address addr, size_t size, - address pc = 0, Thread* thread = NULL) { } - static inline void record_virtual_memory_release(address addr, size_t size, - Thread* thread = NULL) { } - static inline void record_virtual_memory_type(address base, MEMFLAGS flags, - Thread* thread = NULL) { } - static inline Tracker get_realloc_tracker() { return _tkr; } - static inline Tracker get_virtual_memory_uncommit_tracker() { return _tkr; } - static inline Tracker get_virtual_memory_release_tracker() { return _tkr; } - static inline bool baseline() { return false; } - static inline bool has_baseline() { return false; } - - static inline void set_autoShutdown(bool value) { } - static void shutdown(ShutdownReason reason) { } - static inline bool shutdown_in_progress() { return false; } - static bool print_memory_usage(BaselineOutputer& out, size_t unit, - bool summary_only = true) { return false; } - static bool compare_memory_usage(BaselineOutputer& out, size_t unit, - bool summary_only = true) { return false; } - - static bool wbtest_wait_for_data_merge() { return false; } - - static inline void sync() { } - static inline void thread_exiting(JavaThread* thread) { } + static void final_report(outputStream*) { } }; - -#else // !INCLUDE_NMT - -#include "memory/allocation.hpp" -#include "runtime/globals.hpp" -#include "runtime/mutex.hpp" -#include "runtime/os.hpp" -#include "runtime/thread.hpp" -#include "services/memPtr.hpp" -#include "services/memRecorder.hpp" -#include "services/memSnapshot.hpp" -#include "services/memTrackWorker.hpp" - -extern bool NMT_track_callsite; - -#ifndef MAX_UNSIGNED_LONG -#define MAX_UNSIGNED_LONG (unsigned long)(-1) -#endif - -#ifdef ASSERT - #define DEBUG_CALLER_PC (NMT_track_callsite ? os::get_caller_pc(2) : 0) #else - #define DEBUG_CALLER_PC 0 -#endif -// The thread closure walks threads to collect per-thread -// memory recorders at NMT sync point -class SyncThreadRecorderClosure : public ThreadClosure { - private: - int _thread_count; +#include "runtime/atomic.hpp" +#include "runtime/threadCritical.hpp" +#include "services/mallocTracker.hpp" +#include "services/virtualMemoryTracker.hpp" + +extern volatile bool NMT_stack_walkable; + +#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \ + NativeCallStack(0, true) : NativeCallStack::EMPTY_STACK) +#define CALLER_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \ + NativeCallStack(1, true) : NativeCallStack::EMPTY_STACK) + +class MemBaseline; +class Mutex; + +// Tracker is used for guarding 'release' semantics of virtual memory operation, to avoid +// the other thread obtains and records the same region that is just 'released' by current +// thread but before it can record the operation. +class Tracker : public StackObj { + public: + enum TrackerType { + uncommit, + release + }; public: - SyncThreadRecorderClosure() { - _thread_count =0; - } - - void do_thread(Thread* thread); - int get_thread_count() const { - return _thread_count; - } + Tracker(enum TrackerType type) : _type(type) { } + void record(address addr, size_t size); + private: + enum TrackerType _type; + // Virtual memory tracking data structures are protected by ThreadCritical lock. + ThreadCritical _tc; }; -class BaselineOutputer; -class MemSnapshot; -class MemTrackWorker; -class Thread; -/* - * MemTracker is the 'gate' class to native memory tracking runtime. - */ class MemTracker : AllStatic { - friend class GenerationData; - friend class MemTrackWorker; - friend class MemSnapshot; - friend class SyncThreadRecorderClosure; - - // NMT state - enum NMTStates { - NMT_uninited, // not yet initialized - NMT_bootstrapping_single_thread, // bootstrapping, VM is in single thread mode - NMT_bootstrapping_multi_thread, // bootstrapping, VM is about to enter multi-thread mode - NMT_started, // NMT fully started - NMT_shutdown_pending, // shutdown pending - NMT_final_shutdown, // in final phase of shutdown - NMT_shutdown // shutdown - }; - public: - class Tracker : public StackObj { - friend class MemTracker; - public: - enum MemoryOperation { - NoOp, // no op - Malloc, // malloc - Realloc, // realloc - Free, // free - Reserve, // virtual memory reserve - Commit, // virtual memory commit - ReserveAndCommit, // virtual memory reserve and commit - StackAlloc = ReserveAndCommit, // allocate thread stack - Type, // assign virtual memory type - Uncommit, // virtual memory uncommit - Release, // virtual memory release - ArenaSize, // set arena size - StackRelease // release thread stack - }; - - - protected: - Tracker(MemoryOperation op, Thread* thr = NULL); - - public: - void discard(); - - void record(address addr, size_t size = 0, MEMFLAGS flags = mtNone, address pc = NULL); - void record(address old_addr, address new_addr, size_t size, - MEMFLAGS flags, address pc = NULL); - - private: - bool _need_thread_critical_lock; - JavaThread* _java_thread; - MemoryOperation _op; // memory operation - jint _seq; // reserved sequence number - }; - - - public: - // native memory tracking level - enum NMTLevel { - NMT_off, // native memory tracking is off - NMT_summary, // don't track callsite - NMT_detail // track callsite also - }; - - enum ShutdownReason { - NMT_shutdown_none, // no shutdown requested - NMT_shutdown_user, // user requested shutdown - NMT_normal, // normal shutdown, process exit - NMT_out_of_memory, // shutdown due to out of memory - NMT_initialization, // shutdown due to initialization failure - NMT_use_malloc_only, // can not combine NMT with UseMallocOnly flag - NMT_error_reporting, // shutdown by vmError::report_and_die() - NMT_out_of_generation, // running out of generation queue - NMT_sequence_overflow // overflow the sequence number - }; - - public: - // initialize NMT tracking level from command line options, called - // from VM command line parsing code - static void init_tracking_options(const char* option_line); - - // if NMT is enabled to record memory activities - static inline bool is_on() { - return (_tracking_level >= NMT_summary && - _state >= NMT_bootstrapping_single_thread); - } - - static inline enum NMTLevel tracking_level() { + static inline NMT_TrackingLevel tracking_level() { + if (_tracking_level == NMT_unknown) { + // No fencing is needed here, since JVM is in single-threaded + // mode. + _tracking_level = init_tracking_level(); + _cmdline_tracking_level = _tracking_level; + } return _tracking_level; } - // user readable reason for shutting down NMT - static const char* reason() { - switch(_reason) { - case NMT_shutdown_none: - return "Native memory tracking is not enabled"; - case NMT_shutdown_user: - return "Native memory tracking has been shutdown by user"; - case NMT_normal: - return "Native memory tracking has been shutdown due to process exiting"; - case NMT_out_of_memory: - return "Native memory tracking has been shutdown due to out of native memory"; - case NMT_initialization: - return "Native memory tracking failed to initialize"; - case NMT_error_reporting: - return "Native memory tracking has been shutdown due to error reporting"; - case NMT_out_of_generation: - return "Native memory tracking has been shutdown due to running out of generation buffer"; - case NMT_sequence_overflow: - return "Native memory tracking has been shutdown due to overflow the sequence number"; - case NMT_use_malloc_only: - return "Native memory tracking is not supported when UseMallocOnly is on"; - default: - ShouldNotReachHere(); - return NULL; + // A late initialization, for the stuff(s) can not be + // done in init_tracking_level(), which can NOT malloc + // any memory. + static void init(); + + // Shutdown native memory tracking + static void shutdown(); + + // Verify native memory tracking command line option. + // This check allows JVM to detect if compatible launcher + // is used. + // If an incompatible launcher is used, NMT may not be + // able to start, even it is enabled by command line option. + // A warning message should be given if it is encountered. + static bool check_launcher_nmt_support(const char* value); + + // This method checks native memory tracking environment + // variable value passed by launcher. + // Launcher only obligated to pass native memory tracking + // option value, but not obligated to validate the value, + // and launcher has option to discard native memory tracking + // option from the command line once it sets up the environment + // variable, so NMT has to catch the bad value here. + static bool verify_nmt_option(); + + // Transition the tracking level to specified level + static bool transition_to(NMT_TrackingLevel level); + + static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag, + const NativeCallStack& stack, NMT_TrackingLevel level) { + return MallocTracker::record_malloc(mem_base, size, flag, stack, level); + } + + static inline size_t malloc_header_size(NMT_TrackingLevel level) { + return MallocTracker::malloc_header_size(level); + } + + static size_t malloc_header_size(void* memblock) { + if (tracking_level() != NMT_off) { + return MallocTracker::get_header_size(memblock); + } + return 0; + } + + // To malloc base address, which is the starting address + // of malloc tracking header if tracking is enabled. + // Otherwise, it returns the same address. + static void* malloc_base(void* memblock); + + // Record malloc free and return malloc base address + static inline void* record_free(void* memblock) { + return MallocTracker::record_free(memblock); + } + + + // Record creation of an arena + static inline void record_new_arena(MEMFLAGS flag) { + if (tracking_level() < NMT_summary) return; + MallocTracker::record_new_arena(flag); + } + + // Record destruction of an arena + static inline void record_arena_free(MEMFLAGS flag) { + if (tracking_level() < NMT_summary) return; + MallocTracker::record_arena_free(flag); + } + + // Record arena size change. Arena size is the size of all arena + // chuncks that backing up the arena. + static inline void record_arena_size_change(int diff, MEMFLAGS flag) { + if (tracking_level() < NMT_summary) return; + MallocTracker::record_arena_size_change(diff, flag); + } + + static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack, + MEMFLAGS flag = mtNone) { + if (tracking_level() < NMT_summary) return; + if (addr != NULL) { + ThreadCritical tc; + // Recheck to avoid potential racing during NMT shutdown + if (tracking_level() < NMT_summary) return; + VirtualMemoryTracker::add_reserved_region((address)addr, size, stack, flag); } } - // test if we can walk native stack - static bool can_walk_stack() { - // native stack is not walkable during bootstrapping on sparc -#if defined(SPARC) - return (_state == NMT_started); -#else - return (_state >= NMT_bootstrapping_single_thread && _state <= NMT_started); -#endif - } - - // if native memory tracking tracks callsite - static inline bool track_callsite() { return _tracking_level == NMT_detail; } - - // NMT automatically shuts itself down under extreme situation by default. - // When the value is set to false, NMT will try its best to stay alive, - // even it has to slow down VM. - static inline void set_autoShutdown(bool value) { - AutoShutdownNMT = value; - if (AutoShutdownNMT && _slowdown_calling_thread) { - _slowdown_calling_thread = false; + static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size, + const NativeCallStack& stack, MEMFLAGS flag = mtNone) { + if (tracking_level() < NMT_summary) return; + if (addr != NULL) { + ThreadCritical tc; + if (tracking_level() < NMT_summary) return; + VirtualMemoryTracker::add_reserved_region((address)addr, size, + stack, flag, true); } } - // shutdown native memory tracking capability. Native memory tracking - // can be shutdown by VM when it encounters low memory scenarios. - // Memory tracker should gracefully shutdown itself, and preserve the - // latest memory statistics for post morten diagnosis. - static void shutdown(ShutdownReason reason); - - // if there is shutdown requested - static inline bool shutdown_in_progress() { - return (_state >= NMT_shutdown_pending); - } - - // bootstrap native memory tracking, so it can start to collect raw data - // before worker thread can start - - // the first phase of bootstrapping, when VM still in single-threaded mode - static void bootstrap_single_thread(); - // the second phase of bootstrapping, VM is about or already in multi-threaded mode - static void bootstrap_multi_thread(); - - - // start() has to be called when VM still in single thread mode, but after - // command line option parsing is done. - static void start(); - - // record a 'malloc' call - static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, - address pc = 0, Thread* thread = NULL) { - Tracker tkr(Tracker::Malloc, thread); - tkr.record(addr, size, flags, pc); - } - // record a 'free' call - static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { - Tracker tkr(Tracker::Free, thread); - tkr.record(addr, 0, flags, DEBUG_CALLER_PC); - } - - static inline void record_arena_size(address addr, size_t size) { - Tracker tkr(Tracker::ArenaSize); - tkr.record(addr, size); - } - - // record a virtual memory 'reserve' call - static inline void record_virtual_memory_reserve(address addr, size_t size, - MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { - assert(size > 0, "Sanity check"); - Tracker tkr(Tracker::Reserve, thread); - tkr.record(addr, size, flags, pc); - } - - static inline void record_thread_stack(address addr, size_t size, Thread* thr, - address pc = 0) { - Tracker tkr(Tracker::StackAlloc, thr); - tkr.record(addr, size, mtThreadStack, pc); - } - - static inline void release_thread_stack(address addr, size_t size, Thread* thr) { - Tracker tkr(Tracker::StackRelease, thr); - tkr.record(addr, size, mtThreadStack, DEBUG_CALLER_PC); - } - - // record a virtual memory 'commit' call - static inline void record_virtual_memory_commit(address addr, size_t size, - address pc, Thread* thread = NULL) { - Tracker tkr(Tracker::Commit, thread); - tkr.record(addr, size, mtNone, pc); - } - - static inline void record_virtual_memory_reserve_and_commit(address addr, size_t size, - MEMFLAGS flags, address pc, Thread* thread = NULL) { - Tracker tkr(Tracker::ReserveAndCommit, thread); - tkr.record(addr, size, flags, pc); - } - - static inline void record_virtual_memory_release(address addr, size_t size, - Thread* thread = NULL) { - if (is_on()) { - Tracker tkr(Tracker::Release, thread); - tkr.record(addr, size); + static inline void record_virtual_memory_commit(void* addr, size_t size, + const NativeCallStack& stack) { + if (tracking_level() < NMT_summary) return; + if (addr != NULL) { + ThreadCritical tc; + if (tracking_level() < NMT_summary) return; + VirtualMemoryTracker::add_committed_region((address)addr, size, stack); } } - // record memory type on virtual memory base address - static inline void record_virtual_memory_type(address base, MEMFLAGS flags, - Thread* thread = NULL) { - Tracker tkr(Tracker::Type); - tkr.record(base, 0, flags); - } - - // Get memory trackers for memory operations that can result race conditions. - // The memory tracker has to be obtained before realloc, virtual memory uncommit - // and virtual memory release, and call tracker.record() method if operation - // succeeded, or tracker.discard() to abort the tracking. - static inline Tracker get_realloc_tracker() { - return Tracker(Tracker::Realloc); - } - static inline Tracker get_virtual_memory_uncommit_tracker() { - return Tracker(Tracker::Uncommit); + assert(tracking_level() >= NMT_summary, "Check by caller"); + return Tracker(Tracker::uncommit); } static inline Tracker get_virtual_memory_release_tracker() { - return Tracker(Tracker::Release); + assert(tracking_level() >= NMT_summary, "Check by caller"); + return Tracker(Tracker::release); } - - // create memory baseline of current memory snapshot - static bool baseline(); - // is there a memory baseline - static bool has_baseline() { - return _baseline.baselined(); - } - - // print memory usage from current snapshot - static bool print_memory_usage(BaselineOutputer& out, size_t unit, - bool summary_only = true); - // compare memory usage between current snapshot and baseline - static bool compare_memory_usage(BaselineOutputer& out, size_t unit, - bool summary_only = true); - - // the version for whitebox testing support, it ensures that all memory - // activities before this method call, are reflected in the snapshot - // database. - static bool wbtest_wait_for_data_merge(); - - // sync is called within global safepoint to synchronize nmt data - static void sync(); - - // called when a thread is about to exit - static void thread_exiting(JavaThread* thread); - - // retrieve global snapshot - static MemSnapshot* get_snapshot() { - if (shutdown_in_progress()) { - return NULL; - } - return _snapshot; - } - - // print tracker stats - NOT_PRODUCT(static void print_tracker_stats(outputStream* st);) - NOT_PRODUCT(static void walk_stack(int toSkip, char* buf, int len);) - - private: - // start native memory tracking worker thread - static bool start_worker(MemSnapshot* snapshot); - - // called by worker thread to complete shutdown process - static void final_shutdown(); - - protected: - // retrieve per-thread recorder of the specified thread. - // if the recorder is full, it will be enqueued to overflow - // queue, a new recorder is acquired from recorder pool or a - // new instance is created. - // when thread == NULL, it means global recorder - static MemRecorder* get_thread_recorder(JavaThread* thread); - - // per-thread recorder pool - static void release_thread_recorder(MemRecorder* rec); - static void delete_all_pooled_recorders(); - - // pending recorder queue. Recorders are queued to pending queue - // when they are overflowed or collected at nmt sync point. - static void enqueue_pending_recorder(MemRecorder* rec); - static MemRecorder* get_pending_recorders(); - static void delete_all_pending_recorders(); - - // write a memory tracking record in recorder - static void write_tracking_record(address addr, MEMFLAGS type, - size_t size, jint seq, address pc, JavaThread* thread); - - static bool is_single_threaded_bootstrap() { - return _state == NMT_bootstrapping_single_thread; - } - - static void check_NMT_load(Thread* thr) { - assert(thr != NULL, "Sanity check"); - if (_slowdown_calling_thread && thr != _worker_thread) { -#ifdef _WINDOWS - // On Windows, os::NakedYield() does not work as well - // as short sleep. - os::naked_short_sleep(1); -#else - os::naked_yield(); -#endif + static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { + if (tracking_level() < NMT_summary) return; + if (addr != NULL) { + ThreadCritical tc; + if (tracking_level() < NMT_summary) return; + VirtualMemoryTracker::set_reserved_region_type((address)addr, flag); } } - static void inc_pending_op_count() { - Atomic::inc(&_pending_op_count); + static inline void record_thread_stack(void* addr, size_t size) { + if (tracking_level() < NMT_summary) return; + if (addr != NULL) { + // uses thread stack malloc slot for book keeping number of threads + MallocMemorySummary::record_malloc(0, mtThreadStack); + record_virtual_memory_reserve_and_commit(addr, size, CALLER_PC, mtThreadStack); + } } - static void dec_pending_op_count() { - Atomic::dec(&_pending_op_count); - assert(_pending_op_count >= 0, "Sanity check"); + static inline void release_thread_stack(void* addr, size_t size) { + if (tracking_level() < NMT_summary) return; + if (addr != NULL) { + // uses thread stack malloc slot for book keeping number of threads + MallocMemorySummary::record_free(0, mtThreadStack); + ThreadCritical tc; + if (tracking_level() < NMT_summary) return; + VirtualMemoryTracker::remove_released_region((address)addr, size); + } } + // Query lock is used to synchronize the access to tracking data. + // So far, it is only used by JCmd query, but it may be used by + // other tools. + static inline Mutex* query_lock() { return _query_lock; } + + // Make a final report and shutdown. + // This function generates summary report without creating snapshots, + // to avoid additional memory allocation. It uses native memory summary + // counters, and makes adjustment to them, once the adjustment is made, + // the counters are no longer accurate. As the result, this function + // should only be used for final reporting before shutting down. + static void final_report(outputStream*); + + // Stored baseline + static inline MemBaseline& get_baseline() { + return _baseline; + } + + static NMT_TrackingLevel cmdline_tracking_level() { + return _cmdline_tracking_level; + } + + static void tuning_statistics(outputStream* out); private: - // retrieve a pooled memory record or create new one if there is not - // one available - static MemRecorder* get_new_or_pooled_instance(); - static void create_memory_record(address addr, MEMFLAGS type, - size_t size, address pc, Thread* thread); - static void create_record_in_recorder(address addr, MEMFLAGS type, - size_t size, address pc, JavaThread* thread); - - static void set_current_processing_generation(unsigned long generation) { - _worker_thread_idle = false; - _processing_generation = generation; - } - - static void report_worker_idle() { - _worker_thread_idle = true; - } + static NMT_TrackingLevel init_tracking_level(); private: - // global memory snapshot - static MemSnapshot* _snapshot; - - // a memory baseline of snapshot + // Tracking level + static volatile NMT_TrackingLevel _tracking_level; + // If NMT option value passed by launcher through environment + // variable is valid + static bool _is_nmt_env_valid; + // command line tracking level + static NMT_TrackingLevel _cmdline_tracking_level; + // Stored baseline static MemBaseline _baseline; - - // query lock + // Query lock static Mutex* _query_lock; - - // a thread can start to allocate memory before it is attached - // to VM 'Thread', those memory activities are recorded here. - // ThreadCritical is required to guard this global recorder. - static MemRecorder* volatile _global_recorder; - - // main thread id - debug_only(static intx _main_thread_tid;) - - // pending recorders to be merged - static MemRecorder* volatile _merge_pending_queue; - - NOT_PRODUCT(static volatile jint _pending_recorder_count;) - - // pooled memory recorders - static MemRecorder* volatile _pooled_recorders; - - // memory recorder pool management, uses following - // counter to determine if a released memory recorder - // should be pooled - - // latest thread count - static int _thread_count; - // pooled recorder count - static volatile jint _pooled_recorder_count; - - - // worker thread to merge pending recorders into snapshot - static MemTrackWorker* _worker_thread; - - // how many safepoints we skipped without entering sync point - static int _sync_point_skip_count; - - // if the tracker is properly intialized - static bool _is_tracker_ready; - // tracking level (off, summary and detail) - static enum NMTLevel _tracking_level; - - // current nmt state - static volatile enum NMTStates _state; - // the reason for shutting down nmt - static enum ShutdownReason _reason; - // the generation that NMT is processing - static volatile unsigned long _processing_generation; - // although NMT is still procesing current generation, but - // there is not more recorder to process, set idle state - static volatile bool _worker_thread_idle; - - // if NMT should slow down calling thread to allow - // worker thread to catch up - static volatile bool _slowdown_calling_thread; - - // pending memory op count. - // Certain memory ops need to pre-reserve sequence number - // before memory operation can happen to avoid race condition. - // See MemTracker::Tracker for detail - static volatile jint _pending_op_count; }; -#endif // !INCLUDE_NMT +#endif // INCLUDE_NMT #endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP + diff --git a/hotspot/src/share/vm/services/nmtCommon.cpp b/hotspot/src/share/vm/services/nmtCommon.cpp new file mode 100644 index 00000000000..0934e96dd7f --- /dev/null +++ b/hotspot/src/share/vm/services/nmtCommon.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013, 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 "services/nmtCommon.hpp" + +const char* NMTUtil::_memory_type_names[] = { + "Java Heap", + "Class", + "Thread", + "Thread Stack", + "Code", + "GC", + "Compiler", + "Internal", + "Other", + "Symbol", + "Native Memory Tracking", + "Shared class space", + "Arena Chunk", + "Test", + "Tracing", + "Unknown" +}; + + +const char* NMTUtil::scale_name(size_t scale) { + switch(scale) { + case K: return "KB"; + case M: return "MB"; + case G: return "GB"; + } + ShouldNotReachHere(); + return NULL; +} + +size_t NMTUtil::scale_from_name(const char* scale) { + assert(scale != NULL, "Null pointer check"); + if (strncmp(scale, "KB", 2) == 0 || + strncmp(scale, "kb", 2) == 0) { + return K; + } else if (strncmp(scale, "MB", 2) == 0 || + strncmp(scale, "mb", 2) == 0) { + return M; + } else if (strncmp(scale, "GB", 2) == 0 || + strncmp(scale, "gb", 2) == 0) { + return G; + } else { + return 0; // Invalid value + } + return K; +} + diff --git a/hotspot/src/share/vm/services/nmtCommon.hpp b/hotspot/src/share/vm/services/nmtCommon.hpp new file mode 100644 index 00000000000..f057484074f --- /dev/null +++ b/hotspot/src/share/vm/services/nmtCommon.hpp @@ -0,0 +1,84 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_SERVICES_NMT_COMMON_HPP +#define SHARE_VM_SERVICES_NMT_COMMON_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +#define CALC_OBJ_SIZE_IN_TYPE(obj, type) (align_size_up_(sizeof(obj), sizeof(type))/sizeof(type)) + +// Data type for memory counters +#ifdef _LP64 + typedef jlong MemoryCounterType; +#else + typedef jint MemoryCounterType; +#endif + +// Native memory tracking level +enum NMT_TrackingLevel { + NMT_unknown = 0xFF, + NMT_off = 0x00, + NMT_minimal = 0x01, + NMT_summary = 0x02, + NMT_detail = 0x03 +}; + +// Number of stack frames to capture. This is a +// build time decision. +const int NMT_TrackingStackDepth = 4; + +// A few common utilities for native memory tracking +class NMTUtil : AllStatic { + public: + // Map memory type to index + static inline int flag_to_index(MEMFLAGS flag) { + return (flag & 0xff); + } + + // Map memory type to human readable name + static const char* flag_to_name(MEMFLAGS flag) { + return _memory_type_names[flag_to_index(flag)]; + } + + // Map an index to memory type + static MEMFLAGS index_to_flag(int index) { + return (MEMFLAGS)index; + } + + // Memory size scale + static const char* scale_name(size_t scale); + static size_t scale_from_name(const char* scale); + + // Translate memory size in specified scale + static size_t amount_in_scale(size_t amount, size_t scale) { + return (amount + scale / 2) / scale; + } + private: + static const char* _memory_type_names[mt_number_of_types]; +}; + + +#endif diff --git a/hotspot/src/share/vm/services/nmtDCmd.cpp b/hotspot/src/share/vm/services/nmtDCmd.cpp index 8ced28772f3..fcad784f586 100644 --- a/hotspot/src/share/vm/services/nmtDCmd.cpp +++ b/hotspot/src/share/vm/services/nmtDCmd.cpp @@ -22,6 +22,8 @@ * */ #include "precompiled.hpp" + +#include "runtime/mutexLocker.hpp" #include "services/nmtDCmd.hpp" #include "services/memReporter.hpp" #include "services/memTracker.hpp" @@ -49,13 +51,8 @@ NMTDCmd::NMTDCmd(outputStream* output, _shutdown("shutdown", "request runtime to shutdown itself and free the " \ "memory used by runtime.", "BOOLEAN", false, "false"), - _auto_shutdown("autoShutdown", "automatically shutdown itself under " \ - "stress situation", - "BOOLEAN", true, "true"), -#ifndef PRODUCT - _debug("debug", "print tracker statistics. Debug only, not thread safe", \ + _statistics("statistics", "print tracker statistics for tuning purpose.", \ "BOOLEAN", false, "false"), -#endif _scale("scale", "Memory usage in which scale, KB, MB or GB", "STRING", false, "KB") { _dcmdparser.add_dcmd_option(&_summary); @@ -64,25 +61,30 @@ NMTDCmd::NMTDCmd(outputStream* output, _dcmdparser.add_dcmd_option(&_summary_diff); _dcmdparser.add_dcmd_option(&_detail_diff); _dcmdparser.add_dcmd_option(&_shutdown); - _dcmdparser.add_dcmd_option(&_auto_shutdown); -#ifndef PRODUCT - _dcmdparser.add_dcmd_option(&_debug); -#endif + _dcmdparser.add_dcmd_option(&_statistics); _dcmdparser.add_dcmd_option(&_scale); } + +size_t NMTDCmd::get_scale(const char* scale) const { + if (scale == NULL) return 0; + return NMTUtil::scale_from_name(scale); +} + void NMTDCmd::execute(DCmdSource source, TRAPS) { + // Check NMT state + // native memory tracking has to be on + if (MemTracker::tracking_level() == NMT_off) { + output()->print_cr("Native memory tracking is not enabled"); + return; + } else if (MemTracker::tracking_level() == NMT_minimal) { + output()->print_cr("Native memory tracking has been shutdown"); + return; + } + const char* scale_value = _scale.value(); - size_t scale_unit; - if (strcmp(scale_value, "KB") == 0 || strcmp(scale_value, "kb") == 0) { - scale_unit = K; - } else if (strcmp(scale_value, "MB") == 0 || - strcmp(scale_value, "mb") == 0) { - scale_unit = M; - } else if (strcmp(scale_value, "GB") == 0 || - strcmp(scale_value, "gb") == 0) { - scale_unit = G; - } else { + size_t scale_unit = get_scale(scale_value); + if (scale_unit == 0) { output()->print_cr("Incorrect scale value: %s", scale_value); return; } @@ -94,19 +96,11 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { if (_summary_diff.is_set() && _summary_diff.value()) { ++nopt; } if (_detail_diff.is_set() && _detail_diff.value()) { ++nopt; } if (_shutdown.is_set() && _shutdown.value()) { ++nopt; } - if (_auto_shutdown.is_set()) { ++nopt; } - -#ifndef PRODUCT - if (_debug.is_set() && _debug.value()) { ++nopt; } -#endif + if (_statistics.is_set() && _statistics.value()) { ++nopt; } if (nopt > 1) { output()->print_cr("At most one of the following option can be specified: " \ - "summary, detail, baseline, summary.diff, detail.diff, shutdown" -#ifndef PRODUCT - ", debug" -#endif - ); + "summary, detail, baseline, summary.diff, detail.diff, shutdown"); return; } else if (nopt == 0) { if (_summary.is_set()) { @@ -117,53 +111,47 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { } } -#ifndef PRODUCT - if (_debug.value()) { - output()->print_cr("debug command is NOT thread-safe, may cause crash"); - MemTracker::print_tracker_stats(output()); - return; - } -#endif - - // native memory tracking has to be on - if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { - // if it is not on, what's the reason? - output()->print_cr("%s", MemTracker::reason()); - return; - } + // Serialize NMT query + MutexLocker locker(MemTracker::query_lock()); if (_summary.value()) { - BaselineTTYOutputer outputer(output()); - MemTracker::print_memory_usage(outputer, scale_unit, true); + report(true, scale_unit); } else if (_detail.value()) { - BaselineTTYOutputer outputer(output()); - MemTracker::print_memory_usage(outputer, scale_unit, false); + if (!check_detail_tracking_level(output())) { + return; + } + report(false, scale_unit); } else if (_baseline.value()) { - if (MemTracker::baseline()) { - output()->print_cr("Successfully baselined."); + MemBaseline& baseline = MemTracker::get_baseline(); + if (!baseline.baseline(MemTracker::tracking_level() != NMT_detail)) { + output()->print_cr("Baseline failed"); } else { - output()->print_cr("Baseline failed."); + output()->print_cr("Baseline succeeded"); } } else if (_summary_diff.value()) { - if (MemTracker::has_baseline()) { - BaselineTTYOutputer outputer(output()); - MemTracker::compare_memory_usage(outputer, scale_unit, true); + MemBaseline& baseline = MemTracker::get_baseline(); + if (baseline.baseline_type() >= MemBaseline::Summary_baselined) { + report_diff(true, scale_unit); } else { - output()->print_cr("No baseline to compare, run 'baseline' command first"); + output()->print_cr("No baseline for comparison"); } } else if (_detail_diff.value()) { - if (MemTracker::has_baseline()) { - BaselineTTYOutputer outputer(output()); - MemTracker::compare_memory_usage(outputer, scale_unit, false); + if (!check_detail_tracking_level(output())) { + return; + } + MemBaseline& baseline = MemTracker::get_baseline(); + if (baseline.baseline_type() == MemBaseline::Detail_baselined) { + report_diff(false, scale_unit); } else { - output()->print_cr("No baseline to compare to, run 'baseline' command first"); + output()->print_cr("No detail baseline for comparison"); } } else if (_shutdown.value()) { - MemTracker::shutdown(MemTracker::NMT_shutdown_user); - output()->print_cr("Shutdown is in progress, it will take a few moments to " \ - "completely shutdown"); - } else if (_auto_shutdown.is_set()) { - MemTracker::set_autoShutdown(_auto_shutdown.value()); + MemTracker::shutdown(); + output()->print_cr("Native memory tracking has been turned off"); + } else if (_statistics.value()) { + if (check_detail_tracking_level(output())) { + MemTracker::tuning_statistics(output()); + } } else { ShouldNotReachHere(); output()->print_cr("Unknown command"); @@ -181,3 +169,46 @@ int NMTDCmd::num_arguments() { } } +void NMTDCmd::report(bool summaryOnly, size_t scale_unit) { + MemBaseline baseline; + if (baseline.baseline(summaryOnly)) { + if (summaryOnly) { + MemSummaryReporter rpt(baseline, output(), scale_unit); + rpt.report(); + } else { + MemDetailReporter rpt(baseline, output(), scale_unit); + rpt.report(); + } + } +} + +void NMTDCmd::report_diff(bool summaryOnly, size_t scale_unit) { + MemBaseline& early_baseline = MemTracker::get_baseline(); + assert(early_baseline.baseline_type() != MemBaseline::Not_baselined, + "Not yet baselined"); + assert(summaryOnly || early_baseline.baseline_type() == MemBaseline::Detail_baselined, + "Not a detail baseline"); + + MemBaseline baseline; + if (baseline.baseline(summaryOnly)) { + if (summaryOnly) { + MemSummaryDiffReporter rpt(early_baseline, baseline, output(), scale_unit); + rpt.report_diff(); + } else { + MemDetailDiffReporter rpt(early_baseline, baseline, output(), scale_unit); + rpt.report_diff(); + } + } +} + +bool NMTDCmd::check_detail_tracking_level(outputStream* out) { + if (MemTracker::tracking_level() == NMT_detail) { + return true; + } else if (MemTracker::cmdline_tracking_level() == NMT_detail) { + out->print_cr("Tracking level has been downgraded due to lack of resources"); + return false; + } else { + out->print_cr("Detail tracking is not enabled"); + return false; + } +} diff --git a/hotspot/src/share/vm/services/nmtDCmd.hpp b/hotspot/src/share/vm/services/nmtDCmd.hpp index 62872c63a76..df1ab367fd1 100644 --- a/hotspot/src/share/vm/services/nmtDCmd.hpp +++ b/hotspot/src/share/vm/services/nmtDCmd.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -25,8 +25,12 @@ #ifndef SHARE_VM_SERVICES_NMT_DCMD_HPP #define SHARE_VM_SERVICES_NMT_DCMD_HPP +#if INCLUDE_NMT + #include "services/diagnosticArgument.hpp" #include "services/diagnosticFramework.hpp" +#include "services/memBaseline.hpp" +#include "services/mallocTracker.hpp" /** * Native memory tracking DCmd implementation @@ -39,10 +43,7 @@ class NMTDCmd: public DCmdWithParser { DCmdArgument _summary_diff; DCmdArgument _detail_diff; DCmdArgument _shutdown; - DCmdArgument _auto_shutdown; -#ifndef PRODUCT - DCmdArgument _debug; -#endif + DCmdArgument _statistics; DCmdArgument _scale; public: @@ -61,6 +62,17 @@ class NMTDCmd: public DCmdWithParser { } static int num_arguments(); virtual void execute(DCmdSource source, TRAPS); + + private: + void report(bool summaryOnly, size_t scale); + void report_diff(bool summaryOnly, size_t scale); + + size_t get_scale(const char* scale) const; + + // check if NMT running at detail tracking level + bool check_detail_tracking_level(outputStream* out); }; +#endif // INCLUDE_NMT + #endif // SHARE_VM_SERVICES_NMT_DCMD_HPP diff --git a/hotspot/src/share/vm/services/virtualMemoryTracker.cpp b/hotspot/src/share/vm/services/virtualMemoryTracker.cpp new file mode 100644 index 00000000000..20c45363f6a --- /dev/null +++ b/hotspot/src/share/vm/services/virtualMemoryTracker.cpp @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2013, 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 "runtime/threadCritical.hpp" +#include "services/virtualMemoryTracker.hpp" + +size_t VirtualMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(VirtualMemorySnapshot, size_t)]; + +void VirtualMemorySummary::initialize() { + assert(sizeof(_snapshot) >= sizeof(VirtualMemorySnapshot), "Sanity Check"); + // Use placement operator new to initialize static data area. + ::new ((void*)_snapshot) VirtualMemorySnapshot(); +} + +SortedLinkedList* VirtualMemoryTracker::_reserved_regions; + +int compare_committed_region(const CommittedMemoryRegion& r1, const CommittedMemoryRegion& r2) { + return r1.compare(r2); +} + +int compare_reserved_region_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2) { + return r1.compare(r2); +} + +bool ReservedMemoryRegion::add_committed_region(address addr, size_t size, const NativeCallStack& stack) { + assert(addr != NULL, "Invalid address"); + assert(size > 0, "Invalid size"); + assert(contain_region(addr, size), "Not contain this region"); + + if (all_committed()) return true; + + CommittedMemoryRegion committed_rgn(addr, size, stack); + LinkedListNode* node = _committed_regions.find_node(committed_rgn); + if (node != NULL) { + CommittedMemoryRegion* rgn = node->data(); + if (rgn->same_region(addr, size)) { + return true; + } + + if (rgn->adjacent_to(addr, size)) { + // check if the next region covers this committed region, + // the regions may not be merged due to different call stacks + LinkedListNode* next = + node->next(); + if (next != NULL && next->data()->contain_region(addr, size)) { + if (next->data()->same_region(addr, size)) { + next->data()->set_call_stack(stack); + } + return true; + } + if (rgn->call_stack()->equals(stack)) { + VirtualMemorySummary::record_uncommitted_memory(rgn->size(), flag()); + // the two adjacent regions have the same call stack, merge them + rgn->expand_region(addr, size); + VirtualMemorySummary::record_committed_memory(rgn->size(), flag()); + return true; + } + VirtualMemorySummary::record_committed_memory(size, flag()); + if (rgn->base() > addr) { + return _committed_regions.insert_before(committed_rgn, node) != NULL; + } else { + return _committed_regions.insert_after(committed_rgn, node) != NULL; + } + } + assert(rgn->contain_region(addr, size), "Must cover this region"); + return true; + } else { + // New committed region + VirtualMemorySummary::record_committed_memory(size, flag()); + return add_committed_region(committed_rgn); + } +} + +void ReservedMemoryRegion::set_all_committed(bool b) { + if (all_committed() != b) { + _all_committed = b; + if (b) { + VirtualMemorySummary::record_committed_memory(size(), flag()); + } + } +} + +bool ReservedMemoryRegion::remove_uncommitted_region(LinkedListNode* node, + address addr, size_t size) { + assert(addr != NULL, "Invalid address"); + assert(size > 0, "Invalid size"); + + CommittedMemoryRegion* rgn = node->data(); + assert(rgn->contain_region(addr, size), "Has to be contained"); + assert(!rgn->same_region(addr, size), "Can not be the same region"); + + if (rgn->base() == addr || + rgn->end() == addr + size) { + rgn->exclude_region(addr, size); + return true; + } else { + // split this region + address top =rgn->end(); + // use this region for lower part + size_t exclude_size = rgn->end() - addr; + rgn->exclude_region(addr, exclude_size); + + // higher part + address high_base = addr + size; + size_t high_size = top - high_base; + + CommittedMemoryRegion high_rgn(high_base, high_size, *rgn->call_stack()); + LinkedListNode* high_node = _committed_regions.add(high_rgn); + assert(high_node == NULL || node->next() == high_node, "Should be right after"); + return (high_node != NULL); + } + + return false; +} + +bool ReservedMemoryRegion::remove_uncommitted_region(address addr, size_t sz) { + // uncommit stack guard pages + if (flag() == mtThreadStack && !same_region(addr, sz)) { + return true; + } + + assert(addr != NULL, "Invalid address"); + assert(sz > 0, "Invalid size"); + + if (all_committed()) { + assert(_committed_regions.is_empty(), "Sanity check"); + assert(contain_region(addr, sz), "Reserved region does not contain this region"); + set_all_committed(false); + VirtualMemorySummary::record_uncommitted_memory(sz, flag()); + if (same_region(addr, sz)) { + return true; + } else { + CommittedMemoryRegion rgn(base(), size(), *call_stack()); + if (rgn.base() == addr || rgn.end() == (addr + sz)) { + rgn.exclude_region(addr, sz); + return add_committed_region(rgn); + } else { + // split this region + // top of the whole region + address top =rgn.end(); + // use this region for lower part + size_t exclude_size = rgn.end() - addr; + rgn.exclude_region(addr, exclude_size); + if (add_committed_region(rgn)) { + // higher part + address high_base = addr + sz; + size_t high_size = top - high_base; + CommittedMemoryRegion high_rgn(high_base, high_size, NativeCallStack::EMPTY_STACK); + return add_committed_region(high_rgn); + } else { + return false; + } + } + } + } else { + // we have to walk whole list to remove the committed regions in + // specified range + LinkedListNode* head = + _committed_regions.head(); + LinkedListNode* prev = NULL; + VirtualMemoryRegion uncommitted_rgn(addr, sz); + + while (head != NULL && !uncommitted_rgn.is_empty()) { + CommittedMemoryRegion* crgn = head->data(); + // this committed region overlaps to region to uncommit + if (crgn->overlap_region(uncommitted_rgn.base(), uncommitted_rgn.size())) { + if (crgn->same_region(uncommitted_rgn.base(), uncommitted_rgn.size())) { + // find matched region, remove the node will do + VirtualMemorySummary::record_uncommitted_memory(uncommitted_rgn.size(), flag()); + _committed_regions.remove_after(prev); + return true; + } else if (crgn->contain_region(uncommitted_rgn.base(), uncommitted_rgn.size())) { + // this committed region contains whole uncommitted region + VirtualMemorySummary::record_uncommitted_memory(uncommitted_rgn.size(), flag()); + return remove_uncommitted_region(head, uncommitted_rgn.base(), uncommitted_rgn.size()); + } else if (uncommitted_rgn.contain_region(crgn->base(), crgn->size())) { + // this committed region has been uncommitted + size_t exclude_size = crgn->end() - uncommitted_rgn.base(); + uncommitted_rgn.exclude_region(uncommitted_rgn.base(), exclude_size); + VirtualMemorySummary::record_uncommitted_memory(crgn->size(), flag()); + LinkedListNode* tmp = head; + head = head->next(); + _committed_regions.remove_after(prev); + continue; + } else if (crgn->contain_address(uncommitted_rgn.base())) { + size_t toUncommitted = crgn->end() - uncommitted_rgn.base(); + crgn->exclude_region(uncommitted_rgn.base(), toUncommitted); + uncommitted_rgn.exclude_region(uncommitted_rgn.base(), toUncommitted); + VirtualMemorySummary::record_uncommitted_memory(toUncommitted, flag()); + } else if (uncommitted_rgn.contain_address(crgn->base())) { + size_t toUncommitted = uncommitted_rgn.end() - crgn->base(); + crgn->exclude_region(crgn->base(), toUncommitted); + uncommitted_rgn.exclude_region(uncommitted_rgn.end() - toUncommitted, + toUncommitted); + VirtualMemorySummary::record_uncommitted_memory(toUncommitted, flag()); + } + } + prev = head; + head = head->next(); + } + } + + return true; +} + +void ReservedMemoryRegion::move_committed_regions(address addr, ReservedMemoryRegion& rgn) { + assert(addr != NULL, "Invalid address"); + + // split committed regions + LinkedListNode* head = + _committed_regions.head(); + LinkedListNode* prev = NULL; + + while (head != NULL) { + if (head->data()->base() >= addr) { + break; + } + prev = head; + head = head->next(); + } + + if (head != NULL) { + if (prev != NULL) { + prev->set_next(head->next()); + } else { + _committed_regions.set_head(NULL); + } + } + + rgn._committed_regions.set_head(head); +} + +size_t ReservedMemoryRegion::committed_size() const { + if (all_committed()) { + return size(); + } else { + size_t committed = 0; + LinkedListNode* head = + _committed_regions.head(); + while (head != NULL) { + committed += head->data()->size(); + head = head->next(); + } + return committed; + } +} + +void ReservedMemoryRegion::set_flag(MEMFLAGS f) { + assert((flag() == mtNone || flag() == f), "Overwrite memory type"); + if (flag() != f) { + VirtualMemorySummary::move_reserved_memory(flag(), f, size()); + VirtualMemorySummary::move_committed_memory(flag(), f, committed_size()); + _flag = f; + } +} + +bool VirtualMemoryTracker::initialize(NMT_TrackingLevel level) { + if (level >= NMT_summary) { + VirtualMemorySummary::initialize(); + } + return true; +} + +bool VirtualMemoryTracker::late_initialize(NMT_TrackingLevel level) { + if (level >= NMT_summary) { + _reserved_regions = new (std::nothrow, ResourceObj::C_HEAP, mtNMT) + SortedLinkedList(); + return (_reserved_regions != NULL); + } + return true; +} + +bool VirtualMemoryTracker::add_reserved_region(address base_addr, size_t size, + const NativeCallStack& stack, MEMFLAGS flag, bool all_committed) { + assert(base_addr != NULL, "Invalid address"); + assert(size > 0, "Invalid size"); + assert(_reserved_regions != NULL, "Sanity check"); + ReservedMemoryRegion rgn(base_addr, size, stack, flag); + ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn); + LinkedListNode* node; + if (reserved_rgn == NULL) { + VirtualMemorySummary::record_reserved_memory(size, flag); + node = _reserved_regions->add(rgn); + if (node != NULL) { + node->data()->set_all_committed(all_committed); + return true; + } else { + return false; + } + } else { + if (reserved_rgn->same_region(base_addr, size)) { + reserved_rgn->set_call_stack(stack); + reserved_rgn->set_flag(flag); + return true; + } else if (reserved_rgn->adjacent_to(base_addr, size)) { + VirtualMemorySummary::record_reserved_memory(size, flag); + reserved_rgn->expand_region(base_addr, size); + reserved_rgn->set_call_stack(stack); + return true; + } else { + // Overlapped reservation. + // It can happen when the regions are thread stacks, as JNI + // thread does not detach from VM before exits, and leads to + // leak JavaThread object + if (reserved_rgn->flag() == mtThreadStack) { + guarantee(!CheckJNICalls, "Attached JNI thread exited without being detached"); + // Overwrite with new region + + // Release old region + VirtualMemorySummary::record_uncommitted_memory(reserved_rgn->committed_size(), reserved_rgn->flag()); + VirtualMemorySummary::record_released_memory(reserved_rgn->size(), reserved_rgn->flag()); + + // Add new region + VirtualMemorySummary::record_reserved_memory(rgn.size(), flag); + + *reserved_rgn = rgn; + return true; + } + + // CDS mapping region. + // CDS reserves the whole region for mapping CDS archive, then maps each section into the region. + // NMT reports CDS as a whole. + if (reserved_rgn->flag() == mtClassShared) { + assert(reserved_rgn->contain_region(base_addr, size), "Reserved CDS region should contain this mapping region"); + return true; + } + + ShouldNotReachHere(); + return false; + } + } +} + +void VirtualMemoryTracker::set_reserved_region_type(address addr, MEMFLAGS flag) { + assert(addr != NULL, "Invalid address"); + assert(_reserved_regions != NULL, "Sanity check"); + + ReservedMemoryRegion rgn(addr, 1); + ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn); + if (reserved_rgn != NULL) { + assert(reserved_rgn->contain_address(addr), "Containment"); + if (reserved_rgn->flag() != flag) { + assert(reserved_rgn->flag() == mtNone, "Overwrite memory type"); + reserved_rgn->set_flag(flag); + } + } +} + +bool VirtualMemoryTracker::add_committed_region(address addr, size_t size, + const NativeCallStack& stack) { + assert(addr != NULL, "Invalid address"); + assert(size > 0, "Invalid size"); + assert(_reserved_regions != NULL, "Sanity check"); + + ReservedMemoryRegion rgn(addr, size); + ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn); + + assert(reserved_rgn != NULL, "No reserved region"); + assert(reserved_rgn->contain_region(addr, size), "Not completely contained"); + return reserved_rgn->add_committed_region(addr, size, stack); +} + +bool VirtualMemoryTracker::remove_uncommitted_region(address addr, size_t size) { + assert(addr != NULL, "Invalid address"); + assert(size > 0, "Invalid size"); + assert(_reserved_regions != NULL, "Sanity check"); + + ReservedMemoryRegion rgn(addr, size); + ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn); + assert(reserved_rgn != NULL, "No reserved region"); + assert(reserved_rgn->contain_region(addr, size), "Not completely contained"); + return reserved_rgn->remove_uncommitted_region(addr, size); +} + +bool VirtualMemoryTracker::remove_released_region(address addr, size_t size) { + assert(addr != NULL, "Invalid address"); + assert(size > 0, "Invalid size"); + assert(_reserved_regions != NULL, "Sanity check"); + + ReservedMemoryRegion rgn(addr, size); + ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn); + + assert(reserved_rgn != NULL, "No reserved region"); + + // uncommit regions within the released region + if (!reserved_rgn->remove_uncommitted_region(addr, size)) { + return false; + } + + + VirtualMemorySummary::record_released_memory(size, reserved_rgn->flag()); + + if (reserved_rgn->same_region(addr, size)) { + return _reserved_regions->remove(rgn); + } else { + assert(reserved_rgn->contain_region(addr, size), "Not completely contained"); + if (reserved_rgn->base() == addr || + reserved_rgn->end() == addr + size) { + reserved_rgn->exclude_region(addr, size); + return true; + } else { + address top = reserved_rgn->end(); + address high_base = addr + size; + ReservedMemoryRegion high_rgn(high_base, top - high_base, + *reserved_rgn->call_stack(), reserved_rgn->flag()); + + // use original region for lower region + reserved_rgn->exclude_region(addr, top - addr); + LinkedListNode* new_rgn = _reserved_regions->add(high_rgn); + if (new_rgn == NULL) { + return false; + } else { + reserved_rgn->move_committed_regions(addr, *new_rgn->data()); + return true; + } + } + } +} + + +bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) { + assert(_reserved_regions != NULL, "Sanity check"); + ThreadCritical tc; + LinkedListNode* head = _reserved_regions->head(); + while (head != NULL) { + const ReservedMemoryRegion* rgn = head->peek(); + if (!walker->do_allocation_site(rgn)) { + return false; + } + head = head->next(); + } + return true; +} + +// Transition virtual memory tracking level. +bool VirtualMemoryTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) { + if (from == NMT_minimal) { + assert(to == NMT_summary || to == NMT_detail, "Just check"); + VirtualMemorySummary::reset(); + } else if (to == NMT_minimal) { + assert(from == NMT_summary || from == NMT_detail, "Just check"); + // Clean up virtual memory tracking data structures. + ThreadCritical tc; + if (_reserved_regions != NULL) { + delete _reserved_regions; + _reserved_regions = NULL; + } + } + + return true; +} + + diff --git a/hotspot/src/share/vm/services/virtualMemoryTracker.hpp b/hotspot/src/share/vm/services/virtualMemoryTracker.hpp new file mode 100644 index 00000000000..bdb686c819f --- /dev/null +++ b/hotspot/src/share/vm/services/virtualMemoryTracker.hpp @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2013, 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_SERVICES_VIRTUAL_MEMORY_TRACKER_HPP +#define SHARE_VM_SERVICES_VIRTUAL_MEMORY_TRACKER_HPP + +#if INCLUDE_NMT + +#include "memory/allocation.hpp" +#include "services/allocationSite.hpp" +#include "services/nmtCommon.hpp" +#include "utilities/linkedlist.hpp" +#include "utilities/nativeCallStack.hpp" +#include "utilities/ostream.hpp" + + +/* + * Virtual memory counter + */ +class VirtualMemory VALUE_OBJ_CLASS_SPEC { + private: + size_t _reserved; + size_t _committed; + + public: + VirtualMemory() : _reserved(0), _committed(0) { } + + inline void reserve_memory(size_t sz) { _reserved += sz; } + inline void commit_memory (size_t sz) { + _committed += sz; + assert(_committed <= _reserved, "Sanity check"); + } + + inline void release_memory (size_t sz) { + assert(_reserved >= sz, "Negative amount"); + _reserved -= sz; + } + + inline void uncommit_memory(size_t sz) { + assert(_committed >= sz, "Negative amount"); + _committed -= sz; + } + + void reset() { + _reserved = 0; + _committed = 0; + } + + inline size_t reserved() const { return _reserved; } + inline size_t committed() const { return _committed; } +}; + +// Virtual memory allocation site, keeps track where the virtual memory is reserved. +class VirtualMemoryAllocationSite : public AllocationSite { + public: + VirtualMemoryAllocationSite(const NativeCallStack& stack) : + AllocationSite(stack) { } + + inline void reserve_memory(size_t sz) { data()->reserve_memory(sz); } + inline void commit_memory (size_t sz) { data()->commit_memory(sz); } + inline void uncommit_memory(size_t sz) { data()->uncommit_memory(sz); } + inline void release_memory(size_t sz) { data()->release_memory(sz); } + inline size_t reserved() const { return peek()->reserved(); } + inline size_t committed() const { return peek()->committed(); } +}; + +class VirtualMemorySummary; + +// This class represents a snapshot of virtual memory at a given time. +// The latest snapshot is saved in a static area. +class VirtualMemorySnapshot : public ResourceObj { + friend class VirtualMemorySummary; + + private: + VirtualMemory _virtual_memory[mt_number_of_types]; + + public: + inline VirtualMemory* by_type(MEMFLAGS flag) { + int index = NMTUtil::flag_to_index(flag); + return &_virtual_memory[index]; + } + + inline VirtualMemory* by_index(int index) { + assert(index >= 0, "Index out of bound"); + assert(index < mt_number_of_types, "Index out of bound"); + return &_virtual_memory[index]; + } + + inline size_t total_reserved() const { + size_t amount = 0; + for (int index = 0; index < mt_number_of_types; index ++) { + amount += _virtual_memory[index].reserved(); + } + return amount; + } + + inline size_t total_committed() const { + size_t amount = 0; + for (int index = 0; index < mt_number_of_types; index ++) { + amount += _virtual_memory[index].committed(); + } + return amount; + } + + inline void reset() { + for (int index = 0; index < mt_number_of_types; index ++) { + _virtual_memory[index].reset(); + } + } + + void copy_to(VirtualMemorySnapshot* s) { + for (int index = 0; index < mt_number_of_types; index ++) { + s->_virtual_memory[index] = _virtual_memory[index]; + } + } +}; + +class VirtualMemorySummary : AllStatic { + public: + static void initialize(); + + static inline void record_reserved_memory(size_t size, MEMFLAGS flag) { + as_snapshot()->by_type(flag)->reserve_memory(size); + } + + static inline void record_committed_memory(size_t size, MEMFLAGS flag) { + as_snapshot()->by_type(flag)->commit_memory(size); + } + + static inline void record_uncommitted_memory(size_t size, MEMFLAGS flag) { + as_snapshot()->by_type(flag)->uncommit_memory(size); + } + + static inline void record_released_memory(size_t size, MEMFLAGS flag) { + as_snapshot()->by_type(flag)->release_memory(size); + } + + // Move virtual memory from one memory type to another. + // Virtual memory can be reserved before it is associated with a memory type, and tagged + // as 'unknown'. Once the memory is tagged, the virtual memory will be moved from 'unknown' + // type to specified memory type. + static inline void move_reserved_memory(MEMFLAGS from, MEMFLAGS to, size_t size) { + as_snapshot()->by_type(from)->release_memory(size); + as_snapshot()->by_type(to)->reserve_memory(size); + } + + static inline void move_committed_memory(MEMFLAGS from, MEMFLAGS to, size_t size) { + as_snapshot()->by_type(from)->uncommit_memory(size); + as_snapshot()->by_type(to)->commit_memory(size); + } + + static inline void snapshot(VirtualMemorySnapshot* s) { + as_snapshot()->copy_to(s); + } + + static inline void reset() { + as_snapshot()->reset(); + } + + static VirtualMemorySnapshot* as_snapshot() { + return (VirtualMemorySnapshot*)_snapshot; + } + + private: + static size_t _snapshot[CALC_OBJ_SIZE_IN_TYPE(VirtualMemorySnapshot, size_t)]; +}; + + + +/* + * A virtual memory region + */ +class VirtualMemoryRegion VALUE_OBJ_CLASS_SPEC { + private: + address _base_address; + size_t _size; + + public: + VirtualMemoryRegion(address addr, size_t size) : + _base_address(addr), _size(size) { + assert(addr != NULL, "Invalid address"); + assert(size > 0, "Invalid size"); + } + + inline address base() const { return _base_address; } + inline address end() const { return base() + size(); } + inline size_t size() const { return _size; } + + inline bool is_empty() const { return size() == 0; } + + inline bool contain_address(address addr) const { + return (addr >= base() && addr < end()); + } + + + inline bool contain_region(address addr, size_t size) const { + return contain_address(addr) && contain_address(addr + size - 1); + } + + inline bool same_region(address addr, size_t sz) const { + return (addr == base() && sz == size()); + } + + + inline bool overlap_region(address addr, size_t sz) const { + VirtualMemoryRegion rgn(addr, sz); + return contain_address(addr) || + contain_address(addr + sz - 1) || + rgn.contain_address(base()) || + rgn.contain_address(end() - 1); + } + + inline bool adjacent_to(address addr, size_t sz) const { + return (addr == end() || (addr + sz) == base()); + } + + void exclude_region(address addr, size_t sz) { + assert(contain_region(addr, sz), "Not containment"); + assert(addr == base() || addr + sz == end(), "Can not exclude from middle"); + size_t new_size = size() - sz; + + if (addr == base()) { + set_base(addr + sz); + } + set_size(new_size); + } + + void expand_region(address addr, size_t sz) { + assert(adjacent_to(addr, sz), "Not adjacent regions"); + if (base() == addr + sz) { + set_base(addr); + } + set_size(size() + sz); + } + + protected: + void set_base(address base) { + assert(base != NULL, "Sanity check"); + _base_address = base; + } + + void set_size(size_t size) { + assert(size > 0, "Sanity check"); + _size = size; + } +}; + + +class CommittedMemoryRegion : public VirtualMemoryRegion { + private: + NativeCallStack _stack; + + public: + CommittedMemoryRegion(address addr, size_t size, const NativeCallStack& stack) : + VirtualMemoryRegion(addr, size), _stack(stack) { } + + inline int compare(const CommittedMemoryRegion& rgn) const { + if (overlap_region(rgn.base(), rgn.size()) || + adjacent_to (rgn.base(), rgn.size())) { + return 0; + } else { + if (base() == rgn.base()) { + return 0; + } else if (base() > rgn.base()) { + return 1; + } else { + return -1; + } + } + } + + inline bool equals(const CommittedMemoryRegion& rgn) const { + return compare(rgn) == 0; + } + + inline void set_call_stack(const NativeCallStack& stack) { _stack = stack; } + inline const NativeCallStack* call_stack() const { return &_stack; } +}; + + +typedef LinkedListIterator CommittedRegionIterator; + +int compare_committed_region(const CommittedMemoryRegion&, const CommittedMemoryRegion&); +class ReservedMemoryRegion : public VirtualMemoryRegion { + private: + SortedLinkedList + _committed_regions; + + NativeCallStack _stack; + MEMFLAGS _flag; + + bool _all_committed; + + public: + ReservedMemoryRegion(address base, size_t size, const NativeCallStack& stack, + MEMFLAGS flag = mtNone) : + VirtualMemoryRegion(base, size), _stack(stack), _flag(flag), + _all_committed(false) { } + + + ReservedMemoryRegion(address base, size_t size) : + VirtualMemoryRegion(base, size), _stack(NativeCallStack::EMPTY_STACK), _flag(mtNone), + _all_committed(false) { } + + // Copy constructor + ReservedMemoryRegion(const ReservedMemoryRegion& rr) : + VirtualMemoryRegion(rr.base(), rr.size()) { + *this = rr; + } + + inline void set_call_stack(const NativeCallStack& stack) { _stack = stack; } + inline const NativeCallStack* call_stack() const { return &_stack; } + + void set_flag(MEMFLAGS flag); + inline MEMFLAGS flag() const { return _flag; } + + inline int compare(const ReservedMemoryRegion& rgn) const { + if (overlap_region(rgn.base(), rgn.size())) { + return 0; + } else { + if (base() == rgn.base()) { + return 0; + } else if (base() > rgn.base()) { + return 1; + } else { + return -1; + } + } + } + + inline bool equals(const ReservedMemoryRegion& rgn) const { + return compare(rgn) == 0; + } + + bool add_committed_region(address addr, size_t size, const NativeCallStack& stack); + bool remove_uncommitted_region(address addr, size_t size); + + size_t committed_size() const; + + // move committed regions that higher than specified address to + // the new region + void move_committed_regions(address addr, ReservedMemoryRegion& rgn); + + inline bool all_committed() const { return _all_committed; } + void set_all_committed(bool b); + + CommittedRegionIterator iterate_committed_regions() const { + return CommittedRegionIterator(_committed_regions.head()); + } + + ReservedMemoryRegion& operator= (const ReservedMemoryRegion& other) { + set_base(other.base()); + set_size(other.size()); + + _stack = *other.call_stack(); + _flag = other.flag(); + _all_committed = other.all_committed(); + if (other.all_committed()) { + set_all_committed(true); + } else { + CommittedRegionIterator itr = other.iterate_committed_regions(); + const CommittedMemoryRegion* rgn = itr.next(); + while (rgn != NULL) { + _committed_regions.add(*rgn); + rgn = itr.next(); + } + } + return *this; + } + + private: + // The committed region contains the uncommitted region, subtract the uncommitted + // region from this committed region + bool remove_uncommitted_region(LinkedListNode* node, + address addr, size_t sz); + + bool add_committed_region(const CommittedMemoryRegion& rgn) { + assert(rgn.base() != NULL, "Invalid base address"); + assert(size() > 0, "Invalid size"); + return _committed_regions.add(rgn) != NULL; + } +}; + +int compare_reserved_region_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2); + +class VirtualMemoryWalker : public StackObj { + public: + virtual bool do_allocation_site(const ReservedMemoryRegion* rgn) { return false; } +}; + +// Main class called from MemTracker to track virtual memory allocations, commits and releases. +class VirtualMemoryTracker : AllStatic { + public: + static bool initialize(NMT_TrackingLevel level); + + // Late phase initialization + static bool late_initialize(NMT_TrackingLevel level); + + static bool add_reserved_region (address base_addr, size_t size, const NativeCallStack& stack, + MEMFLAGS flag = mtNone, bool all_committed = false); + + static bool add_committed_region (address base_addr, size_t size, const NativeCallStack& stack); + static bool remove_uncommitted_region (address base_addr, size_t size); + static bool remove_released_region (address base_addr, size_t size); + static void set_reserved_region_type (address addr, MEMFLAGS flag); + + // Walk virtual memory data structure for creating baseline, etc. + static bool walk_virtual_memory(VirtualMemoryWalker* walker); + + static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to); + + private: + static SortedLinkedList* _reserved_regions; +}; + + +#endif // INCLUDE_NMT + +#endif // SHARE_VM_SERVICES_VIRTUAL_MEMORY_TRACKER_HPP diff --git a/hotspot/src/share/vm/shark/sharkBuilder.cpp b/hotspot/src/share/vm/shark/sharkBuilder.cpp index 34de2737d15..329a94aa83c 100644 --- a/hotspot/src/share/vm/shark/sharkBuilder.cpp +++ b/hotspot/src/share/vm/shark/sharkBuilder.cpp @@ -413,7 +413,7 @@ CallInst* SharkBuilder::CreateDump(Value* value) { const char *name; if (value->hasName()) // XXX this leaks, but it's only debug code - name = strdup(value->getName().str().c_str()); + name = os::strdup(value->getName().str().c_str()); else name = "unnamed_value"; diff --git a/hotspot/src/share/vm/utilities/bitMap.cpp b/hotspot/src/share/vm/utilities/bitMap.cpp index acb5d6d892a..865ae79e775 100644 --- a/hotspot/src/share/vm/utilities/bitMap.cpp +++ b/hotspot/src/share/vm/utilities/bitMap.cpp @@ -567,7 +567,7 @@ class TestBitMap : public AllStatic { } static void testResizeNonResource() { - const uintx bitmap_bytes = BITMAP_SIZE / BitsPerByte; + const size_t bitmap_bytes = BITMAP_SIZE / BitsPerByte; // Test the default behavior testResize(false); @@ -575,13 +575,13 @@ class TestBitMap : public AllStatic { { // Make sure that AllocatorMallocLimit is larger than our allocation request // forcing it to call standard malloc() - UIntFlagSetting fs(ArrayAllocatorMallocLimit, bitmap_bytes * 4); + SizeTFlagSetting fs(ArrayAllocatorMallocLimit, bitmap_bytes * 4); testResize(false); } { // Make sure that AllocatorMallocLimit is smaller than our allocation request // forcing it to call mmap() (or equivalent) - UIntFlagSetting fs(ArrayAllocatorMallocLimit, bitmap_bytes / 4); + SizeTFlagSetting fs(ArrayAllocatorMallocLimit, bitmap_bytes / 4); testResize(false); } } diff --git a/hotspot/src/share/vm/utilities/exceptions.cpp b/hotspot/src/share/vm/utilities/exceptions.cpp index 0759eda3789..5295c9b3608 100644 --- a/hotspot/src/share/vm/utilities/exceptions.cpp +++ b/hotspot/src/share/vm/utilities/exceptions.cpp @@ -85,9 +85,13 @@ bool Exceptions::special_exception(Thread* thread, const char* file, int line, H #endif // ASSERT if (thread->is_VM_thread() - || thread->is_Compiler_thread() ) { + || thread->is_Compiler_thread() + || DumpSharedSpaces ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object + // + // We also cannot throw a proper exception when dumping, because we cannot run + // Java bytecodes now. A dummy exception will suffice. thread->set_pending_exception(Universe::vm_exception(), file, line); return true; } @@ -108,9 +112,13 @@ bool Exceptions::special_exception(Thread* thread, const char* file, int line, S } if (thread->is_VM_thread() - || thread->is_Compiler_thread() ) { + || thread->is_Compiler_thread() + || DumpSharedSpaces ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object + // + // We also cannot throw a proper exception when dumping, because we cannot run + // Java bytecodes now. A dummy exception will suffice. thread->set_pending_exception(Universe::vm_exception(), file, line); return true; } diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 2bbd31afb76..269853ee674 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -558,6 +558,27 @@ inline double fabsd(double value) { return fabs(value); } +//---------------------------------------------------------------------------------------------------- +// Special casts +// Cast floats into same-size integers and vice-versa w/o changing bit-pattern +typedef union { + jfloat f; + jint i; +} FloatIntConv; + +typedef union { + jdouble d; + jlong l; + julong ul; +} DoubleLongConv; + +inline jint jint_cast (jfloat x) { return ((FloatIntConv*)&x)->i; } +inline jfloat jfloat_cast (jint x) { return ((FloatIntConv*)&x)->f; } + +inline jlong jlong_cast (jdouble x) { return ((DoubleLongConv*)&x)->l; } +inline julong julong_cast (jdouble x) { return ((DoubleLongConv*)&x)->ul; } +inline jdouble jdouble_cast (jlong x) { return ((DoubleLongConv*)&x)->d; } + inline jint low (jlong value) { return jint(value); } inline jint high(jlong value) { return jint(value >> 32); } diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp index 22e5d277c81..576b0235af4 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp @@ -167,17 +167,6 @@ typedef uint16_t jushort; typedef uint32_t juint; typedef uint64_t julong; -//---------------------------------------------------------------------------------------------------- -// Special (possibly not-portable) casts -// Cast floats into same-size integers and vice-versa w/o changing bit-pattern -// %%%%%% These seem like standard C++ to me--how about factoring them out? - Ungar - -inline jint jint_cast (jfloat x) { return *(jint* )&x; } -inline jlong jlong_cast (jdouble x) { return *(jlong* )&x; } -inline julong julong_cast (jdouble x) { return *(julong* )&x; } - -inline jfloat jfloat_cast (jint x) { return *(jfloat* )&x; } -inline jdouble jdouble_cast(jlong x) { return *(jdouble*)&x; } //---------------------------------------------------------------------------------------------------- // Constant for jlong (specifying an long long canstant is C++ compiler specific) diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp index e91e6078098..b64bbf8da0f 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp @@ -183,15 +183,6 @@ typedef unsigned short jushort; typedef unsigned int juint; typedef unsigned long long julong; -//---------------------------------------------------------------------------------------------------- -// Special (possibly not-portable) casts -// Cast floats into same-size integers and vice-versa w/o changing bit-pattern - -inline jint jint_cast (jfloat x) { return *(jint* )&x; } -inline jlong jlong_cast (jdouble x) { return *(jlong* )&x; } - -inline jfloat jfloat_cast (jint x) { return *(jfloat* )&x; } -inline jdouble jdouble_cast(jlong x) { return *(jdouble*)&x; } //---------------------------------------------------------------------------------------------------- // Constant for jlong (specifying an long long constant is C++ compiler specific) diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp index db22cc8ada6..46e8f9e8e93 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp @@ -116,16 +116,6 @@ typedef unsigned short jushort; typedef unsigned int juint; typedef unsigned __int64 julong; -//---------------------------------------------------------------------------------------------------- -// Special (possibly not-portable) casts -// Cast floats into same-size integers and vice-versa w/o changing bit-pattern - -inline jint jint_cast (jfloat x) { return *(jint* )&x; } -inline jlong jlong_cast (jdouble x) { return *(jlong* )&x; } - -inline jfloat jfloat_cast (jint x) { return *(jfloat* )&x; } -inline jdouble jdouble_cast(jlong x) { return *(jdouble*)&x; } - //---------------------------------------------------------------------------------------------------- // Non-standard stdlib-like stuff: diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp index 8a340062129..ad71883f81d 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp @@ -114,16 +114,6 @@ typedef uint16_t jushort; typedef uint32_t juint; typedef uint64_t julong; -//---------------------------------------------------------------------------------------------------- -// Special (possibly not-portable) casts -// Cast floats into same-size integers and vice-versa w/o changing bit-pattern -// %%%%%% These seem like standard C++ to me--how about factoring them out? - Ungar - -inline jint jint_cast (jfloat x) { return *(jint* )&x; } -inline jlong jlong_cast (jdouble x) { return *(jlong* )&x; } - -inline jfloat jfloat_cast (jint x) { return *(jfloat* )&x; } -inline jdouble jdouble_cast(jlong x) { return *(jdouble*)&x; } //---------------------------------------------------------------------------------------------------- // Constant for jlong (specifying an long long canstant is C++ compiler specific) diff --git a/hotspot/src/share/vm/utilities/linkedlist.cpp b/hotspot/src/share/vm/utilities/linkedlist.cpp new file mode 100644 index 00000000000..ba96b2e247f --- /dev/null +++ b/hotspot/src/share/vm/utilities/linkedlist.cpp @@ -0,0 +1,114 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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" + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +#include "runtime/os.hpp" +#include "utilities/linkedlist.hpp" +#include "memory/allocation.hpp" +#include "memory/allocation.inline.hpp" + +class Integer : public StackObj { + private: + int _value; + public: + Integer(int i) : _value(i) { } + + int value() const { return _value; } + bool equals(const Integer& i) const { + return _value == i.value(); + } +}; + +int compare_Integer(const Integer& i1, const Integer& i2) { + return i1.value() - i2.value(); +} + +void check_list_values(const int* expected, const LinkedList* list) { + LinkedListNode* head = list->head(); + int index = 0; + while (head != NULL) { + assert(head->peek()->value() == expected[index], "Unexpected value"); + head = head->next(); + index ++; + } +} + +void Test_linked_list() { + LinkedListImpl ll; + + + // Test regular linked list + assert(ll.is_empty(), "Start with empty list"); + Integer one(1), two(2), three(3), four(4), five(5), six(6); + + ll.add(six); + assert(!ll.is_empty(), "Should not be empty"); + + Integer* i = ll.find(six); + assert(i != NULL, "Should find it"); + + i = ll.find(three); + assert(i == NULL, "Not in the list"); + + LinkedListNode* node = ll.find_node(six); + assert(node != NULL, "6 is in the list"); + + ll.insert_after(three, node); + ll.insert_before(one, node); + int expected[3] = {1, 6, 3}; + check_list_values(expected, &ll); + + ll.add(two); + ll.add(four); + ll.add(five); + + // Test sorted linked list + SortedLinkedList sl; + assert(sl.is_empty(), "Start with empty list"); + + size_t ll_size = ll.size(); + sl.move(&ll); + size_t sl_size = sl.size(); + + assert(ll_size == sl_size, "Should be the same size"); + assert(ll.is_empty(), "No more entires"); + + // sorted result + int sorted_result[] = {1, 2, 3, 4, 5, 6}; + check_list_values(sorted_result, &sl); + + node = sl.find_node(four); + assert(node != NULL, "4 is in the list"); + sl.remove_before(node); + sl.remove_after(node); + int remains[] = {1, 2, 4, 6}; + check_list_values(remains, &sl); +} +#endif // PRODUCT + diff --git a/hotspot/src/share/vm/utilities/linkedlist.hpp b/hotspot/src/share/vm/utilities/linkedlist.hpp new file mode 100644 index 00000000000..a76c15cca0e --- /dev/null +++ b/hotspot/src/share/vm/utilities/linkedlist.hpp @@ -0,0 +1,416 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_UTILITIES_LINKED_LIST_HPP +#define SHARE_VM_UTILITIES_LINKED_LIST_HPP + +#include "memory/allocation.hpp" + +/* + * The implementation of a generic linked list, which uses various + * backing storages, such as C heap, arena and resource, etc. + */ + + +// An entry in a linked list. It should use the same backing storage +// as the linked list that contains this entry. +template class LinkedListNode : public ResourceObj { + private: + E _data; // embedded content + LinkedListNode* _next; // next entry + + protected: + LinkedListNode() : _next(NULL) { } + + public: + LinkedListNode(const E& e): _data(e), _next(NULL) { } + + inline void set_next(LinkedListNode* node) { _next = node; } + inline LinkedListNode * next() const { return _next; } + + E* data() { return &_data; } + const E* peek() const { return &_data; } +}; + +// A linked list interface. It does not specify +// any storage type it uses, so all methods involving +// memory allocation or deallocation are pure virtual +template class LinkedList : public ResourceObj { + protected: + LinkedListNode* _head; + + public: + LinkedList() : _head(NULL) { } + + inline void set_head(LinkedListNode* h) { _head = h; } + inline LinkedListNode* head() const { return _head; } + inline bool is_empty() const { return head() == NULL; } + + inline size_t size() const { + LinkedListNode* p; + size_t count = 0; + for (p = head(); p != NULL; count++, p = p->next()); + return count; + } + + // Move all entries from specified linked list to this one + virtual void move(LinkedList* list) = 0; + + // Add an entry to this linked list + virtual LinkedListNode* add(const E& e) = 0; + // Add all entries from specified linked list to this one, + virtual void add(LinkedListNode* node) = 0; + + // Add a linked list to this linked list + virtual bool add(const LinkedList* list) = 0; + + // Search entry in the linked list + virtual LinkedListNode* find_node(const E& e) = 0; + virtual E* find(const E& e) = 0; + + // Insert entry to the linked list + virtual LinkedListNode* insert_before(const E& e, LinkedListNode* ref) = 0; + virtual LinkedListNode* insert_after (const E& e, LinkedListNode* ref) = 0; + + // Remove entry from the linked list + virtual bool remove(const E& e) = 0; + virtual bool remove(LinkedListNode* node) = 0; + virtual bool remove_before(LinkedListNode* ref) = 0; + virtual bool remove_after(LinkedListNode* ref) = 0; + + LinkedListNode* unlink_head() { + LinkedListNode* h = this->head(); + if (h != NULL) { + this->set_head(h->next()); + } + return h; + } + + DEBUG_ONLY(virtual ResourceObj::allocation_type storage_type() = 0;) +}; + +// A linked list implementation. +// The linked list can be allocated in various type of memory: C heap, arena and resource area, etc. +template + class LinkedListImpl : public LinkedList { + protected: + Arena* _arena; + public: + LinkedListImpl() : _arena(NULL) { } + LinkedListImpl(Arena* a) : _arena(a) { } + + virtual ~LinkedListImpl() { + clear(); + } + + virtual void clear() { + LinkedListNode* p = this->head(); + this->set_head(NULL); + while (p != NULL) { + LinkedListNode* to_delete = p; + p = p->next(); + delete_node(to_delete); + } + } + + // Add an entry to the linked list + virtual LinkedListNode* add(const E& e) { + LinkedListNode* node = this->new_node(e); + if (node != NULL) { + this->add(node); + } + + return node; + } + + virtual void add(LinkedListNode* node) { + assert(node != NULL, "NULL pointer"); + node->set_next(this->head()); + this->set_head(node); + } + + // Move a linked list to this linked list, both have to be allocated on the same + // storage type. + virtual void move(LinkedList* list) { + assert(list->storage_type() == this->storage_type(), "Different storage type"); + LinkedListNode* node = this->head(); + while (node != NULL && node->next() != NULL) { + node = node->next(); + } + if (node == NULL) { + this->set_head(list->head()); + } else { + node->set_next(list->head()); + } + // All entries are moved + list->set_head(NULL); + } + + virtual bool add(const LinkedList* list) { + LinkedListNode* node = list->head(); + while (node != NULL) { + if (this->add(*node->peek()) == NULL) { + return false; + } + node = node->next(); + } + return true; + } + + + virtual LinkedListNode* find_node(const E& e) { + LinkedListNode* p = this->head(); + while (p != NULL && !p->peek()->equals(e)) { + p = p->next(); + } + return p; + } + + E* find(const E& e) { + LinkedListNode* node = find_node(e); + return (node == NULL) ? NULL : node->data(); + } + + + // Add an entry in front of the reference entry + LinkedListNode* insert_before(const E& e, LinkedListNode* ref_node) { + LinkedListNode* node = this->new_node(e); + if (node == NULL) return NULL; + if (ref_node == this->head()) { + node->set_next(ref_node); + this->set_head(node); + } else { + LinkedListNode* p = this->head(); + while (p != NULL && p->next() != ref_node) { + p = p->next(); + } + assert(p != NULL, "ref_node not in the list"); + node->set_next(ref_node); + p->set_next(node); + } + return node; + } + + // Add an entry behind the reference entry + LinkedListNode* insert_after(const E& e, LinkedListNode* ref_node) { + LinkedListNode* node = this->new_node(e); + if (node == NULL) return NULL; + node->set_next(ref_node->next()); + ref_node->set_next(node); + return node; + } + + // Remove an entry from the linked list. + // Return true if the entry is successfully removed + virtual bool remove(const E& e) { + LinkedListNode* tmp = this->head(); + LinkedListNode* prev = NULL; + + while (tmp != NULL) { + if (tmp->peek()->equals(e)) { + return remove_after(prev); + } + prev = tmp; + tmp = tmp->next(); + } + return false; + } + + // Remove the node after the reference entry + virtual bool remove_after(LinkedListNode* prev) { + LinkedListNode* to_delete; + if (prev == NULL) { + to_delete = this->unlink_head(); + } else { + to_delete = prev->next(); + if (to_delete != NULL) { + prev->set_next(to_delete->next()); + } + } + + if (to_delete != NULL) { + delete_node(to_delete); + return true; + } + return false; + } + + virtual bool remove(LinkedListNode* node) { + LinkedListNode* p = this->head(); + while (p != NULL && p->next() != node) { + p = p->next(); + } + if (p != NULL) { + p->set_next(node->next()); + delete_node(node); + return true; + } else { + return false; + } + } + + virtual bool remove_before(LinkedListNode* ref) { + assert(ref != NULL, "NULL pointer"); + LinkedListNode* p = this->head(); + LinkedListNode* to_delete = NULL; // to be deleted + LinkedListNode* prev = NULL; // node before the node to be deleted + while (p != NULL && p != ref) { + prev = to_delete; + to_delete = p; + p = p->next(); + } + if (p == NULL || to_delete == NULL) return false; + assert(to_delete->next() == ref, "Wrong node to delete"); + assert(prev == NULL || prev->next() == to_delete, + "Sanity check"); + if (prev == NULL) { + assert(to_delete == this->head(), "Must be head"); + this->set_head(to_delete->next()); + } else { + prev->set_next(to_delete->next()); + } + delete_node(to_delete); + return true; + } + + DEBUG_ONLY(ResourceObj::allocation_type storage_type() { return T; }) + protected: + // Create new linked list node object in specified storage + LinkedListNode* new_node(const E& e) const { + switch(T) { + case ResourceObj::ARENA: { + assert(_arena != NULL, "Arena not set"); + return new(_arena) LinkedListNode(e); + } + case ResourceObj::RESOURCE_AREA: + case ResourceObj::C_HEAP: { + if (alloc_failmode == AllocFailStrategy::RETURN_NULL) { + return new(std::nothrow, T, F) LinkedListNode(e); + } else { + return new(T, F) LinkedListNode(e); + } + } + default: + ShouldNotReachHere(); + } + return NULL; + } + + // Delete linked list node object + void delete_node(LinkedListNode* node) { + if (T == ResourceObj::C_HEAP) { + delete node; + } + } +}; + +// Sorted linked list. The linked list maintains sorting order specified by the comparison +// function +template + class SortedLinkedList : public LinkedListImpl { + public: + SortedLinkedList() { } + SortedLinkedList(Arena* a) : LinkedListImpl(a) { } + + virtual LinkedListNode* add(const E& e) { + return LinkedListImpl::add(e); + } + + virtual void move(LinkedList* list) { + assert(list->storage_type() == this->storage_type(), "Different storage type"); + LinkedListNode* node; + while ((node = list->unlink_head()) != NULL) { + this->add(node); + } + assert(list->is_empty(), "All entries are moved"); + } + + virtual void add(LinkedListNode* node) { + assert(node != NULL, "NULL pointer"); + LinkedListNode* tmp = this->head(); + LinkedListNode* prev = NULL; + + int cmp_val; + while (tmp != NULL) { + cmp_val = FUNC(*tmp->peek(), *node->peek()); + if (cmp_val >= 0) { + break; + } + prev = tmp; + tmp = tmp->next(); + } + + if (prev != NULL) { + node->set_next(prev->next()); + prev->set_next(node); + } else { + node->set_next(this->head()); + this->set_head(node); + } + } + + virtual bool add(const LinkedList* list) { + return LinkedListImpl::add(list); + } + + virtual LinkedListNode* find_node(const E& e) { + LinkedListNode* p = this->head(); + + while (p != NULL) { + int comp_val = FUNC(*p->peek(), e); + if (comp_val == 0) { + return p; + } else if (comp_val > 0) { + return NULL; + } + p = p->next(); + } + return NULL; + } +}; + +// Iterates all entries in the list +template class LinkedListIterator : public StackObj { + private: + LinkedListNode* _p; + bool _is_empty; + public: + LinkedListIterator(LinkedListNode* head) : _p(head) { + _is_empty = (head == NULL); + } + + bool is_empty() const { return _is_empty; } + + const E* next() { + if (_p == NULL) return NULL; + const E* e = _p->peek(); + _p = _p->next(); + return e; + } +}; + +#endif diff --git a/hotspot/src/share/vm/utilities/nativeCallStack.cpp b/hotspot/src/share/vm/utilities/nativeCallStack.cpp new file mode 100644 index 00000000000..aa3a1e67a5d --- /dev/null +++ b/hotspot/src/share/vm/utilities/nativeCallStack.cpp @@ -0,0 +1,119 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/nativeCallStack.hpp" + +const NativeCallStack NativeCallStack::EMPTY_STACK(0, false); + +NativeCallStack::NativeCallStack(int toSkip, bool fillStack) : + _hash_value(0) { + +#if !PLATFORM_NATIVE_STACK_WALKING_SUPPORTED + fillStack = false; +#endif + + if (fillStack) { + os::get_native_stack(_stack, NMT_TrackingStackDepth, toSkip); + } else { + for (int index = 0; index < NMT_TrackingStackDepth; index ++) { + _stack[index] = NULL; + } + } +} + +NativeCallStack::NativeCallStack(address* pc, int frameCount) { + int frameToCopy = (frameCount < NMT_TrackingStackDepth) ? + frameCount : NMT_TrackingStackDepth; + int index; + for (index = 0; index < frameToCopy; index ++) { + _stack[index] = pc[index]; + } + for (; index < NMT_TrackingStackDepth; index ++) { + _stack[index] = NULL; + } +} + +// number of stack frames captured +int NativeCallStack::frames() const { + int index; + for (index = 0; index < NMT_TrackingStackDepth; index ++) { + if (_stack[index] == NULL) { + break; + } + } + return index; +} + +// Hash code. Any better algorithm? +int NativeCallStack::hash() const { + long hash_val = _hash_value; + if (hash_val == 0) { + long pc; + int index; + for (index = 0; index < NMT_TrackingStackDepth; index ++) { + pc = (long)_stack[index]; + if (pc == 0) break; + hash_val += pc; + } + + NativeCallStack* p = const_cast(this); + p->_hash_value = (int)(hash_val & 0xFFFFFFFF); + } + return _hash_value; +} + +void NativeCallStack::print_on(outputStream* out) const { + print_on(out, 0); +} + +// Decode and print this call path +void NativeCallStack::print_on(outputStream* out, int indent) const { + address pc; + char buf[1024]; + int offset; + if (is_empty()) { + for (int index = 0; index < indent; index ++) out->print(" "); +#if PLATFORM_NATIVE_STACK_WALKING_SUPPORTED + out->print("[BOOTSTRAP]"); +#else + out->print("[No stack]"); +#endif + } else { + for (int frame = 0; frame < NMT_TrackingStackDepth; frame ++) { + pc = get_frame(frame); + if (pc == NULL) break; + // Print indent + for (int index = 0; index < indent; index ++) out->print(" "); + if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { + out->print_cr("[" PTR_FORMAT "] %s+0x%x", p2i(pc), buf, offset); + } else { + out->print_cr("[" PTR_FORMAT "]", p2i(pc)); + } + } + } +} + diff --git a/hotspot/src/share/vm/utilities/nativeCallStack.hpp b/hotspot/src/share/vm/utilities/nativeCallStack.hpp new file mode 100644 index 00000000000..b6d6a35303e --- /dev/null +++ b/hotspot/src/share/vm/utilities/nativeCallStack.hpp @@ -0,0 +1,98 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_UTILITIES_NATIVE_CALL_STACK_HPP +#define SHARE_VM_UTILITIES_NATIVE_CALL_STACK_HPP + +#include "memory/allocation.hpp" +#include "services/nmtCommon.hpp" +#include "utilities/ostream.hpp" + +/* + * This class represents a native call path (does not include Java frame) + * + * This class is developed in the context of native memory tracking, it can + * be an useful tool for debugging purpose. + * + * For example, following code should print out native call path: + * + * .... + * NativeCallStack here; + * here.print_on(tty); + * .... + * + * However, there are a couple of restrictions on this class. If the restrictions are + * not strictly followed, it may break native memory tracking badly. + * + * 1. Number of stack frames to capture, is defined by native memory tracking. + * This number has impacts on how much memory to be used by native + * memory tracking. + * 2. The class is strict stack object, no heap or virtual memory can be allocated + * from it. + */ +class NativeCallStack : public StackObj { + public: + static const NativeCallStack EMPTY_STACK; + + private: + address _stack[NMT_TrackingStackDepth]; + int _hash_value; + + public: + NativeCallStack(int toSkip = 0, bool fillStack = false); + NativeCallStack(address* pc, int frameCount); + + + // if it is an empty stack + inline bool is_empty() const { + return _stack[0] == NULL; + } + + // number of stack frames captured + int frames() const; + + inline int compare(const NativeCallStack& other) const { + return memcmp(_stack, other._stack, sizeof(_stack)); + } + + inline bool equals(const NativeCallStack& other) const { + // compare hash values + if (hash() != other.hash()) return false; + // compare each frame + return compare(other) == 0; + } + + inline address get_frame(int index) const { + assert(index >= 0 && index < NMT_TrackingStackDepth, "Index out of bound"); + return _stack[index]; + } + + // Hash code. Any better algorithm? + int hash() const; + + void print_on(outputStream* out) const; + void print_on(outputStream* out, int indent) const; +}; + +#endif diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index 59943c4b161..ceb5774fe81 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -352,6 +352,7 @@ 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; #define EXTRACHARLEN 32 @@ -463,7 +464,8 @@ static const char* make_log_name_internal(const char* log_name, const char* forc return buf; } -// log_name comes from -XX:LogFile=log_name or -Xloggc:log_name +// log_name comes from -XX:LogFile=log_name, -Xloggc:log_name or +// -XX:DumpLoadedClassList= // in log_name, %p => pid1234 and // %t => YYYY-MM-DD_HH-MM-SS static const char* make_log_name(const char* log_name, const char* force_directory) { @@ -1103,6 +1105,16 @@ void ostream_init_log() { gclog_or_tty = gclog; } +#if INCLUDE_CDS + // For -XX:DumpLoadedClassList= option + if (DumpLoadedClassList != NULL) { + const char* list_name = make_log_name(DumpLoadedClassList, NULL); + classlist_file = new(ResourceObj::C_HEAP, mtInternal) + fileStream(list_name); + FREE_C_HEAP_ARRAY(char, list_name, mtInternal); + } +#endif + // If we haven't lazily initialized the logfile yet, do it now, // to avoid the possibility of lazy initialization during a VM // crash, which can affect the stability of the fatal error handler. @@ -1115,6 +1127,11 @@ void ostream_exit() { static bool ostream_exit_called = false; if (ostream_exit_called) return; ostream_exit_called = true; +#if INCLUDE_CDS + if (classlist_file != NULL) { + delete classlist_file; + } +#endif if (gclog_or_tty != tty) { delete gclog_or_tty; } diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp index 86d8099caa9..5bf1ce43828 100644 --- a/hotspot/src/share/vm/utilities/ostream.hpp +++ b/hotspot/src/share/vm/utilities/ostream.hpp @@ -214,6 +214,8 @@ class fileStream : public outputStream { void flush(); }; +CDS_ONLY(extern fileStream* classlist_file;) + // unlike fileStream, fdStream does unbuffered I/O by calling // open() and write() directly. It is async-safe, but output // from multiple thread may be mixed together. Used by fatal diff --git a/hotspot/src/share/vm/utilities/stringUtils.cpp b/hotspot/src/share/vm/utilities/stringUtils.cpp new file mode 100644 index 00000000000..6d906249cec --- /dev/null +++ b/hotspot/src/share/vm/utilities/stringUtils.cpp @@ -0,0 +1,43 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "utilities/stringUtils.hpp" + +int StringUtils::replace_no_expand(char* string, const char* from, const char* to) { + int replace_count = 0; + size_t from_len = strlen(from); + size_t to_len = strlen(to); + assert(from_len >= to_len, "must not expand input"); + + for (char* dst = string; *dst && (dst = strstr(dst, from)) != NULL;) { + char* left_over = dst + from_len; + memmove(dst, to, to_len); // does not copy trailing 0 of + dst += to_len; // skip over the replacement. + memmove(dst, left_over, strlen(left_over) + 1); // copies the trailing 0 of + ++ replace_count; + } + + return replace_count; +} diff --git a/hotspot/src/share/vm/utilities/stringUtils.hpp b/hotspot/src/share/vm/utilities/stringUtils.hpp new file mode 100644 index 00000000000..dfae74df8cd --- /dev/null +++ b/hotspot/src/share/vm/utilities/stringUtils.hpp @@ -0,0 +1,42 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_UTILITIES_STRINGUTILS_HPP +#define SHARE_VM_UTILITIES_STRINGUTILS_HPP + +#include "memory/allocation.hpp" + +class StringUtils : AllStatic { +public: + // Replace the substring with another string . must be + // no longer than . The input string is modified in-place. + // + // Replacement is done in a single pass left-to-right. So replace_no_expand("aaa", "aa", "a") + // will result in "aa", not "a". + // + // Returns the count of substrings that have been replaced. + static int replace_no_expand(char* string, const char* from, const char* to); +}; + +#endif // SHARE_VM_UTILITIES_STRINGUTILS_HPP diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index 2bff5f5c824..3678068bed9 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -774,6 +774,11 @@ void VMError::report(outputStream* st) { st->cr(); } + STEP(228, "(Native Memory Tracking)" ) + if (_verbose) { + MemTracker::final_report(st); + } + STEP(230, "" ) if (_verbose) { @@ -897,9 +902,6 @@ void VMError::report_and_die() { static bool log_done = false; // done saving error log static bool transmit_report_done = false; // done error reporting - // disble NMT to avoid further exception - MemTracker::shutdown(MemTracker::NMT_error_reporting); - if (SuppressFatalErrorMessage) { os::abort(); } diff --git a/hotspot/test/TEST.ROOT b/hotspot/test/TEST.ROOT index e646c1aa08d..6bf9e9a9009 100644 --- a/hotspot/test/TEST.ROOT +++ b/hotspot/test/TEST.ROOT @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 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 @@ -27,6 +27,6 @@ # It also contains test-suite configuration information. # The list of keywords supported in this test suite -keys=cte_test jcmd nmt regression gc +keys=cte_test jcmd nmt regression gc stress groups=TEST.groups [closed/TEST.groups] diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index b88243644c0..4f394f62aad 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -70,21 +70,29 @@ needs_jdk = \ runtime/7194254/Test7194254.java \ runtime/Metaspace/FragmentMetaspace.java \ runtime/NMT/BaselineWithParameter.java \ + runtime/NMT/JcmdBaselineDetail.java \ + runtime/NMT/JcmdDetailDiff.java \ + runtime/NMT/JcmdScaleDetail.java \ runtime/NMT/JcmdScale.java \ + runtime/NMT/JcmdSummaryDiff.java \ runtime/NMT/JcmdWithNMTDisabled.java \ + runtime/NMT/MallocRoundingReportTest.java \ + runtime/NMT/MallocSiteHashOverflow.java \ + runtime/NMT/MallocStressTest.java \ runtime/NMT/MallocTestType.java \ runtime/NMT/ReleaseCommittedMemory.java \ + runtime/NMT/ReleaseNoCommit.java \ runtime/NMT/ShutdownTwice.java \ runtime/NMT/SummaryAfterShutdown.java \ runtime/NMT/SummarySanityCheck.java \ runtime/NMT/ThreadedMallocTestType.java \ runtime/NMT/ThreadedVirtualAllocTestType.java \ + runtime/NMT/VirtualAllocCommitUncommitRecommit.java \ runtime/NMT/VirtualAllocTestType.java \ runtime/RedefineObject/TestRedefineObject.java \ runtime/Thread/TestThreadDumpMonitorContention.java \ runtime/XCheckJniJsig/XCheckJSig.java \ serviceability/attach/AttachWithStalePidFile.java \ - serviceability/jvmti/8036666/GetObjectLockCount.java \ serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java \ serviceability/dcmd/DynLibDcmdTest.java @@ -120,16 +128,12 @@ needs_compact3 = \ gc/6581734/Test6581734.java \ gc/7072527/TestFullGCCount.java \ gc/g1/TestHumongousAllocInitialMark.java \ - gc/g1/TestHumongousShrinkHeap.java \ gc/arguments/TestG1HeapRegionSize.java \ gc/metaspace/TestMetaspaceMemoryPool.java \ gc/arguments/TestDynMinHeapFreeRatio.java \ gc/arguments/TestDynMaxHeapFreeRatio.java \ - gc/parallelScavenge/TestDynShrinkHeap.java \ runtime/InternalApi/ThreadCpuTimesDeadlock.java \ serviceability/threads/TestFalseDeadLock.java \ - serviceability/jvmti/GetObjectSizeOverflow.java \ - serviceability/jvmti/TestRedefineWithUnresolvedClass.java # Compact 2 adds full VM tests compact2 = \ @@ -217,6 +221,7 @@ needs_g1gc = \ gc/arguments/TestMaxHeapSizeTools.java \ gc/arguments/TestMaxNewSize.java \ gc/arguments/TestUseCompressedOopsErgo.java \ + gc/class_unloading/TestG1ClassUnloadingHWM.java \ gc/g1/ \ gc/metaspace/G1AddMetaspaceDependency.java \ gc/metaspace/TestMetaspacePerfCounters.java \ @@ -257,7 +262,7 @@ needs_cmsgc = \ gc/arguments/TestCMSHeapSizeFlags.java \ gc/arguments/TestMaxNewSize.java \ gc/arguments/TestUseCompressedOopsErgo.java \ - gc/class_unloading/TestCMSClassUnloadingDisabledHWM.java \ + gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java \ gc/concurrentMarkSweep/ \ gc/startup_warnings/TestCMS.java \ gc/startup_warnings/TestCMSIncrementalMode.java \ @@ -323,6 +328,21 @@ hotspot_gc = \ sanity/ExecuteInternalVMTests.java hotspot_runtime = \ + runtime/ \ + -runtime/6888954/vmerrors.sh \ + -runtime/RedefineObject/TestRedefineObject.java \ + -runtime/8003720/Test8003720.java \ + -runtime/Metaspace/FragmentMetaspace.java \ + -runtime/Metaspace/FragmentMetaspaceSimple.java \ + -runtime/Thread/TestThreadDumpMonitorContention.java \ + -runtime/SharedArchiveFile/SharedBaseAddress.java \ + -runtime/memory/ReserveMemory.java \ + -runtime/Unsafe/RangeCheck.java \ + -runtime/SharedArchiveFile/CdsSameObjectAlignment.java \ + -runtime/SharedArchiveFile/DefaultUseWithClient.java \ + -runtime/Thread/CancellableThreadTest.java + +hotspot_runtime_closed = \ sanity/ExecuteInternalVMTests.java hotspot_serviceability = \ diff --git a/hotspot/test/compiler/5091921/Test7005594.sh b/hotspot/test/compiler/5091921/Test7005594.sh index 2ca434ae876..4fa458ca723 100644 --- a/hotspot/test/compiler/5091921/Test7005594.sh +++ b/hotspot/test/compiler/5091921/Test7005594.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2011, 2013, 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 @@ -78,7 +78,7 @@ cp ${TESTSRC}/Test7005594.sh . ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7005594.java -${TESTJAVA}/bin/java ${TESTVMOPTS} -Xmx1600m -Xms1600m -XX:+IgnoreUnrecognizedVMOptions -XX:-ZapUnusedHeapArea -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 > test.out 2>&1 +${TESTJAVA}/bin/java ${TESTOPTS} -Xmx1600m -Xms1600m -XX:+IgnoreUnrecognizedVMOptions -XX:-ZapUnusedHeapArea -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 > test.out 2>&1 result=$? diff --git a/hotspot/test/compiler/6857159/Test6857159.sh b/hotspot/test/compiler/6857159/Test6857159.sh index e0430c43abc..cb790127c9c 100644 --- a/hotspot/test/compiler/6857159/Test6857159.sh +++ b/hotspot/test/compiler/6857159/Test6857159.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 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 @@ -39,7 +39,7 @@ cp ${TESTSRC}/Test6857159.sh . ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test6857159.java -${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbatch -XX:+PrintCompilation -XX:CompileOnly=Test6857159\$ct.run Test6857159 > test.out 2>&1 +${TESTJAVA}/bin/java ${TESTOPTS} -Xbatch -XX:+PrintCompilation -XX:CompileOnly=Test6857159\$ct.run Test6857159 > test.out 2>&1 grep "COMPILE SKIPPED" test.out diff --git a/hotspot/test/compiler/6894807/IsInstanceTest.java b/hotspot/test/compiler/6894807/IsInstanceTest.java index ddc3fed365a..d838c6ec662 100644 --- a/hotspot/test/compiler/6894807/IsInstanceTest.java +++ b/hotspot/test/compiler/6894807/IsInstanceTest.java @@ -1,3 +1,26 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 6894807 diff --git a/hotspot/test/compiler/6894807/Test6894807.sh b/hotspot/test/compiler/6894807/Test6894807.sh index 229fb545108..609af074eda 100644 --- a/hotspot/test/compiler/6894807/Test6894807.sh +++ b/hotspot/test/compiler/6894807/Test6894807.sh @@ -1,55 +1,38 @@ #!/bin/sh +# +# 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# if [ "${TESTSRC}" = "" ] -then TESTSRC=. -fi - -if [ "${TESTJAVA}" = "" ] then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - echo "TESTJAVA not set, selecting " ${TESTJAVA} - echo "If this is incorrect, try setting the variable manually." + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi +echo "TESTSRC=${TESTSRC}" -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin ) - NULL=/dev/null - PS=":" - FS="/" - ;; - Windows_* ) - NULL=NUL - PS=";" - FS="\\" - ;; - CYGWIN_* ) - NULL=/dev/null - PS=";" - FS="/" - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - -JEMMYPATH=${CPAPPEND} -CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH - -THIS_DIR=`pwd` - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -version - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} IsInstanceTest > test.out 2>&1 +${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} IsInstanceTest > test.out 2>&1 cat test.out diff --git a/hotspot/test/compiler/6932496/Test6932496.java b/hotspot/test/compiler/6932496/Test6932496.java index 721b4e00b72..7f3c1697355 100644 --- a/hotspot/test/compiler/6932496/Test6932496.java +++ b/hotspot/test/compiler/6932496/Test6932496.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -26,26 +26,162 @@ * @test * @bug 6932496 * @summary incorrect deopt of jsr subroutine on 64 bit c1 - * - * @compile -source 1.5 -target 1.5 -XDjsrlimit=0 Test6932496.java - * @run main/othervm -Xcomp -XX:CompileOnly=Test6932496.m Test6932496 + * @run main/othervm -Xcomp -XX:CompileOnly=Test.test Test6932496 */ +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.io.IOException; -public class Test6932496 { - static class A { - volatile boolean flag = false; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; +import jdk.internal.org.objectweb.asm.Label; + +public class Test6932496 extends ClassLoader { + private static final int CLASS_FILE_VERSION = 49; + private static final String CLASS_TEST = "Test"; + private static final String CLASS_OBJECT = "java/lang/Object"; + private static final String METHOD_INIT = ""; + private static final String METHOD_TEST = "test"; + private static final String DESC_VOID_METHOD = "()V"; + private static final String FIELD_FLAG = "flag"; + + public static void main(String[] args) { + Test6932496 test = new Test6932496(); + test.execute(); } - static void m() { + private void execute() { + byte[] bytecode = Test6932496.generateTestClass(); + try { - } finally { - A a = new A(); - a.flag = true; + Files.write(Paths.get("Test.class.dump"), bytecode); + } catch (IOException e) { + System.err.println("classfile dump failed : " + e.getMessage()); + e.printStackTrace(); + } + try { + Class aClass = defineClass(CLASS_TEST, bytecode, 0, bytecode.length); + Method test = aClass.getDeclaredMethod(METHOD_TEST); + test.invoke(null); + } catch (ClassFormatError | IllegalArgumentException + | ReflectiveOperationException e) { + throw new RuntimeException("TESTBUG : generated class is invalid", e); } } + /* + public class Test { + volatile boolean flag = false; + public static void m() { + try { + } finally { + Test test = new Test(); + test.flag = true; + } + } + } + */ + private static byte[] generateTestClass() { + ClassWriter cw = new ClassWriter(0); + cw.visit(CLASS_FILE_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, + CLASS_TEST, null, CLASS_OBJECT, null); + // volatile boolean flag; + { + FieldVisitor fv = cw.visitField(Opcodes.ACC_VOLATILE, FIELD_FLAG, + Type.BOOLEAN_TYPE.getDescriptor(), + /* signature = */ null, /* value = */ null); + } - static public void main(String[] args) { - m(); + /* + public Test() { + flag = false; + } + */ + { + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, + METHOD_INIT, DESC_VOID_METHOD, + /* signature = */ null, /* exceptions = */ null); + + mv.visitCode(); + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, CLASS_OBJECT, METHOD_INIT, + DESC_VOID_METHOD, false); + + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitInsn(Opcodes.ICONST_0); + mv.visitFieldInsn(Opcodes.PUTFIELD, CLASS_TEST, FIELD_FLAG, + Type.BOOLEAN_TYPE.getDescriptor()); + + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(/* stack = */ 2, /* locals = */ 1); + mv.visitEnd(); + } + + /* + public static void m() { + try { + } finally { + Test test = new Test(); + test.flag = true; + } + } + */ + { + MethodVisitor mv = cw.visitMethod( + Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC, + METHOD_TEST, DESC_VOID_METHOD, + /* signature = */ null, /* exceptions = */ null); + Label beginLabel = new Label(); + Label block1EndLabel = new Label(); + Label handlerLabel = new Label(); + Label block2EndLabel = new Label(); + Label label = new Label(); + Label endLabel = new Label(); + + mv.visitCode(); + mv.visitTryCatchBlock(beginLabel, block1EndLabel, handlerLabel, + /* type = */ null); + mv.visitTryCatchBlock(handlerLabel, block2EndLabel, handlerLabel, + /* type = */ null); + + mv.visitLabel(beginLabel); + mv.visitJumpInsn(Opcodes.JSR, label); + mv.visitLabel(block1EndLabel); + mv.visitJumpInsn(Opcodes.GOTO, endLabel); + + mv.visitLabel(handlerLabel); + mv.visitVarInsn(Opcodes.ASTORE, 0); + mv.visitJumpInsn(Opcodes.JSR, label); + mv.visitLabel(block2EndLabel); + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitInsn(Opcodes.ATHROW); + + mv.visitLabel(label); + mv.visitVarInsn(Opcodes.ASTORE, 1); + mv.visitTypeInsn(Opcodes.NEW, CLASS_TEST); + mv.visitInsn(Opcodes.DUP); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, CLASS_TEST, METHOD_INIT, + DESC_VOID_METHOD); + mv.visitVarInsn(Opcodes.ASTORE, 2); + + mv.visitVarInsn(Opcodes.ALOAD, 2); + mv.visitInsn(Opcodes.ICONST_1); + mv.visitFieldInsn(Opcodes.PUTFIELD, CLASS_TEST, FIELD_FLAG, + Type.BOOLEAN_TYPE.getDescriptor()); + + mv.visitVarInsn(Opcodes.RET, 1); + + mv.visitLabel(endLabel); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(/* stack = */ 2, /* locals = */ 3); + mv.visitEnd(); + } + + cw.visitEnd(); + return cw.toByteArray(); } } diff --git a/hotspot/test/compiler/7068051/Test7068051.sh b/hotspot/test/compiler/7068051/Test7068051.sh index e287c243163..35bc0f72efd 100644 --- a/hotspot/test/compiler/7068051/Test7068051.sh +++ b/hotspot/test/compiler/7068051/Test7068051.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2011, 2013, 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 @@ -41,5 +41,5 @@ ${COMPILEJAVA}/bin/jar -uf0 foo.jar Test7068051.java ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7068051.java -${TESTJAVA}/bin/java ${TESTVMOPTS} -showversion -Xbatch Test7068051 foo.jar +${TESTJAVA}/bin/java ${TESTOPTS} -showversion -Xbatch Test7068051 foo.jar diff --git a/hotspot/test/compiler/7070134/Test7070134.sh b/hotspot/test/compiler/7070134/Test7070134.sh index 2ef12d04b67..87618616c97 100644 --- a/hotspot/test/compiler/7070134/Test7070134.sh +++ b/hotspot/test/compiler/7070134/Test7070134.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2011, 2013, 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 @@ -39,7 +39,7 @@ cp ${TESTSRC}/words . ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Stemmer.java -${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbatch Stemmer words > test.out 2>&1 +${TESTJAVA}/bin/java ${TESTOPTS} -Xbatch Stemmer words > test.out 2>&1 exit $? diff --git a/hotspot/test/compiler/7200264/Test7200264.sh b/hotspot/test/compiler/7200264/Test7200264.sh index da1a59a29d7..5e7e508a5f2 100644 --- a/hotspot/test/compiler/7200264/Test7200264.sh +++ b/hotspot/test/compiler/7200264/Test7200264.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2012, 2013, 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 @@ -33,7 +33,7 @@ echo "TESTSRC=${TESTSRC}" ## Adding common setup Variables for running shell tests. . ${TESTSRC}/../../test_env.sh -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xinternalversion | sed 's/amd64/x86/' | grep "x86" | grep "Server VM" | grep "debug" +${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xinternalversion | sed 's/amd64/x86/' | grep "x86" | grep "Server VM" | grep "debug" # Only test fastdebug Server VM on x86 if [ $? != 0 ] @@ -43,7 +43,7 @@ then fi # grep for support integer multiply vectors (cpu with SSE4.1) -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -XX:+PrintMiscellaneous -XX:+Verbose -version | grep "cores per cpu" | grep "sse4.1" +${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -XX:+PrintMiscellaneous -XX:+Verbose -version | grep "cores per cpu" | grep "sse4.1" if [ $? != 0 ] then @@ -55,7 +55,7 @@ fi cp ${TESTSRC}${FS}TestIntVect.java . ${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} -d . TestIntVect.java -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+PrintCompilation -XX:+TraceNewVectors TestIntVect > test.out 2>&1 +${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+PrintCompilation -XX:+TraceNewVectors TestIntVect > test.out 2>&1 COUNT=`grep AddVI test.out | wc -l | awk '{print $1}'` if [ $COUNT -lt 4 ] diff --git a/hotspot/test/compiler/8009761/Test8009761.java b/hotspot/test/compiler/8009761/Test8009761.java index ed0f94665e4..46aad286840 100644 --- a/hotspot/test/compiler/8009761/Test8009761.java +++ b/hotspot/test/compiler/8009761/Test8009761.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -31,6 +31,7 @@ import java.lang.reflect.Method; * @summary Deoptimization on sparc doesn't set Llast_SP correctly in the interpreter frames it creates * @build Test8009761 * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=exclude,Test8009761::m2 -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -Xss256K Test8009761 */ public class Test8009761 { diff --git a/hotspot/test/compiler/8010927/Test8010927.java b/hotspot/test/compiler/8010927/Test8010927.java index 6c9d9ab3d69..3c0f0915d36 100644 --- a/hotspot/test/compiler/8010927/Test8010927.java +++ b/hotspot/test/compiler/8010927/Test8010927.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -28,6 +28,7 @@ * @library /testlibrary/whitebox /testlibrary * @build Test8010927 * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. -Xmx64m -XX:NewSize=20971520 -XX:MaxNewSize=32m -XX:-UseTLAB -XX:-UseParNewGC -XX:-UseAdaptiveSizePolicy Test8010927 */ diff --git a/hotspot/test/compiler/IntegerArithmetic/TestIntegerComparison.java b/hotspot/test/compiler/IntegerArithmetic/TestIntegerComparison.java new file mode 100644 index 00000000000..8d3c383a7ee --- /dev/null +++ b/hotspot/test/compiler/IntegerArithmetic/TestIntegerComparison.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +/* + * @test TestIntegerComparison + * @bug 8043284 8042786 + * @summary "Tests optimizations of signed and unsigned integer comparison." + * @run main/othervm -server -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:CompileOnly=TestIntegerComparison::testSigned,TestIntegerComparison::testUnsigned TestIntegerComparison + */ +public class TestIntegerComparison { + /** + * Tests optimization of signed integer comparison (see BoolNode::Ideal). + * The body of the if statement is unreachable and should not be compiled. + * @param c Character (value in the integer range [0, 65535]) + */ + public static void testSigned(char c) { + // The following addition may overflow. The result is in one + // of the two ranges [IntMax] and [IntMin, IntMin + CharMax - 1]. + int result = c + Integer.MAX_VALUE; + // CmpINode has to consider both result ranges instead of only + // the general [IntMin, IntMax] range to be able to prove that + // result is always unequal to CharMax. + if (result == Character.MAX_VALUE) { + // Unreachable + throw new RuntimeException("Should not reach here!"); + } + } + + /** + * Tests optimization of unsigned integer comparison (see CmpUNode::Value). + * The body of the if statement is unreachable and should not be compiled. + * @param c Character (value in the integer range [0, 65535]) + */ + public static void testUnsigned(char c) { + /* + * The following if statement consisting of two CmpIs is replaced + * by a CmpU during optimization (see 'IfNode::fold_compares'). + * + * The signed (lo < i) and (i < hi) are replaced by the unsigned + * (i - (lo+1) < hi - (lo+1)). In this case the unsigned comparison + * equals (result - 2) < 98 leading to the following CmpUNode: + * + * CmpU (AddI result, -2) 98 + * + * With the value of result this is simplified to: + * + * CmpU (AddI c, -(CharMax - IntMin)) 98 + * + * The subtraction may underflow. The result is in one of the two + * ranges [IntMin], [IntMax - CharMax + 1]. Both ranges have to be + * considered instead of only the general [IntMin, IntMax] to prove + * that due to the overflow the signed comparison result < 98 is + * always false. + */ + int result = c - (Character.MAX_VALUE - Integer.MIN_VALUE) + 2; + if (1 < result && result < 100) { + // Unreachable + throw new RuntimeException("Should not reach here!"); + } + } + + /** + * Tests optimizations of signed and unsigned integer comparison. + */ + public static void main(String[] args) { + // We use characters to get a limited integer range for free + for (int i = Character.MIN_VALUE; i <= Character.MAX_VALUE; ++i) { + testSigned((char) i); + testUnsigned((char) i); + } + } +} diff --git a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java index 559c3a6a643..bf797b1773f 100644 --- a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java +++ b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java @@ -30,6 +30,7 @@ * @build TestUseBMI1InstructionsOnSupportedCPU * BMISupportedCPUTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseBMI1InstructionsOnSupportedCPU */ diff --git a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java index 3df8d659cf0..2347181043c 100644 --- a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java +++ b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java @@ -30,6 +30,7 @@ * @build TestUseBMI1InstructionsOnUnsupportedCPU * BMIUnsupportedCPUTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseBMI1InstructionsOnUnsupportedCPU */ diff --git a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java index c8437748341..68f2267a27c 100644 --- a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java +++ b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java @@ -30,6 +30,7 @@ * @build TestUseCountLeadingZerosInstructionOnSupportedCPU * BMISupportedCPUTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestUseCountLeadingZerosInstructionOnSupportedCPU diff --git a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java index e2ffba28a43..68c855a78ef 100644 --- a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java +++ b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java @@ -30,6 +30,7 @@ * @build TestUseCountLeadingZerosInstructionOnUnsupportedCPU * BMIUnsupportedCPUTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestUseCountLeadingZerosInstructionOnUnsupportedCPU diff --git a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java index d6628b1ed0c..2e4400b5fe7 100644 --- a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java +++ b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java @@ -30,6 +30,7 @@ * @build TestUseCountTrailingZerosInstructionOnSupportedCPU * BMISupportedCPUTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestUseCountTrailingZerosInstructionOnSupportedCPU diff --git a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java index 67b6ea318ca..648c112282c 100644 --- a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java +++ b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java @@ -30,6 +30,7 @@ * @build TestUseCountTrailingZerosInstructionOnUnsupportedCPU * BMIUnsupportedCPUTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestUseCountTrailingZerosInstructionOnUnsupportedCPU diff --git a/hotspot/test/compiler/arraycopy/TestMissingControl.java b/hotspot/test/compiler/arraycopy/TestMissingControl.java new file mode 100644 index 00000000000..503e24be3b4 --- /dev/null +++ b/hotspot/test/compiler/arraycopy/TestMissingControl.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8055153 + * @summary missing control on LoadRange and LoadKlass when array copy macro node is expanded + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:-TieredCompilation TestMissingControl + * + */ +public class TestMissingControl { + + static int[] m1(int[] a2) { + int[] a1 = new int[10]; + System.arraycopy(a1, 0, a2, 0, 10); + return a1; + } + + static class A { + } + + static Object m2(Object[] a2) { + A[] a1 = new A[10]; + System.arraycopy(a1, 0, a2, 0, 10); + return a1; + } + + static void test1() { + int[] a2 = new int[10]; + int[] a3 = new int[5]; + + // compile m1 with arraycopy intrinsified + for (int i = 0; i < 20000; i++) { + m1(a2); + } + + // make m1 trap + for (int i = 0; i < 10; i++) { + try { + m1(a3); + } catch(IndexOutOfBoundsException ioobe) { + } + } + + // recompile m1 + for (int i = 0; i < 20000; i++) { + m1(a2); + } + + try { + m1(null); + } catch(NullPointerException npe) {} + } + + static void test2() { + A[] a2 = new A[10]; + A[] a3 = new A[5]; + + // compile m2 with arraycopy intrinsified + for (int i = 0; i < 20000; i++) { + m2(a2); + } + + // make m2 trap + for (int i = 0; i < 10; i++) { + try { + m2(a3); + } catch(IndexOutOfBoundsException ioobe) { + } + } + + // recompile m2 + for (int i = 0; i < 20000; i++) { + m2(a2); + } + + try { + m2(null); + } catch(NullPointerException npe) {} + } + + static public void main(String[] args) { + test1(); + test2(); + } +} diff --git a/hotspot/test/compiler/ciReplay/TestSA.sh b/hotspot/test/compiler/ciReplay/TestSA.sh index 56736c7807e..cc5f5037e7a 100644 --- a/hotspot/test/compiler/ciReplay/TestSA.sh +++ b/hotspot/test/compiler/ciReplay/TestSA.sh @@ -68,7 +68,7 @@ then fi echo "dumpreplaydata -a > ${replay_data}" | \ - ${JAVA} ${TESTVMOPTS} \ + ${JAVA} ${TESTOPTS} \ -cp ${TESTJAVA}${FS}lib${FS}sa-jdi.jar \ sun.jvm.hotspot.CLHSDB ${JAVA} ${core_file} diff --git a/hotspot/test/compiler/ciReplay/common.sh b/hotspot/test/compiler/ciReplay/common.sh index b7c5b7b4292..c7b656d26aa 100644 --- a/hotspot/test/compiler/ciReplay/common.sh +++ b/hotspot/test/compiler/ciReplay/common.sh @@ -22,6 +22,7 @@ # questions. # # +set -x # $1 - error code # $2 - test name @@ -56,7 +57,7 @@ positive_test() { shift name=$1 shift - VMOPTS="${TESTVMOPTS} $@" + VMOPTS="${TESTOPTS} $@" echo "POSITIVE TEST [$name]" start_test ${VMOPTS} exit_code=$? @@ -75,7 +76,7 @@ negative_test() { shift name=$1 shift - VMOPTS="${TESTVMOPTS} $@" + VMOPTS="${TESTOPTS} $@" echo "NEGATIVE TEST [$name]" start_test ${VMOPTS} exit_code=$? @@ -149,7 +150,7 @@ JAVA=${TESTJAVA}${FS}bin${FS}java replay_data=test_replay.txt -${JAVA} ${TESTVMOPTS} -Xinternalversion 2>&1 | grep debug +${JAVA} ${TESTOPTS} -Xinternalversion 2>&1 | grep debug # Only test fastdebug if [ $? -ne 0 ] @@ -158,7 +159,7 @@ then exit 0 fi -is_int=`${JAVA} ${TESTVMOPTS} -version 2>&1 | grep -c "interpreted mode"` +is_int=`${JAVA} ${TESTOPTS} -version 2>&1 | grep -c "interpreted mode"` # Not applicable for Xint if [ $is_int -ne 0 ] then @@ -168,14 +169,14 @@ fi cleanup -client_available=`${JAVA} ${TESTVMOPTS} -client -Xinternalversion 2>&1 | \ +client_available=`${JAVA} ${TESTOPTS} -client -Xinternalversion 2>&1 | \ grep -c Client` -server_available=`${JAVA} ${TESTVMOPTS} -server -Xinternalversion 2>&1 | \ +server_available=`${JAVA} ${TESTOPTS} -server -Xinternalversion 2>&1 | \ grep -c Server` -tiered_available=`${JAVA} ${TESTVMOPTS} -XX:+TieredCompilation -XX:+PrintFlagsFinal -version | \ +tiered_available=`${JAVA} ${TESTOPTS} -XX:+TieredCompilation -XX:+PrintFlagsFinal -version | \ grep TieredCompilation | \ grep -c true` -is_tiered=`${JAVA} ${TESTVMOPTS} -XX:+PrintFlagsFinal -version | \ +is_tiered=`${JAVA} ${TESTOPTS} -XX:+PrintFlagsFinal -version | \ grep TieredCompilation | \ grep -c true` # CompLevel_simple -- C1 @@ -207,7 +208,7 @@ generate_replay() { fi fi - cmd="${JAVA} ${TESTVMOPTS} $@ \ + cmd="${JAVA} ${TESTOPTS} $@ \ -Xms8m \ -Xmx32m \ -XX:MetaspaceSize=4m \ diff --git a/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java b/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java new file mode 100644 index 00000000000..c8ebd48d3eb --- /dev/null +++ b/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; +import sun.misc.IOUtils; + +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLConnection; + +/* + * @test TestAnonymousClassUnloading + * @bug 8054402 + * @summary "Tests unloading of anonymous classes." + * @library /testlibrary /testlibrary/whitebox + * @compile TestAnonymousClassUnloading.java + * @run main ClassFileInstaller TestAnonymousClassUnloading sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestAnonymousClassUnloading + */ +public class TestAnonymousClassUnloading { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + private static int COMP_LEVEL_SIMPLE = 1; + private static int COMP_LEVEL_FULL_OPTIMIZATION = 4; + + /** + * We override hashCode here to be able to access this implementation + * via an Object reference (we cannot cast to TestAnonymousClassUnloading). + */ + @Override + public int hashCode() { + return 42; + } + + /** + * Does some work by using the anonymousClass. + * @param anonymousClass Class performing some work (will be unloaded) + */ + static private void doWork(Class anonymousClass) throws InstantiationException, IllegalAccessException { + // Create a new instance + Object anon = anonymousClass.newInstance(); + // We would like to call a method of anonymousClass here but we cannot cast because the class + // was loaded by a different class loader. One solution would be to use reflection but since + // we want C2 to implement the call as an IC we call Object::hashCode() here which actually + // calls anonymousClass::hashCode(). C2 will then implement this call as an IC. + if (anon.hashCode() != 42) { + new RuntimeException("Work not done"); + } + } + + /** + * Makes sure that method is compiled by forcing compilation if not yet compiled. + * @param m Method to be checked + */ + static private void makeSureIsCompiled(Method m) { + // Make sure background compilation is disabled + if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) { + throw new RuntimeException("Background compilation enabled"); + } + + // Check if already compiled + if (!WHITE_BOX.isMethodCompiled(m)) { + // If not, try to compile it with C2 + if(!WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_FULL_OPTIMIZATION)) { + // C2 compiler not available, try to compile with C1 + WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_SIMPLE); + } + // Because background compilation is disabled, method should now be compiled + if(!WHITE_BOX.isMethodCompiled(m)) { + throw new RuntimeException(m + " not compiled"); + } + } + } + + /** + * This test creates stale Klass* metadata referenced by a compiled IC. + * + * The following steps are performed: + * (1) An anonymous version of TestAnonymousClassUnloading is loaded by a custom class loader + * (2) The method doWork that calls a method of the anonymous class is compiled. The call + * is implemented as an IC referencing Klass* metadata of the anonymous class. + * (3) Unloading of the anonymous class is enforced. The IC now references dead metadata. + */ + static public void main(String[] args) throws Exception { + // (1) Load an anonymous version of this class using the corresponding Unsafe method + URL classUrl = TestAnonymousClassUnloading.class.getResource("TestAnonymousClassUnloading.class"); + URLConnection connection = classUrl.openConnection(); + byte[] classBytes = IOUtils.readFully(connection.getInputStream(), connection.getContentLength(), true); + Class anonymousClass = UNSAFE.defineAnonymousClass(TestAnonymousClassUnloading.class, classBytes, null); + + // (2) Make sure all paths of doWork are profiled and compiled + for (int i = 0; i < 100000; ++i) { + doWork(anonymousClass); + } + + // Make sure doWork is compiled now + Method doWork = TestAnonymousClassUnloading.class.getDeclaredMethod("doWork", Class.class); + makeSureIsCompiled(doWork); + + // (3) Throw away reference to anonymousClass to allow unloading + anonymousClass = null; + + // Force garbage collection to trigger unloading of anonymousClass + // Dead metadata reference to anonymousClass triggers JDK-8054402 + WHITE_BOX.fullGC(); + } +} diff --git a/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java b/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java new file mode 100644 index 00000000000..14b3da6d575 --- /dev/null +++ b/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java @@ -0,0 +1,146 @@ +/* + * 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. + */ + +import sun.hotspot.WhiteBox; + +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; + +/* + * @test MethodUnloadingTest + * @bug 8029443 + * @summary "Tests the unloading of methods to to class unloading" + * @library /testlibrary /testlibrary/whitebox + * @build TestMethodUnloading + * @build WorkerClass + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation -XX:-UseCompressedOops -XX:+UseParallelGC -XX:CompileOnly=TestMethodUnloading::doWork TestMethodUnloading + */ +public class TestMethodUnloading { + private static final String workerClassName = "WorkerClass"; + private static int work = -1; + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static int COMP_LEVEL_SIMPLE = 1; + private static int COMP_LEVEL_FULL_OPTIMIZATION = 4; + + /** + * Does some work by either using the workerClass or locally producing values. + * @param workerClass Class performing some work (will be unloaded) + * @param useWorker If true the workerClass is used + */ + static private void doWork(Class workerClass, boolean useWorker) throws InstantiationException, IllegalAccessException { + if (useWorker) { + // Create a new instance + Object worker = workerClass.newInstance(); + // We would like to call a method of WorkerClass here but we cannot cast to WorkerClass + // because the class was loaded by a different class loader. One solution would be to use + // reflection but since we want C2 to implement the call as an optimized IC we call + // Object::hashCode() here which actually calls WorkerClass::hashCode(). + // C2 will then implement this call as an optimized IC that points to a to-interpreter stub + // referencing the Method* for WorkerClass::hashCode(). + work = worker.hashCode(); + if (work != 42) { + new RuntimeException("Work not done"); + } + } else { + // Do some important work here + work = 1; + } + } + + /** + * Makes sure that method is compiled by forcing compilation if not yet compiled. + * @param m Method to be checked + */ + static private void makeSureIsCompiled(Method m) { + // Make sure background compilation is disabled + if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) { + throw new RuntimeException("Background compilation enabled"); + } + + // Check if already compiled + if (!WHITE_BOX.isMethodCompiled(m)) { + // If not, try to compile it with C2 + if(!WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_FULL_OPTIMIZATION)) { + // C2 compiler not available, try to compile with C1 + WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_SIMPLE); + } + // Because background compilation is disabled, method should now be compiled + if(!WHITE_BOX.isMethodCompiled(m)) { + throw new RuntimeException(m + " not compiled"); + } + } + } + + /** + * This test creates stale Method* metadata in a to-interpreter stub of an optimized IC. + * + * The following steps are performed: + * (1) A workerClass is loaded by a custom class loader + * (2) The method doWork that calls a method of the workerClass is compiled. The call + * is implemented as an optimized IC calling a to-interpreted stub. The to-interpreter + * stub contains a Method* to a workerClass method. + * (3) Unloading of the workerClass is enforced. The to-interpreter stub now contains a dead Method*. + * (4) Depending on the implementation of the IC, the compiled version of doWork should still be + * valid. We call it again without using the workerClass. + */ + static public void main(String[] args) throws Exception { + // (1) Create a custom class loader with no parent class loader + URL url = TestMethodUnloading.class.getProtectionDomain().getCodeSource().getLocation(); + URLClassLoader loader = new URLClassLoader(new URL[] {url}, null); + + // Load worker class with custom class loader + Class workerClass = Class.forName(workerClassName, true, loader); + + // (2) Make sure all paths of doWork are profiled and compiled + for (int i = 0; i < 100000; ++i) { + doWork(workerClass, true); + doWork(workerClass, false); + } + + // Make sure doWork is compiled now + Method doWork = TestMethodUnloading.class.getDeclaredMethod("doWork", Class.class, boolean.class); + makeSureIsCompiled(doWork); + + // (3) Throw away class loader and reference to workerClass to allow unloading + loader.close(); + loader = null; + workerClass = null; + + // Force garbage collection to trigger unloading of workerClass + // Dead reference to WorkerClass::hashCode triggers JDK-8029443 + WHITE_BOX.fullGC(); + + // (4) Depending on the implementation of the IC, the compiled version of doWork + // may still be valid here. Execute it without a workerClass. + doWork(null, false); + if (work != 1) { + throw new RuntimeException("Work not done"); + } + + doWork(Object.class, false); + } +} diff --git a/hotspot/test/compiler/classUnloading/methodUnloading/WorkerClass.java b/hotspot/test/compiler/classUnloading/methodUnloading/WorkerClass.java new file mode 100644 index 00000000000..c67154f2c80 --- /dev/null +++ b/hotspot/test/compiler/classUnloading/methodUnloading/WorkerClass.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/** + * Worker class that is dynamically loaded/unloaded by TestMethodUnloading. + */ +public class WorkerClass { + /** + * We override hashCode here to be able to access this implementation + * via an Object reference (we cannot cast to WorkerClass). + */ + @Override + public int hashCode() { + return 42; + } +} + diff --git a/hotspot/test/compiler/exceptions/TestRecursiveReplacedException.java b/hotspot/test/compiler/exceptions/TestRecursiveReplacedException.java new file mode 100644 index 00000000000..996d82a0feb --- /dev/null +++ b/hotspot/test/compiler/exceptions/TestRecursiveReplacedException.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8054224 + * @summary Recursive method compiled by C1 is unable to catch StackOverflowError + * @run main/othervm -Xcomp -XX:CompileOnly=Test.run -XX:+TieredCompilation -XX:TieredStopAtLevel=2 -Xss256K TestRecursiveReplacedException + * + */ + +public class TestRecursiveReplacedException { + + public static void main(String args[]) { + new TestRecursiveReplacedException().run(); + } + + public void run() { + try { + run(); + } catch (Throwable t) { + } + } +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java b/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java index e8cfaa23f0f..45a79b0df37 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestAndnI BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestAndnI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java b/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java index 0dca7aa399a..8746fefa483 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestAndnL BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestAndnL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java index 9f998bc05d5..7ced5242692 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestBlsiI BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestBlsiI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java index b7a36c65a26..d1fe59c204b 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestBlsiL BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestBlsiL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java index a06b429ec03..7cba5d88e36 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestBlsmskI BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestBlsmskI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java index 794c4c8f9a9..d2f3a3f6aea 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestBlsmskL BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestBlsmskL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java index 73ea886023f..53e7251143b 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestBlsrI BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestBlsrI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java index 861f160806b..5e3c885542b 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestBlsrL BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestBlsrL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java b/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java index a3720dc51e3..d13b89c0246 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestLzcntI BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestLzcntI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java b/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java index a3d788725a7..b75830df18a 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestLzcntL BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestLzcntL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java b/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java index d74c82a9a9e..285519537aa 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestTzcntI BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestTzcntI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java b/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java index 0c1841991d9..36683fe7283 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestTzcntL BMITestRunner Expr * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestTzcntL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java index 2a77347a749..3b6f2f3ee20 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build AddnTestI * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions AddnTestI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java index 72da9a04485..c03469361b7 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build AddnTestL * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions AddnTestL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java index ce234a9b6fd..92a87875a5c 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build BlsiTestI * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions BlsiTestI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java index f8544f30155..2894a53b406 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build BlsiTestL * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions BlsiTestL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java index 1a7dd8f6e56..2f0be6af7bf 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build BlsmskTestI * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions BlsmskTestI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java index e061206bc44..f2b7345b582 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build BlsmskTestL * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions BlsmskTestL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java index e086f9bfea7..67d1b90dcee 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build BlsrTestI * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions BlsrTestI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java index 0185aeb8d88..158f3440663 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build BlsrTestL * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions BlsrTestL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java index 62c8642833b..d74c19ac107 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build LZcntTestI * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCountLeadingZerosInstruction LZcntTestI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java index 16caae2b0d9..5c164ff8ac9 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build LZcntTestL * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCountLeadingZerosInstruction LZcntTestL */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java index 2502641e8da..7fa47ba03e2 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build TZcntTestI * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCountTrailingZerosInstruction TZcntTestI */ diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java index c08dbcc1fc9..e06f9ddb0b1 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox .. * @build TZcntTestL * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCountTrailingZerosInstruction TZcntTestL */ diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java index a2770dcddf3..7f70f1c2a70 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build AddExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java index c5756440769..e577202a87a 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build AddExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java index 19641a1f41a..ae37263e52f 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build DecrementExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java index a5821698f9d..5e42bb1b16e 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build DecrementExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java index bca840ad8f1..32bf0c698ba 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build IncrementExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java index 5348b774f9b..b0f50869c70 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build IncrementExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java index a09c1244905..d565ce7c9bd 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build MultiplyExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java index 23154e9ecef..e7ac5303b5b 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build MultiplyExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java index f41bb7995a9..5aacf77dbba 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build NegateExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java index 27af6553036..37d13a5823e 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build NegateExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java index c2cbbc4ef95..7cd22479131 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build SubtractExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java index bee6d3bafc4..4ab26097487 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,6 +26,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox * @build SubtractExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod diff --git a/hotspot/test/compiler/macronodes/TestEliminateAllocationPhi.java b/hotspot/test/compiler/macronodes/TestEliminateAllocationPhi.java new file mode 100644 index 00000000000..e9a5154e7c7 --- /dev/null +++ b/hotspot/test/compiler/macronodes/TestEliminateAllocationPhi.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8046698 + * @summary PhiNode inserted between AllocateNode and Initialization node confuses allocation elimination + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestEliminateAllocationPhi + * + */ + +public class TestEliminateAllocationPhi { + + // This will return I when called from m(0 and once optimized will + // go away but this will confuse escape analysis in m(): it will + // find I as non escaping but non scalar replaceable. In its own + // method so that we can make the profile of the if() branch look + // like it's taken sometimes. + static Integer m2(Integer I, int i) { + for (; i < 10; i=(i+2)*(i+2)) { + } + if (i == 121) { + return II; + } + return I; + } + + static Integer II = new Integer(42); + + static int m(int[] integers, boolean flag) { + int j = 0; + while(true) { + try { + int k = integers[j++]; + // A branch that will cause loop unswitching + if (flag) { + k += 42; + } + if (k < 1000) { + throw new Exception(); + } + // Because of the try/catch the Allocate node for this + // new will be in the loop while the Initialization + // node will be outside the loop. When loop + // unswitching happens, the Allocate node will be + // cloned and the results of both will be inputs to a + // Phi that will be between the Allocate nodes and the + // Initialization nodes. + Integer I = new Integer(k); + + I = m2(I, 0); + + int i = I.intValue(); + return i; + } catch(Exception e) { + } + } + } + + static public void main(String[] args) { + for (int i = 0; i < 5000; i++) { + m2(null, 1); + } + + int[] integers = { 2000 }; + for (int i = 0; i < 6000; i++) { + m(integers, (i%2) == 0); + } + int[] integers2 = { 1, 2, 3, 4, 5, 2000 }; + for (int i = 0; i < 10000; i++) { + m(integers2, (i%2) == 0); + } + } +} diff --git a/hotspot/test/compiler/membars/TestMemBarAcquire.java b/hotspot/test/compiler/membars/TestMemBarAcquire.java new file mode 100644 index 00000000000..e255cc1ebe7 --- /dev/null +++ b/hotspot/test/compiler/membars/TestMemBarAcquire.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/* + * @test TestMemBarAcquire + * @bug 8048879 + * @summary "Tests optimization of MemBarAcquireNodes" + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation TestMemBarAcquire + */ +public class TestMemBarAcquire { + private volatile static Object defaultObj = new Object(); + private Object obj; + + public TestMemBarAcquire(Object param) { + // Volatile load. MemBarAcquireNode is added after the + // load to prevent following loads from floating up past. + // StoreNode is added to store result of load in 'obj'. + this.obj = defaultObj; + // Overrides 'obj' and therefore makes previous StoreNode + // and the corresponding LoadNode useless. However, the + // LoadNode is still connected to the MemBarAcquireNode + // that should now release the reference. + this.obj = param; + } + + public static void main(String[] args) throws Exception { + // Make sure TestMemBarAcquire:: is compiled + for (int i = 0; i < 100000; ++i) { + TestMemBarAcquire p = new TestMemBarAcquire(new Object()); + } + } +} + diff --git a/hotspot/test/compiler/osr/TestOSRWithNonEmptyStack.java b/hotspot/test/compiler/osr/TestOSRWithNonEmptyStack.java new file mode 100644 index 00000000000..82bbfc2ae4c --- /dev/null +++ b/hotspot/test/compiler/osr/TestOSRWithNonEmptyStack.java @@ -0,0 +1,127 @@ +/* + * 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. + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +/** + * @test + * @bug 8051344 + * @summary Force OSR compilation with non-empty stack at the OSR entry point. + * @compile -XDignore.symbol.file TestOSRWithNonEmptyStack.java + * @run main/othervm -XX:CompileOnly=TestCase.test TestOSRWithNonEmptyStack + */ +public class TestOSRWithNonEmptyStack extends ClassLoader { + private static final int CLASS_FILE_VERSION = 52; + private static final String CLASS_NAME = "TestCase"; + private static final String METHOD_NAME = "test"; + private static final int ITERATIONS = 1_000_000; + + private static byte[] generateTestClass() { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + + cw.visit(TestOSRWithNonEmptyStack.CLASS_FILE_VERSION, ACC_PUBLIC, + TestOSRWithNonEmptyStack.CLASS_NAME, null, "java/lang/Object", + null); + + TestOSRWithNonEmptyStack.generateConstructor(cw); + TestOSRWithNonEmptyStack.generateTestMethod(cw); + + cw.visitEnd(); + return cw.toByteArray(); + } + + private static void generateConstructor(ClassWriter classWriter) { + MethodVisitor mv = classWriter.visitMethod(ACC_PUBLIC, "", "()V", + null, null); + + mv.visitCode(); + + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", + false); + mv.visitInsn(RETURN); + + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + private static void generateTestMethod(ClassWriter classWriter) { + MethodVisitor mv = classWriter.visitMethod(ACC_PUBLIC, + TestOSRWithNonEmptyStack.METHOD_NAME, "()V", null, null); + Label osrEntryPoint = new Label(); + + mv.visitCode(); + // Push 'this' into stack before OSR entry point to bail out compilation + mv.visitVarInsn(ALOAD, 0); + // Setup loop counter + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 1); + // Begin loop + mv.visitLabel(osrEntryPoint); + // Increment loop counter + mv.visitVarInsn(ILOAD, 1); + mv.visitInsn(ICONST_1); + mv.visitInsn(IADD); + // Duplicate it for loop condition check + mv.visitInsn(DUP); + mv.visitVarInsn(ISTORE, 1); + // Check loop condition + mv.visitLdcInsn(TestOSRWithNonEmptyStack.ITERATIONS); + mv.visitJumpInsn(IF_ICMPLT, osrEntryPoint); + // Pop 'this'. + mv.visitInsn(POP); + mv.visitInsn(RETURN); + + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + private void run() { + byte[] bytecode = TestOSRWithNonEmptyStack.generateTestClass(); + + try { + Class klass = defineClass(TestOSRWithNonEmptyStack.CLASS_NAME, + bytecode, 0, bytecode.length); + + Constructor ctor = klass.getConstructor(); + Method method = klass.getDeclaredMethod( + TestOSRWithNonEmptyStack.METHOD_NAME); + + Object testCase = ctor.newInstance(); + method.invoke(testCase); + } catch (Exception e) { + throw new RuntimeException( + "Test bug: generated class should be valid.", e); + } + } + + public static void main(String args[]) { + new TestOSRWithNonEmptyStack().run(); + } +} diff --git a/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java index 0b336c8bc30..93b1a4862b5 100644 --- a/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig diff --git a/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java index b22c6ab4538..5190bb8ec55 100644 --- a/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig diff --git a/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnSupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnSupportedConfig.java index ea3d2d37bff..ffa4bb45a0f 100644 --- a/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnSupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnSupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMAbortRatioOptionOnSupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMAbortRatioOptionOnSupportedConfig */ diff --git a/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnUnsupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnUnsupportedConfig.java index d4807742814..eb952eebdd5 100644 --- a/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnUnsupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnUnsupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMAbortRatioOptionOnUnsupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMAbortRatioOptionOnUnsupportedConfig */ diff --git a/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java index 86ddcdcdaee..979615d6c9e 100644 --- a/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMTotalCountIncrRateOptionOnSupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestRTMTotalCountIncrRateOptionOnSupportedConfig diff --git a/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnUnsupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnUnsupportedConfig.java index 32cd417ba67..8dcffdee53e 100644 --- a/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnUnsupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnUnsupportedConfig.java @@ -35,6 +35,7 @@ import rtm.predicate.SupportedVM; * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMTotalCountIncrRateOptionOnUnsupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestRTMTotalCountIncrRateOptionOnUnsupportedConfig diff --git a/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java index bd9d78266e3..999f73c1bd8 100644 --- a/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMDeoptOptionOnSupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMDeoptOptionOnSupportedConfig */ diff --git a/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java index 2f3b8367519..6679df1297b 100644 --- a/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMDeoptOptionOnUnsupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMDeoptOptionOnUnsupportedConfig */ diff --git a/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java index b01a6a70974..f04c154c8da 100644 --- a/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMForStackLocksOptionOnSupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestUseRTMForStackLocksOptionOnSupportedConfig diff --git a/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java index 557f17a4743..bf84bde179b 100644 --- a/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMForStackLocksOptionOnUnsupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * TestUseRTMForStackLocksOptionOnUnsupportedConfig diff --git a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java index 72af53530d3..ebb69645bde 100644 --- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java +++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMLockingOptionOnSupportedConfig * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMLockingOptionOnSupportedConfig */ diff --git a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java index 6e100240964..a4fe7d07930 100644 --- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java +++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMLockingOptionOnUnsupportedCPU * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMLockingOptionOnUnsupportedCPU */ diff --git a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedVM.java b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedVM.java index 0121856bccf..8119019ae56 100644 --- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedVM.java +++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedVM.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMLockingOptionOnUnsupportedVM * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMLockingOptionOnUnsupportedVM */ diff --git a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java index 89b30bfb21f..c4c65117239 100644 --- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java +++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMLockingOptionWithBiasedLocking * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMLockingOptionWithBiasedLocking */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMAbortRatio.java b/hotspot/test/compiler/rtm/locking/TestRTMAbortRatio.java index 2c179d8eebe..f4eb6a9c458 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMAbortRatio.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMAbortRatio.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMAbortRatio * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMAbortRatio */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMAbortThreshold.java b/hotspot/test/compiler/rtm/locking/TestRTMAbortThreshold.java index dbed5f0fbc7..9447b88c41d 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMAbortThreshold.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMAbortThreshold.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMAbortThreshold * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMAbortThreshold */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java b/hotspot/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java index 2cf81f7f659..d46433da725 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java @@ -32,6 +32,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMAfterNonRTMDeopt * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMAfterNonRTMDeopt */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java b/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java index 911cc21a940..4c662e088ec 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMDeoptOnHighAbortRatio * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMDeoptOnHighAbortRatio */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java b/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java index bcadaab6c52..4101cbf4a52 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMDeoptOnLowAbortRatio * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMDeoptOnLowAbortRatio */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMLockingCalculationDelay.java b/hotspot/test/compiler/rtm/locking/TestRTMLockingCalculationDelay.java index 61f84e430c4..6355d97e487 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMLockingCalculationDelay.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMLockingCalculationDelay.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMLockingCalculationDelay * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMLockingCalculationDelay */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMLockingThreshold.java b/hotspot/test/compiler/rtm/locking/TestRTMLockingThreshold.java index 548a09c6e85..a30ee9a061f 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMLockingThreshold.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMLockingThreshold.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMLockingThreshold * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMLockingThreshold */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMRetryCount.java b/hotspot/test/compiler/rtm/locking/TestRTMRetryCount.java index 1a0c20cd77b..4fceef23919 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMRetryCount.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMRetryCount.java @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMRetryCount * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMRetryCount */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMSpinLoopCount.java b/hotspot/test/compiler/rtm/locking/TestRTMSpinLoopCount.java index 8cb4bbbe9a3..1d78747bb97 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMSpinLoopCount.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMSpinLoopCount.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMSpinLoopCount * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMSpinLoopCount */ diff --git a/hotspot/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java b/hotspot/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java index e1f94d31d93..4af5a59c5b7 100644 --- a/hotspot/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java +++ b/hotspot/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestRTMTotalCountIncrRate * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestRTMTotalCountIncrRate */ diff --git a/hotspot/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java b/hotspot/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java index f1fa1393fb6..d6ee5b6e3ba 100644 --- a/hotspot/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java +++ b/hotspot/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMAfterLockInflation * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMAfterLockInflation */ diff --git a/hotspot/test/compiler/rtm/locking/TestUseRTMDeopt.java b/hotspot/test/compiler/rtm/locking/TestUseRTMDeopt.java index 2e0dcbc7111..9b93ad75f09 100644 --- a/hotspot/test/compiler/rtm/locking/TestUseRTMDeopt.java +++ b/hotspot/test/compiler/rtm/locking/TestUseRTMDeopt.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMDeopt * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMDeopt */ diff --git a/hotspot/test/compiler/rtm/locking/TestUseRTMForInflatedLocks.java b/hotspot/test/compiler/rtm/locking/TestUseRTMForInflatedLocks.java index 34fa34c559e..936abf8005c 100644 --- a/hotspot/test/compiler/rtm/locking/TestUseRTMForInflatedLocks.java +++ b/hotspot/test/compiler/rtm/locking/TestUseRTMForInflatedLocks.java @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMForInflatedLocks * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMForInflatedLocks */ diff --git a/hotspot/test/compiler/rtm/locking/TestUseRTMForStackLocks.java b/hotspot/test/compiler/rtm/locking/TestUseRTMForStackLocks.java index 0a54511a73b..b3b44984df0 100644 --- a/hotspot/test/compiler/rtm/locking/TestUseRTMForStackLocks.java +++ b/hotspot/test/compiler/rtm/locking/TestUseRTMForStackLocks.java @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMForStackLocks * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMForStackLocks */ diff --git a/hotspot/test/compiler/rtm/locking/TestUseRTMXendForLockBusy.java b/hotspot/test/compiler/rtm/locking/TestUseRTMXendForLockBusy.java index 4fc5d999b71..899f96d39cf 100644 --- a/hotspot/test/compiler/rtm/locking/TestUseRTMXendForLockBusy.java +++ b/hotspot/test/compiler/rtm/locking/TestUseRTMXendForLockBusy.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMXendForLockBusy * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMXendForLockBusy */ diff --git a/hotspot/test/compiler/rtm/method_options/TestNoRTMLockElidingOption.java b/hotspot/test/compiler/rtm/method_options/TestNoRTMLockElidingOption.java index 46c9482dc13..265f9e86c1d 100644 --- a/hotspot/test/compiler/rtm/method_options/TestNoRTMLockElidingOption.java +++ b/hotspot/test/compiler/rtm/method_options/TestNoRTMLockElidingOption.java @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestNoRTMLockElidingOption * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestNoRTMLockElidingOption */ diff --git a/hotspot/test/compiler/rtm/method_options/TestUseRTMLockElidingOption.java b/hotspot/test/compiler/rtm/method_options/TestUseRTMLockElidingOption.java index 701cf8d0606..e2ded9c51d7 100644 --- a/hotspot/test/compiler/rtm/method_options/TestUseRTMLockElidingOption.java +++ b/hotspot/test/compiler/rtm/method_options/TestUseRTMLockElidingOption.java @@ -31,6 +31,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestUseRTMLockElidingOption * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestUseRTMLockElidingOption */ diff --git a/hotspot/test/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java b/hotspot/test/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java index eebaac23b32..39dbd2522cf 100644 --- a/hotspot/test/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java +++ b/hotspot/test/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java @@ -32,6 +32,7 @@ * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary * @build TestPrintPreciseRTMLockingStatistics * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI TestPrintPreciseRTMLockingStatistics */ diff --git a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java index ab975e4bdb7..f84903c3502 100644 --- a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java +++ b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java @@ -29,6 +29,7 @@ import java.util.function.IntPredicate; * @ignore 8046268 * @build NonTieredLevelsTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:-TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* diff --git a/hotspot/test/compiler/tiered/TieredLevelsTest.java b/hotspot/test/compiler/tiered/TieredLevelsTest.java index d862f50e904..882762b8e45 100644 --- a/hotspot/test/compiler/tiered/TieredLevelsTest.java +++ b/hotspot/test/compiler/tiered/TieredLevelsTest.java @@ -27,6 +27,7 @@ * @ignore 8046268 * @build TieredLevelsTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* diff --git a/hotspot/test/compiler/types/correctness/CorrectnessTest.java b/hotspot/test/compiler/types/correctness/CorrectnessTest.java index 9c84167aa9f..3d0bca775dd 100644 --- a/hotspot/test/compiler/types/correctness/CorrectnessTest.java +++ b/hotspot/test/compiler/types/correctness/CorrectnessTest.java @@ -29,6 +29,7 @@ * execution/MethodHandleDelegate.java * @build CorrectnessTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation diff --git a/hotspot/test/compiler/types/correctness/OffTest.java b/hotspot/test/compiler/types/correctness/OffTest.java index 52bd8943b85..04be21cd2ee 100644 --- a/hotspot/test/compiler/types/correctness/OffTest.java +++ b/hotspot/test/compiler/types/correctness/OffTest.java @@ -30,6 +30,7 @@ * @build CorrectnessTest * @build OffTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/timeout=1200 OffTest */ diff --git a/hotspot/test/compiler/whitebox/ClearMethodStateTest.java b/hotspot/test/compiler/whitebox/ClearMethodStateTest.java index 8adbf2075a9..94d822ac646 100644 --- a/hotspot/test/compiler/whitebox/ClearMethodStateTest.java +++ b/hotspot/test/compiler/whitebox/ClearMethodStateTest.java @@ -30,6 +30,7 @@ import java.util.function.Function; * @ignore 8046268 * @build ClearMethodStateTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* ClearMethodStateTest * @summary testing of WB::clearMethodState() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java index 1a297ae350e..7c55fe39265 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java @@ -28,6 +28,7 @@ * @ignore 8046268 * @build DeoptimizeAllTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* DeoptimizeAllTest * @summary testing of WB::deoptimizeAll() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java index bee232d2cb0..ce9cfe82da1 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java @@ -28,6 +28,7 @@ * @ignore 8046268 * @build DeoptimizeMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* DeoptimizeMethodTest * @summary testing of WB::deoptimizeMethod() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java b/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java index 5c6c4f39690..f0895bad817 100644 --- a/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java +++ b/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java @@ -28,6 +28,7 @@ * @ignore 8046268 * @build EnqueueMethodForCompilationTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* EnqueueMethodForCompilationTest * @summary testing of WB::enqueueMethodForCompilation() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/compiler/whitebox/GetNMethodTest.java b/hotspot/test/compiler/whitebox/GetNMethodTest.java index 14bc76278dd..8a24fce9e9b 100644 --- a/hotspot/test/compiler/whitebox/GetNMethodTest.java +++ b/hotspot/test/compiler/whitebox/GetNMethodTest.java @@ -31,6 +31,7 @@ import sun.hotspot.code.NMethod; * @ignore 8046268 * @build GetNMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* GetNMethodTest * @summary testing of WB::getNMethod() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java index acede605a4f..0e340f9b238 100644 --- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java +++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /testlibrary/com/oracle/java/testlibrary * @build IsMethodCompilableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest * @summary testing of WB::isMethodCompilable() diff --git a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java index 651002d078e..5891ef7ac05 100644 --- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java +++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java @@ -28,6 +28,7 @@ * @ignore 8046268 * @build MakeMethodNotCompilableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* MakeMethodNotCompilableTest * @summary testing of WB::makeMethodNotCompilable() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java b/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java index ae42d531ab6..67e323ebce5 100644 --- a/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java +++ b/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build SetDontInlineMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* SetDontInlineMethodTest * @summary testing of WB::testSetDontInlineMethod() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java b/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java index 086d7c22ef5..560ad029604 100644 --- a/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java +++ b/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build SetForceInlineMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* SetForceInlineMethodTest * @summary testing of WB::testSetForceInlineMethod() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/gc/arguments/TestArrayAllocatorMallocLimit.java b/hotspot/test/gc/arguments/TestArrayAllocatorMallocLimit.java new file mode 100644 index 00000000000..3bbe15075a4 --- /dev/null +++ b/hotspot/test/gc/arguments/TestArrayAllocatorMallocLimit.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +/* + * @test TestArrayAllocatorMallocLimit + * @summary Sanity check that the ArrayAllocatorMallocLimit flag can be set. + * The test helps verifying that size_t flags can be set/read. + * @bug 8054823 + * @key gc + * @library /testlibrary + * @run driver TestArrayAllocatorMallocLimit + */ + +import com.oracle.java.testlibrary.Asserts; +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; +import java.math.BigInteger; + +public class TestArrayAllocatorMallocLimit { + public static void main(String [] args) throws Exception { + testDefaultValue(); + testSetValue(); + } + + private static final String flagName = "ArrayAllocatorMallocLimit"; + + // size_t ArrayAllocatorMallocLimit = 18446744073709551615{experimental} + private static final String printFlagsFinalPattern = " *size_t *" + flagName + " *:?= *(\\d+) *\\{experimental\\} *"; + + public static void testDefaultValue() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", "-XX:+PrintFlagsFinal", "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + String value = output.firstMatch(printFlagsFinalPattern, 1); + + try { + Asserts.assertNotNull(value, "Couldn't find size_t flag " + flagName); + + // A size_t is not always parseable with Long.parseValue, + // use BigInteger instead. + BigInteger biValue = new BigInteger(value); + + // Sanity check that we got a non-zero value. + Asserts.assertNotEquals(biValue, "0"); + + output.shouldHaveExitValue(0); + } catch (Exception e) { + System.err.println(output.getOutput()); + throw e; + } + } + + public static void testSetValue() throws Exception { + long flagValue = 2048; + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", "-XX:" + flagName + "=" + flagValue, "-XX:+PrintFlagsFinal", "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + String value = output.firstMatch(printFlagsFinalPattern, 1); + + try { + Asserts.assertNotNull("Couldn't find size_t flag " + flagName); + + long longValue = Long.parseLong(value); + + Asserts.assertEquals(longValue, flagValue); + + output.shouldHaveExitValue(0); + } catch (Exception e) { + System.err.println(output.getOutput()); + throw e; + } + } + +} diff --git a/hotspot/test/gc/arguments/TestCMSHeapSizeFlags.java b/hotspot/test/gc/arguments/TestCMSHeapSizeFlags.java index 3dc688ce8ab..f142964e380 100644 --- a/hotspot/test/gc/arguments/TestCMSHeapSizeFlags.java +++ b/hotspot/test/gc/arguments/TestCMSHeapSizeFlags.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestCMSHeapSizeFlags TestMaxHeapSizeTools * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm TestCMSHeapSizeFlags * @author thomas.schatzl@oracle.com */ diff --git a/hotspot/test/gc/arguments/TestG1HeapSizeFlags.java b/hotspot/test/gc/arguments/TestG1HeapSizeFlags.java index 31ab5e333c0..fabc4f02192 100644 --- a/hotspot/test/gc/arguments/TestG1HeapSizeFlags.java +++ b/hotspot/test/gc/arguments/TestG1HeapSizeFlags.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestG1HeapSizeFlags TestMaxHeapSizeTools * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm TestG1HeapSizeFlags * @author thomas.schatzl@oracle.com */ diff --git a/hotspot/test/gc/arguments/TestMinInitialErgonomics.java b/hotspot/test/gc/arguments/TestMinInitialErgonomics.java index 8352d92c8b0..1f90bec1e01 100644 --- a/hotspot/test/gc/arguments/TestMinInitialErgonomics.java +++ b/hotspot/test/gc/arguments/TestMinInitialErgonomics.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestMinInitialErgonomics TestMaxHeapSizeTools * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm TestMinInitialErgonomics * @author thomas.schatzl@oracle.com */ diff --git a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java index 947fd0f9c88..5d7b60395cd 100644 --- a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java +++ b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2013, 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 @@ -31,6 +31,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestParallelHeapSizeFlags TestMaxHeapSizeTools * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm TestParallelHeapSizeFlags * @author thomas.schatzl@oracle.com */ diff --git a/hotspot/test/gc/arguments/TestSerialHeapSizeFlags.java b/hotspot/test/gc/arguments/TestSerialHeapSizeFlags.java index 967adf64147..0313da53aac 100644 --- a/hotspot/test/gc/arguments/TestSerialHeapSizeFlags.java +++ b/hotspot/test/gc/arguments/TestSerialHeapSizeFlags.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestSerialHeapSizeFlags TestMaxHeapSizeTools * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm TestSerialHeapSizeFlags * @author thomas.schatzl@oracle.com */ diff --git a/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java b/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java index 14ca6ed8d3b..eb947c13488 100644 --- a/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java +++ b/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2013, 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 @@ -30,6 +30,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestUseCompressedOopsErgo TestUseCompressedOopsErgoTools * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm TestUseCompressedOopsErgo -XX:+UseG1GC * @run main/othervm TestUseCompressedOopsErgo -XX:+UseParallelGC * @run main/othervm TestUseCompressedOopsErgo -XX:+UseParallelGC -XX:-UseParallelOldGC diff --git a/hotspot/test/gc/class_unloading/AllocateBeyondMetaspaceSize.java b/hotspot/test/gc/class_unloading/AllocateBeyondMetaspaceSize.java new file mode 100644 index 00000000000..4998fa8e562 --- /dev/null +++ b/hotspot/test/gc/class_unloading/AllocateBeyondMetaspaceSize.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +import sun.hotspot.WhiteBox; + +class AllocateBeyondMetaspaceSize { + public static Object dummy; + + public static void main(String [] args) { + if (args.length != 2) { + throw new IllegalArgumentException("Usage: "); + } + + long metaspaceSize = Long.parseLong(args[0]); + long youngGenSize = Long.parseLong(args[1]); + + run(metaspaceSize, youngGenSize); + } + + private static void run(long metaspaceSize, long youngGenSize) { + WhiteBox wb = WhiteBox.getWhiteBox(); + + long allocationBeyondMetaspaceSize = metaspaceSize * 2; + long metaspace = wb.allocateMetaspace(null, allocationBeyondMetaspaceSize); + + triggerYoungGC(youngGenSize); + + wb.freeMetaspace(null, metaspace, metaspace); + } + + private static void triggerYoungGC(long youngGenSize) { + long approxAllocSize = 32 * 1024; + long numAllocations = 2 * youngGenSize / approxAllocSize; + + for (long i = 0; i < numAllocations; i++) { + dummy = new byte[(int)approxAllocSize]; + } + } +} diff --git a/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java b/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java new file mode 100644 index 00000000000..38c1e16cea1 --- /dev/null +++ b/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +/* + * @test + * @key gc + * @bug 8049831 + * @library /testlibrary /testlibrary/whitebox + * @build TestCMSClassUnloadingEnabledHWM AllocateBeyondMetaspaceSize + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver TestCMSClassUnloadingEnabledHWM + * @summary Test that -XX:-CMSClassUnloadingEnabled will trigger a Full GC when more than MetaspaceSize metadata is allocated. + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +import java.util.ArrayList; +import java.util.Arrays; + +public class TestCMSClassUnloadingEnabledHWM { + private static long MetaspaceSize = 32 * 1024 * 1024; + private static long YoungGenSize = 32 * 1024 * 1024; + + private static OutputAnalyzer run(boolean enableUnloading) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:MetaspaceSize=" + MetaspaceSize, + "-Xmn" + YoungGenSize, + "-XX:+UseConcMarkSweepGC", + "-XX:" + (enableUnloading ? "+" : "-") + "CMSClassUnloadingEnabled", + "-XX:+PrintHeapAtGC", + "-XX:+PrintGCDetails", + "AllocateBeyondMetaspaceSize", + "" + MetaspaceSize, + "" + YoungGenSize); + return new OutputAnalyzer(pb.start()); + } + + public static OutputAnalyzer runWithCMSClassUnloading() throws Exception { + return run(true); + } + + public static OutputAnalyzer runWithoutCMSClassUnloading() throws Exception { + return run(false); + } + + public static void testWithoutCMSClassUnloading() throws Exception { + // -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.*"); + } + + 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.*"); + } + + public static void main(String args[]) throws Exception { + testWithCMSClassUnloading(); + testWithoutCMSClassUnloading(); + } +} + diff --git a/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java b/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java new file mode 100644 index 00000000000..c2c17145762 --- /dev/null +++ b/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +/* + * @test + * @key gc + * @bug 8049831 + * @library /testlibrary /testlibrary/whitebox + * @build TestG1ClassUnloadingHWM AllocateBeyondMetaspaceSize + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver TestG1ClassUnloadingHWM + * @summary Test that -XX:-ClassUnloadingWithConcurrentMark will trigger a Full GC when more than MetaspaceSize metadata is allocated. + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +import java.util.ArrayList; +import java.util.Arrays; + +public class TestG1ClassUnloadingHWM { + private static long MetaspaceSize = 32 * 1024 * 1024; + private static long YoungGenSize = 32 * 1024 * 1024; + + private static OutputAnalyzer run(boolean enableUnloading) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:MetaspaceSize=" + MetaspaceSize, + "-Xmn" + YoungGenSize, + "-XX:+UseG1GC", + "-XX:" + (enableUnloading ? "+" : "-") + "ClassUnloadingWithConcurrentMark", + "-XX:+PrintHeapAtGC", + "-XX:+PrintGCDetails", + "AllocateBeyondMetaspaceSize", + "" + MetaspaceSize, + "" + YoungGenSize); + return new OutputAnalyzer(pb.start()); + } + + public static OutputAnalyzer runWithG1ClassUnloading() throws Exception { + return run(true); + } + + public static OutputAnalyzer runWithoutG1ClassUnloading() throws Exception { + return run(false); + } + + public static void testWithoutG1ClassUnloading() throws Exception { + // -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.*"); + } + + 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.*"); + } + + public static void main(String args[]) throws Exception { + testWithG1ClassUnloading(); + testWithoutG1ClassUnloading(); + } +} + diff --git a/hotspot/test/gc/g1/TestDeferredRSUpdate.java b/hotspot/test/gc/g1/TestDeferredRSUpdate.java index 7d2ebdc4eb3..f00967d1df4 100644 --- a/hotspot/test/gc/g1/TestDeferredRSUpdate.java +++ b/hotspot/test/gc/g1/TestDeferredRSUpdate.java @@ -23,7 +23,7 @@ /* * @test TestDeferredRSUpdate - * @bug 8040977 + * @bug 8040977 8052170 * @summary Ensure that running with -XX:-G1DeferredRSUpdate does not crash the VM * @key gc * @library /testlibrary @@ -38,6 +38,7 @@ public class TestDeferredRSUpdate { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-Xmx10M", + "-XX:+PrintGCDetails", // G1DeferredRSUpdate is a develop option, but we cannot limit execution of this test to only debug VMs. "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-G1DeferredRSUpdate", diff --git a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions.java b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions.java new file mode 100644 index 00000000000..b920e7ab832 --- /dev/null +++ b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +/* + * @test TestEagerReclaimHumongousRegions + * @bug 8027959 + * @summary Test to make sure that eager reclaim of humongous objects work. We simply try to fill + * up the heap with humongous objects that should be eagerly reclaimable to avoid Full GC. + * @key gc + * @library /testlibrary + */ + +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.LinkedList; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.Asserts; + +class ReclaimRegionFast { + public static final int M = 1024*1024; + + public static LinkedList garbageList = new LinkedList(); + + public static void genGarbage() { + for (int i = 0; i < 32*1024; i++) { + garbageList.add(new int[100]); + } + garbageList.clear(); + } + + // A large object referenced by a static. + static int[] filler = new int[10 * M]; + + public static void main(String[] args) { + + int[] large = new int[M]; + + Object ref_from_stack = large; + + for (int i = 0; i < 100; i++) { + // A large object that will be reclaimed eagerly. + large = new int[6*M]; + genGarbage(); + // Make sure that the compiler cannot completely remove + // the allocation of the large object until here. + System.out.println(large); + } + + // Keep the reference to the first object alive. + System.out.println(ref_from_stack); + } +} + +public class TestEagerReclaimHumongousRegions { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseG1GC", + "-Xms128M", + "-Xmx128M", + "-Xmn16M", + "-XX:+PrintGC", + ReclaimRegionFast.class.getName()); + + Pattern p = Pattern.compile("Full GC"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + int found = 0; + Matcher m = p.matcher(output.getStdout()); + while (m.find()) { found++; } + System.out.println("Issued " + found + " Full GCs"); + Asserts.assertLT(found, 10, "Found that " + found + " Full GCs were issued. This is larger than the bound. Eager reclaim seems to not work at all"); + + output.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions2.java b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions2.java new file mode 100644 index 00000000000..dafbde0ed6f --- /dev/null +++ b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions2.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +/* + * @test TestEagerReclaimHumongousRegions2 + * @bug 8051973 + * @summary Test to make sure that eager reclaim of humongous objects correctly clears + * mark bitmaps at reclaim. + * @key gc + * @library /testlibrary + */ + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Random; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +// An object that has a few references to other instances to slow down marking. +class ObjectWithSomeRefs { + public ObjectWithSomeRefs other1; + public ObjectWithSomeRefs other2; + public ObjectWithSomeRefs other3; + public ObjectWithSomeRefs other4; +} + +class ReclaimRegionFast { + public static final long MAX_MILLIS_FOR_RUN = 50 * 1000; // The maximum runtime for the actual test. + + public static final int M = 1024*1024; + + public static LinkedList garbageList = new LinkedList(); + + public static void genGarbage(Object large) { + for (int i = 0; i < 64*1024; i++) { + Object[] garbage = new Object[50]; + garbage[0] = large; + garbageList.add(garbage); + } + garbageList.clear(); + } + + public static ArrayList longList = new ArrayList(); + + public static void main(String[] args) { + + for (int i = 0; i < 16*1024; i++) { + longList.add(new ObjectWithSomeRefs()); + } + + Random rnd = new Random(); + for (int i = 0; i < longList.size(); i++) { + int len = longList.size(); + longList.get(i).other1 = longList.get(rnd.nextInt(len)); + longList.get(i).other2 = longList.get(rnd.nextInt(len)); + longList.get(i).other3 = longList.get(rnd.nextInt(len)); + longList.get(i).other4 = longList.get(rnd.nextInt(len)); + } + + int[] large1 = new int[M]; + int[] large2 = null; + int[] large3 = null; + int[] large4 = null; + + Object ref_from_stack = large1; + + long start_millis = System.currentTimeMillis(); + + for (int i = 0; i < 20; i++) { + long current_millis = System.currentTimeMillis(); + if ((current_millis - start_millis) > MAX_MILLIS_FOR_RUN) { + System.out.println("Finishing test because maximum runtime exceeded"); + break; + } + // A set of large objects that will be reclaimed eagerly - and hopefully marked. + large1 = new int[M - 20]; + large2 = new int[M - 20]; + large3 = new int[M - 20]; + large4 = new int[M - 20]; + genGarbage(large1); + // Make sure that the compiler cannot completely remove + // the allocation of the large object until here. + System.out.println(large1 + " " + large2 + " " + large3 + " " + large4); + } + + // Keep the reference to the first object alive. + System.out.println(ref_from_stack); + } +} + +public class TestEagerReclaimHumongousRegions2 { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseG1GC", + "-Xms128M", + "-Xmx128M", + "-Xmn2M", + "-XX:G1HeapRegionSize=1M", + "-XX:InitiatingHeapOccupancyPercent=0", // Want to have as much as possible initial marks. + "-XX:+PrintGC", + "-XX:+VerifyAfterGC", + "-XX:ConcGCThreads=1", // Want to make marking as slow as possible. + "-XX:+IgnoreUnrecognizedVMOptions", // G1VerifyBitmaps is develop only. + "-XX:+G1VerifyBitmaps", + ReclaimRegionFast.class.getName()); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } +} + diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index dbb617001ba..ee338013f4b 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -23,7 +23,7 @@ /* * @test TestGCLogMessages - * @bug 8035406 8027295 8035398 8019342 + * @bug 8035406 8027295 8035398 8019342 8027959 * @summary Ensure that the PrintGCDetails output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -54,6 +54,7 @@ public class TestGCLogMessages { output.shouldNotContain("[String Dedup Fixup"); output.shouldNotContain("[Young Free CSet"); output.shouldNotContain("[Non-Young Free CSet"); + output.shouldNotContain("[Humongous Reclaim"); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", @@ -71,6 +72,10 @@ public class TestGCLogMessages { output.shouldContain("[String Dedup Fixup"); output.shouldNotContain("[Young Free CSet"); output.shouldNotContain("[Non-Young Free CSet"); + output.shouldContain("[Humongous Reclaim"); + output.shouldNotContain("[Humongous Total"); + output.shouldNotContain("[Humongous Candidate"); + output.shouldNotContain("[Humongous Reclaimed"); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", @@ -90,6 +95,10 @@ public class TestGCLogMessages { output.shouldContain("[String Dedup Fixup"); output.shouldContain("[Young Free CSet"); output.shouldContain("[Non-Young Free CSet"); + output.shouldContain("[Humongous Reclaim"); + output.shouldContain("[Humongous Total"); + output.shouldContain("[Humongous Candidate"); + output.shouldContain("[Humongous Reclaimed"); output.shouldHaveExitValue(0); } diff --git a/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java b/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java index 0d3ad500a87..122597aea64 100644 --- a/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java +++ b/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox * @build TestHumongousCodeCacheRoots * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @summary Humongous objects may have references from the code cache * @run main TestHumongousCodeCacheRoots */ diff --git a/hotspot/test/runtime/6626217/Test6626217.sh b/hotspot/test/runtime/6626217/Test6626217.sh index 99ee83a06ec..a697191293a 100644 --- a/hotspot/test/runtime/6626217/Test6626217.sh +++ b/hotspot/test/runtime/6626217/Test6626217.sh @@ -69,7 +69,7 @@ ${MV} many_loader.class many_loader.impl2 ${MV} many_loader.impl1 many_loader.class ${RM} many_loader.java -${JAVA} ${TESTVMOPTS} -Xverify -Xint -cp . bug_21227 >test.out 2>&1 +${JAVA} ${TESTOPTS} -Xverify -Xint -cp . bug_21227 >test.out 2>&1 grep "loader constraint" test.out exit $? diff --git a/hotspot/test/runtime/6888954/vmerrors.sh b/hotspot/test/runtime/6888954/vmerrors.sh index 0fdd4ca0be4..28f6eea0fec 100644 --- a/hotspot/test/runtime/6888954/vmerrors.sh +++ b/hotspot/test/runtime/6888954/vmerrors.sh @@ -1,4 +1,4 @@ -# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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 @@ -44,6 +44,16 @@ # export TESTJAVA TESTVMOPTS # sh test/runtime/6888954/vmerrors.sh +if [ "${TESTSRC}" = "" ] +then + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" +fi +echo "TESTSRC=${TESTSRC}" + +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh + ulimit -c 0 # no core files i=1 @@ -84,7 +94,7 @@ do i2=$i [ $i -lt 10 ] && i2=0$i - "$TESTJAVA/bin/java" $TESTVMOPTS -XX:+IgnoreUnrecognizedVMOptions \ + "$TESTJAVA/bin/java" $TESTOPTS -XX:+IgnoreUnrecognizedVMOptions \ -XX:-TransmitErrorReport -XX:-CreateMinidumpOnCrash \ -XX:ErrorHandlerTest=${i} -version > ${i2}.out 2>&1 diff --git a/hotspot/test/runtime/7107135/Test7107135.sh b/hotspot/test/runtime/7107135/Test7107135.sh index 0aa0e864e1e..30604ff6313 100644 --- a/hotspot/test/runtime/7107135/Test7107135.sh +++ b/hotspot/test/runtime/7107135/Test7107135.sh @@ -25,7 +25,6 @@ # ## -## @ignore 8025519 ## @test Test7107135.sh ## @bug 7107135 ## @bug 8021296 diff --git a/hotspot/test/runtime/7116786/Test7116786.java b/hotspot/test/runtime/7116786/Test7116786.java index b914019258e..48eaf440b86 100644 --- a/hotspot/test/runtime/7116786/Test7116786.java +++ b/hotspot/test/runtime/7116786/Test7116786.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -147,7 +147,8 @@ class VerifyErrorCases { "no stackmap frame at jump location or bad jump", "Inconsistent stackmap frames at branch target "), - new Case("case15", "stackMapTable.cpp", true, "check_new_object", + /* Backward jump with uninit is allowed starting with JDK 8 */ + new Case("case15", "stackMapTable.cpp", false, "check_new_object", "backward jump with uninit", "Uninitialized object exists on backward branch "), diff --git a/hotspot/test/runtime/7158988/FieldMonitor.java b/hotspot/test/runtime/7158988/FieldMonitor.java index 9b16fc3d798..07c40053d34 100644 --- a/hotspot/test/runtime/7158988/FieldMonitor.java +++ b/hotspot/test/runtime/7158988/FieldMonitor.java @@ -26,6 +26,7 @@ * @bug 7158988 * @key regression * @summary verify jvm does not crash while debugging + * @ignore 8055145 * @run compile TestPostFieldModification.java * @run main/othervm FieldMonitor * @author axel.siebenborn@sap.com diff --git a/hotspot/test/runtime/7162488/Test7162488.sh b/hotspot/test/runtime/7162488/Test7162488.sh index fa47ad94746..b87d92b8d0c 100644 --- a/hotspot/test/runtime/7162488/Test7162488.sh +++ b/hotspot/test/runtime/7162488/Test7162488.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2013, 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 @@ -45,14 +45,14 @@ JAVA=${TESTJAVA}${FS}bin${FS}java # OPTION=this_is_not_an_option -${JAVA} ${TESTVMOPTS} -showversion -XX:${OPTION} 2>&1 | grep "Unrecognized VM option" +${JAVA} -showversion -XX:${OPTION} 2>&1 | grep "Unrecognized VM option" if [ "$?" != "0" ] then printf "FAILED: option not flagged as unrecognized.\n" exit 1 fi -${JAVA} ${TESTVMOPTS} -showversion -XX:${OPTION} 2>&1 | grep ${OPTION} +${JAVA} -showversion -XX:${OPTION} 2>&1 | grep ${OPTION} if [ "$?" != "0" ] then printf "FAILED: bad option not named as being bad.\n" diff --git a/hotspot/test/runtime/ClassUnload/KeepAliveClass.java b/hotspot/test/runtime/ClassUnload/KeepAliveClass.java index 57590022f86..4b9d9e41e02 100644 --- a/hotspot/test/runtime/ClassUnload/KeepAliveClass.java +++ b/hotspot/test/runtime/ClassUnload/KeepAliveClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @build KeepAliveClass test.Empty * @build ClassUnloadCommon * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveClass */ diff --git a/hotspot/test/runtime/ClassUnload/KeepAliveClassLoader.java b/hotspot/test/runtime/ClassUnload/KeepAliveClassLoader.java index a14cf0f0443..3b1f814f7f8 100644 --- a/hotspot/test/runtime/ClassUnload/KeepAliveClassLoader.java +++ b/hotspot/test/runtime/ClassUnload/KeepAliveClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @build KeepAliveClassLoader test.Empty * @build ClassUnloadCommon * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveClassLoader */ diff --git a/hotspot/test/runtime/ClassUnload/KeepAliveObject.java b/hotspot/test/runtime/ClassUnload/KeepAliveObject.java index dd460d4da73..8c46a0be4cf 100644 --- a/hotspot/test/runtime/ClassUnload/KeepAliveObject.java +++ b/hotspot/test/runtime/ClassUnload/KeepAliveObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @build KeepAliveObject test.Empty * @build ClassUnloadCommon * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveObject */ diff --git a/hotspot/test/runtime/ClassUnload/KeepAliveSoftReference.java b/hotspot/test/runtime/ClassUnload/KeepAliveSoftReference.java index a7613b886dd..80258dc4ed1 100644 --- a/hotspot/test/runtime/ClassUnload/KeepAliveSoftReference.java +++ b/hotspot/test/runtime/ClassUnload/KeepAliveSoftReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @build KeepAliveSoftReference test.Empty * @build ClassUnloadCommon * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveSoftReference */ diff --git a/hotspot/test/runtime/ClassUnload/UnloadTest.java b/hotspot/test/runtime/ClassUnload/UnloadTest.java index 1dca14b8a28..6398a077a17 100644 --- a/hotspot/test/runtime/ClassUnload/UnloadTest.java +++ b/hotspot/test/runtime/ClassUnload/UnloadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -28,6 +28,7 @@ * @build ClassUnloadCommon test.Empty * @build UnloadTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI UnloadTest */ import sun.hotspot.WhiteBox; diff --git a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java index bb68a6ff074..0855913fe73 100644 --- a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java +++ b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java @@ -26,6 +26,7 @@ * @bug 8024927 * @summary Testing address of compressed class pointer space as best as possible. * @library /testlibrary + * @ignore 8055164 */ import com.oracle.java.testlibrary.*; diff --git a/hotspot/test/runtime/NMT/AutoshutdownNMT.java b/hotspot/test/runtime/NMT/AutoshutdownNMT.java new file mode 100644 index 00000000000..8739dc8d99f --- /dev/null +++ b/hotspot/test/runtime/NMT/AutoshutdownNMT.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +/* + * @test + * @key nmt + * @summary Test for deprecated message if -XX:-AutoShutdownNMT is specified + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class AutoshutdownNMT { + + public static void main(String args[]) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:NativeMemoryTracking=detail", + "-XX:-AutoShutdownNMT", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("ignoring option AutoShutdownNMT"); + } +} diff --git a/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java b/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java index 956cdd26006..fcfa18ab6f2 100644 --- a/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java +++ b/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java @@ -26,6 +26,7 @@ * @key nmt * @summary Empty argument to NMT should result in an informative error message * @library /testlibrary + * @ignore 8055051 */ import com.oracle.java.testlibrary.*; diff --git a/hotspot/test/runtime/NMT/JcmdBaselineDetail.java b/hotspot/test/runtime/NMT/JcmdBaselineDetail.java new file mode 100644 index 00000000000..501b860f8bc --- /dev/null +++ b/hotspot/test/runtime/NMT/JcmdBaselineDetail.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +/* + * @test + * @key nmt jcmd + * @summary Verify that jcmd correctly reports that baseline succeeds with NMT enabled with detailed tracking. + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=detail JcmdBaselineDetail + */ + +import com.oracle.java.testlibrary.*; + +public class JcmdBaselineDetail { + + public static void main(String args[]) throws Exception { + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + OutputAnalyzer output; + + ProcessBuilder pb = new ProcessBuilder(); + + // Run 'jcmd VM.native_memory baseline=true' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "baseline=true"}); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Baseline succeeded"); + } +} diff --git a/hotspot/test/runtime/NMT/JcmdDetailDiff.java b/hotspot/test/runtime/NMT/JcmdDetailDiff.java new file mode 100644 index 00000000000..858883f6174 --- /dev/null +++ b/hotspot/test/runtime/NMT/JcmdDetailDiff.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +/* + * @test + * @summary run NMT baseline, allocate memory and verify output from detail.diff + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @ignore + * @build JcmdDetailDiff + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail JcmdDetailDiff + */ + +import com.oracle.java.testlibrary.*; + +import sun.hotspot.WhiteBox; + +public class JcmdDetailDiff { + + public static WhiteBox wb = WhiteBox.getWhiteBox(); + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = new ProcessBuilder(); + OutputAnalyzer output; + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + + long commitSize = 128 * 1024; + long reserveSize = 256 * 1024; + long addr; + + // Run 'jcmd VM.native_memory baseline=true' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "baseline=true"}); + pb.start().waitFor(); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Baseline succeeded"); + + addr = wb.NMTReserveMemory(reserveSize); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"}); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=256KB +256KB, committed=0KB)"); + output.shouldContain("WB_NMTReserveMemory"); + + wb.NMTCommitMemory(addr, commitSize); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"}); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=256KB +256KB, committed=128KB +128KB)"); + output.shouldContain("WB_NMTReserveMemory"); + + wb.NMTUncommitMemory(addr, commitSize); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"}); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=256KB +256KB, committed=0KB)"); + output.shouldContain("WB_NMTReserveMemory"); + + wb.NMTReleaseMemory(addr, reserveSize); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"}); + + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + } +} diff --git a/hotspot/test/runtime/NMT/JcmdScale.java b/hotspot/test/runtime/NMT/JcmdScale.java index e57d27b59a3..3d8a9518760 100644 --- a/hotspot/test/runtime/NMT/JcmdScale.java +++ b/hotspot/test/runtime/NMT/JcmdScale.java @@ -41,15 +41,15 @@ public class JcmdScale { pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=KB"}); output = new OutputAnalyzer(pb.start()); - output.shouldContain("KB, committed="); + output.shouldContain("KB, committed="); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=MB"}); output = new OutputAnalyzer(pb.start()); - output.shouldContain("MB, committed="); + output.shouldContain("MB, committed="); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=GB"}); output = new OutputAnalyzer(pb.start()); - output.shouldContain("GB, committed="); + output.shouldContain("GB, committed="); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=apa"}); output = new OutputAnalyzer(pb.start()); @@ -57,7 +57,7 @@ public class JcmdScale { pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=GB"}); output = new OutputAnalyzer(pb.start()); - output.shouldContain("GB, committed="); + output.shouldContain("GB, committed="); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=apa"}); output = new OutputAnalyzer(pb.start()); diff --git a/hotspot/test/runtime/NMT/JcmdScaleDetail.java b/hotspot/test/runtime/NMT/JcmdScaleDetail.java new file mode 100644 index 00000000000..97c809dc0a0 --- /dev/null +++ b/hotspot/test/runtime/NMT/JcmdScaleDetail.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +/* + * @test + * @key nmt jcmd + * @summary Test the NMT scale parameter with detail tracking level + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=detail JcmdScaleDetail + */ + +import com.oracle.java.testlibrary.*; + +public class JcmdScaleDetail { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = new ProcessBuilder(); + OutputAnalyzer output; + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=KB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("KB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=MB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("MB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=GB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("GB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=apa"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Incorrect scale value: apa"); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=GB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("GB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=apa"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Incorrect scale value: apa"); + } +} diff --git a/hotspot/test/runtime/NMT/JcmdSummaryDiff.java b/hotspot/test/runtime/NMT/JcmdSummaryDiff.java new file mode 100644 index 00000000000..93c13d7aa3c --- /dev/null +++ b/hotspot/test/runtime/NMT/JcmdSummaryDiff.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +/* + * @test + * @summary run NMT baseline, allocate memory and verify output from summary.diff + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build JcmdSummaryDiff + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=summary JcmdSummaryDiff + */ + +import com.oracle.java.testlibrary.*; + +import sun.hotspot.WhiteBox; + +public class JcmdSummaryDiff { + + public static WhiteBox wb = WhiteBox.getWhiteBox(); + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = new ProcessBuilder(); + OutputAnalyzer output; + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + + long commitSize = 128 * 1024; + long reserveSize = 256 * 1024; + long addr; + + // Run 'jcmd VM.native_memory baseline=true' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "baseline=true"}); + pb.start().waitFor(); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Baseline succeeded"); + + addr = wb.NMTReserveMemory(reserveSize); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary.diff", "scale=KB"}); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=256KB +256KB, committed=0KB)"); + + wb.NMTCommitMemory(addr, commitSize); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary.diff", "scale=KB"}); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=256KB +256KB, committed=128KB +128KB)"); + + wb.NMTUncommitMemory(addr, commitSize); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary.diff", "scale=KB"}); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=256KB +256KB, committed=0KB)"); + + wb.NMTReleaseMemory(addr, reserveSize); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary.diff", "scale=KB"}); + + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + } +} diff --git a/hotspot/test/runtime/NMT/MallocRoundingReportTest.java b/hotspot/test/runtime/NMT/MallocRoundingReportTest.java new file mode 100644 index 00000000000..f0a838a3200 --- /dev/null +++ b/hotspot/test/runtime/NMT/MallocRoundingReportTest.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +/* + * @test + * @summary Test consistency of NMT by creating allocations of the Test type with various sizes and verifying visibility with jcmd + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build MallocRoundingReportTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocRoundingReportTest + * + */ + +import com.oracle.java.testlibrary.*; + +import sun.hotspot.WhiteBox; + +public class MallocRoundingReportTest { + private static long K = 1024; + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + WhiteBox wb = WhiteBox.getWhiteBox(); + + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + long[] additionalBytes = {0, 1, 512, 650}; + long[] kByteSize = {1024, 2048}; + long mallocd_total = 0; + for ( int i = 0; i < kByteSize.length; i++) + { + for (int j = 0; j < (additionalBytes.length); j++) { + long curKB = kByteSize[i] + additionalBytes[j]; + // round up/down to the nearest KB to match NMT reporting + long numKB = (curKB % kByteSize[i] >= 512) ? ((curKB / K) + 1) : curKB / K; + // Use WB API to alloc and free with the mtTest type + mallocd_total = wb.NMTMalloc(curKB); + // Run 'jcmd VM.native_memory summary', check for expected output + // NMT does not track memory allocations less than 1KB, and rounds to the nearest KB + String expectedOut = ("Test (reserved=" + numKB + "KB, committed=" + numKB + "KB)"); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary" }); + output = new OutputAnalyzer(pb.start()); + output.shouldContain(expectedOut); + + wb.NMTFree(mallocd_total); + // Run 'jcmd VM.native_memory summary', check for expected output + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary" }); + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + } + } + } +} diff --git a/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java b/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java new file mode 100644 index 00000000000..32f74430e4c --- /dev/null +++ b/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +/* + * @key stress + * @test + * @summary Test corner case that overflows malloc site hashtable bucket + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @ignore - This test is disabled since it will stress NMT and timeout during normal testing + * @build MallocSiteHashOverflow + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocSiteHashOverflow + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class MallocSiteHashOverflow { + private static long K = 1024; + public static void main(String args[]) throws Exception { + String vm_name = System.getProperty("java.vm.name"); + + // For 32-bit systems, create 257 malloc sites with the same hash bucket to overflow a hash bucket + // For 64-bit systems, create 64K + 1 malloc sites with the same hash bucket to overflow a hash bucket + long entries = 257; + if (Platform.is64bit()) { + entries = 64 * K + 1; + } + + OutputAnalyzer output; + WhiteBox wb = WhiteBox.getWhiteBox(); + + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + wb.NMTOverflowHashBucket(entries); + + // Run 'jcmd VM.native_memory summary' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "statistics"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Tracking level has been downgraded due to lack of resources"); + } +} diff --git a/hotspot/test/runtime/NMT/MallocStressTest.java b/hotspot/test/runtime/NMT/MallocStressTest.java new file mode 100644 index 00000000000..4ac71c99bd1 --- /dev/null +++ b/hotspot/test/runtime/NMT/MallocStressTest.java @@ -0,0 +1,266 @@ +/* + * 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. + */ + +/* + * @key stress + * @test + * @summary Stress test for malloc tracking + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build MallocStressTest + * @ignore - This test is disabled since it will stress NMT and timeout during normal testing + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocStressTest + */ + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class MallocStressTest { + private static int K = 1024; + + // The stress test runs in three phases: + // 1. alloc: A lot of malloc with fewer free, which simulates a burst memory allocation + // that is usually seen during startup or class loading. + // 2. pause: Pause the test to check accuracy of native memory tracking + // 3. release: Release all malloc'd memory and check native memory tracking result. + public enum TestPhase { + alloc, + pause, + release + }; + + static TestPhase phase = TestPhase.alloc; + + // malloc'd memory + static ArrayList mallocd_memory = new ArrayList(); + static long mallocd_total = 0; + static WhiteBox whiteBox; + static AtomicInteger pause_count = new AtomicInteger(); + + static boolean is_64_bit_system; + + private static boolean is_64_bit_system() { return is_64_bit_system; } + + public static void main(String args[]) throws Exception { + is_64_bit_system = (Platform.is64bit()); + + OutputAnalyzer output; + whiteBox = WhiteBox.getWhiteBox(); + + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + AllocThread[] alloc_threads = new AllocThread[256]; + ReleaseThread[] release_threads = new ReleaseThread[64]; + + int index; + // Create many allocation threads + for (index = 0; index < alloc_threads.length; index ++) { + alloc_threads[index] = new AllocThread(); + } + + // Fewer release threads + for (index = 0; index < release_threads.length; index ++) { + release_threads[index] = new ReleaseThread(); + } + + if (is_64_bit_system()) { + sleep_wait(2*60*1000); + } else { + sleep_wait(60*1000); + } + // pause the stress test + phase = TestPhase.pause; + while (pause_count.intValue() < alloc_threads.length + release_threads.length) { + sleep_wait(10); + } + + long mallocd_total_in_KB = (mallocd_total + K / 2) / K; + + // Now check if the result from NMT matches the total memory allocated. + String expected_test_summary = "Test (reserved=" + mallocd_total_in_KB +"KB, committed=" + mallocd_total_in_KB + "KB)"; + // Run 'jcmd VM.native_memory summary' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain(expected_test_summary); + + // Release all allocated memory + phase = TestPhase.release; + synchronized(mallocd_memory) { + mallocd_memory.notifyAll(); + } + + // Join all threads + for (index = 0; index < alloc_threads.length; index ++) { + try { + alloc_threads[index].join(); + } catch (InterruptedException e) { + } + } + + for (index = 0; index < release_threads.length; index ++) { + try { + release_threads[index].join(); + } catch (InterruptedException e) { + } + } + + // All test memory allocated should be released + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + + // Verify that tracking level has not been downgraded + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "statistics"}); + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Tracking level has been downgraded due to lack of resources"); + } + + private static void sleep_wait(int n) { + try { + Thread.sleep(n); + } catch (InterruptedException e) { + } + } + + + static class MallocMemory { + private long addr; + private int size; + + MallocMemory(long addr, int size) { + this.addr = addr; + this.size = size; + } + + long addr() { return this.addr; } + int size() { return this.size; } + } + + static class AllocThread extends Thread { + AllocThread() { + this.setName("MallocThread"); + this.start(); + } + + // AllocThread only runs "Alloc" phase + public void run() { + Random random = new Random(); + while (MallocStressTest.phase == TestPhase.alloc) { + int r = Math.abs(random.nextInt()); + // Only malloc small amount to avoid OOM + int size = r % 32; + if (is_64_bit_system()) { + r = r % 32 * K; + } else { + r = r % 64; + } + if (size == 0) size = 1; + long addr = MallocStressTest.whiteBox.NMTMallocWithPseudoStack(size, r); + if (addr != 0) { + MallocMemory mem = new MallocMemory(addr, size); + synchronized(MallocStressTest.mallocd_memory) { + MallocStressTest.mallocd_memory.add(mem); + MallocStressTest.mallocd_total += size; + } + } else { + System.out.println("Out of malloc memory"); + break; + } + } + MallocStressTest.pause_count.incrementAndGet(); + } + } + + static class ReleaseThread extends Thread { + private Random random = new Random(); + ReleaseThread() { + this.setName("ReleaseThread"); + this.start(); + } + + public void run() { + while(true) { + switch(MallocStressTest.phase) { + case alloc: + slow_release(); + break; + case pause: + enter_pause(); + break; + case release: + quick_release(); + return; + } + } + } + + private void enter_pause() { + MallocStressTest.pause_count.incrementAndGet(); + while (MallocStressTest.phase != MallocStressTest.TestPhase.release) { + try { + synchronized(MallocStressTest.mallocd_memory) { + MallocStressTest.mallocd_memory.wait(10); + } + } catch (InterruptedException e) { + } + } + } + + private void quick_release() { + List free_list; + while (true) { + synchronized(MallocStressTest.mallocd_memory) { + if (MallocStressTest.mallocd_memory.isEmpty()) return; + int size = Math.min(MallocStressTest.mallocd_memory.size(), 5000); + List subList = MallocStressTest.mallocd_memory.subList(0, size); + free_list = new ArrayList(subList); + subList.clear(); + } + for (int index = 0; index < free_list.size(); index ++) { + MallocMemory mem = free_list.get(index); + MallocStressTest.whiteBox.NMTFree(mem.addr()); + } + } + } + + private void slow_release() { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + synchronized(MallocStressTest.mallocd_memory) { + if (MallocStressTest.mallocd_memory.isEmpty()) return; + int n = Math.abs(random.nextInt()) % MallocStressTest.mallocd_memory.size(); + MallocMemory mem = mallocd_memory.remove(n); + MallocStressTest.whiteBox.NMTFree(mem.addr()); + MallocStressTest.mallocd_total -= mem.size(); + } + } + } +} diff --git a/hotspot/test/runtime/NMT/MallocTestType.java b/hotspot/test/runtime/NMT/MallocTestType.java index 8a39af790e4..d570c2fa6a5 100644 --- a/hotspot/test/runtime/NMT/MallocTestType.java +++ b/hotspot/test/runtime/NMT/MallocTestType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -28,6 +28,7 @@ * @library /testlibrary /testlibrary/whitebox * @build MallocTestType * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocTestType */ @@ -51,11 +52,6 @@ public class MallocTestType { long memAlloc1 = wb.NMTMalloc(512 * 1024); wb.NMTFree(memAlloc2); - // Use WB API to ensure that all data has been merged before we continue - if (!wb.NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); - } - // Run 'jcmd VM.native_memory summary' pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); output = new OutputAnalyzer(pb.start()); @@ -64,10 +60,6 @@ public class MallocTestType { // Free the memory allocated by NMTAllocTest wb.NMTFree(memAlloc1); - // Use WB API to ensure that all data has been merged before we continue - if (!wb.NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); - } output = new OutputAnalyzer(pb.start()); output.shouldNotContain("Test (reserved="); } diff --git a/hotspot/test/runtime/NMT/NMTWithCDS.java b/hotspot/test/runtime/NMT/NMTWithCDS.java new file mode 100644 index 00000000000..4672d3d5f75 --- /dev/null +++ b/hotspot/test/runtime/NMT/NMTWithCDS.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8055061 + * @key nmt + * @library /testlibrary + * @run main NMTWithCDS + */ +import com.oracle.java.testlibrary.*; + +public class NMTWithCDS { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb; + pb = ProcessTools.createJavaProcessBuilder("-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + try { + output.shouldContain("Loading classes to share"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:NativeMemoryTracking=detail", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("sharing"); + output.shouldHaveExitValue(0); + + } catch (RuntimeException e) { + // Report 'passed' if CDS was turned off. + output.shouldContain("Unable to use shared archive"); + output.shouldHaveExitValue(1); + } + } +} diff --git a/hotspot/test/runtime/NMT/PrintNMTStatistics.java b/hotspot/test/runtime/NMT/PrintNMTStatistics.java index 534fe7ae421..5a4b6b08f5d 100644 --- a/hotspot/test/runtime/NMT/PrintNMTStatistics.java +++ b/hotspot/test/runtime/NMT/PrintNMTStatistics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox * @build PrintNMTStatistics * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main PrintNMTStatistics */ @@ -45,10 +46,6 @@ public class PrintNMTStatistics { // We start a new java process running with an argument and use WB API to ensure // we have data for NMT on VM exit if (args.length > 0) { - // Use WB API to ensure that all data has been merged before we continue - if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); - } return; } diff --git a/hotspot/test/runtime/NMT/ReleaseCommittedMemory.java b/hotspot/test/runtime/NMT/ReleaseCommittedMemory.java index 66bc3b18969..64ef463e5c0 100644 --- a/hotspot/test/runtime/NMT/ReleaseCommittedMemory.java +++ b/hotspot/test/runtime/NMT/ReleaseCommittedMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox * @build ReleaseCommittedMemory * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ReleaseCommittedMemory */ @@ -44,7 +45,6 @@ public class ReleaseCommittedMemory { addr = wb.NMTReserveMemory(reserveSize); wb.NMTCommitMemory(addr, 128*1024); wb.NMTReleaseMemory(addr, reserveSize); - wb.NMTWaitForDataMerge(); } } diff --git a/hotspot/test/runtime/NMT/ReleaseNoCommit.java b/hotspot/test/runtime/NMT/ReleaseNoCommit.java new file mode 100644 index 00000000000..94fba371df6 --- /dev/null +++ b/hotspot/test/runtime/NMT/ReleaseNoCommit.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +/* + * @test + * @summary Release uncommitted memory and make sure NMT handles it correctly + * @key nmt regression + * @library /testlibrary /testlibrary/whitebox + * @build ReleaseNoCommit + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=summary ReleaseNoCommit + */ + +import com.oracle.java.testlibrary.JDKToolFinder; +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +import sun.hotspot.WhiteBox; + +public class ReleaseNoCommit { + + public static void main(String args[]) throws Exception { + WhiteBox wb = WhiteBox.getWhiteBox(); + long reserveSize = 256 * 1024; + long addr; + + ProcessBuilder pb = new ProcessBuilder(); + OutputAnalyzer output; + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + + addr = wb.NMTReserveMemory(reserveSize); + // Check for reserved + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=KB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain(" Test (reserved=256KB, committed=0KB)"); + + wb.NMTReleaseMemory(addr, reserveSize); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=KB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + } +} diff --git a/hotspot/test/runtime/NMT/ShutdownTwice.java b/hotspot/test/runtime/NMT/ShutdownTwice.java index 1bb327aedb1..436e0c2c643 100644 --- a/hotspot/test/runtime/NMT/ShutdownTwice.java +++ b/hotspot/test/runtime/NMT/ShutdownTwice.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -45,12 +45,12 @@ public class ShutdownTwice { output = new OutputAnalyzer(pb.start()); // Verify that jcmd reports that NMT is shutting down - output.shouldContain("Shutdown is in progress, it will take a few moments to completely shutdown"); + output.shouldContain("Native memory tracking has been turned off"); // Run shutdown again output = new OutputAnalyzer(pb.start()); // Verify that jcmd reports that NMT has been shutdown already - output.shouldContain("Native memory tracking has been shutdown by user"); + output.shouldContain("Native memory tracking has been shutdown"); } } diff --git a/hotspot/test/runtime/NMT/SummaryAfterShutdown.java b/hotspot/test/runtime/NMT/SummaryAfterShutdown.java index 96061f3f004..ea1f3a60737 100644 --- a/hotspot/test/runtime/NMT/SummaryAfterShutdown.java +++ b/hotspot/test/runtime/NMT/SummaryAfterShutdown.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -44,13 +44,13 @@ public class SummaryAfterShutdown { output = new OutputAnalyzer(pb.start()); // Verify that jcmd reports that NMT is shutting down - output.shouldContain("Shutdown is in progress, it will take a few moments to completely shutdown"); + output.shouldContain("Native memory tracking has been turned off"); // Run 'jcmd VM.native_memory summary' pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); output = new OutputAnalyzer(pb.start()); // Verify that jcmd reports that NMT has been shutdown - output.shouldContain("Native memory tracking has been shutdown by user"); + output.shouldContain("Native memory tracking has been shutdown"); } } diff --git a/hotspot/test/runtime/NMT/SummarySanityCheck.java b/hotspot/test/runtime/NMT/SummarySanityCheck.java index 221ad9365e5..04185bb492d 100644 --- a/hotspot/test/runtime/NMT/SummarySanityCheck.java +++ b/hotspot/test/runtime/NMT/SummarySanityCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -28,6 +28,7 @@ * @library /testlibrary /testlibrary/whitebox * @build SummarySanityCheck * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+WhiteBoxAPI SummarySanityCheck */ @@ -44,11 +45,6 @@ public class SummarySanityCheck { // Grab my own PID String pid = Integer.toString(ProcessTools.getProcessId()); - // Use WB API to ensure that all data has been merged before we continue - if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); - } - ProcessBuilder pb = new ProcessBuilder(); // Run 'jcmd VM.native_memory summary scale=KB' @@ -69,13 +65,13 @@ public class SummarySanityCheck { // Match '- (reserved=KB, committed=KB) Pattern mtTypePattern = Pattern.compile("-\\s+(?[\\w\\s]+)\\(reserved=(?\\d+)KB,\\scommitted=(?\\d+)KB\\)"); // Match 'Total: reserved=KB, committed=KB' - Pattern totalMemoryPattern = Pattern.compile("Total\\:\\s\\sreserved=(?\\d+)KB,\\s\\scommitted=(?\\d+)KB"); + Pattern totalMemoryPattern = Pattern.compile("Total\\:\\sreserved=(?\\d+)KB,\\scommitted=(?\\d+)KB"); for (int i = 0; i < lines.length; i++) { if (lines[i].startsWith("Total")) { Matcher totalMemoryMatcher = totalMemoryPattern.matcher(lines[i]); - if (totalMemoryMatcher.matches() && totalMemoryMatcher.groupCount() == 2) { + if (totalMemoryMatcher.matches()) { totalCommitted = Integer.parseInt(totalMemoryMatcher.group("committed")); totalReserved = Integer.parseInt(totalMemoryMatcher.group("reserved")); } else { diff --git a/hotspot/test/runtime/NMT/ThreadedMallocTestType.java b/hotspot/test/runtime/NMT/ThreadedMallocTestType.java index eadb719d50d..036db1ea3c0 100644 --- a/hotspot/test/runtime/NMT/ThreadedMallocTestType.java +++ b/hotspot/test/runtime/NMT/ThreadedMallocTestType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build ThreadedMallocTestType * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ThreadedMallocTestType */ @@ -58,11 +59,6 @@ public class ThreadedMallocTestType { allocThread.start(); allocThread.join(); - // Use WB API to ensure that all data has been merged before we continue - if (!wb.NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); - } - // Run 'jcmd VM.native_memory summary' pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); output = new OutputAnalyzer(pb.start()); @@ -80,11 +76,6 @@ public class ThreadedMallocTestType { freeThread.start(); freeThread.join(); - // Use WB API to ensure that all data has been merged before we continue - if (!wb.NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); - } - output = new OutputAnalyzer(pb.start()); output.shouldNotContain("Test (reserved="); } diff --git a/hotspot/test/runtime/NMT/ThreadedVirtualAllocTestType.java b/hotspot/test/runtime/NMT/ThreadedVirtualAllocTestType.java index 1a7b929f0d6..c0bb7616cbd 100644 --- a/hotspot/test/runtime/NMT/ThreadedVirtualAllocTestType.java +++ b/hotspot/test/runtime/NMT/ThreadedVirtualAllocTestType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build ThreadedVirtualAllocTestType * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ThreadedVirtualAllocTestType */ @@ -60,8 +61,6 @@ public class ThreadedVirtualAllocTestType { reserveThread.start(); reserveThread.join(); - mergeData(); - pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"}); output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=512KB, committed=0KB)"); @@ -77,8 +76,6 @@ public class ThreadedVirtualAllocTestType { commitThread.start(); commitThread.join(); - mergeData(); - output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=512KB, committed=128KB)"); if (has_nmt_detail) { @@ -93,8 +90,6 @@ public class ThreadedVirtualAllocTestType { uncommitThread.start(); uncommitThread.join(); - mergeData(); - output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=512KB, committed=0KB)"); output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed"); @@ -107,17 +102,9 @@ public class ThreadedVirtualAllocTestType { releaseThread.start(); releaseThread.join(); - mergeData(); - output = new OutputAnalyzer(pb.start()); output.shouldNotContain("Test (reserved="); output.shouldNotContain("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved"); } - public static void mergeData() throws Exception { - // Use WB API to ensure that all data has been merged before we continue - if (!wb.NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); } - } -} diff --git a/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java b/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java new file mode 100644 index 00000000000..76a278b8c41 --- /dev/null +++ b/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java @@ -0,0 +1,166 @@ +/* + * 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. + */ + +/* + * @test + * @summary Test reserve/commit/uncommit/release of virtual memory and that we track it correctly + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @ignore + * @build VirtualAllocCommitUncommitRecommit + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocCommitUncommitRecommit + * + */ + +import com.oracle.java.testlibrary.*; + +import sun.hotspot.WhiteBox; + +public class VirtualAllocCommitUncommitRecommit { + + public static WhiteBox wb = WhiteBox.getWhiteBox(); + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + long commitSize = 4 * 1024; // 4KB + long reserveSize = 1024 * 1024; // 1024KB + long addr; + + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + boolean has_nmt_detail = wb.NMTIsDetailSupported(); + if (has_nmt_detail) { + System.out.println("NMT detail support detected."); + } else { + System.out.println("NMT detail support not detected."); + } + + // reserve + addr = wb.NMTReserveMemory(reserveSize); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, + "VM.native_memory", "detail" }); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=1024KB, committed=0KB)"); + if (has_nmt_detail) { + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 1024KB for Test"); + } + + long addrA = addr; + long addrB = addr + commitSize; + long addrC = addr + (2 * commitSize); + long addrD = addr + (3 * commitSize); + long addrE = addr + (4 * commitSize); + long addrF = addr + (5 * commitSize); + + // commit ABCD + wb.NMTCommitMemory(addrA, commitSize); + wb.NMTCommitMemory(addrB, commitSize); + wb.NMTCommitMemory(addrC, commitSize); + wb.NMTCommitMemory(addrD, commitSize); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=1024KB, committed=16KB)"); + + if (has_nmt_detail) { + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 1024KB for Test"); + } + // uncommit BC + wb.NMTUncommitMemory(addrB, commitSize); + wb.NMTUncommitMemory(addrC, commitSize); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=1024KB, committed=8KB)"); + + if (has_nmt_detail) { + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 1024KB for Test"); + } + + // commit EF + wb.NMTCommitMemory(addrE, commitSize); + wb.NMTCommitMemory(addrF, commitSize); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=1024KB, committed=16KB)"); + if (has_nmt_detail) { + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 1024KB for Test"); + } + + // uncommit A + wb.NMTUncommitMemory(addrA, commitSize); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=1024KB, committed=12KB)"); + if (has_nmt_detail) { + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 1024KB for Test"); + } + + // commit ABC + wb.NMTCommitMemory(addrA, commitSize); + wb.NMTCommitMemory(addrB, commitSize); + wb.NMTCommitMemory(addrC, commitSize); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=1024KB, committed=24KB)"); + if (has_nmt_detail) { + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 1024KB for Test"); + } + + // uncommit ABCDEF + wb.NMTUncommitMemory(addrA, commitSize); + wb.NMTUncommitMemory(addrB, commitSize); + wb.NMTUncommitMemory(addrC, commitSize); + wb.NMTUncommitMemory(addrD, commitSize); + wb.NMTUncommitMemory(addrE, commitSize); + wb.NMTUncommitMemory(addrF, commitSize); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=1024KB, committed=0KB)"); + if (has_nmt_detail) { + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 1024KB for Test"); + } + + // release + wb.NMTReleaseMemory(addr, reserveSize); + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + "\\] reserved"); + } +} diff --git a/hotspot/test/runtime/NMT/VirtualAllocTestType.java b/hotspot/test/runtime/NMT/VirtualAllocTestType.java index 86e751c6b31..579fba6b44f 100644 --- a/hotspot/test/runtime/NMT/VirtualAllocTestType.java +++ b/hotspot/test/runtime/NMT/VirtualAllocTestType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -28,6 +28,7 @@ * @library /testlibrary /testlibrary/whitebox * @build VirtualAllocTestType * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocTestType */ @@ -54,7 +55,6 @@ public class VirtualAllocTestType { } addr = wb.NMTReserveMemory(reserveSize); - mergeData(); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"}); output = new OutputAnalyzer(pb.start()); @@ -65,7 +65,6 @@ public class VirtualAllocTestType { wb.NMTCommitMemory(addr, commitSize); - mergeData(); output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=256KB, committed=128KB)"); @@ -75,24 +74,15 @@ public class VirtualAllocTestType { wb.NMTUncommitMemory(addr, commitSize); - mergeData(); output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=256KB, committed=0KB)"); output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed"); wb.NMTReleaseMemory(addr, reserveSize); - mergeData(); output = new OutputAnalyzer(pb.start()); output.shouldNotContain("Test (reserved="); output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved"); } - - public static void mergeData() throws Exception { - // Use WB API to ensure that all data has been merged before we continue - if (!wb.NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); } - } -} diff --git a/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java index dff619248ec..6989a643f59 100644 --- a/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java +++ b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java @@ -21,8 +21,7 @@ * questions. */ -/* @ignore JDK-8043896 - * @test LimitSharedSizes +/* @test LimitSharedSizes * @summary Test handling of limits on shared space size * @library /testlibrary * @run main LimitSharedSizes diff --git a/hotspot/test/runtime/interned/SanityTest.java b/hotspot/test/runtime/interned/SanityTest.java index 779d3fc78c6..84bc1fee7e5 100644 --- a/hotspot/test/runtime/interned/SanityTest.java +++ b/hotspot/test/runtime/interned/SanityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build SanityTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SanityTest */ diff --git a/hotspot/test/runtime/jsig/Test8017498.sh b/hotspot/test/runtime/jsig/Test8017498.sh index a28bbe4b478..315631d059c 100644 --- a/hotspot/test/runtime/jsig/Test8017498.sh +++ b/hotspot/test/runtime/jsig/Test8017498.sh @@ -24,7 +24,6 @@ # ## -## @ignore 8028806 ## @test Test8017498.sh ## @bug 8017498 ## @bug 8020791 @@ -32,6 +31,7 @@ ## @bug 8022301 ## @bug 8025519 ## @summary sigaction(sig) results in process hang/timed-out if sig is much greater than SIGRTMAX +## @ignore 8041727 ## @run shell/timeout=60 Test8017498.sh ## @@ -75,7 +75,7 @@ ${COMPILEJAVA}${FS}bin${FS}javac *.java $gcc_cmd -DLINUX -fPIC -shared \ ${EXTRA_CFLAG} -z noexecstack \ - -o ${TESTSRC}${FS}libTestJNI.so \ + -o libTestJNI.so \ -I${COMPILEJAVA}${FS}include \ -I${COMPILEJAVA}${FS}include${FS}linux \ ${TESTSRC}${FS}TestJNI.c @@ -83,7 +83,7 @@ $gcc_cmd -DLINUX -fPIC -shared \ # run the java test in the background cmd="LD_PRELOAD=$MY_LD_PRELOAD \ ${TESTJAVA}${FS}bin${FS}java \ - -Djava.library.path=${TESTSRC}${FS} -server TestJNI 100" + -Djava.library.path=. -server TestJNI 100" echo "$cmd > test.out 2>&1" eval $cmd > test.out 2>&1 diff --git a/hotspot/test/runtime/memory/ReadFromNoaccessArea.java b/hotspot/test/runtime/memory/ReadFromNoaccessArea.java index 484240287ce..7a6c71d4b4d 100644 --- a/hotspot/test/runtime/memory/ReadFromNoaccessArea.java +++ b/hotspot/test/runtime/memory/ReadFromNoaccessArea.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build ReadFromNoaccessArea * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ReadFromNoaccessArea */ diff --git a/hotspot/test/runtime/memory/ReserveMemory.java b/hotspot/test/runtime/memory/ReserveMemory.java index 3a65ca605c2..1708657f34c 100644 --- a/hotspot/test/runtime/memory/ReserveMemory.java +++ b/hotspot/test/runtime/memory/ReserveMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ * @library /testlibrary /testlibrary/whitebox * @build ReserveMemory * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ReserveMemory */ diff --git a/hotspot/test/runtime/memory/RunUnitTestsConcurrently.java b/hotspot/test/runtime/memory/RunUnitTestsConcurrently.java index 35b855e0af3..e979504c664 100644 --- a/hotspot/test/runtime/memory/RunUnitTestsConcurrently.java +++ b/hotspot/test/runtime/memory/RunUnitTestsConcurrently.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build RunUnitTestsConcurrently * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI RunUnitTestsConcurrently 30 15000 */ diff --git a/hotspot/test/runtime/memory/StressVirtualSpaceResize.java b/hotspot/test/runtime/memory/StressVirtualSpaceResize.java index df978012080..ebe5110a64f 100644 --- a/hotspot/test/runtime/memory/StressVirtualSpaceResize.java +++ b/hotspot/test/runtime/memory/StressVirtualSpaceResize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build StressVirtualSpaceResize * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI StressVirtualSpaceResize */ diff --git a/hotspot/test/runtime/whitebox/WBStackSize.java b/hotspot/test/runtime/whitebox/WBStackSize.java index ff1a4dcca25..b487bb472bc 100644 --- a/hotspot/test/runtime/whitebox/WBStackSize.java +++ b/hotspot/test/runtime/whitebox/WBStackSize.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build WBStackSize * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xss512k WBStackSize */ diff --git a/hotspot/test/sanity/WBApi.java b/hotspot/test/sanity/WBApi.java index 3d926777121..58c100f496e 100644 --- a/hotspot/test/sanity/WBApi.java +++ b/hotspot/test/sanity/WBApi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build WBApi * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI WBApi */ diff --git a/hotspot/test/sanity/WhiteBox.java b/hotspot/test/sanity/WhiteBox.java index a366e4dd117..b47d339f55e 100644 --- a/hotspot/test/sanity/WhiteBox.java +++ b/hotspot/test/sanity/WhiteBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 diff --git a/hotspot/test/serviceability/ParserTest.java b/hotspot/test/serviceability/ParserTest.java index 8db151f4d3f..264b25c89bf 100644 --- a/hotspot/test/serviceability/ParserTest.java +++ b/hotspot/test/serviceability/ParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.parser.* * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ParserTest */ diff --git a/hotspot/test/serviceability/attach/AttachSetGetFlag.java b/hotspot/test/serviceability/attach/AttachSetGetFlag.java new file mode 100644 index 00000000000..230ef3c8c27 --- /dev/null +++ b/hotspot/test/serviceability/attach/AttachSetGetFlag.java @@ -0,0 +1,171 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8054823 + * @summary Tests the setFlag and printFlag attach command + * @library /testlibrary + * @build com.oracle.java.testlibrary.* AttachSetGetFlag + * @run driver AttachSetGetFlag + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import sun.tools.attach.HotSpotVirtualMachine; + +import com.oracle.java.testlibrary.Asserts; +import com.oracle.java.testlibrary.Platform; +import com.oracle.java.testlibrary.ProcessTools; +import com.sun.tools.attach.VirtualMachine; + +public class AttachSetGetFlag { + + public static void main(String... args) throws Exception { + // Test a manageable uintx flag. + testGetFlag("MaxHeapFreeRatio", "60"); + testSetFlag("MaxHeapFreeRatio", "50", "60"); + + // Test a non-manageable size_t flag. + // Since it is not manageable, we can't test the setFlag functionality. + testGetFlag("ArrayAllocatorMallocLimit", "128"); + // testSetFlag("ArrayAllocatorMallocLimit", "64", "128"); + } + + public static ProcessBuilder runTarget(String flagName, String flagValue) throws Exception { + return ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:" + flagName + "=" + flagValue, + "AttachSetGetFlag$Target"); + } + + public static void testGetFlag(String flagName, String flagValue) throws Exception { + ProcessBuilder pb = runTarget(flagName, flagValue); + + Process target = pb.start(); + + try { + waitForReady(target); + + int pid = (int)target.getPid(); + + HotSpotVirtualMachine vm = (HotSpotVirtualMachine)VirtualMachine.attach(((Integer)pid).toString()); + + // Test Get + BufferedReader remoteDataReader = new BufferedReader(new InputStreamReader( + vm.printFlag(flagName))); + + boolean foundExpectedLine = false; + + String line = null; + while((line = remoteDataReader.readLine()) != null) { + System.out.println("printFlag: " + line); + if (line.equals("-XX:" + flagName + "=" + flagValue)) { + foundExpectedLine = true; + } + } + + Asserts.assertTrue(foundExpectedLine, "Didn't get the expected output: '-XX:" + flagName + "=" + flagValue + "'"); + + vm.detach(); + } + finally { + target.destroy(); + target.waitFor(); + } + } + + public static void testSetFlag(String flagName, String initialFlagValue, String flagValue) throws Exception { + ProcessBuilder pb = runTarget(flagName, initialFlagValue); + + Process target = pb.start(); + + try { + waitForReady(target); + + int pid = (int)target.getPid(); + + HotSpotVirtualMachine vm = (HotSpotVirtualMachine)VirtualMachine.attach(((Integer)pid).toString()); + + // First set the value. + BufferedReader remoteDataReader = new BufferedReader(new InputStreamReader( + vm.setFlag(flagName, flagValue))); + + String line; + while((line = remoteDataReader.readLine()) != null) { + System.out.println("setFlag: " + line); + // Just empty the stream. + } + remoteDataReader.close(); + + // Then read and make sure we get back the set value. + remoteDataReader = new BufferedReader(new InputStreamReader(vm.printFlag(flagName))); + + boolean foundExpectedLine = false; + line = null; + while((line = remoteDataReader.readLine()) != null) { + System.out.println("getFlag: " + line); + if (line.equals("-XX:" + flagName + "=" + flagValue)) { + foundExpectedLine = true; + } + } + + Asserts.assertTrue(foundExpectedLine, "Didn't get the expected output: '-XX:" + flagName + "=" + flagValue + "'"); + + vm.detach(); + + } finally { + target.destroy(); + target.waitFor(); + } + } + + private static void waitForReady(Process target) throws Exception { + InputStream os = target.getInputStream(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(os))) { + String line; + while ((line = reader.readLine()) != null) { + if ("Ready".equals(line)) { + return; + } + } + } + } + + + public static class Target { + public static void main(String [] args) throws Exception { + System.out.println("Ready"); + System.out.flush(); + while (true) { + Thread.sleep(1000); + } + } + } +} diff --git a/hotspot/test/test_env.sh b/hotspot/test/test_env.sh index fa912dde237..e9fc3abb0ff 100644 --- a/hotspot/test/test_env.sh +++ b/hotspot/test/test_env.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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 @@ -50,6 +50,9 @@ then fi echo "TESTCLASSES=${TESTCLASSES}" +TESTOPTS="${TESTVMOPTS} ${TESTJAVAOPTS}" +echo "TESTOPTS=${TESTOPTS}" + # set platform-dependent variables OS=`uname -s` case "$OS" in @@ -101,14 +104,14 @@ THIS_DIR=. echo "THIS_DIR=${THIS_DIR}" # Check to ensure the java defined actually works -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -version +${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -version if [ $? != 0 ]; then - echo "Wrong TESTJAVA or TESTVMOPTS:" - echo $TESTJAVA TESTVMOPTS + echo "Wrong TESTJAVA or TESTJAVAOPTS or TESTVMOPTS:" + echo ''$TESTJAVA'' ''$TESTJAVAOPTS'' ''$TESTVMOPTS'' exit 1 fi -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xinternalversion > vm_version.out 2>&1 +${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xinternalversion > vm_version.out 2>&1 VM_TYPE="unknown" grep "Server" vm_version.out > ${NULL} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/BuildHelper.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/BuildHelper.java new file mode 100644 index 00000000000..0297b2ca6a0 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/BuildHelper.java @@ -0,0 +1,106 @@ +/* + * 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 com.oracle.java.testlibrary; + +import java.io.File; +import java.io.FileReader; +import java.util.Properties; + +public class BuildHelper { + + /** + * Commercial builds should have the BUILD_TYPE set to commercial + * within the release file, found at the root of the JDK. + */ + public static boolean isCommercialBuild() throws Exception { + String buildType = getReleaseProperty("BUILD_TYPE","notFound"); + return buildType.equals("commercial"); + } + + + /** + * Return the value for property key, or defaultValue if no property not found. + * If present, double quotes are trimmed. + */ + public static String getReleaseProperty(String key, String defaultValue) throws Exception { + Properties properties = getReleaseProperties(); + String value = properties.getProperty(key, defaultValue); + return trimDoubleQuotes(value); + } + + /** + * Return the value for property key, or null if no property not found. + * If present, double quotes are trimmed. + */ + public static String getReleaseProperty(String key) throws Exception { + return getReleaseProperty(key, null); + } + + /** + * Get properties from the release file + */ + public static Properties getReleaseProperties() throws Exception { + Properties properties = new Properties(); + properties.load(new FileReader(getReleaseFile())); + return properties; + } + + /** + * Every JDK has a release file in its root. + * @return A handler to the release file. + */ + public static File getReleaseFile() throws Exception { + String jdkPath = getJDKRoot(); + File releaseFile = new File(jdkPath,"release"); + if ( ! releaseFile.canRead() ) { + throw new Exception("Release file is not readable, or it is absent: " + + releaseFile.getCanonicalPath()); + } + return releaseFile; + } + + /** + * Returns path to the JDK under test. + * This path is obtained through the test.jdk property, usually set by JTREG. + */ + public static String getJDKRoot() { + String jdkPath = System.getProperty("test.jdk"); + if (jdkPath == null) { + throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. " + + "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'."); + } + return jdkPath; + } + + /** + * Trim double quotes from the beginning and the end of the given string. + * @param original string to trim. + * @return a new trimmed string. + */ + public static String trimDoubleQuotes(String original) { + if (original == null) { return null; } + String trimmed = original.replaceAll("^\"+|\"+$", ""); + return trimmed; + } +} diff --git a/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java b/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java index cc28d403400..5cbaaf9a66a 100644 --- a/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java +++ b/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src * @build ClassFileInstaller sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassesDirTest prepare * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes * @run main ClassesDirTest check ctw.log diff --git a/hotspot/test/testlibrary/ctw/test/ClassesListTest.java b/hotspot/test/testlibrary/ctw/test/ClassesListTest.java index 64c5203cf10..ea8abe27106 100644 --- a/hotspot/test/testlibrary/ctw/test/ClassesListTest.java +++ b/hotspot/test/testlibrary/ctw/test/ClassesListTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src * @build ClassFileInstaller sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassesListTest prepare * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst * @run main ClassesListTest check ctw.log diff --git a/hotspot/test/testlibrary/ctw/test/JarDirTest.java b/hotspot/test/testlibrary/ctw/test/JarDirTest.java index abc5a0843d2..193aea4f647 100644 --- a/hotspot/test/testlibrary/ctw/test/JarDirTest.java +++ b/hotspot/test/testlibrary/ctw/test/JarDirTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main JarDirTest prepare * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/* * @run main JarDirTest check ctw.log diff --git a/hotspot/test/testlibrary/ctw/test/JarsTest.java b/hotspot/test/testlibrary/ctw/test/JarsTest.java index c9bfb303132..87bafe85898 100644 --- a/hotspot/test/testlibrary/ctw/test/JarsTest.java +++ b/hotspot/test/testlibrary/ctw/test/JarsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main JarsTest prepare * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar * @run main JarsTest check ctw.log diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java index bb58361ffda..605e42c1a98 100644 --- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java @@ -73,6 +73,8 @@ public class WhiteBox { // Memory public native long getObjectAddress(Object o); public native int getHeapOopSize(); + public native boolean isObjectInOldGen(Object o); + public native long getObjectSize(Object o); // Runtime // Make sure class name is in the correct format @@ -95,7 +97,8 @@ public class WhiteBox { public native void NMTCommitMemory(long addr, long size); public native void NMTUncommitMemory(long addr, long size); public native void NMTReleaseMemory(long addr, long size); - public native boolean NMTWaitForDataMerge(); + public native void NMTOverflowHashBucket(long num); + public native long NMTMallocWithPseudoStack(long size, int index); public native boolean NMTIsDetailSupported(); // Compiler @@ -149,6 +152,9 @@ public class WhiteBox { public native long allocateMetaspace(ClassLoader classLoader, long size); public native void freeMetaspace(ClassLoader classLoader, long addr, long size); + // force Young GC + public native void youngGC(); + // force Full GC public native void fullGC(); @@ -167,17 +173,20 @@ public class WhiteBox { public native void setIntxVMFlag(String name, long value); public native void setUintxVMFlag(String name, long value); public native void setUint64VMFlag(String name, long value); + public native void setSizeTVMFlag(String name, long value); public native void setStringVMFlag(String name, String value); public native void setDoubleVMFlag(String name, double value); public native Boolean getBooleanVMFlag(String name); public native Long getIntxVMFlag(String name); public native Long getUintxVMFlag(String name); public native Long getUint64VMFlag(String name); + public native Long getSizeTVMFlag(String name); public native String getStringVMFlag(String name); public native Double getDoubleVMFlag(String name); private final List> flagsGetters = Arrays.asList( this::getBooleanVMFlag, this::getIntxVMFlag, this::getUintxVMFlag, - this::getUint64VMFlag, this::getStringVMFlag, this::getDoubleVMFlag); + this::getUint64VMFlag, this::getSizeTVMFlag, this::getStringVMFlag, + this::getDoubleVMFlag); public Object getVMFlag(String name) { return flagsGetters.stream() diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java index a76fd4d9a22..ae068f8867a 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build BooleanTest ClassFileInstaller sun.hotspot.WhiteBox com.oracle.java.testlibrary.* * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI BooleanTest * @summary testing of WB::set/getBooleanVMFlag() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java index 2110fb9d7a7..0b320e7b21b 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build DoubleTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI DoubleTest * @summary testing of WB::set/getDoubleVMFlag() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java index 6ffbd832611..3b957eff084 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build IntxTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI IntxTest * @summary testing of WB::set/getIntxVMFlag() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/SizeTTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/SizeTTest.java new file mode 100644 index 00000000000..51559cfbb53 --- /dev/null +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/SizeTTest.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/* + * @test SizeTTest + * @bug 8054823 + * @library /testlibrary /testlibrary/whitebox + * @build SizeTTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions SizeTTest + * @summary testing of WB::set/getSizeTVMFlag() + */ +import com.oracle.java.testlibrary.Platform; + +public class SizeTTest { + private static final String FLAG_NAME = "ArrayAllocatorMallocLimit"; + private static final Long[] TESTS = {0L, 100L, (long) Integer.MAX_VALUE, + (1L << 32L) - 1L, 1L << 32L}; + private static final Long[] EXPECTED_64 = TESTS; + private static final Long[] EXPECTED_32 = {0L, 100L, + (long) Integer.MAX_VALUE, (1L << 32L) - 1L, 0L}; + + public static void main(String[] args) throws Exception { + VmFlagTest.runTest(FLAG_NAME, TESTS, + Platform.is64bit() ? EXPECTED_64 : EXPECTED_32, + VmFlagTest.WHITE_BOX::setSizeTVMFlag, + VmFlagTest.WHITE_BOX::getSizeTVMFlag); + } +} diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/StringTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/StringTest.java index 70aa0664c54..77a02d3d2d4 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/StringTest.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/StringTest.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build StringTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI StringTest * @summary testing of WB::set/getStringVMFlag() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/Uint64Test.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/Uint64Test.java index 2f616d45507..fd3a82c41e8 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/Uint64Test.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/Uint64Test.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build Uint64Test * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI Uint64Test * @summary testing of WB::set/getUint64VMFlag() * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/UintxTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/UintxTest.java index 7141221f204..40eb85f868f 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/UintxTest.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/UintxTest.java @@ -27,6 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build UintxTest * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI UintxTest * @summary testing of WB::set/getUintxVMFlag() * @author igor.ignatyev@oracle.com diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 051c0879c7b..40f6d552164 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -269,3 +269,5 @@ f9c82769a6bc2b219a8f01c24afe5c91039267d7 jdk9-b19 345af113f57206711f75089c3ebf84a36a789122 jdk9-b24 73757f4b8aa353ca8937abc07e79e7ece4c011a1 jdk9-b25 a5aea8318ae4a9c2105228568688875142d70344 jdk9-b26 +2bfaf29cc90b19948938e3ef1a0983eee68806c7 jdk9-b27 +dc1e26434b3fd7e9b8eeab149103c1e30965f95c jdk9-b28 diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/Constants.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/Constants.java index 4e276fb6ad6..3a84797138b 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/Constants.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/Constants.java @@ -1,13 +1,10 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - */ - -/* - * Copyright 2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -41,6 +38,9 @@ public final class Constants { public static final String NS_XMLSCHEMA = "http://www.w3.org/2001/XMLSchema".intern(); public static final String NS_DTD = "http://www.w3.org/TR/REC-xml".intern(); + // Schema Versions: + public static final String W3C_XML_SCHEMA10_NS_URI = "http://www.w3.org/XML/XMLSchema/v1.0".intern(); + // Schema features public static final String SUN_SCHEMA_FEATURE_PREFIX = "http://java.sun.com/xml/schema/features/"; public static final String SUN_REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE = "report-ignored-element-content-whitespace"; @@ -487,6 +487,40 @@ public final class Constants { /** XInclude fixup language feature ("xinclude/fixup-language"). */ public static final String XINCLUDE_FIXUP_LANGUAGE_FEATURE = "xinclude/fixup-language"; + /** + * Feature to ignore xsi:type attributes on elements during validation, + * until a global element declaration is found. ("validation/schema/ignore-xsi-type-until-elemdecl") + * If this feature is on when validating a document, then beginning at the validation root + * element, xsi:type attributes are ignored until a global element declaration is + * found for an element. Once a global element declaration has been found, xsi:type + * attributes will start being processed for the sub-tree beginning at the element for + * which the declaration was found. + * + * Suppose an element A has two element children, B and C. + * + * If a global element declaration is found for A, xsi:type attributes on A, B and C, + * and all of B and C's descendents, will be processed. + * + * If no global element declaration is found for A or B, but one is found for C, + * then xsi:type attributes will be ignored on A and B (and any descendents of B, + * until a global element declaration is found), but xsi:type attributes will be + * processed for C and all of C's descendents. + * + * Once xsi:type attributes stop being ignored for a subtree, they do not start + * being ignored again, even if more elements are encountered for which no global + * element declaration can be found. + */ + public static final String IGNORE_XSI_TYPE_FEATURE = "validation/schema/ignore-xsi-type-until-elemdecl"; + + /** Perform checking of ID/IDREFs ("validation/id-idref-checking") */ + public static final String ID_IDREF_CHECKING_FEATURE = "validation/id-idref-checking"; + + /** Feature to ignore errors caused by identity constraints ("validation/identity-constraint-checking") */ + public static final String IDC_CHECKING_FEATURE = "validation/identity-constraint-checking"; + + /** Feature to ignore errors caused by unparsed entities ("validation/unparsed-entity-checking") */ + public static final String UNPARSED_ENTITY_CHECKING_FEATURE = "validation/unparsed-entity-checking"; + /** * Internal feature. When set to true the schema validator will only use * schema components from the grammar pool provided. @@ -598,6 +632,8 @@ public final class Constants { /** Validation manager property ("internal/validation-manager"). */ public static final String VALIDATION_MANAGER_PROPERTY = "internal/validation-manager"; + /** Schema type of the root element in a document ("validation/schema/root-type-definition"). */ + public static final String ROOT_TYPE_DEFINITION_PROPERTY = "validation/schema/root-type-definition"; /** XPointer Schema property ("xpointer-schema"). */ public static final String XPOINTER_SCHEMA_PROPERTY = "xpointer-schema"; @@ -739,6 +775,10 @@ public final class Constants { XINCLUDE_FEATURE, XINCLUDE_FIXUP_BASE_URIS_FEATURE, XINCLUDE_FIXUP_LANGUAGE_FEATURE, + IGNORE_XSI_TYPE_FEATURE, + ID_IDREF_CHECKING_FEATURE, + IDC_CHECKING_FEATURE, + UNPARSED_ENTITY_CHECKING_FEATURE, NAMESPACE_GROWTH_FEATURE, TOLERATE_DUPLICATES_FEATURE, }; @@ -762,6 +802,7 @@ public final class Constants { VALIDATION_MANAGER_PROPERTY, BUFFER_SIZE_PROPERTY, SECURITY_MANAGER_PROPERTY, + ROOT_TYPE_DEFINITION_PROPERTY, LOCALE_PROPERTY, SCHEMA_DV_FACTORY_PROPERTY, }; diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/ValidatedInfo.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/ValidatedInfo.java index e6b8f267a5d..cc84353bd64 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/ValidatedInfo.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/ValidatedInfo.java @@ -1,13 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 2001, 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -21,6 +18,7 @@ package com.sun.org.apache.xerces.internal.impl.dv; import com.sun.org.apache.xerces.internal.xs.ShortList; +import com.sun.org.apache.xerces.internal.xs.XSConstants; /** * Class to get the information back after content is validated. This info @@ -95,4 +93,60 @@ public class ValidatedInfo { else return actualValue.toString(); } + + /** + * Returns true if the two ValidatedInfo objects can be compared in the same + * value space. + */ + public static boolean isComparable(ValidatedInfo info1, ValidatedInfo info2) { + final short primitiveType1 = convertToPrimitiveKind(info1.actualValueType); + final short primitiveType2 = convertToPrimitiveKind(info2.actualValueType); + if (primitiveType1 != primitiveType2) { + return (primitiveType1 == XSConstants.ANYSIMPLETYPE_DT && primitiveType2 == XSConstants.STRING_DT || + primitiveType1 == XSConstants.STRING_DT && primitiveType2 == XSConstants.ANYSIMPLETYPE_DT); + } + else if (primitiveType1 == XSConstants.LIST_DT || primitiveType1 == XSConstants.LISTOFUNION_DT) { + final ShortList typeList1 = info1.itemValueTypes; + final ShortList typeList2 = info2.itemValueTypes; + final int typeList1Length = typeList1 != null ? typeList1.getLength() : 0; + final int typeList2Length = typeList2 != null ? typeList2.getLength() : 0; + if (typeList1Length != typeList2Length) { + return false; + } + for (int i = 0; i < typeList1Length; ++i) { + final short primitiveItem1 = convertToPrimitiveKind(typeList1.item(i)); + final short primitiveItem2 = convertToPrimitiveKind(typeList2.item(i)); + if (primitiveItem1 != primitiveItem2) { + if (primitiveItem1 == XSConstants.ANYSIMPLETYPE_DT && primitiveItem2 == XSConstants.STRING_DT || + primitiveItem1 == XSConstants.STRING_DT && primitiveItem2 == XSConstants.ANYSIMPLETYPE_DT) { + continue; + } + return false; + } + } + } + return true; + } + + /** + * Returns the primitive type of the given type. + * @param valueType A value type as defined in XSConstants. + * @return The primitive type from which valueType was derived. + */ + private static short convertToPrimitiveKind(short valueType) { + /** Primitive datatypes. */ + if (valueType <= XSConstants.NOTATION_DT) { + return valueType; + } + /** Types derived from string. */ + if (valueType <= XSConstants.ENTITY_DT) { + return XSConstants.STRING_DT; + } + /** Types derived from decimal. */ + if (valueType <= XSConstants.POSITIVEINTEGER_DT) { + return XSConstants.DECIMAL_DT; + } + /** Other types. */ + return valueType; + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties index d986140a86e..5b73376eb50 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties @@ -14,20 +14,18 @@ # Identity constraints - AbsentKeyValue = Identity Constraint error (cvc-identity-constraint.4.2.1): element \"{0}\" has a key with no value. + AbsentKeyValue = cvc-identity-constraint.4.2.1.a: Element \"{0}\" has no value for the key \"{1}\". DuplicateField = Duplicate match in scope for field \"{0}\". - DuplicateKey = Duplicate key value [{0}] declared for identity constraint of element \"{1}\". - DuplicateUnique = Duplicate unique value [{0}] declared for identity constraint of element \"{1}\". - FieldMultipleMatch = Identity constraint error: field \"{0}\" matches more than one value within the scope of its selector; fields must match unique values. + DuplicateKey = cvc-identity-constraint.4.2.2: Duplicate key value [{0}] declared for identity constraint \"{2}\" of element \"{1}\". + DuplicateUnique = cvc-identity-constraint.4.1: Duplicate unique value [{0}] declared for identity constraint \"{2}\" of element \"{1}\". + FieldMultipleMatch = cvc-identity-constraint.3: Field \"{0}\" of identity constraint \"{1}\" matches more than one value within the scope of its selector; fields must match unique values. FixedDiffersFromActual = The content of this element is not equivalent to the value of the \"fixed\" attribute in the element's declaration in the schema. - KeyMatchesNillable = Identity Constraint error (cvc-identity-constraint.4.2.3): element \"{0}\" has a key which matches an element which has nillable set to true. - KeyNotEnoughValues = Not enough values specified for identity constraint specified for element \"{0}\". - KeyNotFound = Key ''{0}'' with value ''{1}'' not found for identity constraint of element ''{2}''. - KeyRefNotEnoughValues = Not enough values specified for identity constraint specified for element \"{0}\". + KeyMatchesNillable = cvc-identity-constraint.4.2.3: Element \"{0}\" has the key \"{1}\" which matches an element which has nillable set to true. + KeyNotEnoughValues = cvc-identity-constraint.4.2.1.b: Not enough values specified for identity constraint specified for element \"{0}\". + KeyNotFound = cvc-identity-constraint.4.3: Key ''{0}'' with value ''{1}'' not found for identity constraint of element ''{2}''. KeyRefOutOfScope = Identity Constraint error: identity constraint \"{0}\" has a keyref which refers to a key or unique that is out of scope. KeyRefReferNotFound = Key reference declaration \"{0}\" refers to unknown key with name \"{1}\". - UniqueNotEnoughValues = Not enough values specified for identity constraint specified for element \"{0}\". - UnknownField = Internal identity constraint error; unknown field \"{0}\". + UnknownField = Internal identity constraint error; unknown field \"{0}\" for identity constraint \"{2}\" specified for element \"{1}\". # Ideally, we should only use the following error keys, not the ones under # "Identity constraints". And we should cover all of the following errors. @@ -79,6 +77,7 @@ cvc-minLength-valid = cvc-minLength-valid: Value ''{0}'' with length = ''{1}'' is not facet-valid with respect to minLength ''{2}'' for type ''{3}''. cvc-pattern-valid = cvc-pattern-valid: Value ''{0}'' is not facet-valid with respect to pattern ''{1}'' for type ''{2}''. cvc-totalDigits-valid = cvc-totalDigits-valid: Value ''{0}'' has {1} total digits, but the number of total digits has been limited to {2}. + cvc-type.1 = cvc-type.1: The type definition ''{0}'' was not found. cvc-type.2 = cvc-type.2: The type definition cannot be abstract for element {0}. cvc-type.3.1.1 = cvc-type.3.1.1: Element ''{0}'' is a simple type, so it cannot have attributes, excepting those whose namespace name is identical to ''http://www.w3.org/2001/XMLSchema-instance'' and whose [local name] is one of ''type'', ''nil'', ''schemaLocation'' or ''noNamespaceSchemaLocation''. However, the attribute, ''{1}'' was found. cvc-type.3.1.2 = cvc-type.3.1.2: Element ''{0}'' is a simple type, so it must have no element information item [children]. diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/validation/ConfigurableValidationState.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/validation/ConfigurableValidationState.java new file mode 100644 index 00000000000..ac8406dd325 --- /dev/null +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/validation/ConfigurableValidationState.java @@ -0,0 +1,123 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.sun.org.apache.xerces.internal.impl.validation; + +/** + *

An extension of ValidationState which can be configured to turn + * off checking for ID/IDREF errors and unparsed entity errors.

+ * + * @xerces.internal + * + * @author Peter McCracken, IBM + */ +public final class ConfigurableValidationState extends ValidationState { + + /** + * Whether to check for ID/IDREF errors + */ + private boolean fIdIdrefChecking; + + /** + * Whether to check for unparsed entity errors + */ + private boolean fUnparsedEntityChecking; + + /** + * Creates a new ConfigurableValidationState. + * By default, error checking for both ID/IDREFs + * and unparsed entities are turned on. + */ + public ConfigurableValidationState() { + super(); + fIdIdrefChecking = true; + fUnparsedEntityChecking = true; + } + + /** + * Turns checking for ID/IDREF errors on and off. + * @param setting: true to turn on error checking + * false to turn off error checking + */ + public void setIdIdrefChecking(boolean setting) { + fIdIdrefChecking = setting; + } + + /** + * Turns checking for unparsed entity errors on and off. + * @param setting: true to turn on error checking + * false to turn off error checking + */ + public void setUnparsedEntityChecking(boolean setting) { + fUnparsedEntityChecking = setting; + } + + /** + * Checks if all IDREFs have a corresponding ID. + * @return null, if ID/IDREF checking is turned off + * otherwise, returns the value of the super implementation + */ + public String checkIDRefID() { + return (fIdIdrefChecking) ? super.checkIDRefID() : null; + } + + /** + * Checks if an ID has already been declared. + * @return false, if ID/IDREF checking is turned off + * otherwise, returns the value of the super implementation + */ + public boolean isIdDeclared(String name) { + return (fIdIdrefChecking) ? super.isIdDeclared(name) : false; + } + + /** + * Checks if an entity is declared. + * @return true, if unparsed entity checking is turned off + * otherwise, returns the value of the super implementation + */ + public boolean isEntityDeclared(String name) { + return (fUnparsedEntityChecking) ? super.isEntityDeclared(name) : true; + } + + /** + * Checks if an entity is unparsed. + * @return true, if unparsed entity checking is turned off + * otherwise, returns the value of the super implementation + */ + public boolean isEntityUnparsed(String name) { + return (fUnparsedEntityChecking) ? super.isEntityUnparsed(name) : true; + } + + /** + * Adds the ID, if ID/IDREF checking is enabled. + * @param the ID to add + */ + public void addId(String name) { + if (fIdIdrefChecking) { + super.addId(name); + } + } + + /** + * Adds the IDREF, if ID/IDREF checking is enabled. + * @param the IDREF to add + */ + public void addIdRef(String name) { + if (fIdIdrefChecking) { + super.addIdRef(name); + } + } +} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaValidator.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaValidator.java index fd03b7a8f75..dbe788ac599 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaValidator.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaValidator.java @@ -1,13 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -38,6 +35,7 @@ import com.sun.org.apache.xerces.internal.impl.dv.DatatypeException; import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException; import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo; import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType; +import com.sun.org.apache.xerces.internal.impl.validation.ConfigurableValidationState; import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager; import com.sun.org.apache.xerces.internal.impl.validation.ValidationState; import com.sun.org.apache.xerces.internal.impl.xs.identity.Field; @@ -185,6 +183,22 @@ public class XMLSchemaValidator protected static final String TOLERATE_DUPLICATES = Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE; + /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */ + protected static final String IGNORE_XSI_TYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE; + + /** Feature identifier: whether to ignore ID/IDREF errors */ + protected static final String ID_IDREF_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore unparsed entity errors */ + protected static final String UNPARSED_ENTITY_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore identity constraint errors */ + protected static final String IDENTITY_CONSTRAINT_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE; + protected static final String REPORT_WHITESPACE = Constants.SUN_SCHEMA_FEATURE_PREFIX + Constants.SUN_REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE; @@ -228,6 +242,10 @@ public class XMLSchemaValidator protected static final String JAXP_SCHEMA_LANGUAGE = Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE; + /** Property identifier: root type definition. */ + protected static final String ROOT_TYPE_DEF = + Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_TYPE_DEFINITION_PROPERTY; + /** Property identifier: Schema DV Factory */ protected static final String SCHEMA_DV_FACTORY = Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY; @@ -254,6 +272,10 @@ public class XMLSchemaValidator VALIDATE_ANNOTATIONS, HONOUR_ALL_SCHEMALOCATIONS, USE_GRAMMAR_POOL_ONLY, + IGNORE_XSI_TYPE, + ID_IDREF_CHECKING, + IDENTITY_CONSTRAINT_CHECKING, + UNPARSED_ENTITY_CHECKING, NAMESPACE_GROWTH, TOLERATE_DUPLICATES, USE_SERVICE_MECHANISM @@ -267,6 +289,10 @@ public class XMLSchemaValidator // those set by the application. This goes against the // whole purpose of XMLComponent#getFeatureDefault but // it can't be helped in this case. -Ac + // NOTE: Instead of adding default values here, add them (and + // the corresponding recognized features) to the objects + // that have an XMLSchemaValidator instance as a member, + // such as the parser configurations. -PM null, //Boolean.FALSE, null, //Boolean.FALSE, null, //Boolean.FALSE, @@ -279,6 +305,10 @@ public class XMLSchemaValidator null, null, null, + null, + null, + null, + null, Boolean.TRUE }; @@ -293,13 +323,14 @@ public class XMLSchemaValidator SCHEMA_NONS_LOCATION, JAXP_SCHEMA_SOURCE, JAXP_SCHEMA_LANGUAGE, + ROOT_TYPE_DEF, SCHEMA_DV_FACTORY, XML_SECURITY_PROPERTY_MANAGER }; /** Property defaults. */ private static final Object[] PROPERTY_DEFAULTS = - { null, null, null, null, null, null, null, null, null, null, null, null, null}; + { null, null, null, null, null, null, null, null, null, null, null}; // this is the number of valuestores of each kind // we expect an element to have. It's almost @@ -482,7 +513,7 @@ public class XMLSchemaValidator // updated during reset protected ValidationManager fValidationManager = null; - protected ValidationState fValidationState = new ValidationState(); + protected ConfigurableValidationState fValidationState = new ConfigurableValidationState(); protected XMLGrammarPool fGrammarPool; // schema location property values @@ -562,6 +593,9 @@ public class XMLSchemaValidator * this exception. */ public void setProperty(String propertyId, Object value) throws XMLConfigurationException { + if (propertyId.equals(ROOT_TYPE_DEF)) { + fRootTypeQName = (javax.xml.namespace.QName)value; + } } // setProperty(String,Object) /** @@ -1234,6 +1268,12 @@ public class XMLSchemaValidator /** temporary qname */ private final QName fTempQName = new QName(); + private javax.xml.namespace.QName fRootTypeQName = null; + + private int fIgnoreXSITypeDepth; + + private boolean fIDCChecking; + /** temporary validated info */ private ValidatedInfo fValidatedInfo = new ValidatedInfo(); @@ -1384,6 +1424,38 @@ public class XMLSchemaValidator fValidationManager.addValidationState(fValidationState); fValidationState.setSymbolTable(fSymbolTable); + boolean ignoreXSIType; + try { + ignoreXSIType = componentManager.getFeature(IGNORE_XSI_TYPE); + } + catch (XMLConfigurationException e) { + ignoreXSIType = false; + } + // An initial value of -1 means that the root element considers itself + // below the depth where xsi:type stopped being ignored (which means that + // xsi:type attributes will not be ignored for the entire document) + fIgnoreXSITypeDepth = ignoreXSIType ? 0 : -1; + + try { + fIDCChecking = componentManager.getFeature(IDENTITY_CONSTRAINT_CHECKING); + } + catch (XMLConfigurationException e) { + fIDCChecking = true; + } + + try { + fValidationState.setIdIdrefChecking(componentManager.getFeature(ID_IDREF_CHECKING)); + } + catch (XMLConfigurationException e) { + fValidationState.setIdIdrefChecking(true); + } + + try { + fValidationState.setUnparsedEntityChecking(componentManager.getFeature(UNPARSED_ENTITY_CHECKING)); + } + catch (XMLConfigurationException e) { + fValidationState.setUnparsedEntityChecking(true); + } // get schema location properties try { @@ -1550,7 +1622,9 @@ public class XMLSchemaValidator // handle start document void handleStartDocument(XMLLocator locator, String encoding) { - fValueStoreCache.startDocument(); + if (fIDCChecking) { + fValueStoreCache.startDocument(); + } if (fAugPSVI) { fCurrentPSVI.fGrammars = null; fCurrentPSVI.fSchemaInformation = null; @@ -1558,7 +1632,9 @@ public class XMLSchemaValidator } // handleStartDocument(XMLLocator,String) void handleEndDocument() { - fValueStoreCache.endDocument(); + if (fIDCChecking) { + fValueStoreCache.endDocument(); + } } // handleEndDocument() // handle character contents @@ -1850,22 +1926,54 @@ public class XMLSchemaValidator return augs; } - // try again to get the element decl: - // case 1: find declaration for root element - // case 2: find declaration for element from another namespace - if (fCurrentElemDecl == null) { - if (sGrammar != null) { - fCurrentElemDecl = sGrammar.getGlobalElementDecl(element.localpart); + // 1.2.1.1 A type definition was stipulated by the processor + if (fElementDepth == 0 && fRootTypeQName != null) { + String rootTypeNamespace = fRootTypeQName.getNamespaceURI(); + if (rootTypeNamespace != null && rootTypeNamespace.equals(XMLConstants.NULL_NS_URI)) { + rootTypeNamespace = null; + } + SchemaGrammar grammarForRootType = + findSchemaGrammar( + XSDDescription.CONTEXT_ELEMENT, rootTypeNamespace, null, null, null); + if (grammarForRootType != null) { + fCurrentType = grammarForRootType.getGlobalTypeDecl(fRootTypeQName.getLocalPart()); + } + if (fCurrentType == null) { + String typeName = (fRootTypeQName.getPrefix().equals(XMLConstants.DEFAULT_NS_PREFIX)) ? + fRootTypeQName.getLocalPart() : + fRootTypeQName.getPrefix()+":"+fRootTypeQName.getLocalPart(); + reportSchemaError("cvc-type.1", new Object[] {typeName}); } } - if (fCurrentElemDecl != null) { - // then get the type - fCurrentType = fCurrentElemDecl.fType; + // if there was no processor stipulated type + if (fCurrentType == null) { + // try again to get the element decl: + // case 1: find declaration for root element + // case 2: find declaration for element from another namespace + if (fCurrentElemDecl == null) { + if (sGrammar != null) { + fCurrentElemDecl = sGrammar.getGlobalElementDecl(element.localpart); + } + } + + if (fCurrentElemDecl != null) { + // then get the type + fCurrentType = fCurrentElemDecl.fType; + } } - // get type from xsi:type - String xsiType = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_TYPE); + + // check if we should be ignoring xsi:type on this element + if (fElementDepth == fIgnoreXSITypeDepth && fCurrentElemDecl == null) { + fIgnoreXSITypeDepth++; + } + + // process xsi:type attribute information + String xsiType = null; + if (fElementDepth >= fIgnoreXSITypeDepth) { + xsiType = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_TYPE); + } // if no decl/type found for the current element if (fCurrentType == null && xsiType == null) { @@ -2044,13 +2152,17 @@ public class XMLSchemaValidator XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; attrGrp = ctype.getAttrGrp(); } - // activate identity constraints - fValueStoreCache.startElement(); - fMatcherStack.pushContext(); - if (fCurrentElemDecl != null && fCurrentElemDecl.fIDCPos > 0) { - fIdConstraint = true; - // initialize when identity constrains are defined for the elem - fValueStoreCache.initValueStoresFor(fCurrentElemDecl, this); + + if (fIDCChecking) { + // activate identity constraints + fValueStoreCache.startElement(); + fMatcherStack.pushContext(); + //if (fCurrentElemDecl != null && fCurrentElemDecl.fIDCPos > 0 && !fIgnoreIDC) { + if (fCurrentElemDecl != null && fCurrentElemDecl.fIDCPos > 0) { + fIdConstraint = true; + // initialize when identity constrains are defined for the elem + fValueStoreCache.initValueStoresFor(fCurrentElemDecl, this); + } } processAttributes(element, attributes, attrGrp); @@ -2138,66 +2250,75 @@ public class XMLSchemaValidator // now validate the content of the element processElementContent(element); - // Element Locally Valid (Element) - // 6 The element information item must be valid with respect to each of the {identity-constraint definitions} as per Identity-constraint Satisfied (3.11.4). + if (fIDCChecking) { + // Element Locally Valid (Element) + // 6 The element information item must be valid with respect to each of the {identity-constraint definitions} as per Identity-constraint Satisfied (3.11.4). - // call matchers and de-activate context - int oldCount = fMatcherStack.getMatcherCount(); - for (int i = oldCount - 1; i >= 0; i--) { - XPathMatcher matcher = fMatcherStack.getMatcherAt(i); - if (fCurrentElemDecl == null) - matcher.endElement(element, null, false, fValidatedInfo.actualValue, fValidatedInfo.actualValueType, fValidatedInfo.itemValueTypes); + // call matchers and de-activate context + int oldCount = fMatcherStack.getMatcherCount(); + for (int i = oldCount - 1; i >= 0; i--) { + XPathMatcher matcher = fMatcherStack.getMatcherAt(i); + if (fCurrentElemDecl == null) + matcher.endElement(element, null, false, fValidatedInfo.actualValue, fValidatedInfo.actualValueType, fValidatedInfo.itemValueTypes); - else - matcher.endElement( - element, - fCurrentType, - fCurrentElemDecl.getNillable(), - fDefaultValue == null - ? fValidatedInfo.actualValue - : fCurrentElemDecl.fDefault.actualValue, - fDefaultValue == null - ? fValidatedInfo.actualValueType - : fCurrentElemDecl.fDefault.actualValueType, - fDefaultValue == null - ? fValidatedInfo.itemValueTypes - : fCurrentElemDecl.fDefault.itemValueTypes); - } + else + matcher.endElement( + element, + fCurrentType, + fCurrentElemDecl.getNillable(), + fDefaultValue == null + ? fValidatedInfo.actualValue + : fCurrentElemDecl.fDefault.actualValue, + fDefaultValue == null + ? fValidatedInfo.actualValueType + : fCurrentElemDecl.fDefault.actualValueType, + fDefaultValue == null + ? fValidatedInfo.itemValueTypes + : fCurrentElemDecl.fDefault.itemValueTypes); + } - if (fMatcherStack.size() > 0) { - fMatcherStack.popContext(); - } + if (fMatcherStack.size() > 0) { + fMatcherStack.popContext(); + } - int newCount = fMatcherStack.getMatcherCount(); - // handle everything *but* keyref's. - for (int i = oldCount - 1; i >= newCount; i--) { - XPathMatcher matcher = fMatcherStack.getMatcherAt(i); - if (matcher instanceof Selector.Matcher) { - Selector.Matcher selMatcher = (Selector.Matcher) matcher; - IdentityConstraint id; - if ((id = selMatcher.getIdentityConstraint()) != null - && id.getCategory() != IdentityConstraint.IC_KEYREF) { - fValueStoreCache.transplant(id, selMatcher.getInitialDepth()); + int newCount = fMatcherStack.getMatcherCount(); + // handle everything *but* keyref's. + for (int i = oldCount - 1; i >= newCount; i--) { + XPathMatcher matcher = fMatcherStack.getMatcherAt(i); + if (matcher instanceof Selector.Matcher) { + Selector.Matcher selMatcher = (Selector.Matcher) matcher; + IdentityConstraint id; + if ((id = selMatcher.getIdentityConstraint()) != null + && id.getCategory() != IdentityConstraint.IC_KEYREF) { + fValueStoreCache.transplant(id, selMatcher.getInitialDepth()); + } } } - } - // now handle keyref's/... - for (int i = oldCount - 1; i >= newCount; i--) { - XPathMatcher matcher = fMatcherStack.getMatcherAt(i); - if (matcher instanceof Selector.Matcher) { - Selector.Matcher selMatcher = (Selector.Matcher) matcher; - IdentityConstraint id; - if ((id = selMatcher.getIdentityConstraint()) != null - && id.getCategory() == IdentityConstraint.IC_KEYREF) { - ValueStoreBase values = - fValueStoreCache.getValueStoreFor(id, selMatcher.getInitialDepth()); - if (values != null) // nothing to do if nothing matched! - values.endDocumentFragment(); + // now handle keyref's/... + for (int i = oldCount - 1; i >= newCount; i--) { + XPathMatcher matcher = fMatcherStack.getMatcherAt(i); + if (matcher instanceof Selector.Matcher) { + Selector.Matcher selMatcher = (Selector.Matcher) matcher; + IdentityConstraint id; + if ((id = selMatcher.getIdentityConstraint()) != null + && id.getCategory() == IdentityConstraint.IC_KEYREF) { + ValueStoreBase values = + fValueStoreCache.getValueStoreFor(id, selMatcher.getInitialDepth()); + if (values != null) // nothing to do if nothing matched! + values.endDocumentFragment(); + } } } + fValueStoreCache.endElement(); + } + + // Check if we should modify the xsi:type ignore depth + // This check is independent of whether this is the validation root, + // and should be done before the element depth is decremented. + if (fElementDepth < fIgnoreXSITypeDepth) { + fIgnoreXSITypeDepth--; } - fValueStoreCache.endElement(); SchemaGrammar[] grammars = null; // have we reached the end tag of the validation root? @@ -2290,7 +2411,14 @@ public class XMLSchemaValidator // otherwise partial, and anything above this level will be partial else { fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_PARTIAL; - fNFullValidationDepth = fNNoneValidationDepth = fElementDepth - 1; + } + + // this guarantees that depth settings do not cross-over between sibling nodes + if (fNFullValidationDepth == fElementDepth) { + fNFullValidationDepth = fElementDepth - 1; + } + if (fNNoneValidationDepth == fElementDepth) { + fNNoneValidationDepth = fElementDepth - 1; } if (fDefaultValue != null) @@ -2554,14 +2682,22 @@ public class XMLSchemaValidator // if there is no current type, set this one as current. // and we don't need to do extra checking if (fCurrentType != null) { + short block = XSConstants.DERIVATION_NONE; // 4.3 The local type definition must be validly derived from the {type definition} given the union of the {disallowed substitutions} and the {type definition}'s {prohibited substitutions}, as defined in Type Derivation OK (Complex) (3.4.6) (if it is a complex type definition), or given {disallowed substitutions} as defined in Type Derivation OK (Simple) (3.14.6) (if it is a simple type definition). - short block = fCurrentElemDecl.fBlock; - if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) + // Note: It's possible to have fCurrentType be non-null and fCurrentElemDecl + // be null, if the current type is set using the property "root-type-definition". + // In that case, we don't disallow any substitutions. -PM + if (fCurrentElemDecl != null) { + block = fCurrentElemDecl.fBlock; + } + if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { block |= ((XSComplexTypeDecl) fCurrentType).fBlock; - if (!XSConstraints.checkTypeDerivationOk(type, fCurrentType, block)) + } + if (!XSConstraints.checkTypeDerivationOk(type, fCurrentType, block)) { reportSchemaError( - "cvc-elt.4.3", - new Object[] { element.rawname, xsiType, fCurrentType.getName()}); + "cvc-elt.4.3", + new Object[] { element.rawname, xsiType, fCurrentType.getName()}); + } } return type; @@ -2835,9 +2971,10 @@ public class XMLSchemaValidator } // get the value constraint from use or decl - // 4 The item's actual value must match the value of the {value constraint}, if it is present and fixed. // now check the value against the simpleType + // 4 The item's actual value must match the value of the {value constraint}, if it is present and fixed. + // now check the value against the simpleType if (actualValue != null && currDecl.getConstraintType() == XSConstants.VC_FIXED) { - if (!isComparable(fValidatedInfo, currDecl.fDefault) || !actualValue.equals(currDecl.fDefault.actualValue)) { + if (!ValidatedInfo.isComparable(fValidatedInfo, currDecl.fDefault) || !actualValue.equals(currDecl.fDefault.actualValue)) { reportSchemaError( "cvc-attribute.4", new Object[] { @@ -2852,7 +2989,7 @@ public class XMLSchemaValidator if (actualValue != null && currUse != null && currUse.fConstraintType == XSConstants.VC_FIXED) { - if (!isComparable(fValidatedInfo, currUse.fDefault) || !actualValue.equals(currUse.fDefault.actualValue)) { + if (!ValidatedInfo.isComparable(fValidatedInfo, currUse.fDefault) || !actualValue.equals(currUse.fDefault.actualValue)) { reportSchemaError( "cvc-complex-type.3.1", new Object[] { @@ -3083,7 +3220,7 @@ public class XMLSchemaValidator } // 5.2.2.2.2 If the {content type} of the actual type definition is a simple type definition, then the actual value of the item must match the canonical lexical representation of the {value constraint} value. else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { - if (actualValue != null && (!isComparable(fValidatedInfo, fCurrentElemDecl.fDefault) + if (actualValue != null && (!ValidatedInfo.isComparable(fValidatedInfo, fCurrentElemDecl.fDefault) || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) { reportSchemaError( "cvc-elt.5.2.2.2.2", @@ -3094,7 +3231,7 @@ public class XMLSchemaValidator } } } else if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { - if (actualValue != null && (!isComparable(fValidatedInfo, fCurrentElemDecl.fDefault) + if (actualValue != null && (!ValidatedInfo.isComparable(fValidatedInfo, fCurrentElemDecl.fDefault) || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) { // REVISIT: the spec didn't mention this case: fixed // value with simple type @@ -3240,53 +3377,6 @@ public class XMLSchemaValidator XMLErrorReporter.SEVERITY_ERROR); } - /** Returns true if the two ValidatedInfo objects can be compared in the same value space. **/ - private boolean isComparable(ValidatedInfo info1, ValidatedInfo info2) { - final short primitiveType1 = convertToPrimitiveKind(info1.actualValueType); - final short primitiveType2 = convertToPrimitiveKind(info2.actualValueType); - if (primitiveType1 != primitiveType2) { - return (primitiveType1 == XSConstants.ANYSIMPLETYPE_DT && primitiveType2 == XSConstants.STRING_DT || - primitiveType1 == XSConstants.STRING_DT && primitiveType2 == XSConstants.ANYSIMPLETYPE_DT); - } - else if (primitiveType1 == XSConstants.LIST_DT || primitiveType1 == XSConstants.LISTOFUNION_DT) { - final ShortList typeList1 = info1.itemValueTypes; - final ShortList typeList2 = info2.itemValueTypes; - final int typeList1Length = typeList1 != null ? typeList1.getLength() : 0; - final int typeList2Length = typeList2 != null ? typeList2.getLength() : 0; - if (typeList1Length != typeList2Length) { - return false; - } - for (int i = 0; i < typeList1Length; ++i) { - final short primitiveItem1 = convertToPrimitiveKind(typeList1.item(i)); - final short primitiveItem2 = convertToPrimitiveKind(typeList2.item(i)); - if (primitiveItem1 != primitiveItem2) { - if (primitiveItem1 == XSConstants.ANYSIMPLETYPE_DT && primitiveItem2 == XSConstants.STRING_DT || - primitiveItem1 == XSConstants.STRING_DT && primitiveItem2 == XSConstants.ANYSIMPLETYPE_DT) { - continue; - } - return false; - } - } - } - return true; - } - - private short convertToPrimitiveKind(short valueType) { - /** Primitive datatypes. */ - if (valueType <= XSConstants.NOTATION_DT) { - return valueType; - } - /** Types derived from string. */ - if (valueType <= XSConstants.ENTITY_DT) { - return XSConstants.STRING_DT; - } - /** Types derived from decimal. */ - if (valueType <= XSConstants.POSITIVEINTEGER_DT) { - return XSConstants.DECIMAL_DT; - } - /** Other types. */ - return valueType; - } private String expectedStr(Vector expected) { StringBuffer ret = new StringBuffer("{"); diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchema.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchema.java index 070086aa98b..5b05a6d1c28 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchema.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchema.java @@ -1,13 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -32,11 +29,19 @@ final class XMLSchema extends AbstractXMLSchema { /** The grammar pool is immutable */ private final XMLGrammarPool fGrammarPool; + /** Whether to consider this schema to be fully composed */ + private final boolean fFullyComposed; + /** Constructor */ public XMLSchema(XMLGrammarPool grammarPool) { - fGrammarPool = grammarPool; + this(grammarPool, true); } + public XMLSchema(XMLGrammarPool grammarPool, boolean fullyComposed) { + fGrammarPool = grammarPool; + fFullyComposed = fullyComposed; + } + /* * XSGrammarPoolContainer methods */ @@ -60,7 +65,7 @@ final class XMLSchema extends AbstractXMLSchema { * can be considered to be a fully composed schema */ public boolean isFullyComposed() { - return true; + return fFullyComposed; } } // XMLSchema diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaFactory.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaFactory.java index a453dbf4227..3542750efaf 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaFactory.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaFactory.java @@ -1,13 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -68,12 +65,21 @@ import org.xml.sax.SAXParseException; */ public final class XMLSchemaFactory extends SchemaFactory { - // property identifiers + // feature identifiers + + /** JAXP Source feature prefix. */ + private static final String JAXP_SOURCE_FEATURE_PREFIX = "http://javax.xml.transform"; /** Feature identifier: schema full checking. */ private static final String SCHEMA_FULL_CHECKING = Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; + /** Feature identifier: use grammar pool only. */ + private static final String USE_GRAMMAR_POOL_ONLY = + Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; + + // property identifiers + /** Property identifier: grammar pool. */ private static final String XMLGRAMMAR_POOL = Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; @@ -104,7 +110,7 @@ public final class XMLSchemaFactory extends SchemaFactory { private final DOMEntityResolverWrapper fDOMEntityResolverWrapper; /** The ErrorHandlerWrapper */ - private ErrorHandlerWrapper fErrorHandlerWrapper; + private final ErrorHandlerWrapper fErrorHandlerWrapper; /** The SecurityManager. */ private XMLSecurityManager fSecurityManager; @@ -113,7 +119,10 @@ public final class XMLSchemaFactory extends SchemaFactory { private XMLSecurityPropertyManager fSecurityPropertyMgr; /** The container for the real grammar pool. */ - private XMLGrammarPoolWrapper fXMLGrammarPoolWrapper; + private final XMLGrammarPoolWrapper fXMLGrammarPoolWrapper; + + /** Whether or not to allow new schemas to be added to the grammar pool */ + private boolean fUseGrammarPoolOnly; /** * Indicates whether implementation parts should use @@ -138,6 +147,7 @@ public final class XMLSchemaFactory extends SchemaFactory { fXMLSchemaLoader.setProperty(XMLGRAMMAR_POOL, fXMLGrammarPoolWrapper); fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper); fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper); + fUseGrammarPoolOnly = true; // Enable secure processing feature by default fSecurityManager = new XMLSecurityManager(true); @@ -170,7 +180,8 @@ public final class XMLSchemaFactory extends SchemaFactory { "SchemaLanguageLengthZero", null)); } // only W3C XML Schema 1.0 is supported - return schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI); + return schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI) || + schemaLanguage.equals(Constants.W3C_XML_SCHEMA10_NS_URI); } public LSResourceResolver getResourceResolver() { @@ -202,7 +213,7 @@ public final class XMLSchemaFactory extends SchemaFactory { XMLInputSource[] xmlInputSources = new XMLInputSource[schemas.length]; InputStream inputStream; Reader reader; - for( int i=0; i 1) { - schema = new XMLSchema(new ReadOnlyGrammarPool(pool)); - } - else if (grammarCount == 1) { - Grammar[] grammars = pool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA); - schema = new SimpleXMLSchema(grammars[0]); + if (fUseGrammarPoolOnly) { + if (grammarCount > 1) { + schema = new XMLSchema(new ReadOnlyGrammarPool(pool)); + } + else if (grammarCount == 1) { + Grammar[] grammars = pool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA); + schema = new SimpleXMLSchema(grammars[0]); + } + else { + schema = new EmptyXMLSchema(); + } } else { - schema = new EmptyXMLSchema(); + schema = new XMLSchema(new ReadOnlyGrammarPool(pool), false); } propagateFeatures(schema); propagateProperties(schema); @@ -286,6 +305,14 @@ public final class XMLSchemaFactory extends SchemaFactory { } public Schema newSchema() throws SAXException { + /* + * It would make sense to return an EmptyXMLSchema object here, if + * fUseGrammarPoolOnly is set to true. However, because the default + * value of this feature is true, doing so would change the default + * behaviour of this method. Thus, we return a WeakReferenceXMLSchema + * regardless of the value of fUseGrammarPoolOnly. -PM + */ + // Use a Schema that uses the system id as the equality source. AbstractXMLSchema schema = new WeakReferenceXMLSchema(); propagateFeatures(schema); @@ -293,15 +320,38 @@ public final class XMLSchemaFactory extends SchemaFactory { return schema; } + public Schema newSchema(XMLGrammarPool pool) throws SAXException { + // If the "use-grammar-pool-only" feature is set to true + // prevent the application's grammar pool from being mutated + // by wrapping it in a ReadOnlyGrammarPool. + final AbstractXMLSchema schema = (fUseGrammarPoolOnly) ? + new XMLSchema(new ReadOnlyGrammarPool(pool)) : + new XMLSchema(pool, false); + propagateFeatures(schema); + return schema; + } + public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { if (name == null) { throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), "FeatureNameNull", null)); } + if (name.startsWith(JAXP_SOURCE_FEATURE_PREFIX)) { + // Indicates to the caller that this SchemaFactory supports a specific JAXP Source. + if (name.equals(StreamSource.FEATURE) || + name.equals(SAXSource.FEATURE) || + name.equals(DOMSource.FEATURE) || + name.equals(StAXSource.FEATURE)) { + return true; + } + } if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { return (fSecurityManager != null && fSecurityManager.isSecureProcessing()); } + else if (name.equals(USE_GRAMMAR_POOL_ONLY)) { + return fUseGrammarPoolOnly; + } try { return fXMLSchemaLoader.getFeature(name); } @@ -358,6 +408,16 @@ public final class XMLSchemaFactory extends SchemaFactory { throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), "FeatureNameNull", null)); } + if (name.startsWith(JAXP_SOURCE_FEATURE_PREFIX)) { + if (name.equals(StreamSource.FEATURE) || + name.equals(SAXSource.FEATURE) || + name.equals(DOMSource.FEATURE) || + name.equals(StAXSource.FEATURE)) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "feature-read-only", new Object [] {name})); + } + } if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { if (System.getSecurityManager() != null && (!value)) { throw new SAXNotSupportedException( @@ -377,7 +437,12 @@ public final class XMLSchemaFactory extends SchemaFactory { fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager); return; - } else if (name.equals(Constants.ORACLE_FEATURE_SERVICE_MECHANISM)) { + } + else if (name.equals(USE_GRAMMAR_POOL_ONLY)) { + fUseGrammarPoolOnly = value; + return; + } + else if (name.equals(Constants.ORACLE_FEATURE_SERVICE_MECHANISM)) { //in secure mode, let _useServicesMechanism be determined by the constructor if (System.getSecurityManager() != null) return; diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaValidatorComponentManager.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaValidatorComponentManager.java index 58a74191cf0..807dc917908 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaValidatorComponentManager.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaValidatorComponentManager.java @@ -1,13 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -69,13 +66,41 @@ final class XMLSchemaValidatorComponentManager extends ParserConfigurationSettin private static final String VALIDATION = Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + /** Feature identifier: use grammar pool only. */ + private static final String USE_GRAMMAR_POOL_ONLY = + Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; + + /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */ + protected static final String IGNORE_XSI_TYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE; + + /** Feature identifier: whether to ignore ID/IDREF errors */ + protected static final String ID_IDREF_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore unparsed entity errors */ + protected static final String UNPARSED_ENTITY_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore identity constraint errors */ + protected static final String IDENTITY_CONSTRAINT_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE; + + /** Feature identifier: disallow DOCTYPE declaration */ + private static final String DISALLOW_DOCTYPE_DECL_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE; + + /** Feature identifier: expose schema normalized value */ + private static final String NORMALIZE_DATA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; + /** Feature identifier: send element default value via characters() */ private static final String SCHEMA_ELEMENT_DEFAULT = Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT; - /** Feature identifier: use grammar pool only. */ - private static final String USE_GRAMMAR_POOL_ONLY = - Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; + /** Feature identifier: augment PSVI */ + private static final String SCHEMA_AUGMENT_PSVI = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI; // property identifiers @@ -230,10 +255,32 @@ final class XMLSchemaValidatorComponentManager extends ParserConfigurationSettin fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter()); // add all recognized features and properties and apply their defaults + final String [] recognizedFeatures = { + DISALLOW_DOCTYPE_DECL_FEATURE, + NORMALIZE_DATA, + SCHEMA_ELEMENT_DEFAULT, + SCHEMA_AUGMENT_PSVI + }; + addRecognizedFeatures(recognizedFeatures); + fFeatures.put(DISALLOW_DOCTYPE_DECL_FEATURE, Boolean.FALSE); + fFeatures.put(NORMALIZE_DATA, Boolean.FALSE); + fFeatures.put(SCHEMA_ELEMENT_DEFAULT, Boolean.FALSE); + fFeatures.put(SCHEMA_AUGMENT_PSVI, Boolean.TRUE); + addRecognizedParamsAndSetDefaults(fEntityManager, grammarContainer); addRecognizedParamsAndSetDefaults(fErrorReporter, grammarContainer); addRecognizedParamsAndSetDefaults(fSchemaValidator, grammarContainer); + /* TODO: are other XMLSchemaValidator default values never set? + * Initial investigation indicates that they aren't set, but + * that they all have default values of false, so it works out + * anyway -PM + */ + fFeatures.put(IGNORE_XSI_TYPE, Boolean.FALSE); + fFeatures.put(ID_IDREF_CHECKING, Boolean.TRUE); + fFeatures.put(IDENTITY_CONSTRAINT_CHECKING, Boolean.TRUE); + fFeatures.put(UNPARSED_ENTITY_CHECKING, Boolean.TRUE); + boolean secureProcessing = grammarContainer.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING); if (System.getSecurityManager() != null) { _isSecureMode = true; diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/StandardParserConfiguration.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/StandardParserConfiguration.java index 5ac09f8f866..464f93e8c92 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/StandardParserConfiguration.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/StandardParserConfiguration.java @@ -1,13 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -109,6 +106,22 @@ public class StandardParserConfiguration protected static final String HONOUR_ALL_SCHEMALOCATIONS = Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE; + /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */ + protected static final String IGNORE_XSI_TYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE; + + /** Feature identifier: whether to ignore ID/IDREF errors */ + protected static final String ID_IDREF_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore unparsed entity errors */ + protected static final String UNPARSED_ENTITY_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore identity constraint errors */ + protected static final String IDENTITY_CONSTRAINT_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE; + /** Feature identifier: namespace growth */ protected static final String NAMESPACE_GROWTH = Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE; @@ -135,6 +148,10 @@ public class StandardParserConfiguration protected static final String SCHEMA_DV_FACTORY = Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY; + /** Property identifier: root type definition. */ + protected static final String ROOT_TYPE_DEF = + Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_TYPE_DEFINITION_PROPERTY; + // // Data // @@ -211,6 +228,10 @@ public class StandardParserConfiguration // not-recognized exception to be thrown. -Ac XMLSCHEMA_VALIDATION, XMLSCHEMA_FULL_CHECKING, + IGNORE_XSI_TYPE, + ID_IDREF_CHECKING, + IDENTITY_CONSTRAINT_CHECKING, + UNPARSED_ENTITY_CHECKING, }; addRecognizedFeatures(recognizedFeatures); @@ -221,6 +242,10 @@ public class StandardParserConfiguration setFeature(GENERATE_SYNTHETIC_ANNOTATIONS, false); setFeature(VALIDATE_ANNOTATIONS, false); setFeature(HONOUR_ALL_SCHEMALOCATIONS, false); + setFeature(IGNORE_XSI_TYPE, false); + setFeature(ID_IDREF_CHECKING, true); + setFeature(IDENTITY_CONSTRAINT_CHECKING, true); + setFeature(UNPARSED_ENTITY_CHECKING, true); setFeature(NAMESPACE_GROWTH, false); setFeature(TOLERATE_DUPLICATES, false); @@ -233,11 +258,11 @@ public class StandardParserConfiguration // not-recognized exception to be thrown. -Ac SCHEMA_LOCATION, SCHEMA_NONS_LOCATION, + ROOT_TYPE_DEF, SCHEMA_DV_FACTORY, - }; - - addRecognizedProperties(recognizedProperties); + }; + addRecognizedProperties(recognizedProperties); } // (SymbolTable,XMLGrammarPool) // diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/XML11Configuration.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/XML11Configuration.java index c0283f74e3c..975367eb2be 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/XML11Configuration.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/XML11Configuration.java @@ -1,13 +1,10 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 2001-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -184,7 +181,21 @@ public class XML11Configuration extends ParserConfigurationSettings protected static final String EXTERNAL_PARAMETER_ENTITIES = Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE; + /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */ + protected static final String IGNORE_XSI_TYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE; + /** Feature identifier: whether to ignore ID/IDREF errors */ + protected static final String ID_IDREF_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore unparsed entity errors */ + protected static final String UNPARSED_ENTITY_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore identity constraint errors */ + protected static final String IDENTITY_CONSTRAINT_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE; // property identifiers @@ -267,6 +278,10 @@ public class XML11Configuration extends ParserConfigurationSettings protected static final String JAXP_SCHEMA_SOURCE = Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE; + /** Property identifier: root type definition. */ + protected static final String ROOT_TYPE_DEF = + Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_TYPE_DEFINITION_PROPERTY; + /** Property identifier: locale. */ protected static final String LOCALE = Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; @@ -467,25 +482,27 @@ public class XML11Configuration extends ParserConfigurationSettings // add default recognized features final String[] recognizedFeatures = - { - CONTINUE_AFTER_FATAL_ERROR, LOAD_EXTERNAL_DTD, // from XMLDTDScannerImpl - VALIDATION, - NAMESPACES, - NORMALIZE_DATA, SCHEMA_ELEMENT_DEFAULT, SCHEMA_AUGMENT_PSVI, - GENERATE_SYNTHETIC_ANNOTATIONS, VALIDATE_ANNOTATIONS, - HONOUR_ALL_SCHEMALOCATIONS, NAMESPACE_GROWTH, - TOLERATE_DUPLICATES, - USE_GRAMMAR_POOL_ONLY, - // NOTE: These shouldn't really be here but since the XML Schema - // validator is constructed dynamically, its recognized - // features might not have been set and it would cause a - // not-recognized exception to be thrown. -Ac - XMLSCHEMA_VALIDATION, XMLSCHEMA_FULL_CHECKING, - EXTERNAL_GENERAL_ENTITIES, - EXTERNAL_PARAMETER_ENTITIES, - PARSER_SETTINGS, - XMLConstants.FEATURE_SECURE_PROCESSING - }; + { + CONTINUE_AFTER_FATAL_ERROR, LOAD_EXTERNAL_DTD, // from XMLDTDScannerImpl + VALIDATION, + NAMESPACES, + NORMALIZE_DATA, SCHEMA_ELEMENT_DEFAULT, SCHEMA_AUGMENT_PSVI, + GENERATE_SYNTHETIC_ANNOTATIONS, VALIDATE_ANNOTATIONS, + HONOUR_ALL_SCHEMALOCATIONS, IGNORE_XSI_TYPE, + ID_IDREF_CHECKING, IDENTITY_CONSTRAINT_CHECKING, + UNPARSED_ENTITY_CHECKING, + NAMESPACE_GROWTH, TOLERATE_DUPLICATES, + USE_GRAMMAR_POOL_ONLY, + // NOTE: These shouldn't really be here but since the XML Schema + // validator is constructed dynamically, its recognized + // features might not have been set and it would cause a + // not-recognized exception to be thrown. -Ac + XMLSCHEMA_VALIDATION, XMLSCHEMA_FULL_CHECKING, + EXTERNAL_GENERAL_ENTITIES, + EXTERNAL_PARAMETER_ENTITIES, + PARSER_SETTINGS, + XMLConstants.FEATURE_SECURE_PROCESSING + }; addRecognizedFeatures(recognizedFeatures); // set state for default features fFeatures.put(VALIDATION, Boolean.FALSE); @@ -500,6 +517,10 @@ public class XML11Configuration extends ParserConfigurationSettings fFeatures.put(GENERATE_SYNTHETIC_ANNOTATIONS, Boolean.FALSE); fFeatures.put(VALIDATE_ANNOTATIONS, Boolean.FALSE); fFeatures.put(HONOUR_ALL_SCHEMALOCATIONS, Boolean.FALSE); + fFeatures.put(IGNORE_XSI_TYPE, Boolean.FALSE); + fFeatures.put(ID_IDREF_CHECKING, Boolean.TRUE); + fFeatures.put(IDENTITY_CONSTRAINT_CHECKING, Boolean.TRUE); + fFeatures.put(UNPARSED_ENTITY_CHECKING, Boolean.TRUE); fFeatures.put(NAMESPACE_GROWTH, Boolean.FALSE); fFeatures.put(TOLERATE_DUPLICATES, Boolean.FALSE); fFeatures.put(USE_GRAMMAR_POOL_ONLY, Boolean.FALSE); @@ -508,41 +529,42 @@ public class XML11Configuration extends ParserConfigurationSettings // add default recognized properties final String[] recognizedProperties = - { - SYMBOL_TABLE, - ERROR_HANDLER, - ENTITY_RESOLVER, - ERROR_REPORTER, - ENTITY_MANAGER, - DOCUMENT_SCANNER, - DTD_SCANNER, - DTD_PROCESSOR, - DTD_VALIDATOR, - DATATYPE_VALIDATOR_FACTORY, - VALIDATION_MANAGER, - SCHEMA_VALIDATOR, - XML_STRING, - XMLGRAMMAR_POOL, - JAXP_SCHEMA_SOURCE, - JAXP_SCHEMA_LANGUAGE, - // NOTE: These shouldn't really be here but since the XML Schema - // validator is constructed dynamically, its recognized - // properties might not have been set and it would cause a - // not-recognized exception to be thrown. -Ac - SCHEMA_LOCATION, - SCHEMA_NONS_LOCATION, - LOCALE, - SCHEMA_DV_FACTORY, - SECURITY_MANAGER, - XML_SECURITY_PROPERTY_MANAGER + { + SYMBOL_TABLE, + ERROR_HANDLER, + ENTITY_RESOLVER, + ERROR_REPORTER, + ENTITY_MANAGER, + DOCUMENT_SCANNER, + DTD_SCANNER, + DTD_PROCESSOR, + DTD_VALIDATOR, + DATATYPE_VALIDATOR_FACTORY, + VALIDATION_MANAGER, + SCHEMA_VALIDATOR, + XML_STRING, + XMLGRAMMAR_POOL, + JAXP_SCHEMA_SOURCE, + JAXP_SCHEMA_LANGUAGE, + // NOTE: These shouldn't really be here but since the XML Schema + // validator is constructed dynamically, its recognized + // properties might not have been set and it would cause a + // not-recognized exception to be thrown. -Ac + SCHEMA_LOCATION, + SCHEMA_NONS_LOCATION, + ROOT_TYPE_DEF, + LOCALE, + SCHEMA_DV_FACTORY, + SECURITY_MANAGER, + XML_SECURITY_PROPERTY_MANAGER }; addRecognizedProperties(recognizedProperties); - if (symbolTable == null) { - symbolTable = new SymbolTable(); - } - fSymbolTable = symbolTable; - fProperties.put(SYMBOL_TABLE, fSymbolTable); + if (symbolTable == null) { + symbolTable = new SymbolTable(); + } + fSymbolTable = symbolTable; + fProperties.put(SYMBOL_TABLE, fSymbolTable); fGrammarPool = grammarPool; if (fGrammarPool != null) { @@ -597,8 +619,7 @@ public class XML11Configuration extends ParserConfigurationSettings // REVISIT: What is the right thing to do? -Ac } - fConfigUpdated = false; - + fConfigUpdated = false; } // (SymbolTable,XMLGrammarPool) // diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 121910c3483..f1c5ee39bb4 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -272,3 +272,5 @@ ce19e0403ec8a80223cc47320c905b2a4d45881d jdk9-b23 0b35542d6bf32af23a9fc59a37c52aa091fee388 jdk9-b24 ab8726a0fcde897e4cfd1ea581ed90b0d8a7cbb7 jdk9-b25 9b43f3993b96c2213428e95127a2d3fd0e709d3a jdk9-b26 +dcaa586ab756420e9a62643793bacef2c84bf637 jdk9-b27 +5282a14f131f897cc9575872c0fae72d47dc4e65 jdk9-b28 diff --git a/jdk/.hgtags b/jdk/.hgtags index 9b0360a42ef..51acdfa12e1 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -269,3 +269,5 @@ f87c5be90e01a7ffb47947108eb3e0b0b1920880 jdk9-b20 875450e7ef8dde8f59db662ec1351ea30b8cb35d jdk9-b24 a31efe49556a7c12f9ea2c9ee8b4fae8aa67723a jdk9-b25 dde9f5cfde5f46e62ceb5fab81151578e5277aef jdk9-b26 +f0870554049807d3392bd7976ab114f7f2b7bafa jdk9-b27 +1828f73b35cfe35e460e41fd6e087ab1f83e0621 jdk9-b28 diff --git a/jdk/make/Bundles.gmk b/jdk/make/Bundles.gmk index 57ab08784cf..470a1e9bfb5 100644 --- a/jdk/make/Bundles.gmk +++ b/jdk/make/Bundles.gmk @@ -35,7 +35,7 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) # JDK_BUNDLE_DIR and JRE_BUNDLE_DIR are defined in SPEC. - MACOSX_PLIST_SRC := $(JDK_TOPDIR)/make/bundle + MACOSX_PLIST_SRC := $(JDK_TOPDIR)/make/data/bundle # All these OPENJDK checks are needed since there is no coherency between # these values in open and closed. Should probably be fixed. diff --git a/jdk/make/CompileDemos.gmk b/jdk/make/CompileDemos.gmk index 531e61765a2..35bf0b4a691 100644 --- a/jdk/make/CompileDemos.gmk +++ b/jdk/make/CompileDemos.gmk @@ -29,9 +29,7 @@ include $(SPEC) include MakeBase.gmk include JavaCompilation.gmk include NativeCompilation.gmk - -# Setup the java compilers for the JDK build. -include SetupJava.gmk +include SetupJavaCompilers.gmk # Prepare the find cache. $(eval $(call FillCacheFind, $(JDK_TOPDIR)/src)) @@ -316,19 +314,6 @@ $(eval $(call SetupJVMTIDemo,compiledMethodLoad, agent_util)) $(eval $(call SetupJVMTIDemo,gctest, agent_util)) $(eval $(call SetupJVMTIDemo,heapTracker, agent_util java_crw_demo)) $(eval $(call SetupJVMTIDemo,heapViewer, agent_util)) - -# On AIX, hprof requires 'dladdr' from src/aix/porting/porting_aix.cpp -BUILD_LIBHPROF_AIX_EXTRA_SRC := -BUILD_LIBHPROF_AIX_EXTRA_CFLAGS := -ifeq ($(OPENJDK_TARGET_OS), aix) - BUILD_LIBHPROF_AIX_EXTRA_SRC += $(JDK_TOPDIR)/src/aix/porting - BUILD_LIBHPROF_AIX_EXTRA_CFLAGS += -I$(JDK_TOPDIR)/src/aix/porting -endif - -$(eval $(call SetupJVMTIDemo,hprof, java_crw_demo, \ - $(BUILD_LIBHPROF_AIX_EXTRA_CFLAGS), C, \ - -ldl, ws2_32.lib winmm.lib, -lsocket -lnsl, -lpthread, $(BUILD_LIBHPROF_AIX_EXTRA_SRC))) - $(eval $(call SetupJVMTIDemo,minst, agent_util java_crw_demo)) $(eval $(call SetupJVMTIDemo,mtrace, agent_util java_crw_demo)) $(eval $(call SetupJVMTIDemo,waiters, agent_util, , C++)) @@ -336,34 +321,6 @@ $(eval $(call SetupJVMTIDemo,versionCheck, agent_util)) ################################################################################################## -$(JDK_OUTPUTDIR)/demo/jpda/com/sun/tools/example/README: \ - $(JDK_TOPDIR)/src/demo/share/jpda/com/sun/tools/example/README - $(call install-file) - $(CHMOD) -f ug+w $@ - -$(eval $(call SetupArchive,JPDA_JAR, \ - $(JDK_OUTPUTDIR)/demo/jpda/com/sun/tools/example/README, \ - SRCS := $(JDK_TOPDIR)/src/demo/share/jpda \ - $(JDK_TOPDIR)/src/jdk.jdi/share/classes \ - $(JDK_OUTPUTDIR)/demo/jpda/com/sun/tools/example, \ - INCLUDES := com/sun/tools/example README, \ - SUFFIXES := .java .html .jj README, \ - JAR := $(JDK_OUTPUTDIR)/demo/jpda/examples.jar, \ - MANIFEST := $(JDK_TOPDIR)/make/data/mainmanifest/manifest.mf, \ - EXTRA_MANIFEST_ATTR := Main-Class:$$(SPACE), \ - SKIP_METAINF := true)) - -$(eval $(call SetupZipArchive,JPDA_ZIP, \ - SRC := $(JDK_TOPDIR)/src/demo/share/jpda \ - $(JDK_TOPDIR)/src/jdk.jdi/share/classes, \ - INCLUDES := com/sun/tools/example, \ - SUFFIXES := .java .html .jj README, \ - ZIP := $(JDK_OUTPUTDIR)/demo/jpda/src.zip)) - -BUILD_DEMOS += $(JPDA_JAR) $(JPDA_ZIP) - -################################################################################################## - $(JDK_OUTPUTDIR)/demo/management/index.html: $(DEMO_SHARE_SRC)/management/index.html $(call install-file) $(CHMOD) -f ug+w $@ diff --git a/jdk/make/CompileInterimRmic.gmk b/jdk/make/CompileInterimRmic.gmk index 74f789dfa61..79082cd415c 100644 --- a/jdk/make/CompileInterimRmic.gmk +++ b/jdk/make/CompileInterimRmic.gmk @@ -28,7 +28,7 @@ default: all include $(SPEC) include MakeBase.gmk include JavaCompilation.gmk -include SetupJava.gmk +include SetupJavaCompilers.gmk ########################################################################################## diff --git a/jdk/make/CopyIntoClasses.gmk b/jdk/make/CopyIntoClasses.gmk deleted file mode 100644 index a80c661ace9..00000000000 --- a/jdk/make/CopyIntoClasses.gmk +++ /dev/null @@ -1,202 +0,0 @@ -# -# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# Copy icu and _dict files used by the text break iterator - -COPY_PATTERNS := .icu _dict .dat _options .js aliasmap .spp .wav .css \ - .png .gif .xml .dtd .txt oqlhelp.html content-types.properties - -# These directories should not be copied at all -EXCLUDES += \ - java/awt/doc-files \ - java/lang/doc-files \ - javax/swing/doc-files \ - javax/swing/text/doc-files \ - javax/swing/plaf/synth/doc-files \ - javax/swing/undo/doc-files \ - sun/awt/X11/doc-files \ - sun/util/cldr/resources \ - # - -# These files should never be included -EXFILES += build.xml README.txt version.txt - -# These icons are handled in GensrcIcons.gmk -EXFILES += \ - sun/awt/X11/java-icon16.png \ - sun/awt/X11/java-icon24.png \ - sun/awt/X11/java-icon32.png \ - sun/awt/X11/java-icon48.png \ - $(wildcard $(JDK_TOPDIR)/src/share/classes/sun/awt/resources/*.png) \ - # - -ifndef OPENJDK - # Theses icons have closed replacements - SWING_PLAF_MOTIF_RESOURCES_DIR := $(JDK_TOPDIR)/src/share/classes/com/sun/java/swing/plaf/motif - EXFILES += \ - $(JDK_TOPDIR)/src/share/classes/com/sun/java/swing/plaf/windows/icons/JavaCup32.png \ - $(JDK_TOPDIR)/src/share/classes/javax/swing/plaf/basic/icons/JavaCup16.png \ - $(wildcard $(SWING_PLAF_MOTIF_RESOURCES_DIR)/icons/*.gif) \ - $(wildcard $(SWING_PLAF_MOTIF_RESOURCES_DIR)/icons/*.png) \ - # - - EXFILES += mib_core.txt -endif - -ifeq ($(ENABLE_JFR), true) - JFR_CONFIGURATION_DIR_CLOSED := $(JDK_TOPDIR)/src/closed/share/classes/oracle/jrockit/jfr/settings - COPY_FILES += \ - $(JFR_CONFIGURATION_DIR_CLOSED)/jfc.xsd -endif - -SWING_BEANINFO_RESOURCES_SRC_DIR = $(JDK_TOPDIR)/make/data/swingbeaninfo/images -SWING_BEANINFO_RESOURCES_SRC = $(wildcard $(SWING_BEANINFO_RESOURCES_SRC_DIR)/*.gif) -OUT_BEANINFO_RESOURCES = $(patsubst $(SWING_BEANINFO_RESOURCES_SRC_DIR)%, \ - $(JDK_OUTPUTDIR)/classes/javax/swing/beaninfo/images/%, \ - $(SWING_BEANINFO_RESOURCES_SRC)) - -COPY_EXTRA += $(OUT_BEANINFO_RESOURCES) - -# The exception handling of swing beaninfo -# These resources violates the convention of having code and resources together under -# $(JDK_TOPDIR)/src/.../classes directories -$(JDK_OUTPUTDIR)/classes/javax/swing/beaninfo/images/%.gif: \ - $(JDK_TOPDIR)/make/data/swingbeaninfo/images/%.gif - $(call install-file) - -########################################################################################## -# -# Copy the META-INF/services configuration files that are scattered around the source tree -# into classes/META-INF/services. Be aware that META-INF directories that are located at a -# source root (.../classes/META-INF) are automatically copied verbatim by the -# SetupJavaCompilation macro. -# -# Any other META-INF/services configuration file is found here and platform specific comments -# are uncommented and the configuration file is stored in the output META-INF directory. - -# Make sure the output directory is created. -$(eval $(call MakeDir, $(JDK_OUTPUTDIR)/classes/META-INF/services)) -# Find all META-INF/services/* files -ALL_META-INF_DIRS_share := $(shell $(FIND) $(JDK_TOPDIR)/src/share/classes -type d -a -name META-INF) -ALL_META-INF_DIRS_targetapi := $(shell $(FIND) $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes -type d -a -name META-INF) -# Platform specific overrides shared -ifneq ($(ALL_META-INF_DIRS_targetapi), ) - ALL_META-INF_DIRS := $(ALL_META-INF_DIRS_targetapi) \ - $(filter-out %$(patsubst $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes%,%,$(ALL_META-INF_DIRS_targetapi)), \ - $(ALL_META-INF_DIRS_share)) -else - ALL_META-INF_DIRS := $(ALL_META-INF_DIRS_share) -endif - -SRC_SERVICES_FILES := $(wildcard $(addsuffix /services/*, $(ALL_META-INF_DIRS))) - -# The number of services files are relatively few. If the increase in numbers, then -# we have to use ListPathsSafelyNow here. -# Change $(JDK_TOPDIR)/src/.../META-INF/services/yyyy into $(JDK_OUTPUTDIR)/classes/META-INF/services/yyyy -# The \n in the printf command is needed to make sed work on Solaris. -OUT_SERVICES_FILES := $(addprefix $(JDK_OUTPUTDIR)/classes/META-INF/services/, \ - $(shell $(PRINTF) "$(SRC_SERVICES_FILES)\n" | $(SED) -e 's|/[^ ]*/META-INF/services/||g')) -OUT_SERVICES_FILES_COLON := $(addsuffix :, $(OUT_SERVICES_FILES)) -# Exception handling for print services with no META-INF directory -SRC_SERVICES_FILES_PRINT = $(wildcard $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes/sun/print/services/*) -OUT_SERVICES_FILES_PRINT = $(addprefix $(JDK_OUTPUTDIR)/classes/META-INF/services/, \ - $(patsubst $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes/sun/print/services/%, %, \ - $(SRC_SERVICES_FILES_PRINT))) -OUT_SERVICES_FILES_PRINT_COLON = $(addsuffix :, $(OUT_SERVICES_FILES_PRINT)) -RULES_SERVICES_PRINT = $(join $(OUT_SERVICES_FILES_PRINT_COLON), $(SRC_SERVICES_FILES_PRINT)) - -# Now setup the dependency rules to generate a META-INF/services/... from the correct source. -META-INF_RULES_SERVICES := $(RULES_SERVICES_PRINT) $(join $(OUT_SERVICES_FILES_COLON), $(SRC_SERVICES_FILES)) -# Eval the newly created rules to incorporate them into the make tree. -define addto_meta-inf_services - $1 - echo $(LOG_INFO) Installing META-INF/services/$$(@F) - $(CAT) $$< | $(SED) -e "s/^#\[$(OPENJDK_TARGET_OS)\]//" > $$@ -endef -$(foreach i, $(META-INF_RULES_SERVICES), $(eval $(call addto_meta-inf_services, $i))) -# Here is the generic rule, whose receipt the above rules will trigger. - -COPY_EXTRA += $(OUT_SERVICES_FILES) -COPY_EXTRA += $(OUT_SERVICES_FILES_PRINT) - -################################################################################ - -JAVAX_SOUND_SRC := $(JDK_TOPDIR)/src/share/classes/com/sun/media/sound/services - -JAVAX_SOUND_SRC_FILES := \ - javax.sound.midi.spi.MidiDeviceProvider \ - javax.sound.midi.spi.MidiFileReader \ - javax.sound.midi.spi.MidiFileWriter \ - javax.sound.midi.spi.SoundbankReader \ - javax.sound.sampled.spi.AudioFileReader \ - javax.sound.sampled.spi.AudioFileWriter \ - javax.sound.sampled.spi.FormatConversionProvider \ - javax.sound.sampled.spi.MixerProvider - -COPY_EXTRA += $(addprefix $(JDK_OUTPUTDIR)/classes/META-INF/services/, $(JAVAX_SOUND_SRC_FILES)) - -JAVAX_SOUND_RULES := $(foreach F, $(JAVAX_SOUND_SRC_FILES), $(JDK_OUTPUTDIR)/classes/META-INF/services/$(notdir $F):$(JAVAX_SOUND_SRC)/$F) - -$(foreach R, $(JAVAX_SOUND_RULES), $(eval $(call addto_meta-inf_services, $R))) - -################################################################################ - -ifneq ($(OPENJDK_TARGET_OS), macosx) - OPENJDK_TARGET_OS_FLAVORMAP_PROPERTIES = $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes/sun/awt/datatransfer/flavormap.properties -else - OPENJDK_TARGET_OS_FLAVORMAP_PROPERTIES = $(JDK_TOPDIR)/src/macosx/classes/sun/awt/datatransfer/flavormap.properties -endif - -$(JDK_OUTPUTDIR)/classes/sun/awt/datatransfer/flavormap.properties: $(OPENJDK_TARGET_OS_FLAVORMAP_PROPERTIES) - $(install-file) - -COPY_EXTRA += $(JDK_OUTPUTDIR)/classes/sun/awt/datatransfer/flavormap.properties - -################################################################################ - -CLEAN_FILES := $(wildcard \ - $(JDK_TOPDIR)/src/share/classes/com/sun/imageio/plugins/common/*.properties \ - $(JDK_TOPDIR)/src/share/classes/com/sun/java/util/jar/pack/*.properties \ - $(JDK_TOPDIR)/src/share/classes/com/sun/jndi/cosnaming/jndiprovider.properties \ - $(JDK_TOPDIR)/src/share/classes/com/sun/jndi/ldap/jndiprovider.properties \ - $(JDK_TOPDIR)/src/share/classes/com/sun/org/apache/xml/internal/security/resource/*.properties \ - $(JDK_TOPDIR)/src/share/classes/com/sun/rowset/*.properties \ - $(JDK_TOPDIR)/src/share/classes/com/sun/tools/script/shell/*.properties \ - $(JDK_TOPDIR)/src/share/classes/javax/sql/rowset/*.properties \ - $(JDK_TOPDIR)/src/share/classes/sun/rmi/registry/resources/*.properties \ - $(JDK_TOPDIR)/src/share/classes/sun/rmi/rmic/resources/*.properties \ - $(JDK_TOPDIR)/src/share/classes/sun/rmi/server/resources/*.properties \ - $(JDK_TOPDIR)/src/share/classes/sun/tools/javac/resources/*.properties \ - $(JDK_TOPDIR)/src/share/classes/sun/tools/jconsole/resources/*.properties \ - $(JDK_TOPDIR)/src/share/classes/sun/tools/serialver/resources/*.properties \ - ) - -# Copy zh_HK files from zh_TW - -$(JDK_OUTPUTDIR)/classes/%_zh_HK.properties: $(JDK_OUTPUTDIR)/classes/%_zh_TW.properties - $(install-file) - -COPY_EXTRA += $(patsubst $(JDK_TOPDIR)/src/share/classes/%, $(JDK_OUTPUTDIR)/classes/%, \ - $(subst _zh_TW,_zh_HK, $(filter %_zh_TW.properties, $(CLEAN_FILES)))) diff --git a/jdk/make/CreateJars.gmk b/jdk/make/CreateJars.gmk index 1e250456507..d65fb7ea737 100644 --- a/jdk/make/CreateJars.gmk +++ b/jdk/make/CreateJars.gmk @@ -524,7 +524,6 @@ $(eval $(call SetupArchive,BUILD_TOOLS_JAR, , \ EXCLUDES := $(TOOLS_JAR_EXCLUDES), \ EXTRA_FILES := \ $(JDK_OUTPUTDIR)/modules/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector \ - $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.jdi.connect.Connector \ META-INF/services/com.sun.jdi.connect.spi.TransportService \ META-INF/services/com.sun.tools.attach.spi.AttachProvider \ META-INF/services/com.sun.tools.internal.ws.wscompile.Plugin \ diff --git a/jdk/make/CreateSecurityJars.gmk b/jdk/make/CreateSecurityJars.gmk index 1a3d3343c53..097ac813821 100644 --- a/jdk/make/CreateSecurityJars.gmk +++ b/jdk/make/CreateSecurityJars.gmk @@ -32,8 +32,6 @@ include JavaCompilation.gmk # The jars created in this file are required for the exploded jdk image to function and # cannot wait to be built in the images target. -SECURITY_CLASSES_SUBDIR := modules - ########################################################################################## # Create manifest for security jars # @@ -67,7 +65,7 @@ SUNPKCS11_JAR_DST := $(JDK_OUTPUTDIR)/lib/ext/sunpkcs11.jar SUNPKCS11_JAR_UNSIGNED := $(JDK_OUTPUTDIR)/jce/unsigned/sunpkcs11.jar $(eval $(call SetupArchive,BUILD_SUNPKCS11_JAR, , \ - SRCS := $(JDK_OUTPUTDIR)/$(SECURITY_CLASSES_SUBDIR)/jdk.crypto.pkcs11, \ + SRCS := $(JDK_OUTPUTDIR)/modules/jdk.crypto.pkcs11, \ SUFFIXES := .class, \ INCLUDES := sun/security/pkcs11, \ JAR := $(SUNPKCS11_JAR_UNSIGNED), \ @@ -94,7 +92,7 @@ SUNEC_JAR_DST := $(JDK_OUTPUTDIR)/lib/ext/sunec.jar SUNEC_JAR_UNSIGNED := $(JDK_OUTPUTDIR)/jce/unsigned/sunec.jar $(eval $(call SetupArchive,BUILD_SUNEC_JAR, , \ - SRCS := $(JDK_OUTPUTDIR)/$(SECURITY_CLASSES_SUBDIR)/jdk.crypto.ec, \ + SRCS := $(JDK_OUTPUTDIR)/modules/jdk.crypto.ec, \ SUFFIXES := .class, \ INCLUDES := sun/security/ec, \ JAR := $(SUNEC_JAR_UNSIGNED), \ @@ -122,7 +120,7 @@ SUNJCE_PROVIDER_JAR_UNSIGNED := $(JDK_OUTPUTDIR)/jce/unsigned/sunjce_provider.ja ifneq ($(BUILD_CRYPTO), no) $(eval $(call SetupArchive,BUILD_SUNJCE_PROVIDER_JAR, , \ - SRCS := $(JDK_OUTPUTDIR)/$(SECURITY_CLASSES_SUBDIR)/java.base, \ + SRCS := $(JDK_OUTPUTDIR)/modules/java.base, \ SUFFIXES := .class, \ INCLUDES := com/sun/crypto/provider, \ JAR := $(SUNJCE_PROVIDER_JAR_UNSIGNED), \ @@ -153,7 +151,7 @@ JCE_JAR_UNSIGNED := $(JDK_OUTPUTDIR)/jce/unsigned/jce.jar ifneq ($(BUILD_CRYPTO), no) $(eval $(call SetupArchive,BUILD_JCE_JAR, , \ - SRCS := $(JDK_OUTPUTDIR)/$(SECURITY_CLASSES_SUBDIR)/java.base, \ + SRCS := $(JDK_OUTPUTDIR)/modules/java.base, \ SUFFIXES := .class, \ INCLUDES := javax/crypto sun/security/internal, \ JAR := $(JCE_JAR_UNSIGNED), \ @@ -185,7 +183,7 @@ ifeq ($(OPENJDK_TARGET_OS), windows) SUNMSCAPI_JAR_UNSIGNED := $(JDK_OUTPUTDIR)/jce/unsigned/sunmscapi.jar $(eval $(call SetupArchive,BUILD_SUNMSCAPI_JAR, , \ - SRCS := $(JDK_OUTPUTDIR)/$(SECURITY_CLASSES_SUBDIR)/jdk.crypto.mscapi, \ + SRCS := $(JDK_OUTPUTDIR)/modules/jdk.crypto.mscapi, \ SUFFIXES := .class, \ INCLUDES := sun/security/mscapi, \ JAR := $(SUNMSCAPI_JAR_UNSIGNED), \ @@ -218,7 +216,7 @@ ifeq ($(OPENJDK_TARGET_OS), solaris) UCRYPTO_JAR_SRC := $(JDK_TOPDIR)/make/closed/tools/crypto/ucrypto/ucrypto.jar $(eval $(call SetupArchive,BUILD_UCRYPTO_JAR, , \ - SRCS := $(JDK_OUTPUTDIR)/$(SECURITY_CLASSES_SUBDIR)/jdk.crypto.ucrypto, \ + SRCS := $(JDK_OUTPUTDIR)/modules/jdk.crypto.ucrypto, \ SUFFIXES := .class, \ INCLUDES := com/oracle/security/ucrypto, \ JAR := $(UCRYPTO_JAR_UNSIGNED), \ diff --git a/jdk/make/Tools.gmk b/jdk/make/Tools.gmk index c384643ab67..b68d19c3d34 100644 --- a/jdk/make/Tools.gmk +++ b/jdk/make/Tools.gmk @@ -32,10 +32,7 @@ include $(SPEC) include MakeBase.gmk include JavaCompilation.gmk include NativeCompilation.gmk -include SetupJava.gmk - -# Cache all finds needed for this file. -$(eval $(call FillCacheFind, $(JDK_TOPDIR)/make/src/classes)) +include SetupJavaCompilers.gmk # The exception handling of swing beaninfo which have the own tool directory ifeq (, $(BUILD_TOOLS_JDK)) @@ -101,6 +98,9 @@ TOOL_TZDB = $(JAVA_SMALL) -cp $(JDK_OUTPUTDIR)/btclasses \ TOOL_BLACKLISTED_CERTS = $(JAVA_SMALL) -cp $(JDK_OUTPUTDIR)/btclasses \ build.tools.blacklistedcertsconverter.BlacklistedCertsConverter +TOOL_MAKEJAVASECURITY = $(JAVA_SMALL) -cp $(JDK_OUTPUTDIR)/btclasses \ + build.tools.makejavasecurity.MakeJavaSecurity + # TODO: There are references to the jdwpgen.jar in jdk/make/netbeans/jdwpgen/build.xml # and nbproject/project.properties in the same dir. Needs to be looked at. @@ -134,10 +134,7 @@ TOOL_CHECKDEPS = $(JAVA_SMALL) -Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR) \ TOOL_GENMODULESXML = $(JAVA_SMALL) -Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR) \ -cp "$(JDK_OUTPUTDIR)/btclasses$(PATH_SEP)$(JDK_OUTPUTDIR)" \ - build.tools.module.GenerateModulesXml - -TOOL_ADDTORESTRICTEDPKGS = $(JAVA_SMALL) -cp $(JDK_OUTPUTDIR)/btclasses \ - build.tools.addtorestrictedpkgs.AddToRestrictedPkgs + build.tools.module.GenJdepsModulesXml ########################################################################################## diff --git a/jdk/make/copy/Copy-java.base.gmk b/jdk/make/copy/Copy-java.base.gmk index 36a2c9da66a..c624ff80874 100644 --- a/jdk/make/copy/Copy-java.base.gmk +++ b/jdk/make/copy/Copy-java.base.gmk @@ -32,17 +32,17 @@ $(eval $(call IncludeCustomExtension, jdk, copy/Copy-java.base.gmk)) # Copy exported header files to outputdir. # JAVA_BASE_HEADERS := \ - $(INCLUDEDIR)/jni.h \ - $(INCLUDEDIR)/jvmti.h \ - $(INCLUDEDIR)/jvmticmlr.h \ - $(INCLUDEDIR)/classfile_constants.h \ - $(OPENJDK_TARGET_OS_INCLUDE)/jni_md.h \ + $(INCLUDE_DST_DIR)/jni.h \ + $(INCLUDE_DST_DIR)/jvmti.h \ + $(INCLUDE_DST_DIR)/jvmticmlr.h \ + $(INCLUDE_DST_DIR)/classfile_constants.h \ + $(INCLUDE_DST_OS_DIR)/jni_md.h \ # -$(INCLUDEDIR)/%.h: $(JDK_TOPDIR)/src/java.base/share/native/include/%.h +$(INCLUDE_DST_DIR)/%.h: $(JDK_TOPDIR)/src/java.base/share/native/include/%.h $(call install-file) -$(OPENJDK_TARGET_OS_INCLUDE)/%.h: \ +$(INCLUDE_DST_OS_DIR)/%.h: \ $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_EXPORT_DIR)/native/include/%.h $(call install-file) @@ -50,17 +50,17 @@ $(OPENJDK_TARGET_OS_INCLUDE)/%.h: \ CALENDARS_SRC := $(JDK_TOPDIR)/src/java.base/share/conf -$(LIBDIR)/calendars.properties: $(CALENDARS_SRC)/calendars.properties +$(LIB_DST_DIR)/calendars.properties: $(CALENDARS_SRC)/calendars.properties $(call install-file) -BASE_CONF_FILES += $(LIBDIR)/calendars.properties +BASE_CONF_FILES += $(LIB_DST_DIR)/calendars.properties -$(LIBDIR)/hijrah-config-umalqura.properties: $(CALENDARS_SRC)/hijrah-config-umalqura.properties +$(LIB_DST_DIR)/hijrah-config-umalqura.properties: $(CALENDARS_SRC)/hijrah-config-umalqura.properties $(MKDIR) -p $(@D) $(RM) $@ $(CP) $< $@ -BASE_CONF_FILES += $(LIBDIR)/hijrah-config-umalqura.properties +BASE_CONF_FILES += $(LIB_DST_DIR)/hijrah-config-umalqura.properties ################################################################################ @@ -68,10 +68,10 @@ ifneq ($(findstring $(OPENJDK_TARGET_OS), windows aix),) TZMAPPINGS_SRC := $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/conf - $(LIBDIR)/tzmappings: $(TZMAPPINGS_SRC)/tzmappings + $(LIB_DST_DIR)/tzmappings: $(TZMAPPINGS_SRC)/tzmappings $(call install-file) - BASE_CONF_FILES += $(LIBDIR)/tzmappings + BASE_CONF_FILES += $(LIB_DST_DIR)/tzmappings endif diff --git a/jdk/make/copy/Copy-java.desktop.gmk b/jdk/make/copy/Copy-java.desktop.gmk index e724a862b28..2460ffe6a54 100644 --- a/jdk/make/copy/Copy-java.desktop.gmk +++ b/jdk/make/copy/Copy-java.desktop.gmk @@ -30,20 +30,20 @@ $(eval $(call IncludeCustomExtension, jdk, copy/Copy-java.desktop.gmk)) ################################################################################ JAVA_DESKTOP_HEADERS := \ - $(INCLUDEDIR)/jawt.h \ - $(OPENJDK_TARGET_OS_INCLUDE)/jawt_md.h \ + $(INCLUDE_DST_DIR)/jawt.h \ + $(INCLUDE_DST_OS_DIR)/jawt_md.h \ # -$(INCLUDEDIR)/%.h: $(JDK_TOPDIR)/src/java.desktop/share/native/include/%.h +$(INCLUDE_DST_DIR)/%.h: $(JDK_TOPDIR)/src/java.desktop/share/native/include/%.h $(call install-file) -$(OPENJDK_TARGET_OS_INCLUDE)/%.h: \ +$(INCLUDE_DST_OS_DIR)/%.h: \ $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_EXPORT_DIR)/native/include/%.h $(call install-file) ################################################################################ -ICCPROFILE_DEST_DIR := $(LIBDIR)/cmm +ICCPROFILE_DEST_DIR := $(LIB_DST_DIR)/cmm ifdef OPENJDK ICCPROFILE_SRC_DIR := $(JDK_TOPDIR)/src/java.desktop/share/conf/cmm/lcms @@ -102,20 +102,20 @@ DESKTOP_CONF_FILES += $(JDK_OUTPUTDIR)/lib/sound.properties ################################################################################ # -# Copy property files from sun/print to LIBDIR +# Copy property files from sun/print to LIB_DST_DIR # PSFONTPROPFILE_SRC_DIR := $(JDK_TOPDIR)/src/java.desktop/share/conf PSFONTPROPFILE_SRCS := $(wildcard $(PSFONTPROPFILE_SRC_DIR)/psfont*.properties*) -PSFONTPROPFILE_TARGET_FILES := $(subst $(PSFONTPROPFILE_SRC_DIR),$(LIBDIR),$(PSFONTPROPFILE_SRCS)) +PSFONTPROPFILE_TARGET_FILES := $(subst $(PSFONTPROPFILE_SRC_DIR),$(LIB_DST_DIR),$(PSFONTPROPFILE_SRCS)) -$(LIBDIR)/%: $(PSFONTPROPFILE_SRC_DIR)/% +$(LIB_DST_DIR)/%: $(PSFONTPROPFILE_SRC_DIR)/% $(call install-file) DESKTOP_CONF_FILES += $(PSFONTPROPFILE_TARGET_FILES) ################################################################################ # -# Copy cursor.properties and cursors gif files to LIBDIR +# Copy cursor.properties and cursors gif files to LIB_DST_DIR # ifneq ($(OPENJDK_TARGET_OS), macosx) OPENJDK_TARGET_OS_LIB_SRC := $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_API_DIR)/conf @@ -123,7 +123,7 @@ else OPENJDK_TARGET_OS_LIB_SRC := $(JDK_TOPDIR)/src/java.desktop/macosx/conf endif -CURSORS_DEST_DIR := $(LIBDIR)/images/cursors +CURSORS_DEST_DIR := $(LIB_DST_DIR)/images/cursors CURSORS_OPENJDK_TARGET_OS_LIB_SRC := $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_API_DIR)/conf/images/cursors $(CURSORS_DEST_DIR)/cursors.properties: $(CURSORS_OPENJDK_TARGET_OS_LIB_SRC)/cursors.properties diff --git a/jdk/make/copy/Copy-java.logging.gmk b/jdk/make/copy/Copy-java.logging.gmk index f2644df1a17..da77f247276 100644 --- a/jdk/make/copy/Copy-java.logging.gmk +++ b/jdk/make/copy/Copy-java.logging.gmk @@ -29,10 +29,10 @@ include CopyCommon.gmk LOGGING_LIB_SRC := $(JDK_TOPDIR)/src/java.logging/share/conf -$(LIBDIR)/logging.properties: $(LOGGING_LIB_SRC)/logging.properties +$(LIB_DST_DIR)/logging.properties: $(LOGGING_LIB_SRC)/logging.properties $(call install-file) -LOGGING_CONF_FILES := $(LIBDIR)/logging.properties +LOGGING_CONF_FILES := $(LIB_DST_DIR)/logging.properties ################################################################################ diff --git a/jdk/make/copy/Copy-java.management.gmk b/jdk/make/copy/Copy-java.management.gmk index 55657a963ba..2352c909cad 100644 --- a/jdk/make/copy/Copy-java.management.gmk +++ b/jdk/make/copy/Copy-java.management.gmk @@ -27,7 +27,7 @@ include CopyCommon.gmk ################################################################################ -MGMT_LIBDIR := $(LIBDIR)/management +MGMT_LIBDIR := $(LIB_DST_DIR)/management MGMT_LIB_SRC := $(JDK_TOPDIR)/src/java.management/share/conf MGMT_SRC_FILES := $(wildcard $(MGMT_LIB_SRC)/*) MGMT_TARGET_FILES := $(subst $(MGMT_LIB_SRC),$(MGMT_LIBDIR),$(MGMT_SRC_FILES)) diff --git a/jdk/make/copy/Copy-jdk.hprof.agent.gmk b/jdk/make/copy/Copy-jdk.hprof.agent.gmk index ccec153a5b7..069e915514f 100644 --- a/jdk/make/copy/Copy-jdk.hprof.agent.gmk +++ b/jdk/make/copy/Copy-jdk.hprof.agent.gmk @@ -27,12 +27,12 @@ include CopyCommon.gmk ################################################################################ -HPROF_SRC := $(JDK_TOPDIR)/src/demo/share/jvmti/hprof/jvm.hprof.txt +HPROF_SRC := $(JDK_TOPDIR)/src/jdk.hprof.agent/share/native/libhprof/jvm.hprof.txt -$(LIBDIR)/jvm.hprof.txt: $(HPROF_SRC) +$(LIB_DST_DIR)/jvm.hprof.txt: $(HPROF_SRC) $(call install-file) -HPROF_CONF_FILES := $(LIBDIR)/jvm.hprof.txt +HPROF_CONF_FILES := $(LIB_DST_DIR)/jvm.hprof.txt ################################################################################ diff --git a/jdk/make/copy/Copy-jdk.jdwp.agent.gmk b/jdk/make/copy/Copy-jdk.jdwp.agent.gmk index c02ae7bd9be..dd7ccf01c44 100644 --- a/jdk/make/copy/Copy-jdk.jdwp.agent.gmk +++ b/jdk/make/copy/Copy-jdk.jdwp.agent.gmk @@ -28,9 +28,9 @@ include CopyCommon.gmk ################################################################################ -JDK_DEBUG_AGENT_HEADERS := $(INCLUDEDIR)/jdwpTransport.h +JDK_DEBUG_AGENT_HEADERS := $(INCLUDE_DST_DIR)/jdwpTransport.h -$(INCLUDEDIR)/%.h: $(JDK_TOPDIR)/src/jdk.jdwp.agent/share/native/include/%.h +$(INCLUDE_DST_DIR)/%.h: $(JDK_TOPDIR)/src/jdk.jdwp.agent/share/native/include/%.h $(call install-file) ################################################################################ diff --git a/jdk/make/copy/CopyCommon.gmk b/jdk/make/copy/CopyCommon.gmk index 3baefab75c8..f9c951287fc 100644 --- a/jdk/make/copy/CopyCommon.gmk +++ b/jdk/make/copy/CopyCommon.gmk @@ -28,13 +28,13 @@ default: all include $(SPEC) include MakeBase.gmk -INCLUDEDIR = $(JDK_OUTPUTDIR)/include -LIBDIR := $(JDK_OUTPUTDIR)/lib +INCLUDE_DST_DIR := $(JDK_OUTPUTDIR)/include +LIB_DST_DIR := $(JDK_OUTPUTDIR)/lib -OPENJDK_TARGET_OS_INCLUDE = $(INCLUDEDIR)/$(OPENJDK_TARGET_OS) +INCLUDE_DST_OS_DIR := $(INCLUDE_DST_DIR)/$(OPENJDK_TARGET_OS) ifeq ($(OPENJDK_TARGET_OS), windows) - OPENJDK_TARGET_OS_INCLUDE = $(INCLUDEDIR)/win32 + INCLUDE_DST_OS_DIR := $(INCLUDE_DST_DIR)/win32 else ifeq ($(OPENJDK_TARGET_OS), macosx) - OPENJDK_TARGET_OS_INCLUDE = $(INCLUDEDIR)/darwin + INCLUDE_DST_OS_DIR := $(INCLUDE_DST_DIR)/darwin endif diff --git a/jdk/make/bundle/JDK-Info.plist b/jdk/make/data/bundle/JDK-Info.plist similarity index 100% rename from jdk/make/bundle/JDK-Info.plist rename to jdk/make/data/bundle/JDK-Info.plist diff --git a/jdk/make/bundle/JRE-Info.plist b/jdk/make/data/bundle/JRE-Info.plist similarity index 100% rename from jdk/make/bundle/JRE-Info.plist rename to jdk/make/data/bundle/JRE-Info.plist diff --git a/jdk/make/data/fontconfig/aix.fontconfig.properties b/jdk/make/data/fontconfig/aix.fontconfig.properties index 29e7c7d9510..f203f759894 100644 --- a/jdk/make/data/fontconfig/aix.fontconfig.properties +++ b/jdk/make/data/fontconfig/aix.fontconfig.properties @@ -24,9 +24,14 @@ # questions. # -# Minimal version for AIX using the standard Latin Type1 Fonts from the -# package X11.fnt.iso_T1. These fonts are installed by default into -# "/usr/lpp/X11/lib/X11/fonts/Type1" and sym-linked to "/usr/lib/X11/fonts/Type1" +# +# Portions Copyright (c) 2014 IBM Corporation +# + +# This file references the standard Latin Type1 fonts from the AIX package +# X11.fnt.iso_T1 and the Unicode TrueType fonts from X11.fnt.ucs.ttf. They +# are located by default under "/usr/lpp/X11/lib/X11/fonts/{Type1,TrueType}" +# and sym-linked to "/usr/lib/X11/fonts/". # Version @@ -34,44 +39,381 @@ version=1 # Component Font Mappings -dialog.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso10646-1 -dialog.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso10646-1 -dialog.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso10646-1 -dialog.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso10646-1 +allfonts.iso10646-extB=-monotype-sansmonowtextb-medium-r-normal--*-%d-75-75-m-*-unicode-2 -dialoginput.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso10646-1 -dialoginput.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso10646-1 -dialoginput.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso10646-1 -dialoginput.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso10646-1 -sansserif.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso10646-1 -sansserif.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso10646-1 -sansserif.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso10646-1 -sansserif.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso10646-1 +dialog.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso8859-1 +dialog.plain.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +dialog.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0 +dialog.plain.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +dialog.plain.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +dialog.plain.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +dialog.plain.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +dialog.plain.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +dialog.plain.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +dialog.plain.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +dialog.plain.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +dialog.plain.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 -serif.plain.latin-1=-*-times new roman-medium-r-normal--*-%d-100-100-p-*-iso10646-1 -serif.bold.latin-1=-*-times new roman-bold-r-normal--*-%d-100-100-p-*-iso10646-1 -serif.italic.latin-1=-*-times new roman-medium-i-normal--*-%d-100-100-p-*-iso10646-1 -serif.bolditalic.latin-1=-*-times new roman-bold-i-normal--*-%d-100-100-p-*-iso10646-1 +dialog.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso8859-1 +dialog.bold.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +dialog.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-p-*-ucs2.i18n-0 +dialog.bold.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +dialog.bold.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +dialog.bold.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +dialog.bold.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +dialog.bold.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +dialog.bold.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +dialog.bold.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +dialog.bold.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +dialog.bold.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 -monospaced.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso10646-1 -monospaced.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso10646-1 -monospaced.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso10646-1 -monospaced.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso10646-1 +dialog.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso8859-1 +dialog.italic.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +dialog.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-p-*-ucs2.i18n-0 +dialog.italic.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +dialog.italic.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +dialog.italic.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +dialog.italic.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +dialog.italic.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +dialog.italic.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +dialog.italic.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +dialog.italic.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +dialog.italic.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +dialog.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso8859-1 +dialog.bolditalic.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +dialog.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0 +dialog.bolditalic.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +dialog.bolditalic.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +dialog.bolditalic.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +dialog.bolditalic.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +dialog.bolditalic.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +dialog.bolditalic.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +dialog.bolditalic.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +dialog.bolditalic.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +dialog.bolditalic.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +dialoginput.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso8859-1 +dialoginput.plain.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0 +dialoginput.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0 +dialoginput.plain.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +dialoginput.plain.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +dialoginput.plain.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +dialoginput.plain.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +dialoginput.plain.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +dialoginput.plain.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +dialoginput.plain.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +dialoginput.plain.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +dialoginput.plain.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +dialoginput.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso8859-1 +dialoginput.bold.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0 +dialoginput.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-m-*-ucs2.i18n-0 +dialoginput.bold.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +dialoginput.bold.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +dialoginput.bold.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +dialoginput.bold.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +dialoginput.bold.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +dialoginput.bold.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +dialoginput.bold.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +dialoginput.bold.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +dialoginput.bold.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +dialoginput.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso8859-1 +dialoginput.italic.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0 +dialoginput.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-m-*-ucs2.i18n-0 +dialoginput.italic.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +dialoginput.italic.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +dialoginput.italic.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +dialoginput.italic.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +dialoginput.italic.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +dialoginput.italic.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +dialoginput.italic.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +dialoginput.italic.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +dialoginput.italic.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +dialoginput.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso8859-1 +dialoginput.bolditalic.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0 +dialoginput.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0 +dialoginput.bolditalic.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +dialoginput.bolditalic.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +dialoginput.bolditalic.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +dialoginput.bolditalic.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +dialoginput.bolditalic.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +dialoginput.bolditalic.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +dialoginput.bolditalic.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +dialoginput.bolditalic.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +dialoginput.bolditalic.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +sansserif.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso8859-1 +sansserif.plain.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +sansserif.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0 +sansserif.plain.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +sansserif.plain.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +sansserif.plain.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +sansserif.plain.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +sansserif.plain.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +sansserif.plain.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +sansserif.plain.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +sansserif.plain.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +sansserif.plain.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +sansserif.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso8859-1 +sansserif.bold.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +sansserif.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-p-*-ucs2.i18n-0 +sansserif.bold.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +sansserif.bold.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +sansserif.bold.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +sansserif.bold.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +sansserif.bold.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +sansserif.bold.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +sansserif.bold.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +sansserif.bold.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +sansserif.bold.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +sansserif.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso8859-1 +sansserif.italic.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +sansserif.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-p-*-ucs2.i18n-0 +sansserif.italic.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +sansserif.italic.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +sansserif.italic.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +sansserif.italic.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +sansserif.italic.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +sansserif.italic.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +sansserif.italic.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +sansserif.italic.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +sansserif.italic.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +sansserif.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso8859-1 +sansserif.bolditalic.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +sansserif.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0 +sansserif.bolditalic.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +sansserif.bolditalic.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +sansserif.bolditalic.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +sansserif.bolditalic.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +sansserif.bolditalic.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +sansserif.bolditalic.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +sansserif.bolditalic.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +sansserif.bolditalic.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +sansserif.bolditalic.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +serif.plain.latin-1=-*-times new roman-medium-r-normal--*-%d-100-100-p-*-iso8859-1 +serif.plain.thai=-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +serif.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0 +serif.plain.japanese-x0208=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +serif.plain.japanese-x0201=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +serif.plain.japanese-udc=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +serif.plain.japanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +serif.plain.korean=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +serif.plain.korean-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +serif.plain.chinese=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +serif.plain.chinese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +serif.plain.taiwanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +serif.bold.latin-1=-*-times new roman-bold-r-normal--*-%d-100-100-p-*-iso8859-1 +serif.bold.thai=-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +serif.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-p-*-ucs2.i18n-0 +serif.bold.japanese-x0208=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +serif.bold.japanese-x0201=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +serif.bold.japanese-udc=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +serif.bold.japanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +serif.bold.korean=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +serif.bold.korean-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +serif.bold.chinese=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +serif.bold.chinese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +serif.bold.taiwanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + + +serif.italic.latin-1=-*-times new roman-medium-i-normal--*-%d-100-100-p-*-iso8859-1 +serif.italic.thai=-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +serif.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-p-*-ucs2.i18n-0 +serif.italic.japanese-x0208=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +serif.italic.japanese-x0201=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +serif.italic.japanese-udc=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +serif.italic.japanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +serif.italic.korean=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +serif.italic.korean-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +serif.italic.chinese=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +serif.italic.chinese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +serif.italic.taiwanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +serif.bolditalic.latin-1=-*-times new roman-bold-i-normal--*-%d-100-100-p-*-iso8859-1 +serif.bolditalic.thai=-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0 +serif.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0 +serif.bolditalic.japanese-x0208=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +serif.bolditalic.japanese-x0201=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +serif.bolditalic.japanese-udc=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +serif.bolditalic.japanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +serif.bolditalic.korean=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +serif.bolditalic.korean-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +serif.bolditalic.chinese=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +serif.bolditalic.chinese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +serif.bolditalic.taiwanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +monospaced.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso8859-1 +monospaced.plain.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0 +monospaced.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0 +monospaced.plain.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +monospaced.plain.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +monospaced.plain.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +monospaced.plain.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +monospaced.plain.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +monospaced.plain.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +monospaced.plain.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +monospaced.plain.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +monospaced.plain.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +monospaced.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso8859-1 +monospaced.bold.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0 +monospaced.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-m-*-ucs2.i18n-0 +monospaced.bold.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +monospaced.bold.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +monospaced.bold.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +monospaced.bold.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +monospaced.bold.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +monospaced.bold.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +monospaced.bold.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +monospaced.bold.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +monospaced.bold.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +monospaced.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso8859-1 +monospaced.italic.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0 +monospaced.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-m-*-ucs2.i18n-0 +monospaced.italic.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +monospaced.italic.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +monospaced.italic.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +monospaced.italic.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +monospaced.italic.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +monospaced.italic.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +monospaced.italic.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +monospaced.italic.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +monospaced.italic.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 + +monospaced.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso8859-1 +monospaced.bolditalic.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0 +monospaced.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0 +monospaced.bolditalic.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0 +monospaced.bolditalic.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0 +monospaced.bolditalic.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp +monospaced.bolditalic.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0 +monospaced.bolditalic.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0 +monospaced.bolditalic.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0 +monospaced.bolditalic.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0 +monospaced.bolditalic.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0 +monospaced.bolditalic.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0 # Search Sequences sequence.allfonts=latin-1 +sequence.allfonts.UTF-8=latin-1,japanese-iso10646 +# Uk_UA +sequence.allfonts.x-IBM1124=latin-1,ukranian-ibm1124 +# Japanese +sequence.allfonts.x-IBM943C=latin-1,japanese-x0201,japanese-x0208,japanese-udc +sequence.allfonts.x-IBM29626C=latin-1,japanese-x0201,japanese-x0208,japanese-udc +sequence.allfonts.UTF-8.ja=japanese-iso10646,latin-1,iso10646-extB +# Chinese +sequence.allfonts.x-EUC_CN=latin-1,chinese +sequence.allfonts.GB18030=latin-1,chinese-iso10646,iso10646-extB +sequence.allfonts.UTF-8.zh.CN=latin-1,chinese-iso10646,iso10646-extB +# Taiwanese +sequence.allfonts.x-IBM964=latin-1,taiwanese-iso10646 +sequence.allfonts.Big5=latin-1,taiwanese-iso10646 +sequence.allfonts.UTF-8.zh.TW=latin-1,taiwanese-iso10646 +# Korean +sequence.allfonts.x-IBM970=latin-1,korean +sequence.allfonts.UTF-8.ko=latin-1,korean-iso10646 +# Thai +sequence.allfonts.TIS-620=latin-1,thai +sequence.allfonts.UTF-8.th=latin-1,thai +# fallback +sequence.fallback=thai,chinese-iso10646,taiwanese-iso10646,japanese-iso10646,korean-iso10646,iso10646-extB + +# Exclusion Ranges +exclusion.japanese-iso10646=0000-00ff + +# Font File Names +filename.-*-courier-medium-r-normal--*-%d-100-100-m-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/cour.pfa +filename.-*-courier-bold-r-normal--*-%d-100-100-m-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/courb.pfa +filename.-*-courier-medium-o-normal--*-%d-100-100-m-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/couri.pfa +filename.-*-courier-bold-o-normal--*-%d-100-100-m-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/courbi.pfa +filename.-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/helv.pfa +filename.-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvb.pfa +filename.-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvi.pfa +filename.-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvbi.pfa +filename.-*-times_new_roman-medium-r-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnr.pfa +filename.-*-times_new_roman-bold-r-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrb.pfa +filename.-*-times_new_roman-medium-i-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnri.pfa +filename.-*-times_new_roman-bold-i-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrbi.pfa + + +filename.-monotype-sansmonowtextb-medium-r-normal--*-%d-75-75-m-*-unicode-2=/usr/lpp/X11/lib/X11/fonts/TrueType/MTSanXBA.ttf + +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_k.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_k.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_s.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_s.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_s.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_s.ttf +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_t.ttf + +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdk.ttf +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdk.ttf +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansds.ttf +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansds.ttf +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdt.ttf +filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_j.ttf +filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_j.ttf +filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_j.ttf +filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_j.ttf +filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_k.ttf +filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_k.ttf +filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_s.ttf +filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_s.ttf +filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_t.ttf + +filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-iso8859-15=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-iso8859-15=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf + +filename.-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0=/usr/lpp/X11/lib/X11/fonts/TrueType/courth.ttf +filename.-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0=/usr/lpp/X11/lib/X11/fonts/TrueType/helvth.ttf +filename.-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0=/usr/lpp/X11/lib/X11/fonts/TrueType/timeth.ttf + +filename.-*-*-medium-r-normal--*-%d-*-*-p-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-*-*-bold-r-normal--*-%d-*-*-p-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-*-*-medium-i-normal--*-%d-*-*-p-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-*-*-bold-i-normal--*-%d-*-*-p-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-*-*-medium-r-normal--*-%d-*-*-m-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf +filename.-*-*-bold-r-normal--*-%d-*-*-m-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf +filename.-*-*-medium-i-normal--*-%d-*-*-m-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf +filename.-*-*-bold-i-normal--*-%d-*-*-m-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf + +filename.-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-*-*-bold-r-normal--*-%d-75-75-p-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-*-*-medium-i-normal--*-%d-75-75-p-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf +filename.-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf +filename.-*-*-bold-r-normal--*-%d-75-75-m-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf +filename.-*-*-medium-i-normal--*-%d-75-75-m-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf + +# AWT font path +awtfontpath.japanese-x0201=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.japanese-x0208=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.japanese-udc=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.japanese-iso10646=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.korean=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.korean-iso10646=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.chinese=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.chinese-iso10646=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.taiwanese-iso10646=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.thai=/usr/lpp/X11/lib/X11/fonts/TrueType +awtfontpath.iso10646-extB=/usr/lpp/X11/lib/X11/fonts/TrueType -filename.-*-courier-medium-r-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/cour.pfa -filename.-*-courier-bold-r-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/courb.pfa -filename.-*-courier-medium-o-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/couri.pfa -filename.-*-courier-bold-o-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/courbi.pfa -filename.-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helv.pfa -filename.-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvb.pfa -filename.-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvi.pfa -filename.-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvbi.pfa -filename.-*-times_new_roman-medium-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnr.pfa -filename.-*-times_new_roman-bold-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrb.pfa -filename.-*-times_new_roman-medium-i-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnri.pfa -filename.-*-times_new_roman-bold-i-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrbi.pfa diff --git a/jdk/make/gendata/Gendata-java.base.gmk b/jdk/make/gendata/Gendata-java.base.gmk index 71ee403d7a8..a7135abe563 100644 --- a/jdk/make/gendata/Gendata-java.base.gmk +++ b/jdk/make/gendata/Gendata-java.base.gmk @@ -62,25 +62,18 @@ GENDATA += $(GENDATA_CURDATA) ########################################################################################## -PROPS_SRC := $(JDK_TOPDIR)/src/java.base/share/conf/security/java.security-$(OPENJDK_TARGET_OS) -PROPS_DST := $(JDK_OUTPUTDIR)/lib/security/java.security +GENDATA_JAVA_SECURITY_SRC := $(JDK_TOPDIR)/src/java.base/share/conf/security/java.security +GENDATA_JAVA_SECURITY := $(JDK_OUTPUTDIR)/lib/security/java.security -# Optionally set this variable to a file to add extra restricted packages. -ifneq ($(RESTRICTED_PKGS_SRC), ) +# RESTRICTED_PKGS_SRC is optionally set in custom extension for this makefile - $(PROPS_DST): $(PROPS_SRC) $(RESTRICTED_PKGS_SRC) +$(GENDATA_JAVA_SECURITY): $(BUILD_TOOLS) $(GENDATA_JAVA_SECURITY_SRC) $(RESTRICTED_PKGS_SRC) + $(ECHO) "Generating java.security" $(MKDIR) -p $(@D) - $(TOOL_ADDTORESTRICTEDPKGS) $(PROPS_SRC) $@.tmp `$(CAT) $(RESTRICTED_PKGS_SRC) | $(TR) "\n" " "` - $(MV) $@.tmp $@ + $(TOOL_MAKEJAVASECURITY) $(GENDATA_JAVA_SECURITY_SRC) $@ $(OPENJDK_TARGET_OS) \ + $(RESTRICTED_PKGS_SRC) || exit 1 -else - - $(PROPS_DST): $(PROPS_SRC) - $(call install-file) - -endif - -GENDATA += $(PROPS_DST) +GENDATA += $(GENDATA_JAVA_SECURITY) ########################################################################################## diff --git a/jdk/test/sun/tools/jps/jps-help.sh b/jdk/make/gendata/Gendata-jdk.dev.gmk similarity index 52% rename from jdk/test/sun/tools/jps/jps-help.sh rename to jdk/make/gendata/Gendata-jdk.dev.gmk index c6c1cbdd7d4..3c24cf4b703 100644 --- a/jdk/test/sun/tools/jps/jps-help.sh +++ b/jdk/make/gendata/Gendata-jdk.dev.gmk @@ -1,10 +1,12 @@ # -# Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. +# 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. +# 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 @@ -21,37 +23,24 @@ # questions. # -# @test -# @bug 4990825 -# @run shell jps-help.sh -# @summary Test that output of 'jps -?' matches the usage.out file +include GendataCommon.gmk -. ${TESTSRC-.}/../../jvmstat/testlibrary/utils.sh +$(eval $(call IncludeCustomExtension, jdk, gendata/Gendata-jdk.dev.gmk)) -setup +GENDATA := $(JDK_OUTPUTDIR)/modules/jdk.dev/com/sun/tools/jdeps/resources/jdeps-modules.xml +METADATA_FILES += $(TOPDIR)/modules.xml -JPS="${TESTJAVA}/bin/jps" +# +# Generate modules.xml for jdeps to use +# It augments $(TOPDIR)/modules.xml to include module membership +# +$(GENDATA): $(BUILD_TOOLS_JDK) $(METADATA_FILES) + $(MKDIR) -p $(@D) + $(RM) $@ + $(TOOL_GENMODULESXML) -o $@ -mp $(JDK_OUTPUTDIR)/modules $(METADATA_FILES) -rm -f jps.out 2>/dev/null -${JPS} -J-XX:+UsePerfData -? > jps.out 2>&1 +jdk.dev: $(GENDATA) -diff -w jps.out ${TESTSRC}/usage.out -if [ $? != 0 ] -then - echo "Output of jps -? differ from expected output. Failed." - rm -f jps.out 2>/dev/null - exit 1 -fi +all: $(GENDATA) -rm -f jps.out 2>/dev/null -${JPS} -J-XX:+UsePerfData -help > jps.out 2>&1 - -diff -w jps.out ${TESTSRC}/usage.out -if [ $? != 0 ] -then - echo "Output of jps -help differ from expected output. Failed." - rm -f jps.out 2>/dev/null - exit 1 -fi - -exit 0 +.PHONY: all jdk.dev diff --git a/jdk/make/gendata/GendataCommon.gmk b/jdk/make/gendata/GendataCommon.gmk index c199a377378..e5e0336b325 100644 --- a/jdk/make/gendata/GendataCommon.gmk +++ b/jdk/make/gendata/GendataCommon.gmk @@ -28,9 +28,7 @@ default: all include $(SPEC) include MakeBase.gmk include JavaCompilation.gmk - -# Setup the java compilers for the JDK build. -include SetupJava.gmk +include SetupJavaCompilers.gmk # We need the tools. include Tools.gmk diff --git a/jdk/make/gensrc/GensrcCommon.gmk b/jdk/make/gensrc/GensrcCommon.gmk index 3c271c81d77..09819e19d57 100644 --- a/jdk/make/gensrc/GensrcCommon.gmk +++ b/jdk/make/gensrc/GensrcCommon.gmk @@ -30,9 +30,7 @@ include MakeBase.gmk include JavaCompilation.gmk include NativeCompilation.gmk include TextFileProcessing.gmk - -# Setup the java compilers for the JDK build. -include SetupJava.gmk +include SetupJavaCompilers.gmk # We need the tools. include Tools.gmk diff --git a/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk b/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk index b3f0335d7e0..f4a3575218e 100644 --- a/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk +++ b/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2013, 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 @@ -28,13 +28,15 @@ # into LocaleDataMetaInfo.java # First go look for all locale files -LOCALE_FILES := $(shell $(FIND) $(JDK_TOPDIR)/src/*/share/classes \ +LOCALE_FILES := $(shell $(FIND) $(JDK_TOPDIR)/src/java.base/share/classes \ + $(JDK_TOPDIR)/src/jdk.localedata/share/classes \ -name "FormatData_*.java" -o -name "FormatData_*.properties" -o \ -name "CollationData_*.java" -o -name "CollationData_*.properties" -o \ -name "TimeZoneNames_*.java" -o -name "TimeZoneNames_*.properties" -o \ -name "LocaleNames_*.java" -o -name "LocaleNames_*.properties" -o \ -name "CurrencyNames_*.java" -o -name "CurrencyNames_*.properties" -o \ - -name "CalendarData_*.java" -o -name "CalendarData_*.properties") + -name "CalendarData_*.java" -o -name "CalendarData_*.properties" -o \ + -name "BreakIteratorInfo_*.java" -o -name "BreakIteratorRules_*.java") # Then translate the locale files into for example: FormatData_sv LOCALE_RESOURCES := $(sort $(subst .properties,,$(subst .java,,$(notdir $(LOCALE_FILES))))) @@ -86,6 +88,12 @@ $(eval $(call CaptureLocale,FormatData)) #sun.text.resources.CollationData $(eval $(call CaptureLocale,CollationData)) +#sun.text.resources.BreakIteratorInfo +$(eval $(call CaptureLocale,BreakIteratorInfo)) + +#sun.text.resources.BreakIteratorRules +$(eval $(call CaptureLocale,BreakIteratorRules)) + #sun.util.resources.TimeZoneNames $(eval $(call CaptureLocale,TimeZoneNames)) diff --git a/jdk/make/gensrc/GensrcProperties.gmk b/jdk/make/gensrc/GensrcProperties.gmk index c387d52ffe2..a33015b150c 100644 --- a/jdk/make/gensrc/GensrcProperties.gmk +++ b/jdk/make/gensrc/GensrcProperties.gmk @@ -23,9 +23,6 @@ # questions. # -# Prepare the find cache. -$(eval $(call FillCacheFind, $(wildcard $(JDK_TOPDIR)/src/*/*/classes))) - # All .properties files to be compiled are appended to this variable. ALL_COMPILED_PROPSOURCES := # All generated .java files from compilation are appended to this variable. @@ -76,7 +73,6 @@ COMPILE_PROP_SRC_FILES := \ $(JDK_TOPDIR)/src/java.management/share/classes/sun/management/resources \ $(JDK_TOPDIR)/src/java.desktop/share/classes/sun/print/resources \ $(JDK_TOPDIR)/src/jdk.dev/share/classes/sun/tools/jar/resources \ - $(JDK_TOPDIR)/src/jdk.dev/share/classes/jdk/jigsaw/tools/jlink/resources \ $(JDK_TOPDIR)/src/java.logging/share/classes/sun/util/logging/resources)) \ # diff --git a/jdk/make/gensrc/GensrcProviders.gmk b/jdk/make/gensrc/GensrcProviders.gmk index 985f032169e..dca14083054 100644 --- a/jdk/make/gensrc/GensrcProviders.gmk +++ b/jdk/make/gensrc/GensrcProviders.gmk @@ -32,15 +32,6 @@ endef ################################################################################ -# Filter com.sun.tools.attach.spi.AttachProvider -$(JDK_OUTPUTDIR)/gensrc/jdk.attach/META-INF/services/com.sun.tools.attach.spi.AttachProvider: \ - $(JDK_TOPDIR)/src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider - $(process-provider) - -GENSRC_JDK_ATTACH += $(JDK_OUTPUTDIR)/gensrc/jdk.attach/META-INF/services/com.sun.tools.attach.spi.AttachProvider - -################################################################################ - # Filter com.sun.jdi.connect.Connector $(JDK_OUTPUTDIR)/gensrc/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector: \ $(JDK_TOPDIR)/src/jdk.jdi/share/classes/META-INF/services/com.sun.jdi.connect.Connector diff --git a/jdk/make/gensrc/GensrcSwing.gmk b/jdk/make/gensrc/GensrcSwing.gmk index 12e2445bb32..c7571269c98 100644 --- a/jdk/make/gensrc/GensrcSwing.gmk +++ b/jdk/make/gensrc/GensrcSwing.gmk @@ -78,11 +78,8 @@ $(JDK_OUTPUTDIR)/gensrc_no_srczip/_the.generated_beaninfo: $(BEANS_SRC) \ $(MKDIR) -p $(JDK_OUTPUTDIR)/gensrc_no_srczip/java.desktop/javax/swing $(JAVA) -Djava.awt.headless=true $(NEW_JAVADOC) \ -sourcepath "$(subst $(SPACE),$(PATH_SEP),\ - $(if $(SHUFFLED),$(wildcard $(JDK_TOPDIR)/src/*/*/classes) \ - $(JDK_OUTPUTDIR)/gensrc/java.base, \ - $(JDK_TOPDIR)/src/share/classes \ - $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes \ - $(JDK_OUTPUTDIR)/gensrc))" \ + $(wildcard $(JDK_TOPDIR)/src/*/*/classes) \ + $(JDK_OUTPUTDIR)/gensrc/java.base)" \ -doclet build.tools.swingbeaninfo.GenDocletBeanInfo \ -x $(SWINGBEAN_DEBUG_FLAG) -d $(JDK_OUTPUTDIR)/gensrc_no_srczip/java.desktop/javax/swing \ -t $(DOCLET_DATA_DIR)/SwingBeanInfo.template -docletpath $(JDK_OUTPUTDIR)/btclasses \ diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk index 774a2675836..e5161a35552 100644 --- a/jdk/make/lib/Awt2dLibraries.gmk +++ b/jdk/make/lib/Awt2dLibraries.gmk @@ -23,12 +23,9 @@ # questions. # -# Hook to include the corresponding custom file, if present. -$(eval $(call IncludeCustomExtension, jdk, lib/Awt2dLibraries.gmk)) - WIN_AWT_LIB := $(JDK_OUTPUTDIR)/objs/libawt/awt.lib -########################################################################################## +################################################################################ BUILD_LIBMLIB_SRC := $(JDK_TOPDIR)/src/java.desktop/share/native/libmlib_image \ $(JDK_TOPDIR)/src/java.desktop/share/native/common/sun/awt/medialib @@ -76,7 +73,7 @@ $(BUILD_LIBMLIB_IMAGE): $(BUILD_LIBJAVA) DESKTOP_LIBRARIES += $(BUILD_LIBMLIB_IMAGE) -########################################################################################## +################################################################################ ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc) @@ -144,7 +141,7 @@ ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc) endif -########################################################################################## +################################################################################ LIBAWT_DIRS := $(JDK_TOPDIR)/src/java.desktop/share/native/libawt \ $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_API_DIR)/native/libawt \ @@ -152,13 +149,17 @@ LIBAWT_DIRS := $(JDK_TOPDIR)/src/java.desktop/share/native/libawt \ $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_API_DIR)/native/common/sun/awt \ # +ifeq ($(OPENJDK_TARGET_OS), aix) + LIBAWT_DIRS += $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS)/native/libawt +endif + ifeq ($(OPENJDK_TARGET_OS), windows) LIBAWT_DIRS += $(JDK_TOPDIR)/src/java.desktop/share/native/common/sun/awt/utility else LIBAWT_EXFILES := sun/java2d/ShaderList.c endif -ifneq ($(filter $(OPENJDK_TARGET_OS), solaris linux macosx), ) +ifneq ($(filter $(OPENJDK_TARGET_OS), solaris linux macosx aix), ) LIBAWT_EXFILES += awt_Font.c CUPSfuncs.c fontpath.c X11Color.c endif @@ -168,14 +169,11 @@ endif LIBAWT_CFLAGS += -I$(JDK_OUTPUTDIR)/gensrc_headers/java.desktop \ $(addprefix -I, $(shell find $(LIBAWT_DIRS) -type d)) \ - -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_API_DIR)/native/common/sun/awt \ $(LIBJAVA_HEADER_FLAGS) \ $(addprefix -I, $(BUILD_LIBMLIB_IMAGE_SRC)) \ # -LIBAWT_CFLAGS += -D__MEDIALIB_OLD_NAMES -D__USE_J2D_NAMES \ - $(X_CFLAGS) \ - $(foreach dir, $(LIBAWT_DIRS), -I$(dir)) +LIBAWT_CFLAGS += -D__MEDIALIB_OLD_NAMES -D__USE_J2D_NAMES $(X_CFLAGS) ifeq ($(OPENJDK_TARGET_OS), macosx) endif @@ -296,7 +294,7 @@ endif DESKTOP_LIBRARIES += $(BUILD_LIBAWT) -########################################################################################## +################################################################################ ifeq ($(findstring $(OPENJDK_TARGET_OS),windows macosx),) ifndef BUILD_HEADLESS_ONLY @@ -388,7 +386,7 @@ ifeq ($(findstring $(OPENJDK_TARGET_OS),windows macosx),) endif endif -########################################################################################## +################################################################################ LIBLCMS_SRC := $(JDK_TOPDIR)/src/java.desktop/share/native/liblcms LIBLCMS_CPPFLAGS += -I$(JDK_OUTPUTDIR)/gensrc_headers/java.desktop \ @@ -441,7 +439,7 @@ DESKTOP_LIBRARIES += $(BUILD_LIBLCMS) $(BUILD_LIBLCMS): $(BUILD_LIBAWT) -########################################################################################## +################################################################################ ifdef OPENJDK BUILD_LIBJAVAJPEG_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjpeg/mapfile-vers @@ -515,7 +513,7 @@ $(BUILD_LIBJAVAJPEG): $(BUILD_LIBJAVA) DESKTOP_LIBRARIES += $(BUILD_LIBJAVAJPEG) -########################################################################################## +################################################################################ LIBFONTMANAGER_SRC := $(JDK_TOPDIR)/src/java.desktop/share/native/libfontmanager \ $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_API_DIR)/native/libfontmanager @@ -607,54 +605,7 @@ endif DESKTOP_LIBRARIES += $(BUILD_LIBFONTMANAGER) -########################################################################################## - -ifndef OPENJDK - - LIBT2K_SRC := $(JDK_TOPDIR)/src/closed/java.desktop/share/native/libt2k - LIBT2K_CFLAGS := $(addprefix -I, $(LIBT2K_SRC)) \ - -I$(JDK_TOPDIR)/src/closed/java.desktop/share/native/libt2k/t2k \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/libfontmanager \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/sun/java2d \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/sun/java2d/loops \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/sun/font \ - -I$(JDK_TOPDIR)/src/java.base/share/native/libjava \ - -I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_API_DIR)/native/libjava \ - -I$(JDK_OUTPUTDIR)/gensrc_headers/java.desktop \ - # - - $(eval $(call SetupNativeCompilation,BUILD_LIBT2K, \ - LIBRARY := t2k, \ - OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ - SRC := $(LIBT2K_SRC), \ - EXCLUDE_FILES := t2k/orion.c, \ - LANG := C++, \ - OPTIMIZATION := HIGH, \ - CFLAGS := $(CFLAGS_JDKLIB) $(LIBT2K_CFLAGS), \ - CXXFLAGS := $(CXXFLAGS_JDKLIB) $(LIBT2K_CFLAGS), \ - CFLAGS_windows = -DCC_NOEX, \ - CXXFLAGS_windows = -DCC_NOEX, \ - MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libt2k/mapfile-vers, \ - LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \ - $(call SET_SHARED_LIBRARY_ORIGIN), \ - LDFLAGS_windows := user32.lib $(JDK_OUTPUTDIR)/objs/libfontmanager/fontmanager.lib, \ - LDFLAGS_SUFFIX_posix := $(LIBM) $(LIBCXX) -lfontmanager -ljava -ljvm -lc, \ - LDFLAGS_SUFFIX_solaris := -lawt -lawt_xawt, \ - VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \ - RC_FLAGS := $(RC_FLAGS) \ - -D "JDK_FNAME=t2k.dll" \ - -D "JDK_INTERNAL_NAME=t2k" \ - -D "JDK_FTYPE=0x2L", \ - OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libt2k, \ - DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES))) - - # t2k is linked against fontmanager - $(BUILD_LIBT2K): $(BUILD_LIBFONTMANAGER) - - DESKTOP_LIBRARIES += $(BUILD_LIBT2K) -endif - -########################################################################################## +################################################################################ ifeq ($(OPENJDK_TARGET_OS), windows) LIBJAWT_SRC := $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_API_DIR)/native/libjawt @@ -768,99 +719,7 @@ endif # OPENJDK_TARGET_OS DESKTOP_LIBRARIES += $(BUILD_LIBJAWT) -########################################################################################## - -ifndef OPENJDK - - LIBKCMS_SRC := $(JDK_TOPDIR)/src/closed/java.desktop/share/native/libkcms \ - $(JDK_TOPDIR)/src/closed/java.desktop/$(OPENJDK_TARGET_OS_API_DIR)/native/libkcms \ - # - LIBKCMS_CFLAGS += $(addprefix -I, $(LIBKCMS_SRC)) \ - -I$(JDK_TOPDIR)/src/java.base/share/native/libjava \ - -I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_API_DIR)/native/libjava \ - -I$(JDK_OUTPUTDIR)/gensrc_headers/java.desktop \ - # - LIBKCMS_VERSIONINFO_RESOURCE := $(JDK_TOPDIR)/src/closed/java.desktop/windows/native/libkcms/cmm.rc - - LIBKCMS_CFLAGS += $(CFLAGS_JDKLIB) - - ifeq ($(OPENJDK_TARGET_OS), solaris) - # This particular library uses a feature called PIC_CODE_SMALL (on solaris) - # implement it like this...since it's only used here - LIBKCMS_CFLAGS := $(patsubst -KPIC, -Kpic, $(LIBKCMS_CFLAGS)) - else ifeq ($(OPENJDK_TARGET_CPU_ARCH), ppc) - LIBKCMS_CFLAGS := $(patsubst -fPIC, -fpic, $(LIBKCMS_CFLAGS)) - endif - - $(eval $(call SetupNativeCompilation,BUILD_LIBKCMS, \ - LIBRARY := kcms, \ - OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ - SRC := $(LIBKCMS_SRC), \ - LANG := C, \ - EXCLUDE_FILES := $(BUILD_LIBKCMS_EXCLUDE_FILES), \ - OPTIMIZATION := LOW, \ - CFLAGS := $(LIBKCMS_CFLAGS) \ - -DJAVACMM -DFUT_CALC_EX -DNO_FUT_GCONST, \ - CFLAGS_linux := -Wno-missing-field-initializers, \ - MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libkcms/mapfile-vers, \ - LDFLAGS := $(LDFLAGS_JDKLIB) \ - $(call SET_SHARED_LIBRARY_ORIGIN), \ - LDFLAGS_SUFFIX_linux := -lc -lpthread, \ - LDFLAGS_SUFFIX_solaris := -lc, \ - LDFLAGS_SUFFIX_windows := $(WIN_JAVA_LIB) advapi32.lib user32.lib version.lib, \ - LDFLAGS_SUFFIX_posix := -lm -ljava -ljvm, \ - VERSIONINFO_RESOURCE := $(LIBKCMS_VERSIONINFO_RESOURCE), \ - RC_FLAGS := $(RC_FLAGS) \ - -D "JDK_FNAME=kcms.dll" \ - -D "JDK_INTERNAL_NAME=kcms" \ - -D "JDK_FTYPE=0x2L", \ - OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libkcms, \ - DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES))) - - $(BUILD_LIBKCMS): $(BUILD_LIBJAVA) - - DESKTOP_LIBRARIES += $(BUILD_LIBKCMS) - -endif - -########################################################################################## - -ifndef OPENJDK - ifeq ($(OPENJDK_TARGET_OS), solaris) - ifneq ($(OPENJDK_TARGET_CPU), x86_64) - - ifeq ($(shell if test "$(OS_VERSION_MAJOR)" -eq 5 -a "$(OS_VERSION_MINOR)" -le 10; then $(ECHO) ok; fi), ok) - - SUNWJDGA_MAPFILE := - ifeq ($(OPENJDK_TARGET_CPU_ARCH), sparc) - SUNWJDGA_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjdga/mapfile-vers - endif - - $(eval $(call SetupNativeCompilation,BUILD_LIBSUNWJDGA, \ - LIBRARY := sunwjdga, \ - OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ - SRC := $(JDK_TOPDIR)/src/java.desktop/unix/native/libsunwjdga, \ - LANG := C, \ - OPTIMIZATION := LOW, \ - CFLAGS := $(CFLAGS_JDKLIB) \ - -I$(JDK_TOPDIR)/src/share/javavm/export \ - -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/javavm/export \ - $(X_CFLAGS), \ - MAPFILE := $(SUNWJDGA_MAPFILE), \ - LDFLAGS := $(LDFLAGS_JDKLIB) \ - $(call SET_SHARED_LIBRARY_ORIGIN), \ - LDFLAGS_SUFFIX := $(X_LIBS) -ldga -lX11 $(LIBDL) -lc, \ - OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libsunwjdga, \ - DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES))) - - DESKTOP_LIBRARIES += $(BUILD_LIBSUNWJDGA) - - endif - endif - endif -endif - -########################################################################################## +################################################################################ ifeq ($(BUILD_HEADLESS), true) # Mac and Windows only use the native AWT lib, do not build libawt_headless @@ -932,7 +791,7 @@ ifeq ($(BUILD_HEADLESS), true) endif endif -########################################################################################## +################################################################################ ifndef BUILD_HEADLESS_ONLY @@ -973,7 +832,6 @@ ifndef BUILD_HEADLESS_ONLY # ifeq ($(OPENJDK_TARGET_OS), macosx) - LIBSPLASHSCREEN_CFLAGS += -F/System/Library/Frameworks/JavaVM.framework/Frameworks LIBSPLASHSCREEN_CFLAGS += -DWITH_MACOSX LIBSPLASHSCREEN_CFLAGS += -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libosxapp @@ -1042,47 +900,7 @@ ifndef BUILD_HEADLESS_ONLY endif -########################################################################################## - -ifndef OPENJDK - - LIBDCPR_SRC_DIRS := $(JDK_TOPDIR)/src/closed/java.desktop/share/native/libdcpr - LIBDCPR_CFLAGS := $(addprefix -I, $(shell $(FIND) $(LIBDCPR_SRC_DIRS) -type d)) \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/sun/java2d/pipe \ - -I$(JDK_TOPDIR)/src/java.base/share/native/libjava \ - -I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_API_DIR)/native/libjava \ - -I$(JDK_OUTPUTDIR)/gensrc_headers/java.desktop \ - # - - $(eval $(call SetupNativeCompilation,BUILD_LIBDCPR, \ - LIBRARY := dcpr, \ - OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ - SRC := $(LIBDCPR_SRC_DIRS), \ - LANG := C, \ - OPTIMIZATION := LOW, \ - CFLAGS := $(CFLAGS_JDKLIB) \ - $(LIBDCPR_CFLAGS), \ - MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libdcpr/mapfile-vers, \ - LDFLAGS := $(LDFLAGS_JDKLIB) \ - $(call SET_SHARED_LIBRARY_ORIGIN), \ - LDFLAGS_SUFFIX := $(LIBM) $(LDFLAGS_JDKLIB_SUFFIX), \ - LDFLAGS_SUFFIX_windows := $(WIN_JAVA_LIB), \ - LDFLAGS_SUFFIX_posix := -lm, \ - VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \ - RC_FLAGS := $(RC_FLAGS) \ - -D "JDK_FNAME=dcpr.dll" \ - -D "JDK_INTERNAL_NAME=dcpr" \ - -D "JDK_FTYPE=0x2L", \ - OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libdcpr, \ - DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES))) - - $(BUILD_LIBDCPR): $(BUILD_LIBJAVA) - - DESKTOP_LIBRARIES += $(BUILD_LIBDCPR) - -endif - -########################################################################################## +################################################################################ ifeq ($(OPENJDK_TARGET_OS), macosx) @@ -1159,7 +977,7 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) endif -########################################################################################## +################################################################################ ifeq ($(OPENJDK_TARGET_OS), macosx) @@ -1200,3 +1018,8 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) #$(BUILD_LIBOSXUI): $(BUILD_LIBJAVA) endif + +################################################################################ + +# Hook to include the corresponding custom file, if present. +$(eval $(call IncludeCustomExtension, jdk, lib/Awt2dLibraries.gmk)) diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk index 99a0c46f114..852879f09ee 100644 --- a/jdk/make/lib/CoreLibraries.gmk +++ b/jdk/make/lib/CoreLibraries.gmk @@ -26,6 +26,8 @@ WIN_VERIFY_LIB := $(JDK_OUTPUTDIR)/objs/libverify/verify.lib ########################################################################################## +# libfdlibm is statically linked with libjava below and not delivered into the +# product on its own. BUILD_LIBFDLIBM_OPTIMIZATION := HIGH diff --git a/jdk/make/lib/Lib-java.base.gmk b/jdk/make/lib/Lib-java.base.gmk index cf7f663d6fa..301e31c2df8 100644 --- a/jdk/make/lib/Lib-java.base.gmk +++ b/jdk/make/lib/Lib-java.base.gmk @@ -25,6 +25,10 @@ include LibCommon.gmk +# Prepare the find cache. +$(eval $(call FillCacheFind, $(wildcard $(JDK_TOPDIR)/src/java.base/*/native \ + $(JDK_TOPDIR)/src/*/java.base/*/native))) + include CoreLibraries.gmk include NetworkingLibraries.gmk include NioLibraries.gmk diff --git a/jdk/make/lib/Lib-java.desktop.gmk b/jdk/make/lib/Lib-java.desktop.gmk index bdd919cfeb7..e8661508e93 100644 --- a/jdk/make/lib/Lib-java.desktop.gmk +++ b/jdk/make/lib/Lib-java.desktop.gmk @@ -25,6 +25,10 @@ include LibCommon.gmk +# Prepare the find cache. +$(eval $(call FillCacheFind, $(wildcard $(JDK_TOPDIR)/src/java.desktop/*/native \ + $(JDK_TOPDIR)/src/*/java.desktop/*/native))) + include PlatformLibraries.gmk include Awt2dLibraries.gmk include SoundLibraries.gmk diff --git a/jdk/make/lib/Lib-jdk.attach.gmk b/jdk/make/lib/Lib-jdk.attach.gmk index 65b7b1397d7..2b58e173efb 100644 --- a/jdk/make/lib/Lib-jdk.attach.gmk +++ b/jdk/make/lib/Lib-jdk.attach.gmk @@ -27,33 +27,11 @@ include LibCommon.gmk ################################################################################ -ifeq ($(OPENJDK_TARGET_OS), aix) - LIBATTACH_OS_API_DIR := aix -else - LIBATTACH_OS_API_DIR := $(OPENJDK_TARGET_OS_API_DIR) -endif - -LIBATTACH_SRC := $(JDK_TOPDIR)/src/jdk.attach/$(LIBATTACH_OS_API_DIR)/native/libattach - -LIBATTACH_EXCLUDE_FILES := -ifneq ($(OPENJDK_TARGET_OS), solaris) - LIBATTACH_EXCLUDE_FILES += SolarisVirtualMachine.c -endif -ifneq ($(OPENJDK_TARGET_OS), linux) - LIBATTACH_EXCLUDE_FILES += LinuxVirtualMachine.c -endif -ifneq ($(OPENJDK_TARGET_OS), macosx) - LIBATTACH_EXCLUDE_FILES += BsdVirtualMachine.c -endif -ifneq ($(OPENJDK_TARGET_OS),aix) - LIBATTACH_EXCLUDE_FILES += AixVirtualMachine.c -endif $(eval $(call SetupNativeCompilation,BUILD_LIBATTACH, \ LIBRARY := attach, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ - SRC := $(LIBATTACH_SRC), \ - EXCLUDE_FILES := $(LIBATTACH_EXCLUDE_FILES), \ + SRC := $(JDK_TOPDIR)/src/jdk.attach/$(OPENJDK_TARGET_OS)/native/libattach, \ LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) \ diff --git a/jdk/make/lib/Lib-jdk.hprof.agent.gmk b/jdk/make/lib/Lib-jdk.hprof.agent.gmk index 7b7ef69b2e0..a58687da251 100644 --- a/jdk/make/lib/Lib-jdk.hprof.agent.gmk +++ b/jdk/make/lib/Lib-jdk.hprof.agent.gmk @@ -27,11 +27,11 @@ include LibCommon.gmk ################################################################################ -BUILD_LIBHPROF_SRC := $(JDK_TOPDIR)/src/demo/share/jvmti/hprof \ - $(JDK_TOPDIR)/src/demo/$(OPENJDK_TARGET_OS_API_DIR)/jvmti/hprof +BUILD_LIBHPROF_SRC := $(call FindSrcDirsForLib, jdk.hprof.agent, hprof) + BUILD_LIBHPROF_CFLAGS := $(addprefix -I, $(BUILD_LIBHPROF_SRC)) \ -I$(JDK_TOPDIR)/src/demo/share/jvmti/java_crw_demo - + BUILD_LIBHPROF_LDFLAGS := LIBHPROF_OPTIMIZATION := HIGHEST diff --git a/jdk/make/lib/LibCommon.gmk b/jdk/make/lib/LibCommon.gmk index 7fadd1c781f..885ba11c780 100644 --- a/jdk/make/lib/LibCommon.gmk +++ b/jdk/make/lib/LibCommon.gmk @@ -29,9 +29,6 @@ include $(SPEC) include MakeBase.gmk include NativeCompilation.gmk -# Prepare the find cache. -$(eval $(call FillCacheFind, $(wildcard $(JDK_TOPDIR)/src/*/*/native))) - # Build tools include Tools.gmk diff --git a/jdk/make/lib/NetworkingLibraries.gmk b/jdk/make/lib/NetworkingLibraries.gmk index e61f80be925..a0825b06ce2 100644 --- a/jdk/make/lib/NetworkingLibraries.gmk +++ b/jdk/make/lib/NetworkingLibraries.gmk @@ -44,7 +44,7 @@ ifneq ($(OPENJDK_TARGET_OS), macosx) endif ifeq ($(OPENJDK_TARGET_OS), aix) - LIBNET_SRC_DIRS += $(JDK_TOPDIR)/src/aix/native/java/net/ + LIBNET_SRC_DIRS += $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libnet/java/net/ endif $(eval $(call SetupNativeCompilation,BUILD_LIBNET, \ diff --git a/jdk/make/lib/NioLibraries.gmk b/jdk/make/lib/NioLibraries.gmk index 259517c2aad..722115fdee5 100644 --- a/jdk/make/lib/NioLibraries.gmk +++ b/jdk/make/lib/NioLibraries.gmk @@ -56,17 +56,8 @@ endif ifeq ($(OPENJDK_TARGET_OS), aix) BUILD_LIBNIO_MAPFILE:=$(JDK_TOPDIR)/make/mapfiles/libnio/mapfile-$(OPENJDK_TARGET_OS) - BUILD_LIBNIO_FILES += \ - AixPollPort.c \ - InheritedChannel.c \ - AixNativeThread.c \ - PollArrayWrapper.c \ - UnixAsynchronousServerSocketChannelImpl.c \ - UnixAsynchronousSocketChannelImpl.c \ - GnomeFileTypeDetector.c \ - UnixCopyFile.c \ - AixNativeDispatcher.c \ - UnixNativeDispatcher.c + BUILD_LIBNIO_EXFILES += \ + NativeThread.c endif $(eval $(call SetupNativeCompilation,BUILD_LIBNIO, \ diff --git a/jdk/make/mapfiles/libattach/mapfile-aix b/jdk/make/mapfiles/libattach/mapfile-aix index 4c02da01fce..10ca49534ba 100644 --- a/jdk/make/mapfiles/libattach/mapfile-aix +++ b/jdk/make/mapfiles/libattach/mapfile-aix @@ -27,13 +27,13 @@ SUNWprivate_1.1 { global: - Java_sun_tools_attach_AixVirtualMachine_socket - Java_sun_tools_attach_AixVirtualMachine_connect - Java_sun_tools_attach_AixVirtualMachine_sendQuitTo - Java_sun_tools_attach_AixVirtualMachine_checkPermissions - Java_sun_tools_attach_AixVirtualMachine_close - Java_sun_tools_attach_AixVirtualMachine_read - Java_sun_tools_attach_AixVirtualMachine_write + Java_sun_tools_attach_VirtualMachineImpl_socket + Java_sun_tools_attach_VirtualMachineImpl_connect + Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo + Java_sun_tools_attach_VirtualMachineImpl_checkPermissions + Java_sun_tools_attach_VirtualMachineImpl_close + Java_sun_tools_attach_VirtualMachineImpl_read + Java_sun_tools_attach_VirtualMachineImpl_write local: *; }; diff --git a/jdk/make/mapfiles/libattach/mapfile-linux b/jdk/make/mapfiles/libattach/mapfile-linux index fbfdedfdad9..b569ae5e637 100644 --- a/jdk/make/mapfiles/libattach/mapfile-linux +++ b/jdk/make/mapfiles/libattach/mapfile-linux @@ -27,17 +27,17 @@ SUNWprivate_1.1 { global: - Java_sun_tools_attach_LinuxVirtualMachine_checkPermissions; - Java_sun_tools_attach_LinuxVirtualMachine_close; - Java_sun_tools_attach_LinuxVirtualMachine_connect; - Java_sun_tools_attach_LinuxVirtualMachine_getLinuxThreadsManager; - Java_sun_tools_attach_LinuxVirtualMachine_isLinuxThreads; - Java_sun_tools_attach_LinuxVirtualMachine_open; - Java_sun_tools_attach_LinuxVirtualMachine_sendQuitTo; - Java_sun_tools_attach_LinuxVirtualMachine_sendQuitToChildrenOf; - Java_sun_tools_attach_LinuxVirtualMachine_socket; - Java_sun_tools_attach_LinuxVirtualMachine_read; - Java_sun_tools_attach_LinuxVirtualMachine_write; + Java_sun_tools_attach_VirtualMachineImpl_checkPermissions; + Java_sun_tools_attach_VirtualMachineImpl_close; + Java_sun_tools_attach_VirtualMachineImpl_connect; + Java_sun_tools_attach_VirtualMachineImpl_getLinuxThreadsManager; + Java_sun_tools_attach_VirtualMachineImpl_isLinuxThreads; + Java_sun_tools_attach_VirtualMachineImpl_open; + Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo; + Java_sun_tools_attach_VirtualMachineImpl_sendQuitToChildrenOf; + Java_sun_tools_attach_VirtualMachineImpl_socket; + Java_sun_tools_attach_VirtualMachineImpl_read; + Java_sun_tools_attach_VirtualMachineImpl_write; local: *; }; diff --git a/jdk/make/mapfiles/libattach/mapfile-solaris b/jdk/make/mapfiles/libattach/mapfile-solaris index 6e61f754b99..df71490fdb8 100644 --- a/jdk/make/mapfiles/libattach/mapfile-solaris +++ b/jdk/make/mapfiles/libattach/mapfile-solaris @@ -27,12 +27,12 @@ SUNWprivate_1.1 { global: - Java_sun_tools_attach_SolarisVirtualMachine_checkPermissions; - Java_sun_tools_attach_SolarisVirtualMachine_enqueue; - Java_sun_tools_attach_SolarisVirtualMachine_open; - Java_sun_tools_attach_SolarisVirtualMachine_close; - Java_sun_tools_attach_SolarisVirtualMachine_read; - Java_sun_tools_attach_SolarisVirtualMachine_sigquit; + Java_sun_tools_attach_VirtualMachineImpl_checkPermissions; + Java_sun_tools_attach_VirtualMachineImpl_enqueue; + Java_sun_tools_attach_VirtualMachineImpl_open; + Java_sun_tools_attach_VirtualMachineImpl_close; + Java_sun_tools_attach_VirtualMachineImpl_read; + Java_sun_tools_attach_VirtualMachineImpl_sigquit; local: *; }; diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index ca99cc5c03b..3b1d894ff71 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -78,13 +78,13 @@ SUNWprivate_1.1 { Java_java_io_FileInputStream_available; Java_java_io_FileInputStream_close0; Java_java_io_FileInputStream_initIDs; - Java_java_io_FileInputStream_open; + Java_java_io_FileInputStream_open0; Java_java_io_FileInputStream_read0; Java_java_io_FileInputStream_readBytes; Java_java_io_FileInputStream_skip; Java_java_io_FileOutputStream_close0; Java_java_io_FileOutputStream_initIDs; - Java_java_io_FileOutputStream_open; + Java_java_io_FileOutputStream_open0; Java_java_io_FileOutputStream_write; Java_java_io_FileOutputStream_writeBytes; Java_java_io_ObjectInputStream_bytesToDoubles; @@ -97,7 +97,7 @@ SUNWprivate_1.1 { Java_java_io_RandomAccessFile_getFilePointer; Java_java_io_RandomAccessFile_initIDs; Java_java_io_RandomAccessFile_length; - Java_java_io_RandomAccessFile_open; + Java_java_io_RandomAccessFile_open0; Java_java_io_RandomAccessFile_read0; Java_java_io_RandomAccessFile_readBytes; Java_java_io_RandomAccessFile_seek0; diff --git a/jdk/make/mapfiles/libjava/reorder-sparc b/jdk/make/mapfiles/libjava/reorder-sparc index 4a5cbf45018..d10037652d1 100644 --- a/jdk/make/mapfiles/libjava/reorder-sparc +++ b/jdk/make/mapfiles/libjava/reorder-sparc @@ -44,7 +44,7 @@ text: .text%Java_java_io_UnixFileSystem_initIDs; text: .text%Java_java_io_UnixFileSystem_canonicalize; text: .text%JNU_GetStringPlatformChars; text: .text%JNU_ReleaseStringPlatformChars; -text: .text%Java_java_io_FileInputStream_open; +text: .text%Java_java_io_FileInputStream_open0; text: .text%fileOpen; text: .text%Java_java_io_FileInputStream_readBytes; text: .text%readBytes; diff --git a/jdk/make/mapfiles/libjava/reorder-sparcv9 b/jdk/make/mapfiles/libjava/reorder-sparcv9 index 81cbfcb2410..2609711c21f 100644 --- a/jdk/make/mapfiles/libjava/reorder-sparcv9 +++ b/jdk/make/mapfiles/libjava/reorder-sparcv9 @@ -47,7 +47,7 @@ text: .text%Java_java_io_UnixFileSystem_initIDs; text: .text%Java_java_io_UnixFileSystem_canonicalize; text: .text%JNU_GetStringPlatformChars; text: .text%JNU_ReleaseStringPlatformChars; -text: .text%Java_java_io_FileInputStream_open; +text: .text%Java_java_io_FileInputStream_open0; text: .text%fileOpen; text: .text%Java_java_io_FileInputStream_readBytes; text: .text%readBytes; diff --git a/jdk/make/mapfiles/libjava/reorder-x86 b/jdk/make/mapfiles/libjava/reorder-x86 index 1c971b80eda..b8ea2d43dae 100644 --- a/jdk/make/mapfiles/libjava/reorder-x86 +++ b/jdk/make/mapfiles/libjava/reorder-x86 @@ -57,7 +57,7 @@ text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_load; text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_find; text: .text%Java_java_lang_Float_floatToIntBits; text: .text%Java_java_lang_Double_doubleToLongBits; -text: .text%Java_java_io_FileInputStream_open; +text: .text%Java_java_io_FileInputStream_open0; text: .text%fileOpen; text: .text%Java_java_io_UnixFileSystem_getLength; text: .text%Java_java_io_FileInputStream_readBytes; @@ -90,7 +90,7 @@ text: .text%JNU_NotifyAll; text: .text%JNU_CallMethodByName; text: .text%JNU_CallMethodByNameV; text: .text%Java_java_util_logging_FileHandler_lockFile; -text: .text%Java_java_io_FileOutputStream_open; +text: .text%Java_java_io_FileOutputStream_open0; text: .text%Java_java_io_UnixFileSystem_createDirectory; text: .text%Java_java_io_UnixFileSystem_getLastModifiedTime; text: .text%Java_java_util_prefs_FileSystemPreferences_lockFile0; diff --git a/jdk/make/mapfiles/libnio/mapfile-linux b/jdk/make/mapfiles/libnio/mapfile-linux index 16f72e43cfa..53555c4763f 100644 --- a/jdk/make/mapfiles/libnio/mapfile-linux +++ b/jdk/make/mapfiles/libnio/mapfile-linux @@ -79,6 +79,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_InheritedChannel_close0; Java_sun_nio_ch_InheritedChannel_dup; Java_sun_nio_ch_InheritedChannel_dup2; + Java_sun_nio_ch_InheritedChannel_initIDs; Java_sun_nio_ch_InheritedChannel_open0; Java_sun_nio_ch_InheritedChannel_peerAddress0; Java_sun_nio_ch_InheritedChannel_peerPort0; diff --git a/jdk/make/mapfiles/libnio/mapfile-macosx b/jdk/make/mapfiles/libnio/mapfile-macosx index 4dd0dc513e4..d4b6dc5a219 100644 --- a/jdk/make/mapfiles/libnio/mapfile-macosx +++ b/jdk/make/mapfiles/libnio/mapfile-macosx @@ -62,6 +62,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_InheritedChannel_close0; Java_sun_nio_ch_InheritedChannel_dup; Java_sun_nio_ch_InheritedChannel_dup2; + Java_sun_nio_ch_InheritedChannel_initIDs; Java_sun_nio_ch_InheritedChannel_open0; Java_sun_nio_ch_InheritedChannel_peerAddress0; Java_sun_nio_ch_InheritedChannel_peerPort0; diff --git a/jdk/make/mapfiles/libnio/mapfile-solaris b/jdk/make/mapfiles/libnio/mapfile-solaris index 3933cef7ada..cdbb851bcad 100644 --- a/jdk/make/mapfiles/libnio/mapfile-solaris +++ b/jdk/make/mapfiles/libnio/mapfile-solaris @@ -67,6 +67,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_InheritedChannel_close0; Java_sun_nio_ch_InheritedChannel_dup; Java_sun_nio_ch_InheritedChannel_dup2; + Java_sun_nio_ch_InheritedChannel_initIDs; Java_sun_nio_ch_InheritedChannel_open0; Java_sun_nio_ch_InheritedChannel_peerAddress0; Java_sun_nio_ch_InheritedChannel_peerPort0; diff --git a/jdk/make/profile-rtjar-includes.txt b/jdk/make/profile-rtjar-includes.txt index 1e954ad625c..8ab7336fb17 100644 --- a/jdk/make/profile-rtjar-includes.txt +++ b/jdk/make/profile-rtjar-includes.txt @@ -201,6 +201,7 @@ FULL_JRE_RTJAR_INCLUDE_PACKAGES := \ sun/audio \ sun/awt \ sun/corba \ + sun/datatransfer \ sun/dc \ sun/font \ sun/java2d \ diff --git a/jdk/make/src/classes/build/tools/addtorestrictedpkgs/AddToRestrictedPkgs.java b/jdk/make/src/classes/build/tools/addtorestrictedpkgs/AddToRestrictedPkgs.java deleted file mode 100644 index ee9deb4b75f..00000000000 --- a/jdk/make/src/classes/build/tools/addtorestrictedpkgs/AddToRestrictedPkgs.java +++ /dev/null @@ -1,105 +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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.addtorestrictedpkgs; - -import java.io.*; - -/** - * Adds additional packages to the package.access and package.definition - * security properties. - */ -public class AddToRestrictedPkgs { - - private static final String PKG_ACC = "package.access"; - private static final String PKG_DEF = "package.definition"; - private static final int PKG_ACC_INDENT = 15; - private static final int PKG_DEF_INDENT = 19; - - public static void main(String[] args) throws Exception { - - if (args.length < 3) { - System.err.println("Usage: java AddToRestrictedPkgs " + - "[input java.security file name] " + - "[output java.security file name] " + - "[packages ...]"); - System.exit(1); - } - - try (FileReader fr = new FileReader(args[0]); - BufferedReader br = new BufferedReader(fr); - FileWriter fw = new FileWriter(args[1]); - BufferedWriter bw = new BufferedWriter(fw)) - { - // parse the file line-by-line, looking for pkg access properties - String line = br.readLine(); - while (line != null) { - if (line.startsWith(PKG_ACC)) { - writePackages(br, bw, line, PKG_ACC_INDENT, args); - } else if (line.startsWith(PKG_DEF)) { - writePackages(br, bw, line, PKG_DEF_INDENT, args); - } else { - writeLine(bw, line); - } - line = br.readLine(); - } - bw.flush(); - } - } - - private static void writePackages(BufferedReader br, BufferedWriter bw, - String line, int numSpaces, - String[] args) throws IOException { - // parse property until EOL, not including line breaks - while (line.endsWith("\\")) { - writeLine(bw, line); - line = br.readLine(); - } - // append comma and line-break to last package - writeLine(bw, line + ",\\"); - // add new packages, one per line - for (int i = 2; i < args.length - 1; i++) { - indent(bw, numSpaces); - writeLine(bw, args[i] + ",\\"); - } - indent(bw, numSpaces); - writeLine(bw, args[args.length - 1]); - } - - private static void writeLine(BufferedWriter bw, String line) - throws IOException - { - bw.write(line); - bw.newLine(); - } - - private static void indent(BufferedWriter bw, int numSpaces) - throws IOException - { - for (int i = 0; i < numSpaces; i++) { - bw.append(' '); - } - } -} diff --git a/jdk/make/src/classes/build/tools/makejavasecurity/MakeJavaSecurity.java b/jdk/make/src/classes/build/tools/makejavasecurity/MakeJavaSecurity.java new file mode 100644 index 00000000000..d5c6e14c7b1 --- /dev/null +++ b/jdk/make/src/classes/build/tools/makejavasecurity/MakeJavaSecurity.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.makejavasecurity; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.*; + +/** + * Builds the java.security file, including + * + * 1. Adds additional packages to the package.access and + * package.definition security properties. + * 2. Filter out platform-unrelated parts + * + * In order to easily maintain platform-related entries, every item + * (including the last line) in package.access and package.definition + * MUST end with ',\'. A blank line MUST exist after the last line. + */ +public class MakeJavaSecurity { + + private static final String PKG_ACC = "package.access"; + private static final String PKG_DEF = "package.definition"; + private static final int PKG_ACC_INDENT = 15; + private static final int PKG_DEF_INDENT = 19; + + public static void main(String[] args) throws Exception { + + if (args.length < 3) { + System.err.println("Usage: java MakeJavaSecurity " + + "[input java.security file name] " + + "[output java.security file name] " + + "[openjdk target os] " + + "[more restricted packages file name?]"); + System.exit(1); + } + + // more restricted packages + List extraLines; + if (args.length == 4) { + extraLines = Files.readAllLines(Paths.get(args[3])); + } else { + extraLines = Collections.emptyList(); + } + + List lines = new ArrayList<>(); + + // read raw java.security and add more restricted packages + try (FileReader fr = new FileReader(args[0]); + BufferedReader br = new BufferedReader(fr)) { + // looking for pkg access properties + String line = br.readLine(); + while (line != null) { + if (line.startsWith(PKG_ACC)) { + addPackages(br, lines, line, PKG_ACC_INDENT, extraLines); + } else if (line.startsWith(PKG_DEF)) { + addPackages(br, lines, line, PKG_DEF_INDENT, extraLines); + } else { + lines.add(line); + } + line = br.readLine(); + } + } + + // Filter out platform-unrelated ones. We only support + // #ifdef, #ifndef, and #endif. + int mode = 0; // 0: out of block, 1: in match, 2: in non-match + Iterator iter = lines.iterator(); + while (iter.hasNext()) { + String line = iter.next(); + if (line.startsWith("#endif")) { + mode = 0; + iter.remove(); + } else if (line.startsWith("#ifdef ")) { + mode = line.endsWith(args[2])?1:2; + iter.remove(); + } else if (line.startsWith("#ifndef ")) { + mode = line.endsWith(args[2])?2:1; + iter.remove(); + } else { + if (mode == 2) iter.remove(); + } + } + + // Update .tbd to .1, .2, etc. + Map count = new HashMap<>(); + for (int i=0; i= 0) { + String prefix = line.substring(0, index); + int n = count.getOrDefault(prefix, 1); + count.put(prefix, n+1); + lines.set(i, prefix + "." + n + line.substring(index+4)); + } + } + + // Clean up the last line of PKG_ACC and PKG_DEF blocks. + // Not really necessary since a blank line follows. + boolean inBlock = false; + for (int i=0; i lines, + String line, int numSpaces, + List args) throws IOException { + // parse property until EOL, not including line breaks + boolean first = true; + while (!line.isEmpty()) { + if (!line.startsWith("#")) { + if (!line.endsWith(",\\") || + (!first && line.contains("="))) { + throw new IOException("Invalid line: " + line); + } + } + lines.add(line); + line = br.readLine(); + first = false; + } + // add new packages, one per line + for (String arg: args) { + if (arg.startsWith("#")) { + lines.add(arg); + } else { + lines.add(String.format("%"+numSpaces+"s", "") + arg + ",\\"); + } + } + lines.add(line); + } +} diff --git a/jdk/make/src/classes/build/tools/module/GenerateModulesXml.java b/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java similarity index 90% rename from jdk/make/src/classes/build/tools/module/GenerateModulesXml.java rename to jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java index c2fdf4ae9d1..43ba458f326 100644 --- a/jdk/make/src/classes/build/tools/module/GenerateModulesXml.java +++ b/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java @@ -25,6 +25,7 @@ package build.tools.module; +import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -49,47 +50,56 @@ import javax.xml.stream.events.Attribute; import javax.xml.stream.events.XMLEvent; /** - * This tool is used to generate com/sun/tools/jdeps/resources/modules.xml - * for jdeps to analyze dependencies and enforce module boundaries. + * GenJdepsModulesXml augments the input modules.xml file(s) + * to include the module membership from the given path to + * the JDK exploded image. The output file is used by jdeps + * to analyze dependencies and enforce module boundaries. * - * $ java build.tools.module.GenerateModulesXml \ - * com/sun/tools/jdeps/resources/modules.xml $OUTPUTDIR/modules + * The input modules.xml file defines the modular structure of + * the JDK as described in JEP 200: The Modular JDK + * (http://openjdk.java.net/jeps/200). * - * This will generate modules.xml as jdeps resources that extend - * the metadata to include module membership (jdeps needs the - * membership information to determine which module a type belongs to.) + * $ java build.tools.module.GenJdepsModulesXml \ + * -o com/sun/tools/jdeps/resources/modules.xml \ + * -mp $OUTPUTDIR/modules \ + * top/modules.xml */ -public final class GenerateModulesXml { +public final class GenJdepsModulesXml { private final static String USAGE = - "Usage: GenerateModulesXml build/modules"; + "Usage: GenJdepsModulesXml -o -mp build/modules path-to-modules-xml"; public static void main(String[] args) throws Exception { - if (args.length < 2) { + Path outfile = null; + Path modulepath = null; + int i = 0; + while (i < args.length) { + String arg = args[i]; + if (arg.equals("-o")) { + outfile = Paths.get(args[i+1]); + i = i+2; + } else if (arg.equals("-mp")) { + modulepath = Paths.get(args[i+1]); + i = i+2; + if (!Files.isDirectory(modulepath)) { + System.err.println(modulepath + " is not a directory"); + System.exit(1); + } + } else { + break; + } + } + if (outfile == null || modulepath == null || i >= args.length) { System.err.println(USAGE); System.exit(-1); } - Path outfile = Paths.get(args[0]); - Path modulepath = Paths.get(args[1]); - - if (!Files.isDirectory(modulepath)) { - System.err.println(modulepath + " is not a directory"); - System.exit(1); - } - GenerateModulesXml gentool = - new GenerateModulesXml(modulepath); - Set modules; - try (InputStream in = GenerateModulesXml.class.getResourceAsStream("modules.xml")) { - modules = gentool.load(in); - } - - InputStream in = GenerateModulesXml.class.getResourceAsStream("closed/modules.xml"); - if (in != null) { - try { + GenJdepsModulesXml gentool = new GenJdepsModulesXml(modulepath); + Set modules = new HashSet<>(); + for (; i < args.length; i++) { + Path p = Paths.get(args[i]); + try (InputStream in = new BufferedInputStream(Files.newInputStream(p))) { Set mods = gentool.load(in); modules.addAll(mods); - } finally { - in.close(); } } @@ -98,7 +108,7 @@ public final class GenerateModulesXml { } final Path modulepath; - public GenerateModulesXml(Path modulepath) { + public GenJdepsModulesXml(Path modulepath) { this.modulepath = modulepath; } @@ -275,7 +285,7 @@ public final class GenerateModulesXml { m.exports().keySet().stream() .filter(pn -> m.exports().get(pn).isEmpty()) .sorted() - .forEach(pn -> GenerateModulesXml.this.writeExportElement(xtw, pn, depth+1)); + .forEach(pn -> writeExportElement(xtw, pn, depth+1)); m.exports().entrySet().stream() .filter(e -> !e.getValue().isEmpty()) .sorted(Map.Entry.comparingByKey()) diff --git a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources.properties b/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources.properties deleted file mode 100644 index 1bbea03ee06..00000000000 --- a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources.properties +++ /dev/null @@ -1 +0,0 @@ -string=This is Java 2D! (Default) diff --git a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_de.properties b/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_de.properties deleted file mode 100644 index d38794cd911..00000000000 --- a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_de.properties +++ /dev/null @@ -1 +0,0 @@ -string=This is Java 2D! (German) \u00f6 \u00df \u00dc diff --git a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_en.properties b/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_en.properties deleted file mode 100644 index efff7d0b1bb..00000000000 --- a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_en.properties +++ /dev/null @@ -1 +0,0 @@ -string=This is Java 2D! (English) A B C diff --git a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_en_GB.properties b/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_en_GB.properties deleted file mode 100644 index be4261d5195..00000000000 --- a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_en_GB.properties +++ /dev/null @@ -1 +0,0 @@ -string=This is Java 2D! (English in Great Britain) \u0075 \u006b Z diff --git a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_ja.properties b/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_ja.properties deleted file mode 100644 index f5cb9d735a0..00000000000 --- a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_ja.properties +++ /dev/null @@ -1 +0,0 @@ -string=Java 2D\u3067\u3059\u3002(\u30C7\u30D5\u30A9\u30EB\u30C8) diff --git a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_ko.properties b/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_ko.properties deleted file mode 100644 index 819d2c3cc60..00000000000 --- a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_ko.properties +++ /dev/null @@ -1 +0,0 @@ -string=This is Java 2D! (Korean) diff --git a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_zh_CN.properties b/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_zh_CN.properties deleted file mode 100644 index 7f7fa0d51d1..00000000000 --- a/jdk/src/demo/share/jfc/Font2DTest/resources/TextResources_zh_CN.properties +++ /dev/null @@ -1 +0,0 @@ -string=\u8FD9\u662F Java 2D! (\u9ED8\u8BA4\u503C) diff --git a/jdk/src/demo/share/jfc/Font2DTest/resources/resource.data b/jdk/src/demo/share/jfc/Font2DTest/resources/resource.data deleted file mode 100644 index f18b78e4cde..00000000000 --- a/jdk/src/demo/share/jfc/Font2DTest/resources/resource.data +++ /dev/null @@ -1,5 +0,0 @@ -en US -en GB -ko KO -ab KO -de DE diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/README b/jdk/src/demo/share/jpda/com/sun/tools/example/README deleted file mode 100644 index 13e1540f14c..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/README +++ /dev/null @@ -1,3 +0,0 @@ -Please refer to the documentation in: - - doc/index.html diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/AccessWatchpointSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/AccessWatchpointSpec.java deleted file mode 100644 index 0d9fe21a7d3..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/AccessWatchpointSpec.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; - -public class AccessWatchpointSpec extends WatchpointSpec { - - AccessWatchpointSpec(EventRequestSpecList specs, - ReferenceTypeSpec refSpec, String fieldId) { - super(specs, refSpec, fieldId); - } - - /** - * The 'refType' is known to match. - */ - @Override - void resolve(ReferenceType refType) throws InvalidTypeException, - NoSuchFieldException { - if (!(refType instanceof ClassType)) { - throw new InvalidTypeException(); - } - Field field = refType.fieldByName(fieldId); - if (field == null) { - throw new NoSuchFieldException(fieldId); - } - setRequest(refType.virtualMachine().eventRequestManager() - .createAccessWatchpointRequest(field)); - } - - @Override - public boolean equals(Object obj) { - return (obj instanceof AccessWatchpointSpec) && super.equals(obj); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/BreakpointSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/BreakpointSpec.java deleted file mode 100644 index 50059c1ff49..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/BreakpointSpec.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public abstract class BreakpointSpec extends EventRequestSpec { - - BreakpointSpec(EventRequestSpecList specs, ReferenceTypeSpec refSpec) { - super(specs, refSpec); - } - - @Override - void notifySet(SpecListener listener, SpecEvent evt) { - listener.breakpointSet(evt); - } - - @Override - void notifyDeferred(SpecListener listener, SpecEvent evt) { - listener.breakpointDeferred(evt); - } - - @Override - void notifyResolved(SpecListener listener, SpecEvent evt) { - listener.breakpointResolved(evt); - } - - @Override - void notifyDeleted(SpecListener listener, SpecEvent evt) { - listener.breakpointDeleted(evt); - } - - @Override - void notifyError(SpecListener listener, SpecErrorEvent evt) { - listener.breakpointError(evt); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ChildSession.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ChildSession.java deleted file mode 100644 index b6042a6e845..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ChildSession.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; -import com.sun.jdi.connect.LaunchingConnector; -import com.sun.jdi.connect.Connector; -import com.sun.jdi.connect.VMStartException; -import com.sun.jdi.connect.IllegalConnectorArgumentsException; -import java.io.*; -import java.util.Map; -import javax.swing.SwingUtilities; - - -class ChildSession extends Session { - - private Process process; - - private PrintWriter in; - private BufferedReader out; - private BufferedReader err; - - private InputListener input; - private OutputListener output; - private OutputListener error; - - public ChildSession(ExecutionManager runtime, - String userVMArgs, String cmdLine, - InputListener input, - OutputListener output, - OutputListener error, - OutputListener diagnostics) { - this(runtime, getVM(diagnostics, userVMArgs, cmdLine), - input, output, error, diagnostics); - } - - public ChildSession(ExecutionManager runtime, - LaunchingConnector connector, - Map arguments, - InputListener input, - OutputListener output, - OutputListener error, - OutputListener diagnostics) { - this(runtime, generalGetVM(diagnostics, connector, arguments), - input, output, error, diagnostics); - } - - private ChildSession(ExecutionManager runtime, - VirtualMachine vm, - InputListener input, - OutputListener output, - OutputListener error, - OutputListener diagnostics) { - super(vm, runtime, diagnostics); - this.input = input; - this.output = output; - this.error = error; - } - - @Override - public boolean attach() { - - if (!connectToVMProcess()) { - diagnostics.putString("Could not launch VM"); - return false; - } - - /* - * Create a Thread that will retrieve and display any output. - * Needs to be high priority, else debugger may exit before - * it can be displayed. - */ - - //### Rename InputWriter and OutputReader classes - //### Thread priorities cribbed from ttydebug. Think about them. - - OutputReader outputReader = - new OutputReader("output reader", "output", - out, output, diagnostics); - outputReader.setPriority(Thread.MAX_PRIORITY-1); - outputReader.start(); - - OutputReader errorReader = - new OutputReader("error reader", "error", - err, error, diagnostics); - errorReader.setPriority(Thread.MAX_PRIORITY-1); - errorReader.start(); - - InputWriter inputWriter = - new InputWriter("input writer", in, input); - inputWriter.setPriority(Thread.MAX_PRIORITY-1); - inputWriter.start(); - - if (!super.attach()) { - if (process != null) { - process.destroy(); - process = null; - } - return false; - } - - //### debug - //System.out.println("IO after attach: "+ inputWriter + " " + outputReader + " "+ errorReader); - - return true; - } - - @Override - public void detach() { - - //### debug - //System.out.println("IO before detach: "+ inputWriter + " " + outputReader + " "+ errorReader); - - super.detach(); - - /* - inputWriter.quit(); - outputReader.quit(); - errorReader.quit(); - */ - - if (process != null) { - process.destroy(); - process = null; - } - - } - - /** - * Launch child java interpreter, return host:port - */ - - static private void dumpStream(OutputListener diagnostics, - InputStream stream) throws IOException { - BufferedReader in = - new BufferedReader(new InputStreamReader(stream)); - String line; - while ((line = in.readLine()) != null) { - diagnostics.putString(line); - } - } - - static private void dumpFailedLaunchInfo(OutputListener diagnostics, - Process process) { - try { - dumpStream(diagnostics, process.getErrorStream()); - dumpStream(diagnostics, process.getInputStream()); - } catch (IOException e) { - diagnostics.putString("Unable to display process output: " + - e.getMessage()); - } - } - - static private VirtualMachine getVM(OutputListener diagnostics, - String userVMArgs, - String cmdLine) { - VirtualMachineManager manager = Bootstrap.virtualMachineManager(); - LaunchingConnector connector = manager.defaultConnector(); - Map arguments = connector.defaultArguments(); - arguments.get("options").setValue(userVMArgs); - arguments.get("main").setValue(cmdLine); - return generalGetVM(diagnostics, connector, arguments); - } - - static private VirtualMachine generalGetVM(OutputListener diagnostics, - LaunchingConnector connector, - Map arguments) { - VirtualMachine vm = null; - try { - diagnostics.putString("Starting child."); - vm = connector.launch(arguments); - } catch (IOException ioe) { - diagnostics.putString("Unable to start child: " + ioe.getMessage()); - } catch (IllegalConnectorArgumentsException icae) { - diagnostics.putString("Unable to start child: " + icae.getMessage()); - } catch (VMStartException vmse) { - diagnostics.putString("Unable to start child: " + vmse.getMessage() + '\n'); - dumpFailedLaunchInfo(diagnostics, vmse.process()); - } - return vm; - } - - private boolean connectToVMProcess() { - if (vm == null) { - return false; - } - process = vm.process(); - in = new PrintWriter(new OutputStreamWriter(process.getOutputStream())); - //### Note small buffer sizes! - out = new BufferedReader(new InputStreamReader(process.getInputStream()), 1); - err = new BufferedReader(new InputStreamReader(process.getErrorStream()), 1); - return true; - } - - /** - * Threads to handle application input/output. - */ - - private static class OutputReader extends Thread { - - private String streamName; - private BufferedReader stream; - private OutputListener output; - private OutputListener diagnostics; - private boolean running = true; - private char[] buffer = new char[512]; - - OutputReader(String threadName, - String streamName, - BufferedReader stream, - OutputListener output, - OutputListener diagnostics) { - super(threadName); - this.streamName = streamName; - this.stream = stream; - this.output = output; - this.diagnostics = diagnostics; - } - - @Override - public void run() { - try { - int count; - while (running && (count = stream.read(buffer, 0, 512)) != -1) { - if (count > 0) { - // Run in Swing event dispatcher thread. - final String chars = new String(buffer, 0, count); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - output.putString(chars); - } - }); - } - //### Should we sleep briefly here? - } - } catch (IOException e) { - // Run in Swing event dispatcher thread. - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - diagnostics.putString("IO error reading " + - streamName + - " stream of child java interpreter"); - } - }); - } - } - } - - private static class InputWriter extends Thread { - - private PrintWriter stream; - private InputListener input; - private boolean running = true; - - InputWriter(String threadName, - PrintWriter stream, - InputListener input) { - super(threadName); - this.stream = stream; - this.input = input; - } - - @Override - public void run() { - String line; - while (running) { - line = input.getLine(); - stream.println(line); - // Should not be needed for println above! - stream.flush(); - } - } - } - -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/EvaluationException.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/EvaluationException.java deleted file mode 100644 index b9a02c37117..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/EvaluationException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public class EvaluationException extends Exception { - - private static final long serialVersionUID = 4947109680354951694L; -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/EventRequestSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/EventRequestSpec.java deleted file mode 100644 index 0ea58fb3ebd..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/EventRequestSpec.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; -import com.sun.jdi.request.EventRequest; - -abstract public class EventRequestSpec { - - static final int STATUS_UNRESOLVED = 1; - static final int STATUS_RESOLVED = 2; - static final int STATUS_ERROR = 3; - - static final Object specPropertyKey = "spec"; - - final EventRequestSpecList specs; - final ReferenceTypeSpec refSpec; - EventRequest request = null; - - int status = STATUS_UNRESOLVED; - - EventRequestSpec(EventRequestSpecList specs, ReferenceTypeSpec refSpec) { - this.specs = specs; - this.refSpec = refSpec; - } - - void setRequest(EventRequest request) { - this.request = request; - request.putProperty(specPropertyKey, this); - request.enable(); - } - - /** - * The 'refType' is known to match. - */ - abstract void resolve(ReferenceType refType) throws Exception; - - abstract void notifySet(SpecListener listener, SpecEvent evt); - abstract void notifyDeferred(SpecListener listener, SpecEvent evt); - abstract void notifyResolved(SpecListener listener, SpecEvent evt); - abstract void notifyDeleted(SpecListener listener, SpecEvent evt); - abstract void notifyError(SpecListener listener, SpecErrorEvent evt); - - /** - * The 'refType' is known to match. - */ - void resolveNotify(ReferenceType refType) { - try { - resolve(refType); - status = STATUS_RESOLVED; - specs.notifyResolved(this); - } catch(Exception exc) { - status = STATUS_ERROR; - specs.notifyError(this, exc); - } - } - - /** - * See if 'refType' matches and resolve. - */ - void attemptResolve(ReferenceType refType) { - if (!isResolved() && refSpec.matches(refType)) { - resolveNotify(refType); - } - } - - void attemptImmediateResolve(VirtualMachine vm) { - // try to resolve immediately - for (ReferenceType refType : vm.allClasses()) { - if (refSpec.matches(refType)) { - try { - resolve(refType); - status = STATUS_RESOLVED; - specs.notifySet(this); - } catch(Exception exc) { - status = STATUS_ERROR; - specs.notifyError(this, exc); - } - return; - } - } - specs.notifyDeferred(this); - } - - public EventRequest getEventRequest() { - return request; - } - - /** - * @return true if this spec has been resolved. - */ - public boolean isResolved() { - return status == STATUS_RESOLVED; - } - - /** - * @return true if this spec has not yet been resolved. - */ - public boolean isUnresolved() { - return status == STATUS_UNRESOLVED; - } - - /** - * @return true if this spec is unresolvable due to error. - */ - public boolean isErroneous() { - return status == STATUS_ERROR; - } - - public String getStatusString() { - switch (status) { - case STATUS_RESOLVED: - return "resolved"; - case STATUS_UNRESOLVED: - return "deferred"; - case STATUS_ERROR: - return "erroneous"; - } - return "unknown"; - } - - boolean isJavaIdentifier(String s) { - return Utils.isJavaIdentifier(s); - } - - public String errorMessageFor(Exception e) { - if (e instanceof IllegalArgumentException) { - return ("Invalid command syntax"); - } else if (e instanceof RuntimeException) { - // A runtime exception that we were not expecting - throw (RuntimeException)e; - } else { - return ("Internal error; unable to set" + this); - } - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/EventRequestSpecList.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/EventRequestSpecList.java deleted file mode 100644 index 17c001483c7..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/EventRequestSpecList.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; -import com.sun.jdi.request.*; - -import java.util.*; - -class EventRequestSpecList { - - // all specs - private List eventRequestSpecs = Collections.synchronizedList( - new ArrayList()); - - final ExecutionManager runtime; - - EventRequestSpecList(ExecutionManager runtime) { - this.runtime = runtime; - } - - /** - * Resolve all deferred eventRequests waiting for 'refType'. - */ - void resolve(ReferenceType refType) { - synchronized(eventRequestSpecs) { - for (EventRequestSpec spec : eventRequestSpecs) { - spec.attemptResolve(refType); - } - } - } - - void install(EventRequestSpec ers, VirtualMachine vm) { - synchronized (eventRequestSpecs) { - eventRequestSpecs.add(ers); - } - if (vm != null) { - ers.attemptImmediateResolve(vm); - } - } - - BreakpointSpec - createClassLineBreakpoint(String classPattern, int line) { - ReferenceTypeSpec refSpec = - new PatternReferenceTypeSpec(classPattern); - return new LineBreakpointSpec(this, refSpec, line); - } - - BreakpointSpec - createSourceLineBreakpoint(String sourceName, int line) { - ReferenceTypeSpec refSpec = - new SourceNameReferenceTypeSpec(sourceName, line); - return new LineBreakpointSpec(this, refSpec, line); - } - - BreakpointSpec - createMethodBreakpoint(String classPattern, - String methodId, List methodArgs) { - ReferenceTypeSpec refSpec = - new PatternReferenceTypeSpec(classPattern); - return new MethodBreakpointSpec(this, refSpec, - methodId, methodArgs); - } - - ExceptionSpec - createExceptionIntercept(String classPattern, - boolean notifyCaught, - boolean notifyUncaught) { - ReferenceTypeSpec refSpec = - new PatternReferenceTypeSpec(classPattern); - return new ExceptionSpec(this, refSpec, - notifyCaught, notifyUncaught); - } - - AccessWatchpointSpec - createAccessWatchpoint(String classPattern, String fieldId) { - ReferenceTypeSpec refSpec = - new PatternReferenceTypeSpec(classPattern); - return new AccessWatchpointSpec(this, refSpec, fieldId); - } - - ModificationWatchpointSpec - createModificationWatchpoint(String classPattern, String fieldId) { - ReferenceTypeSpec refSpec = - new PatternReferenceTypeSpec(classPattern); - return new ModificationWatchpointSpec(this, refSpec, fieldId); - } - - void delete(EventRequestSpec ers) { - EventRequest request = ers.getEventRequest(); - synchronized (eventRequestSpecs) { - eventRequestSpecs.remove(ers); - } - if (request != null) { - request.virtualMachine().eventRequestManager() - .deleteEventRequest(request); - } - notifyDeleted(ers); - //### notify delete - here? - } - - List eventRequestSpecs() { - // We need to make a copy to avoid synchronization problems - synchronized (eventRequestSpecs) { - return new ArrayList(eventRequestSpecs); - } - } - - // -------- notify routines -------------------- - - @SuppressWarnings("unchecked") - private Vector specListeners() { - return (Vector)runtime.specListeners.clone(); - } - - void notifySet(EventRequestSpec spec) { - Vector l = specListeners(); - SpecEvent evt = new SpecEvent(spec); - for (int i = 0; i < l.size(); i++) { - spec.notifySet(l.elementAt(i), evt); - } - } - - void notifyDeferred(EventRequestSpec spec) { - Vector l = specListeners(); - SpecEvent evt = new SpecEvent(spec); - for (int i = 0; i < l.size(); i++) { - spec.notifyDeferred(l.elementAt(i), evt); - } - } - - void notifyDeleted(EventRequestSpec spec) { - Vector l = specListeners(); - SpecEvent evt = new SpecEvent(spec); - for (int i = 0; i < l.size(); i++) { - spec.notifyDeleted(l.elementAt(i), evt); - } - } - - void notifyResolved(EventRequestSpec spec) { - Vector l = specListeners(); - SpecEvent evt = new SpecEvent(spec); - for (int i = 0; i < l.size(); i++) { - spec.notifyResolved(l.elementAt(i), evt); - } - } - - void notifyError(EventRequestSpec spec, Exception exc) { - Vector l = specListeners(); - SpecErrorEvent evt = new SpecErrorEvent(spec, exc); - for (int i = 0; i < l.size(); i++) { - spec.notifyError(l.elementAt(i), evt); - } - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ExceptionSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ExceptionSpec.java deleted file mode 100644 index df87688152c..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ExceptionSpec.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.ReferenceType; - -public class ExceptionSpec extends EventRequestSpec { - - boolean notifyCaught; - boolean notifyUncaught; - - ExceptionSpec(EventRequestSpecList specs, ReferenceTypeSpec refSpec, - boolean notifyCaught, boolean notifyUncaught) - { - super(specs, refSpec); - this.notifyCaught = notifyCaught; - this.notifyUncaught = notifyUncaught; - } - - @Override - void notifySet(SpecListener listener, SpecEvent evt) { - listener.exceptionInterceptSet(evt); - } - - @Override - void notifyDeferred(SpecListener listener, SpecEvent evt) { - listener.exceptionInterceptDeferred(evt); - } - - @Override - void notifyResolved(SpecListener listener, SpecEvent evt) { - listener.exceptionInterceptResolved(evt); - } - - @Override - void notifyDeleted(SpecListener listener, SpecEvent evt) { - listener.exceptionInterceptDeleted(evt); - } - - @Override - void notifyError(SpecListener listener, SpecErrorEvent evt) { - listener.exceptionInterceptError(evt); - } - - /** - * The 'refType' is known to match. - */ - @Override - void resolve(ReferenceType refType) { - setRequest(refType.virtualMachine().eventRequestManager() - .createExceptionRequest(refType, - notifyCaught, notifyUncaught)); - } - - @Override - public int hashCode() { - return refSpec.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ExceptionSpec) { - ExceptionSpec es = (ExceptionSpec)obj; - - return refSpec.equals(es.refSpec); - } else { - return false; - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("exception catch "); - sb.append(refSpec.toString()); - return sb.toString(); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ExecutionManager.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ExecutionManager.java deleted file mode 100644 index b5bc053a3c3..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ExecutionManager.java +++ /dev/null @@ -1,824 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; -import com.sun.jdi.request.*; -import com.sun.jdi.connect.*; -import com.sun.tools.example.debug.expr.ExpressionParser; -import com.sun.tools.example.debug.expr.ParseException; - -import java.io.*; -import java.util.*; - -import com.sun.tools.example.debug.event.*; - -import javax.swing.SwingUtilities; - -/** - * Move this towards being only state and functionality - * that spans across Sessions (and thus VMs). - */ -public class ExecutionManager { - - private Session session; - - /** - * Get/set JDI trace mode. - */ - int traceMode = VirtualMachine.TRACE_NONE; - - ////////////////// Listener registration ////////////////// - - // Session Listeners - - ArrayList sessionListeners = new ArrayList(); - - public void addSessionListener(SessionListener listener) { - sessionListeners.add(listener); - } - - public void removeSessionListener(SessionListener listener) { - sessionListeners.remove(listener); - } - - // Spec Listeners - - ArrayList specListeners = new ArrayList(); - - public void addSpecListener(SpecListener cl) { - specListeners.add(cl); - } - - public void removeSpecListener(SpecListener cl) { - specListeners.remove(cl); - } - - // JDI Listeners - - ArrayList jdiListeners = new ArrayList(); - - /** - * Adds a JDIListener - */ - public void addJDIListener(JDIListener jl) { - jdiListeners.add(jl); - } - - /** - * Adds a JDIListener - at the specified position - */ - public void addJDIListener(int index, JDIListener jl) { - jdiListeners.add(index, jl); - } - - /** - * Removes a JDIListener - */ - public void removeJDIListener(JDIListener jl) { - jdiListeners.remove(jl); - } - - // App Echo Listeners - - private ArrayList appEchoListeners = new ArrayList(); - - public void addApplicationEchoListener(OutputListener l) { - appEchoListeners.add(l); - } - - public void removeApplicationEchoListener(OutputListener l) { - appEchoListeners.remove(l); - } - - // App Output Listeners - - private ArrayList appOutputListeners = new ArrayList(); - - public void addApplicationOutputListener(OutputListener l) { - appOutputListeners.add(l); - } - - public void removeApplicationOutputListener(OutputListener l) { - appOutputListeners.remove(l); - } - - // App Error Listeners - - private ArrayList appErrorListeners = new ArrayList(); - - public void addApplicationErrorListener(OutputListener l) { - appErrorListeners.add(l); - } - - public void removeApplicationErrorListener(OutputListener l) { - appErrorListeners.remove(l); - } - - // Diagnostic Listeners - - private ArrayList diagnosticsListeners = new ArrayList(); - - public void addDiagnosticsListener(OutputListener l) { - diagnosticsListeners.add(l); - } - - public void removeDiagnosticsListener(OutputListener l) { - diagnosticsListeners.remove(l); - } - - /////////// End Listener Registration ////////////// - - //### We probably don't want this public - public VirtualMachine vm() { - return session == null ? null : session.vm; - } - - void ensureActiveSession() throws NoSessionException { - if (session == null) { - throw new NoSessionException(); - } - } - - public EventRequestManager eventRequestManager() { - return vm() == null ? null : vm().eventRequestManager(); - } - - /** - * Get JDI trace mode. - */ - public int getTraceMode(int mode) { - return traceMode; - } - - /** - * Set JDI trace mode. - */ - public void setTraceMode(int mode) { - traceMode = mode; - if (session != null) { - session.setTraceMode(mode); - } - } - - /** - * Determine if VM is interrupted, i.e, present and not running. - */ - public boolean isInterrupted() /* should: throws NoSessionException */ { -// ensureActiveSession(); - return session.interrupted; - } - - /** - * Return a list of ReferenceType objects for all - * currently loaded classes and interfaces. - * Array types are not returned. - */ - public List allClasses() throws NoSessionException { - ensureActiveSession(); - return vm().allClasses(); - } - - /** - * Return a ReferenceType object for the currently - * loaded class or interface whose fully-qualified - * class name is specified, else return null if there - * is none. - * - * In general, we must return a list of types, because - * multiple class loaders could have loaded a class - * with the same fully-qualified name. - */ - public List findClassesByName(String name) throws NoSessionException { - ensureActiveSession(); - return vm().classesByName(name); - } - - /** - * Return a list of ReferenceType objects for all - * currently loaded classes and interfaces whose name - * matches the given pattern. The pattern syntax is - * open to some future revision, but currently consists - * of a fully-qualified class name in which the first - * component may optionally be a "*" character, designating - * an arbitrary prefix. - */ - public List findClassesMatchingPattern(String pattern) - throws NoSessionException { - ensureActiveSession(); - List result = new ArrayList(); //### Is default size OK? - if (pattern.startsWith("*.")) { - // Wildcard matches any leading package name. - pattern = pattern.substring(1); - for (ReferenceType type : vm().allClasses()) { - if (type.name().endsWith(pattern)) { - result.add(type); - } - } - return result; - } else { - // It's a class name. - return vm().classesByName(pattern); - } - } - - /* - * Return a list of ThreadReference objects corresponding - * to the threads that are currently active in the VM. - * A thread is removed from the list just before the - * thread terminates. - */ - - public List allThreads() throws NoSessionException { - ensureActiveSession(); - return vm().allThreads(); - } - - /* - * Return a list of ThreadGroupReference objects corresponding - * to the top-level threadgroups that are currently active in the VM. - * Note that a thread group may be empty, or contain no threads as - * descendents. - */ - - public List topLevelThreadGroups() throws NoSessionException { - ensureActiveSession(); - return vm().topLevelThreadGroups(); - } - - /* - * Return the system threadgroup. - */ - - public ThreadGroupReference systemThreadGroup() - throws NoSessionException { - ensureActiveSession(); - return vm().topLevelThreadGroups().get(0); - } - - /* - * Evaluate an expression. - */ - - public Value evaluate(final StackFrame f, String expr) - throws ParseException, - InvocationException, - InvalidTypeException, - ClassNotLoadedException, - NoSessionException, - IncompatibleThreadStateException { - ExpressionParser.GetFrame frameGetter = null; - ensureActiveSession(); - if (f != null) { - frameGetter = new ExpressionParser.GetFrame() { - @Override - public StackFrame get() /* throws IncompatibleThreadStateException */ { - return f; - } - }; - } - return ExpressionParser.evaluate(expr, vm(), frameGetter); - } - - - /* - * Start a new VM. - */ - - public void run(boolean suspended, - String vmArgs, - String className, - String args) throws VMLaunchFailureException { - - endSession(); - - //### Set a breakpoint on 'main' method. - //### Would be cleaner if we could just bring up VM already suspended. - if (suspended) { - //### Set breakpoint at 'main(java.lang.String[])'. - List argList = new ArrayList(1); - argList.add("java.lang.String[]"); - createMethodBreakpoint(className, "main", argList); - } - - String cmdLine = className + " " + args; - - startSession(new ChildSession(this, vmArgs, cmdLine, - appInput, appOutput, appError, - diagnostics)); - } - - /* - * Attach to an existing VM. - */ - public void attach(String portName) throws VMLaunchFailureException { - endSession(); - - //### Changes made here for connectors have broken the - //### the 'Session' abstraction. The 'Session.attach()' - //### method is intended to encapsulate all of the various - //### ways in which session start-up can fail. (maddox 12/18/98) - - /* - * Now that attaches and launches both go through Connectors, - * it may be worth creating a new subclass of Session for - * attach sessions. - */ - VirtualMachineManager mgr = Bootstrap.virtualMachineManager(); - AttachingConnector connector = mgr.attachingConnectors().get(0); - Map arguments = connector.defaultArguments(); - arguments.get("port").setValue(portName); - - Session newSession = internalAttach(connector, arguments); - if (newSession != null) { - startSession(newSession); - } - } - - private Session internalAttach(AttachingConnector connector, - Map arguments) { - try { - VirtualMachine vm = connector.attach(arguments); - return new Session(vm, this, diagnostics); - } catch (IOException ioe) { - diagnostics.putString("\n Unable to attach to target VM: " + - ioe.getMessage()); - } catch (IllegalConnectorArgumentsException icae) { - diagnostics.putString("\n Invalid connector arguments: " + - icae.getMessage()); - } - return null; - } - - private Session internalListen(ListeningConnector connector, - Map arguments) { - try { - VirtualMachine vm = connector.accept(arguments); - return new Session(vm, this, diagnostics); - } catch (IOException ioe) { - diagnostics.putString( - "\n Unable to accept connection to target VM: " + - ioe.getMessage()); - } catch (IllegalConnectorArgumentsException icae) { - diagnostics.putString("\n Invalid connector arguments: " + - icae.getMessage()); - } - return null; - } - - /* - * Connect via user specified arguments - * @return true on success - */ - public boolean explictStart(Connector connector, Map arguments) - throws VMLaunchFailureException { - Session newSession = null; - - endSession(); - - if (connector instanceof LaunchingConnector) { - // we were launched, use ChildSession - newSession = new ChildSession(this, (LaunchingConnector)connector, - arguments, - appInput, appOutput, appError, - diagnostics); - } else if (connector instanceof AttachingConnector) { - newSession = internalAttach((AttachingConnector)connector, - arguments); - } else if (connector instanceof ListeningConnector) { - newSession = internalListen((ListeningConnector)connector, - arguments); - } else { - diagnostics.putString("\n Unknown connector: " + connector); - } - if (newSession != null) { - startSession(newSession); - } - return newSession != null; - } - - /* - * Detach from VM. If VM was started by debugger, terminate it. - */ - public void detach() throws NoSessionException { - ensureActiveSession(); - endSession(); - } - - private void startSession(Session s) throws VMLaunchFailureException { - if (!s.attach()) { - throw new VMLaunchFailureException(); - } - session = s; - EventRequestManager em = vm().eventRequestManager(); - ClassPrepareRequest classPrepareRequest = em.createClassPrepareRequest(); - //### We must allow the deferred breakpoints to be resolved before - //### we continue executing the class. We could optimize if there - //### were no deferred breakpoints outstanding for a particular class. - //### Can we do this with JDI? - classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); - classPrepareRequest.enable(); - ClassUnloadRequest classUnloadRequest = em.createClassUnloadRequest(); - classUnloadRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE); - classUnloadRequest.enable(); - ThreadStartRequest threadStartRequest = em.createThreadStartRequest(); - threadStartRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE); - threadStartRequest.enable(); - ThreadDeathRequest threadDeathRequest = em.createThreadDeathRequest(); - threadDeathRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE); - threadDeathRequest.enable(); - ExceptionRequest exceptionRequest = - em.createExceptionRequest(null, false, true); - exceptionRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); - exceptionRequest.enable(); - validateThreadInfo(); - session.interrupted = true; - notifySessionStart(); - } - - void endSession() { - if (session != null) { - session.detach(); - session = null; - invalidateThreadInfo(); - notifySessionDeath(); - } - } - - /* - * Suspend all VM activity. - */ - - public void interrupt() throws NoSessionException { - ensureActiveSession(); - vm().suspend(); - //### Is it guaranteed that the interrupt has happened? - validateThreadInfo(); - session.interrupted = true; - notifyInterrupted(); - } - - /* - * Resume interrupted VM. - */ - - public void go() throws NoSessionException, VMNotInterruptedException { - ensureActiveSession(); - invalidateThreadInfo(); - session.interrupted = false; - notifyContinued(); - vm().resume(); - } - - /* - * Stepping. - */ - void clearPreviousStep(ThreadReference thread) { - /* - * A previous step may not have completed on this thread; - * if so, it gets removed here. - */ - EventRequestManager mgr = vm().eventRequestManager(); - for (StepRequest request : mgr.stepRequests()) { - if (request.thread().equals(thread)) { - mgr.deleteEventRequest(request); - break; - } - } - } - - private void generalStep(ThreadReference thread, int size, int depth) - throws NoSessionException { - ensureActiveSession(); - invalidateThreadInfo(); - session.interrupted = false; - notifyContinued(); - - clearPreviousStep(thread); - EventRequestManager reqMgr = vm().eventRequestManager(); - StepRequest request = reqMgr.createStepRequest(thread, - size, depth); - // We want just the next step event and no others - request.addCountFilter(1); - request.enable(); - vm().resume(); - } - - public void stepIntoInstruction(ThreadReference thread) - throws NoSessionException { - generalStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_INTO); - } - - public void stepOverInstruction(ThreadReference thread) - throws NoSessionException { - generalStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_OVER); - } - - public void stepIntoLine(ThreadReference thread) - throws NoSessionException, - AbsentInformationException { - generalStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_INTO); - } - - public void stepOverLine(ThreadReference thread) - throws NoSessionException, - AbsentInformationException { - generalStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_OVER); - } - - public void stepOut(ThreadReference thread) - throws NoSessionException { - generalStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_OUT); - } - - /* - * Thread control. - */ - - public void suspendThread(ThreadReference thread) throws NoSessionException { - ensureActiveSession(); - thread.suspend(); - } - - public void resumeThread(ThreadReference thread) throws NoSessionException { - ensureActiveSession(); - thread.resume(); - } - - public void stopThread(ThreadReference thread) throws NoSessionException { - ensureActiveSession(); - //### Need an exception now. Which one to use? - //thread.stop(); - } - - /* - * ThreadInfo objects -- Allow query of thread status and stack. - */ - - private List threadInfoList = new LinkedList(); - //### Should be weak! (in the value, not the key) - private HashMap threadInfoMap = new HashMap(); - - public ThreadInfo threadInfo(ThreadReference thread) { - if (session == null || thread == null) { - return null; - } - ThreadInfo info = threadInfoMap.get(thread); - if (info == null) { - //### Should not hardcode initial frame count and prefetch here! - //info = new ThreadInfo(thread, 10, 10); - info = new ThreadInfo(thread); - if (session.interrupted) { - info.validate(); - } - threadInfoList.add(info); - threadInfoMap.put(thread, info); - } - return info; - } - - void validateThreadInfo() { - session.interrupted = true; - for (ThreadInfo threadInfo : threadInfoList) { - threadInfo.validate(); - } - } - - private void invalidateThreadInfo() { - if (session != null) { - session.interrupted = false; - for (ThreadInfo threadInfo : threadInfoList) { - threadInfo.invalidate(); - } - } - } - - void removeThreadInfo(ThreadReference thread) { - ThreadInfo info = threadInfoMap.get(thread); - if (info != null) { - info.invalidate(); - threadInfoMap.remove(thread); - threadInfoList.remove(info); - } - } - - /* - * Listen for Session control events. - */ - - private void notifyInterrupted() { - ArrayList l = new ArrayList(sessionListeners); - EventObject evt = new EventObject(this); - for (int i = 0; i < l.size(); i++) { - l.get(i).sessionInterrupt(evt); - } - } - - private void notifyContinued() { - ArrayList l = new ArrayList(sessionListeners); - EventObject evt = new EventObject(this); - for (int i = 0; i < l.size(); i++) { - l.get(i).sessionContinue(evt); - } - } - - private void notifySessionStart() { - ArrayList l = new ArrayList(sessionListeners); - EventObject evt = new EventObject(this); - for (int i = 0; i < l.size(); i++) { - l.get(i).sessionStart(evt); - } - } - - private void notifySessionDeath() { -/*** noop for now - ArrayList l = new ArrayList(sessionListeners); - EventObject evt = new EventObject(this); - for (int i = 0; i < l.size(); i++) { - ((SessionListener)l.get(i)).sessionDeath(evt); - } -****/ - } - - /* - * Listen for input and output requests from the application - * being debugged. These are generated only when the debuggee - * is spawned as a child of the debugger. - */ - - private Object inputLock = new Object(); - private LinkedList inputBuffer = new LinkedList(); - - private void resetInputBuffer() { - synchronized (inputLock) { - inputBuffer = new LinkedList(); - } - } - - public void sendLineToApplication(String line) { - synchronized (inputLock) { - inputBuffer.addFirst(line); - inputLock.notifyAll(); - } - } - - private InputListener appInput = new InputListener() { - @Override - public String getLine() { - // Don't allow reader to be interrupted -- catch and retry. - String line = null; - while (line == null) { - synchronized (inputLock) { - try { - while (inputBuffer.size() < 1) { - inputLock.wait(); - } - line = inputBuffer.removeLast(); - } catch (InterruptedException e) {} - } - } - // We must not be holding inputLock here, as the listener - // that we call to echo a line might call us re-entrantly - // to provide another line of input. - // Run in Swing event dispatcher thread. - final String input = line; - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - echoInputLine(input); - } - }); - return line; - } - }; - - private static String newline = System.getProperty("line.separator"); - - private void echoInputLine(String line) { - ArrayList l = new ArrayList(appEchoListeners); - for (int i = 0; i < l.size(); i++) { - OutputListener ol = l.get(i); - ol.putString(line); - ol.putString(newline); - } - } - - private OutputListener appOutput = new OutputListener() { - @Override - public void putString(String string) { - ArrayList l = new ArrayList(appEchoListeners); - for (int i = 0; i < l.size(); i++) { - l.get(i).putString(string); - } - } - }; - - private OutputListener appError = new OutputListener() { - @Override - public void putString(String string) { - ArrayList l = new ArrayList(appEchoListeners); - for (int i = 0; i < l.size(); i++) { - l.get(i).putString(string); - } - } - }; - - private OutputListener diagnostics = new OutputListener() { - @Override - public void putString(String string) { - ArrayList l = new ArrayList(diagnosticsListeners); - for (int i = 0; i < l.size(); i++) { - l.get(i).putString(string); - } - } - }; - - ///////////// Spec Request Creation/Deletion/Query /////////// - - private EventRequestSpecList specList = new EventRequestSpecList(this); - - public BreakpointSpec - createSourceLineBreakpoint(String sourceName, int line) { - return specList.createSourceLineBreakpoint(sourceName, line); - } - - public BreakpointSpec - createClassLineBreakpoint(String classPattern, int line) { - return specList.createClassLineBreakpoint(classPattern, line); - } - - public BreakpointSpec - createMethodBreakpoint(String classPattern, - String methodId, List methodArgs) { - return specList.createMethodBreakpoint(classPattern, - methodId, methodArgs); - } - - public ExceptionSpec - createExceptionIntercept(String classPattern, - boolean notifyCaught, - boolean notifyUncaught) { - return specList.createExceptionIntercept(classPattern, - notifyCaught, - notifyUncaught); - } - - public AccessWatchpointSpec - createAccessWatchpoint(String classPattern, String fieldId) { - return specList.createAccessWatchpoint(classPattern, fieldId); - } - - public ModificationWatchpointSpec - createModificationWatchpoint(String classPattern, String fieldId) { - return specList.createModificationWatchpoint(classPattern, - fieldId); - } - - public void delete(EventRequestSpec spec) { - specList.delete(spec); - } - - void resolve(ReferenceType refType) { - specList.resolve(refType); - } - - public void install(EventRequestSpec spec) { - specList.install(spec, vm()); - } - - public List eventRequestSpecs() { - return specList.eventRequestSpecs(); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/FrameIndexOutOfBoundsException.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/FrameIndexOutOfBoundsException.java deleted file mode 100644 index 57d4e2a6d9c..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/FrameIndexOutOfBoundsException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public class FrameIndexOutOfBoundsException extends IndexOutOfBoundsException { - - private static final long serialVersionUID = -4870148107027371437L; -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/JDIEventSource.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/JDIEventSource.java deleted file mode 100644 index 2d92094d0d5..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/JDIEventSource.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -import com.sun.tools.example.debug.event.*; - -import javax.swing.SwingUtilities; - -/** - */ -class JDIEventSource extends Thread { - - private /*final*/ EventQueue queue; - private /*final*/ Session session; - private /*final*/ ExecutionManager runtime; - private final JDIListener firstListener = new FirstListener(); - - private boolean wantInterrupt; //### Hack - - /** - * Create event source. - */ - JDIEventSource(Session session) { - super("JDI Event Set Dispatcher"); - this.session = session; - this.runtime = session.runtime; - this.queue = session.vm.eventQueue(); - } - - @Override - public void run() { - try { - runLoop(); - } catch (Exception exc) { - //### Do something different for InterruptedException??? - // just exit - } - session.running = false; - } - - private void runLoop() throws InterruptedException { - AbstractEventSet es; - do { - EventSet jdiEventSet = queue.remove(); - es = AbstractEventSet.toSpecificEventSet(jdiEventSet); - session.interrupted = es.suspendedAll(); - dispatchEventSet(es); - } while(!(es instanceof VMDisconnectEventSet)); - } - - //### Gross foul hackery! - private void dispatchEventSet(final AbstractEventSet es) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - boolean interrupted = es.suspendedAll(); - es.notify(firstListener); - boolean wantInterrupt = JDIEventSource.this.wantInterrupt; - for (JDIListener jl : session.runtime.jdiListeners) { - es.notify(jl); - } - if (interrupted && !wantInterrupt) { - session.interrupted = false; - //### Catch here is a hack - try { - session.vm.resume(); - } catch (VMDisconnectedException ee) {} - } - if (es instanceof ThreadDeathEventSet) { - ThreadReference t = ((ThreadDeathEventSet)es).getThread(); - session.runtime.removeThreadInfo(t); - } - } - }); - } - - private void finalizeEventSet(AbstractEventSet es) { - if (session.interrupted && !wantInterrupt) { - session.interrupted = false; - //### Catch here is a hack - try { - session.vm.resume(); - } catch (VMDisconnectedException ee) {} - } - if (es instanceof ThreadDeathEventSet) { - ThreadReference t = ((ThreadDeathEventSet)es).getThread(); - session.runtime.removeThreadInfo(t); - } - } - - //### This is a Hack, deal with it - private class FirstListener implements JDIListener { - - @Override - public void accessWatchpoint(AccessWatchpointEventSet e) { - session.runtime.validateThreadInfo(); - wantInterrupt = true; - } - - @Override - public void classPrepare(ClassPrepareEventSet e) { - wantInterrupt = false; - runtime.resolve(e.getReferenceType()); - } - - @Override - public void classUnload(ClassUnloadEventSet e) { - wantInterrupt = false; - } - - @Override - public void exception(ExceptionEventSet e) { - wantInterrupt = true; - } - - @Override - public void locationTrigger(LocationTriggerEventSet e) { - session.runtime.validateThreadInfo(); - wantInterrupt = true; - } - - @Override - public void modificationWatchpoint(ModificationWatchpointEventSet e) { - session.runtime.validateThreadInfo(); - wantInterrupt = true; - } - - @Override - public void threadDeath(ThreadDeathEventSet e) { - wantInterrupt = false; - } - - @Override - public void threadStart(ThreadStartEventSet e) { - wantInterrupt = false; - } - - @Override - public void vmDeath(VMDeathEventSet e) { - //### Should have some way to notify user - //### that VM died before the session ended. - wantInterrupt = false; - } - - @Override - public void vmDisconnect(VMDisconnectEventSet e) { - //### Notify user? - wantInterrupt = false; - session.runtime.endSession(); - } - - @Override - public void vmStart(VMStartEventSet e) { - //### Do we need to do anything with it? - wantInterrupt = false; - } - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/LineBreakpointSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/LineBreakpointSpec.java deleted file mode 100644 index f7d66ce2d52..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/LineBreakpointSpec.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; -import java.util.List; - -public class LineBreakpointSpec extends BreakpointSpec { - int lineNumber; - - LineBreakpointSpec(EventRequestSpecList specs, - ReferenceTypeSpec refSpec, int lineNumber) { - super(specs, refSpec); - this.lineNumber = lineNumber; - } - - /** - * The 'refType' is known to match. - */ - @Override - void resolve(ReferenceType refType) throws InvalidTypeException, - LineNotFoundException { - if (!(refType instanceof ClassType)) { - throw new InvalidTypeException(); - } - Location location = location((ClassType)refType); - setRequest(refType.virtualMachine().eventRequestManager() - .createBreakpointRequest(location)); - } - - private Location location(ClassType clazz) throws - LineNotFoundException { - Location location = null; - try { - List locs = clazz.locationsOfLine(lineNumber()); - if (locs.size() == 0) { - throw new LineNotFoundException(); - } - // TODO handle multiple locations - location = locs.get(0); - if (location.method() == null) { - throw new LineNotFoundException(); - } - } catch (AbsentInformationException e) { - /* - * TO DO: throw something more specific, or allow - * AbsentInfo exception to pass through. - */ - throw new LineNotFoundException(); - } - return location; - } - - public int lineNumber() { - return lineNumber; - } - - @Override - public int hashCode() { - return refSpec.hashCode() + lineNumber; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof LineBreakpointSpec) { - LineBreakpointSpec breakpoint = (LineBreakpointSpec)obj; - - return refSpec.equals(breakpoint.refSpec) && - (lineNumber == breakpoint.lineNumber); - } else { - return false; - } - } - - @Override - public String errorMessageFor(Exception e) { - if (e instanceof LineNotFoundException) { - return ("No code at line " + lineNumber() + " in " + refSpec); - } else if (e instanceof InvalidTypeException) { - return ("Breakpoints can be located only in classes. " + - refSpec + " is an interface or array"); - } else { - return super.errorMessageFor( e); - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("breakpoint "); - sb.append(refSpec.toString()); - sb.append(':'); - sb.append(lineNumber); - sb.append(" ("); - sb.append(getStatusString()); - sb.append(')'); - return sb.toString(); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/LineNotFoundException.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/LineNotFoundException.java deleted file mode 100644 index 56b4ba3fa39..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/LineNotFoundException.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public class LineNotFoundException extends Exception -{ - - private static final long serialVersionUID = -5630418117861587582L; - - public LineNotFoundException() - { - super(); - } - - public LineNotFoundException(String s) - { - super(s); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/MalformedMemberNameException.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/MalformedMemberNameException.java deleted file mode 100644 index 1980893a361..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/MalformedMemberNameException.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -class MalformedMemberNameException extends Exception { - - private static final long serialVersionUID = -7726664097374844485L; - - public MalformedMemberNameException() { - super(); - } - - public MalformedMemberNameException(String s) { - super(s); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/MethodBreakpointSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/MethodBreakpointSpec.java deleted file mode 100644 index b414443faf7..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/MethodBreakpointSpec.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; -import java.util.ArrayList; -import java.util.List; - -public class MethodBreakpointSpec extends BreakpointSpec { - String methodId; - List methodArgs; - - MethodBreakpointSpec(EventRequestSpecList specs, - ReferenceTypeSpec refSpec, - String methodId, List methodArgs) { - super(specs, refSpec); - this.methodId = methodId; - this.methodArgs = methodArgs; - } - - /** - * The 'refType' is known to match. - */ - @Override - void resolve(ReferenceType refType) throws MalformedMemberNameException, - AmbiguousMethodException, - InvalidTypeException, - NoSuchMethodException, - NoSessionException { - if (!isValidMethodName(methodId)) { - throw new MalformedMemberNameException(methodId); - } - if (!(refType instanceof ClassType)) { - throw new InvalidTypeException(); - } - Location location = location((ClassType)refType); - setRequest(refType.virtualMachine().eventRequestManager() - .createBreakpointRequest(location)); - } - - private Location location(ClassType clazz) throws - AmbiguousMethodException, - NoSuchMethodException, - NoSessionException { - Method method = findMatchingMethod(clazz); - Location location = method.location(); - return location; - } - - public String methodName() { - return methodId; - } - - public List methodArgs() { - return methodArgs; - } - - @Override - public int hashCode() { - return refSpec.hashCode() + - ((methodId != null) ? methodId.hashCode() : 0) + - ((methodArgs != null) ? methodArgs.hashCode() : 0); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof MethodBreakpointSpec) { - MethodBreakpointSpec breakpoint = (MethodBreakpointSpec)obj; - - return methodId.equals(breakpoint.methodId) && - methodArgs.equals(breakpoint.methodArgs) && - refSpec.equals(breakpoint.refSpec); - } else { - return false; - } - } - - @Override - public String errorMessageFor(Exception e) { - if (e instanceof AmbiguousMethodException) { - return ("Method " + methodName() + " is overloaded; specify arguments"); - /* - * TO DO: list the methods here - */ - } else if (e instanceof NoSuchMethodException) { - return ("No method " + methodName() + " in " + refSpec); - } else if (e instanceof InvalidTypeException) { - return ("Breakpoints can be located only in classes. " + - refSpec + " is an interface or array"); - } else { - return super.errorMessageFor( e); - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("breakpoint "); - sb.append(refSpec.toString()); - sb.append('.'); - sb.append(methodId); - if (methodArgs != null) { - boolean first = true; - sb.append('('); - for (String name : methodArgs) { - if (!first) { - sb.append(','); - } - sb.append(name); - first = false; - } - sb.append(")"); - } - sb.append(" ("); - sb.append(getStatusString()); - sb.append(')'); - return sb.toString(); - } - - private boolean isValidMethodName(String s) { - return isJavaIdentifier(s) || - s.equals("") || - s.equals(""); - } - - /* - * Compare a method's argument types with a Vector of type names. - * Return true if each argument type has a name identical to the - * corresponding string in the vector (allowing for varargs) - * and if the number of arguments in the method matches the - * number of names passed - */ - private boolean compareArgTypes(Method method, List nameList) { - List argTypeNames = method.argumentTypeNames(); - - // If argument counts differ, we can stop here - if (argTypeNames.size() != nameList.size()) { - return false; - } - - // Compare each argument type's name - int nTypes = argTypeNames.size(); - for (int i = 0; i < nTypes; ++i) { - String comp1 = argTypeNames.get(i); - String comp2 = nameList.get(i); - if (! comp1.equals(comp2)) { - /* - * We have to handle varargs. EG, the - * method's last arg type is xxx[] - * while the nameList contains xxx... - * Note that the nameList can also contain - * xxx[] in which case we don't get here. - */ - if (i != nTypes - 1 || - !method.isVarArgs() || - !comp2.endsWith("...")) { - return false; - } - /* - * The last types differ, it is a varargs - * method and the nameList item is varargs. - * We just have to compare the type names, eg, - * make sure we don't have xxx[] for the method - * arg type and yyy... for the nameList item. - */ - int comp1Length = comp1.length(); - if (comp1Length + 1 != comp2.length()) { - // The type names are different lengths - return false; - } - // We know the two type names are the same length - if (!comp1.regionMatches(0, comp2, 0, comp1Length - 2)) { - return false; - } - // We do have xxx[] and xxx... as the last param type - return true; - } - } - - return true; - } - - private VirtualMachine vm() { - return request.virtualMachine(); - } - - /** - * Remove unneeded spaces and expand class names to fully - * qualified names, if necessary and possible. - */ - private String normalizeArgTypeName(String name) throws NoSessionException { - /* - * Separate the type name from any array modifiers, - * stripping whitespace after the name ends. - */ - int i = 0; - StringBuilder typePart = new StringBuilder(); - StringBuilder arrayPart = new StringBuilder(); - name = name.trim(); - int nameLength = name.length(); - /* - * For varargs, there can be spaces before the ... but not - * within the ... So, we will just ignore the ... - * while stripping blanks. - */ - boolean isVarArgs = name.endsWith("..."); - if (isVarArgs) { - nameLength -= 3; - } - - while (i < nameLength) { - char c = name.charAt(i); - if (Character.isWhitespace(c) || c == '[') { - break; // name is complete - } - typePart.append(c); - i++; - } - while (i < nameLength) { - char c = name.charAt(i); - if ( (c == '[') || (c == ']')) { - arrayPart.append(c); - } else if (!Character.isWhitespace(c)) { - throw new IllegalArgumentException( - "Invalid argument type name"); - - } - i++; - } - - name = typePart.toString(); - - /* - * When there's no sign of a package name already, - * try to expand the - * the name to a fully qualified class name - */ - if ((name.indexOf('.') == -1) || name.startsWith("*.")) { - try { - List refs = specs.runtime.findClassesMatchingPattern(name); - if (refs.size() > 0) { //### ambiguity??? - name = ((ReferenceType)(refs.get(0))).name(); - } - } catch (IllegalArgumentException e) { - // We'll try the name as is - } - } - name += arrayPart.toString(); - if (isVarArgs) { - name += "..."; - } - return name; - } - - /* - * Attempt an unambiguous match of the method name and - * argument specification to a method. If no arguments - * are specified, the method must not be overloaded. - * Otherwise, the argument types much match exactly - */ - private Method findMatchingMethod(ClassType clazz) - throws AmbiguousMethodException, - NoSuchMethodException, - NoSessionException { - - // Normalize the argument string once before looping below. - List argTypeNames = null; - if (methodArgs() != null) { - argTypeNames = new ArrayList(methodArgs().size()); - for (String name : methodArgs()) { - name = normalizeArgTypeName(name); - argTypeNames.add(name); - } - } - - // Check each method in the class for matches - Method firstMatch = null; // first method with matching name - Method exactMatch = null; // (only) method with same name & sig - int matchCount = 0; // > 1 implies overload - for (Method candidate : clazz.methods()) { - if (candidate.name().equals(methodName())) { - matchCount++; - - // Remember the first match in case it is the only one - if (matchCount == 1) { - firstMatch = candidate; - } - - // If argument types were specified, check against candidate - if ((argTypeNames != null) - && compareArgTypes(candidate, argTypeNames) == true) { - exactMatch = candidate; - break; - } - } - } - - // Determine method for breakpoint - Method method = null; - if (exactMatch != null) { - // Name and signature match - method = exactMatch; - } else if ((argTypeNames == null) && (matchCount > 0)) { - // At least one name matched and no arg types were specified - if (matchCount == 1) { - method = firstMatch; // Only one match; safe to use it - } else { - throw new AmbiguousMethodException(); - } - } else { - throw new NoSuchMethodException(methodName()); - } - return method; - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/MethodNotFoundException.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/MethodNotFoundException.java deleted file mode 100644 index 820c35cc61b..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/MethodNotFoundException.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public class MethodNotFoundException extends Exception -{ - private static final long serialVersionUID = -2064968107599632609L; - - public MethodNotFoundException() - { - super(); - } - - public MethodNotFoundException(String s) - { - super(s); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ModificationWatchpointSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ModificationWatchpointSpec.java deleted file mode 100644 index b8f2b86e65a..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ModificationWatchpointSpec.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; - -public class ModificationWatchpointSpec extends WatchpointSpec { - - ModificationWatchpointSpec(EventRequestSpecList specs, - ReferenceTypeSpec refSpec, String fieldId) { - super(specs, refSpec, fieldId); - } - - /** - * The 'refType' is known to match. - */ - @Override - void resolve(ReferenceType refType) throws InvalidTypeException, - NoSuchFieldException { - if (!(refType instanceof ClassType)) { - throw new InvalidTypeException(); - } - Field field = refType.fieldByName(fieldId); - if (field == null) { - throw new NoSuchFieldException(fieldId); - } - setRequest(refType.virtualMachine().eventRequestManager() - .createModificationWatchpointRequest(field)); - } - - @Override - public boolean equals(Object obj) { - return (obj instanceof ModificationWatchpointSpec) && - super.equals(obj); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/NoSessionException.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/NoSessionException.java deleted file mode 100644 index 3e92e2eb167..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/NoSessionException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public class NoSessionException extends Exception { - - private static final long serialVersionUID = -7324357828115128603L; -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/OutputListener.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/OutputListener.java deleted file mode 100644 index 8bb6701595e..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/OutputListener.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public interface OutputListener { - void putString(String str); - //void putLine(String line); -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ParseException.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ParseException.java deleted file mode 100644 index 3d407985635..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ParseException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -// dummy placeholder for javaCC-generated code. - -public class ParseException extends Exception {} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/PatternReferenceTypeSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/PatternReferenceTypeSpec.java deleted file mode 100644 index fa034aea3b4..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/PatternReferenceTypeSpec.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; -import java.util.StringTokenizer; - -class PatternReferenceTypeSpec implements ReferenceTypeSpec { - final boolean isWild; - final String classId; - - PatternReferenceTypeSpec(String classId) -// throws ClassNotFoundException - { -// checkClassName(classId); - isWild = classId.startsWith("*."); - if (isWild) { - this.classId = classId.substring(1); - } else { - this.classId = classId; - } - } - - /** - * Does the specified ReferenceType match this spec. - */ - @Override - public boolean matches(ReferenceType refType) { - if (isWild) { - return refType.name().endsWith(classId); - } else { - return refType.name().equals(classId); - } - } - - @Override - public int hashCode() { - return classId.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof PatternReferenceTypeSpec) { - PatternReferenceTypeSpec spec = (PatternReferenceTypeSpec)obj; - - return classId.equals(spec.classId) && (isWild == spec.isWild); - } else { - return false; - } - } - - private void checkClassName(String className) throws ClassNotFoundException { - // Do stricter checking of class name validity on deferred - // because if the name is invalid, it will - // never match a future loaded class, and we'll be silent - // about it. - StringTokenizer tokenizer = new StringTokenizer(className, "."); - boolean first = true; - while (tokenizer.hasMoreTokens()) { - String token = tokenizer.nextToken(); - // Each dot-separated piece must be a valid identifier - // and the first token can also be "*". (Note that - // numeric class ids are not permitted. They must - // match a loaded class.) - if (!Utils.isJavaIdentifier(token) && !(first && token.equals("*"))) { - throw new ClassNotFoundException(); - } - first = false; - } - } - - @Override - public String toString() { - return isWild? "*" + classId : classId; - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/Session.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/Session.java deleted file mode 100644 index 883834a07a1..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/Session.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.VirtualMachine; -import com.sun.jdi.VMDisconnectedException; - -/** - * Our repository of what we know about the state of one - * running VM. - */ -class Session { - - final VirtualMachine vm; - final ExecutionManager runtime; - final OutputListener diagnostics; - - boolean running = true; // Set false by JDIEventSource - boolean interrupted = false; // Set false by JDIEventSource - - private JDIEventSource eventSourceThread = null; - private int traceFlags; - private boolean dead = false; - - public Session(VirtualMachine vm, ExecutionManager runtime, - OutputListener diagnostics) { - this.vm = vm; - this.runtime = runtime; - this.diagnostics = diagnostics; - this.traceFlags = VirtualMachine.TRACE_NONE; - } - - /** - * Determine if VM is interrupted, i.e, present and not running. - */ - public boolean isInterrupted() { - return interrupted; - } - - public void setTraceMode(int traceFlags) { - this.traceFlags = traceFlags; - if (!dead) { - vm.setDebugTraceMode(traceFlags); - } - } - - public boolean attach() { - vm.setDebugTraceMode(traceFlags); - diagnostics.putString("Connected to VM"); - eventSourceThread = new JDIEventSource(this); - eventSourceThread.start(); - return true; - } - - public void detach() { - if (!dead) { - eventSourceThread.interrupt(); - eventSourceThread = null; - //### The VM may already be disconnected - //### if the debuggee did a System.exit(). - //### Exception handler here is a kludge, - //### Rather, there are many other places - //### where we need to handle this exception, - //### and initiate a detach due to an error - //### condition, e.g., connection failure. - try { - vm.dispose(); - } catch (VMDisconnectedException ee) {} - dead = true; - diagnostics.putString("Disconnected from VM"); - } - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SessionListener.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SessionListener.java deleted file mode 100644 index e13c4d70e72..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SessionListener.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import java.util.EventObject; -import java.util.EventListener; - -public interface SessionListener extends EventListener { - - void sessionStart(EventObject e); - - void sessionInterrupt(EventObject e); - void sessionContinue(EventObject e); -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SourceNameReferenceTypeSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SourceNameReferenceTypeSpec.java deleted file mode 100644 index 36061bfc487..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SourceNameReferenceTypeSpec.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; - -class SourceNameReferenceTypeSpec implements ReferenceTypeSpec { - final String sourceName; - final int linenumber; - - SourceNameReferenceTypeSpec(String sourceName, int linenumber) { - this.sourceName = sourceName; - this.linenumber = linenumber; - } - - /** - * Does the specified ReferenceType match this spec. - */ - @Override - public boolean matches(ReferenceType refType) { - try { - if (refType.sourceName().equals(sourceName)) { - try { - refType.locationsOfLine(linenumber); - // if we don't throw an exception then it was found - return true; - } catch(AbsentInformationException exc) { - } catch(ObjectCollectedException exc) { - } - } - } catch(AbsentInformationException exc) { - // for sourceName(), fall through - } - return false; - } - - @Override - public int hashCode() { - return sourceName.hashCode() + linenumber; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof SourceNameReferenceTypeSpec) { - SourceNameReferenceTypeSpec spec = (SourceNameReferenceTypeSpec)obj; - - return sourceName.equals(spec.sourceName) && - (linenumber == spec.linenumber); - } else { - return false; - } - } - - @Override - public String toString() { - return sourceName + "@" + linenumber; - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SpecErrorEvent.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SpecErrorEvent.java deleted file mode 100644 index baab1291d2d..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SpecErrorEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public class SpecErrorEvent extends SpecEvent { - - private static final long serialVersionUID = 8162634387866409578L; - private Exception reason; - - public SpecErrorEvent(EventRequestSpec eventRequestSpec, - Exception reason) { - super(eventRequestSpec); - this.reason = reason; - } - - public Exception getReason() { - return reason; - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SpecEvent.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SpecEvent.java deleted file mode 100644 index 7a321ef4aaa..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SpecEvent.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import java.util.EventObject; - -import com.sun.jdi.request.EventRequest; - -public class SpecEvent extends EventObject { - - private static final long serialVersionUID = 4820735456787276230L; - private EventRequestSpec eventRequestSpec; - - public SpecEvent(EventRequestSpec eventRequestSpec) { - super(eventRequestSpec.specs); - this.eventRequestSpec = eventRequestSpec; - } - - public EventRequestSpec getEventRequestSpec() { - return eventRequestSpec; - } - - public EventRequest getEventRequest() { - return eventRequestSpec.getEventRequest(); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SpecListener.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SpecListener.java deleted file mode 100644 index 2e5df596ea4..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/SpecListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import java.util.EventListener; - -public interface SpecListener extends EventListener { - - void breakpointSet(SpecEvent e); - void breakpointDeferred(SpecEvent e); - void breakpointDeleted(SpecEvent e); - void breakpointResolved(SpecEvent e); - void breakpointError(SpecErrorEvent e); - - void watchpointSet(SpecEvent e); - void watchpointDeferred(SpecEvent e); - void watchpointDeleted(SpecEvent e); - void watchpointResolved(SpecEvent e); - void watchpointError(SpecErrorEvent e); - - void exceptionInterceptSet(SpecEvent e); - void exceptionInterceptDeferred(SpecEvent e); - void exceptionInterceptDeleted(SpecEvent e); - void exceptionInterceptResolved(SpecEvent e); - void exceptionInterceptError(SpecErrorEvent e); -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ThreadGroupIterator.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ThreadGroupIterator.java deleted file mode 100644 index dd8b0cb3f7e..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ThreadGroupIterator.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.ThreadGroupReference; -import java.util.List; -import java.util.Stack; -import java.util.ArrayList; -import java.util.Iterator; - -/** - * Descend the tree of thread groups. - * @author Robert G. Field - */ -public class ThreadGroupIterator implements Iterator { - private final Stack> stack - = new Stack>(); - - public ThreadGroupIterator(List tgl) { - push(tgl); - } - - public ThreadGroupIterator(ThreadGroupReference tg) { - List tgl = new ArrayList(); - tgl.add(tg); - push(tgl); - } - -/* - ThreadGroupIterator() { - this(Env.vm().topLevelThreadGroups()); - } -*/ - - private Iterator top() { - return stack.peek(); - } - - /** - * The invariant in this class is that the top iterator - * on the stack has more elements. If the stack is - * empty, there is no top. This method assures - * this invariant. - */ - private void push(List tgl) { - stack.push(tgl.iterator()); - while (!stack.isEmpty() && !top().hasNext()) { - stack.pop(); - } - } - - @Override - public boolean hasNext() { - return !stack.isEmpty(); - } - - @Override - public ThreadGroupReference next() { - return nextThreadGroup(); - } - - public ThreadGroupReference nextThreadGroup() { - ThreadGroupReference tg = top().next(); - push(tg.threadGroups()); - return tg; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - -/* - static ThreadGroupReference find(String name) { - ThreadGroupIterator tgi = new ThreadGroupIterator(); - while (tgi.hasNext()) { - ThreadGroupReference tg = tgi.nextThreadGroup(); - if (tg.name().equals(name)) { - return tg; - } - } - return null; - } -*/ -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ThreadInfo.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ThreadInfo.java deleted file mode 100644 index 02626ac324f..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ThreadInfo.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.*; - -//### Should handle target VM death or connection failure cleanly. - -public class ThreadInfo { - - private ThreadReference thread; - private int status; - - private int frameCount; - - Object userObject; // User-supplied annotation. - - private boolean interrupted = false; - - private void assureInterrupted() throws VMNotInterruptedException { - if (!interrupted) { - throw new VMNotInterruptedException(); - } - } - - ThreadInfo (ThreadReference thread) { - this.thread = thread; - this.frameCount = -1; - } - - public ThreadReference thread() { - return thread; - } - - public int getStatus() throws VMNotInterruptedException { - assureInterrupted(); - update(); - return status; - } - - public int getFrameCount() throws VMNotInterruptedException { - assureInterrupted(); - update(); - return frameCount; - } - - public StackFrame getFrame(int index) throws VMNotInterruptedException { - assureInterrupted(); - update(); - try { - return thread.frame(index); - } catch (IncompatibleThreadStateException e) { - // Should not happen - interrupted = false; - throw new VMNotInterruptedException(); - } - } - - public Object getUserObject() { - return userObject; - } - - public void setUserObject(Object obj) { - userObject = obj; - } - - // Refresh upon first access after cache is cleared. - - void update() throws VMNotInterruptedException { - if (frameCount == -1) { - try { - status = thread.status(); - frameCount = thread.frameCount(); - } catch (IncompatibleThreadStateException e) { - // Should not happen - interrupted = false; - throw new VMNotInterruptedException(); - } - } - } - - // Called from 'ExecutionManager'. - - void validate() { - interrupted = true; - } - - void invalidate() { - interrupted = false; - frameCount = -1; - status = ThreadReference.THREAD_STATUS_UNKNOWN; - } - -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ThreadIterator.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ThreadIterator.java deleted file mode 100644 index b82d88e6e1e..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/ThreadIterator.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -import com.sun.jdi.ThreadGroupReference; -import com.sun.jdi.ThreadReference; -import java.util.List; -import java.util.Iterator; - -public class ThreadIterator implements Iterator { - Iterator it = null; - ThreadGroupIterator tgi; - - public ThreadIterator(ThreadGroupReference tg) { - tgi = new ThreadGroupIterator(tg); - } - - //### make this package access only? - public ThreadIterator(List tgl) { - tgi = new ThreadGroupIterator(tgl); - } - - @Override - public boolean hasNext() { - while (it == null || !it.hasNext()) { - if (!tgi.hasNext()) { - return false; // no more - } - it = tgi.nextThreadGroup().threads().iterator(); - } - return true; - } - - @Override - public ThreadReference next() { - return it.next(); - } - - public ThreadReference nextThread() { - return next(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/Utils.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/Utils.java deleted file mode 100644 index 34f1d724929..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/Utils.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; //### does it belong here? - -import com.sun.jdi.*; - -public class Utils { - - /** - * Return the thread status description. - */ - public static String getStatus(ThreadReference thr) { - int status = thr.status(); - String result; - switch (status) { - case ThreadReference.THREAD_STATUS_UNKNOWN: - result = "unknown status"; - break; - case ThreadReference.THREAD_STATUS_ZOMBIE: - result = "zombie"; - break; - case ThreadReference.THREAD_STATUS_RUNNING: - result = "running"; - break; - case ThreadReference.THREAD_STATUS_SLEEPING: - result = "sleeping"; - break; - case ThreadReference.THREAD_STATUS_MONITOR: - result = "waiting to acquire a monitor lock"; - break; - case ThreadReference.THREAD_STATUS_WAIT: - result = "waiting on a condition"; - break; - default: - result = ""; - } - if (thr.isSuspended()) { - result += " (suspended)"; - } - return result; - } - - /** - * Return a description of an object. - */ - public static String description(ObjectReference ref) { - ReferenceType clazz = ref.referenceType(); - long id = ref.uniqueID(); //### TODO use real id - if (clazz == null) { - return toHex(id); - } else { - return "(" + clazz.name() + ")" + toHex(id); - } - } - - /** - * Convert a long to a hexadecimal string. - */ - public static String toHex(long n) { - char s1[] = new char[16]; - char s2[] = new char[18]; - - // Store digits in reverse order. - int i = 0; - do { - long d = n & 0xf; - s1[i++] = (char)((d < 10) ? ('0' + d) : ('a' + d - 10)); - } while ((n >>>= 4) > 0); - - // Now reverse the array. - s2[0] = '0'; - s2[1] = 'x'; - int j = 2; - while (--i >= 0) { - s2[j++] = s1[i]; - } - return new String(s2, 0, j); - } - - /** - * Convert hexadecimal strings to longs. - */ - public static long fromHex(String hexStr) { - String str = hexStr.startsWith("0x") ? - hexStr.substring(2).toLowerCase() : hexStr.toLowerCase(); - if (hexStr.length() == 0) { - throw new NumberFormatException(); - } - - long ret = 0; - for (int i = 0; i < str.length(); i++) { - int c = str.charAt(i); - if (c >= '0' && c <= '9') { - ret = (ret * 16) + (c - '0'); - } else if (c >= 'a' && c <= 'f') { - ret = (ret * 16) + (c - 'a' + 10); - } else { - throw new NumberFormatException(); - } - } - return ret; - } - - - /* - * The next two methods are used by this class and by EventHandler - * to print consistent locations and error messages. - */ - public static String locationString(Location loc) { - return loc.declaringType().name() + - "." + loc.method().name() + "(), line=" + - loc.lineNumber(); - } - -//### UNUSED. -/************************ - private String typedName(Method method) { - // TO DO: Use method.signature() instead of method.arguments() so that - // we get sensible results for classes without debugging info - StringBuffer buf = new StringBuffer(); - buf.append(method.name()); - buf.append("("); - Iterator it = method.arguments().iterator(); - while (it.hasNext()) { - buf.append(((LocalVariable)it.next()).typeName()); - if (it.hasNext()) { - buf.append(","); - } - } - buf.append(")"); - return buf.toString(); - } -************************/ - - public static boolean isValidMethodName(String s) { - return isJavaIdentifier(s) || - s.equals("") || - s.equals(""); - } - - public static boolean isJavaIdentifier(String s) { - if (s.length() == 0) { - return false; - } - int cp = s.codePointAt(0); - if (! Character.isJavaIdentifierStart(cp)) { - return false; - } - for (int i = Character.charCount(cp); i < s.length(); i += Character.charCount(cp)) { - cp = s.codePointAt(i); - if (! Character.isJavaIdentifierPart(cp)) { - return false; - } - } - return true; - } - -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/VMLaunchFailureException.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/VMLaunchFailureException.java deleted file mode 100644 index c2429684d29..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/VMLaunchFailureException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public class VMLaunchFailureException extends Exception { - - private static final long serialVersionUID = -2439646729274310108L; -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/VMNotInterruptedException.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/VMNotInterruptedException.java deleted file mode 100644 index 489d88086cb..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/VMNotInterruptedException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public class VMNotInterruptedException extends Exception { - - private static final long serialVersionUID = 8111074582188765600L; -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/WatchpointSpec.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/WatchpointSpec.java deleted file mode 100644 index 367e38c7490..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/bdi/WatchpointSpec.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.bdi; - -public abstract class WatchpointSpec extends EventRequestSpec { - final String fieldId; - - WatchpointSpec(EventRequestSpecList specs, - ReferenceTypeSpec refSpec, String fieldId) { - super(specs, refSpec); - this.fieldId = fieldId; -// if (!isJavaIdentifier(fieldId)) { -// throw new MalformedMemberNameException(fieldId); -// } - } - - @Override - void notifySet(SpecListener listener, SpecEvent evt) { - listener.watchpointSet(evt); - } - - @Override - void notifyDeferred(SpecListener listener, SpecEvent evt) { - listener.watchpointDeferred(evt); - } - - @Override - void notifyResolved(SpecListener listener, SpecEvent evt) { - listener.watchpointResolved(evt); - } - - @Override - void notifyDeleted(SpecListener listener, SpecEvent evt) { - listener.watchpointDeleted(evt); - } - - @Override - void notifyError(SpecListener listener, SpecErrorEvent evt) { - listener.watchpointError(evt); - } - - @Override - public int hashCode() { - return refSpec.hashCode() + fieldId.hashCode() + - getClass().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof WatchpointSpec) { - WatchpointSpec watchpoint = (WatchpointSpec)obj; - - return fieldId.equals(watchpoint.fieldId) && - refSpec.equals(watchpoint.refSpec) && - getClass().equals(watchpoint.getClass()); - } else { - return false; - } - } - - @Override - public String errorMessageFor(Exception e) { - if (e instanceof NoSuchFieldException) { - return ("No field " + fieldId + " in " + refSpec); - } else { - return super.errorMessageFor(e); - } - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/AbstractEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/AbstractEventSet.java deleted file mode 100644 index 0a82f15ee0a..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/AbstractEventSet.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; -import com.sun.jdi.request.*; - -import java.util.*; - -public abstract class AbstractEventSet extends EventObject implements EventSet { - - private static final long serialVersionUID = 2772717574222076977L; - private final EventSet jdiEventSet; - final Event oneEvent; - - /** - */ - AbstractEventSet(EventSet jdiEventSet) { - super(jdiEventSet.virtualMachine()); - this.jdiEventSet = jdiEventSet; - this.oneEvent = eventIterator().nextEvent(); - } - - public static AbstractEventSet toSpecificEventSet(EventSet jdiEventSet) { - Event evt = jdiEventSet.eventIterator().nextEvent(); - if (evt instanceof LocatableEvent) { - if (evt instanceof ExceptionEvent) { - return new ExceptionEventSet(jdiEventSet); - } else if (evt instanceof WatchpointEvent) { - if (evt instanceof AccessWatchpointEvent) { - return new AccessWatchpointEventSet(jdiEventSet); - } else { - return new ModificationWatchpointEventSet(jdiEventSet); - } - } else { - return new LocationTriggerEventSet(jdiEventSet); - } - } else if (evt instanceof ClassPrepareEvent) { - return new ClassPrepareEventSet(jdiEventSet); - } else if (evt instanceof ClassUnloadEvent) { - return new ClassUnloadEventSet(jdiEventSet); - } else if (evt instanceof ThreadDeathEvent) { - return new ThreadDeathEventSet(jdiEventSet); - } else if (evt instanceof ThreadStartEvent) { - return new ThreadStartEventSet(jdiEventSet); - } else if (evt instanceof VMDeathEvent) { - return new VMDeathEventSet(jdiEventSet); - } else if (evt instanceof VMDisconnectEvent) { - return new VMDisconnectEventSet(jdiEventSet); - } else if (evt instanceof VMStartEvent) { - return new VMStartEventSet(jdiEventSet); - } else { - throw new IllegalArgumentException("Unknown event " + evt); - } - } - - public abstract void notify(JDIListener listener); - - // Implement Mirror - - @Override - public VirtualMachine virtualMachine() { - return jdiEventSet.virtualMachine(); - } - - public VirtualMachine getVirtualMachine() { - return jdiEventSet.virtualMachine(); - } - - // Implement EventSet - - /** - * Returns the policy used to suspend threads in the target VM - * for this event set. This policy is selected from the suspend - * policies for each event's request. The one that suspends the - * most threads is chosen when the event occurs in the target VM - * and that policy is returned here. See - * com.sun.jdi.request.EventRequest for the possible policy values. - * - * @return the integer suspendPolicy - */ - public int getSuspendPolicy() { - return jdiEventSet.suspendPolicy(); - } - - @Override - public void resume() { - jdiEventSet.resume(); - } - - @Override - public int suspendPolicy() { - return jdiEventSet.suspendPolicy(); - } - - public boolean suspendedAll() { - return jdiEventSet.suspendPolicy() == EventRequest.SUSPEND_ALL; - } - - public boolean suspendedEventThread() { - return jdiEventSet.suspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD; - } - - public boolean suspendedNone() { - return jdiEventSet.suspendPolicy() == EventRequest.SUSPEND_NONE; - } - - /** - * Return an iterator specific to {@link Event} objects. - */ - @Override - public EventIterator eventIterator() { - return jdiEventSet.eventIterator(); - } - - - // Implement java.util.Set (by pass through) - - /** - * Returns the number of elements in this set (its cardinality). If this - * set contains more than Integer.MAX_VALUE elements, returns - * Integer.MAX_VALUE. - * - * @return the number of elements in this set (its cardinality). - */ - @Override - public int size() { - return jdiEventSet.size(); - } - - /** - * Returns true if this set contains no elements. - * - * @return true if this set contains no elements. - */ - @Override - public boolean isEmpty() { - return jdiEventSet.isEmpty(); - } - - /** - * Returns true if this set contains the specified element. More - * formally, returns true if and only if this set contains an - * element e such that (o==null ? e==null : - * o.equals(e)). - * - * @return true if this set contains the specified element. - */ - @Override - public boolean contains(Object o) { - return jdiEventSet.contains(o); - } - - /** - * Returns an iterator over the elements in this set. The elements are - * returned in no particular order (unless this set is an instance of some - * class that provides a guarantee). - * - * @return an iterator over the elements in this set. - */ - @Override - public Iterator iterator() { - return jdiEventSet.iterator(); - } - - /** - * Returns an array containing all of the elements in this set. - * Obeys the general contract of the Collection.toArray method. - * - * @return an array containing all of the elements in this set. - */ - @Override - public Object[] toArray() { - return jdiEventSet.toArray(); - } - - /** - * Returns an array containing all of the elements in this set whose - * runtime type is that of the specified array. Obeys the general - * contract of the Collection.toArray(Object[]) method. - * - * @param a the array into which the elements of this set are to - * be stored, if it is big enough { - return jdiEventSet.XXX(); - } otherwise, a new array of the - * same runtime type is allocated for this purpose. - * @return an array containing the elements of this set. - * @throws ArrayStoreException the runtime type of a is not a supertype - * of the runtime type of every element in this set. - */ - @Override - public T[] toArray(T a[]) { - return jdiEventSet.toArray(a); - } - - // Bulk Operations - - /** - * Returns true if this set contains all of the elements of the - * specified collection. If the specified collection is also a set, this - * method returns true if it is a subset of this set. - * - * @param c collection to be checked for containment in this set. - * @return true if this set contains all of the elements of the - * specified collection. - */ - @Override - public boolean containsAll(Collection c) { - return jdiEventSet.containsAll(c); - } - - - // Make the rest of Set unmodifiable - - @Override - public boolean add(Event e){ - throw new UnsupportedOperationException(); - } - @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException(); - } - @Override - public boolean addAll(Collection coll) { - throw new UnsupportedOperationException(); - } - @Override - public boolean removeAll(Collection coll) { - throw new UnsupportedOperationException(); - } - @Override - public boolean retainAll(Collection coll) { - throw new UnsupportedOperationException(); - } - @Override - public void clear() { - throw new UnsupportedOperationException(); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/AccessWatchpointEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/AccessWatchpointEventSet.java deleted file mode 100644 index 10462e3bbb4..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/AccessWatchpointEventSet.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.event.*; - -public class AccessWatchpointEventSet extends WatchpointEventSet { - - private static final long serialVersionUID = -2620394219156607673L; - - AccessWatchpointEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - @Override - public void notify(JDIListener listener) { - listener.accessWatchpoint(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ClassPrepareEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ClassPrepareEventSet.java deleted file mode 100644 index 9010415e362..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ClassPrepareEventSet.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -public class ClassPrepareEventSet extends AbstractEventSet { - - private static final long serialVersionUID = 5958493423581010491L; - - ClassPrepareEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - /** - * Returns the thread in which this event has occurred. - * - * @return a {@link ThreadReference} which mirrors the event's thread in - * the target VM. - */ - public ThreadReference getThread() { - return ((ClassPrepareEvent)oneEvent).thread(); - } - - - /** - * Returns the reference type for which this event was generated. - * - * @return a {@link ReferenceType} which mirrors the class, interface, or - * array which has been linked. - */ - public ReferenceType getReferenceType() { - return ((ClassPrepareEvent)oneEvent).referenceType(); - } - - @Override - public void notify(JDIListener listener) { - listener.classPrepare(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ClassUnloadEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ClassUnloadEventSet.java deleted file mode 100644 index ad57b70d059..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ClassUnloadEventSet.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.event.*; - -public class ClassUnloadEventSet extends AbstractEventSet { - - private static final long serialVersionUID = 8370341450345835866L; - - ClassUnloadEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - /** - * Returns the name of the class that has been unloaded. - */ - public String getClassName() { - return ((ClassUnloadEvent)oneEvent).className(); - } - - /** - * Returns the JNI-style signature of the class that has been unloaded. - */ - public String getClassSignature() { - return ((ClassUnloadEvent)oneEvent).classSignature(); - } - - @Override - public void notify(JDIListener listener) { - listener.classUnload(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ExceptionEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ExceptionEventSet.java deleted file mode 100644 index d59cce74d49..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ExceptionEventSet.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -public class ExceptionEventSet extends LocatableEventSet { - - private static final long serialVersionUID = 5328140167954640711L; - - ExceptionEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - /** - * Gets the thrown exception object. The exception object is - * an instance of java.lang.Throwable or a subclass in the - * target VM. - * - * @return an {@link ObjectReference} which mirrors the thrown object in - * the target VM. - */ - public ObjectReference getException() { - return ((ExceptionEvent)oneEvent).exception(); - } - - /** - * Gets the location where the exception will be caught. An exception - * is considered to be caught if, at the point of the throw, the - * current location is dynamically enclosed in a try statement that - * handles the exception. (See the JVM specification for details). - * If there is such a try statement, the catch location is the - * first code index of the appropriate catch clause. - *

- * If there are native methods in the call stack at the time of the - * exception, there are important restrictions to note about the - * returned catch location. In such cases, - * it is not possible to predict whether an exception will be handled - * by some native method on the call stack. - * Thus, it is possible that exceptions considered uncaught - * here will, in fact, be handled by a native method and not cause - * termination of the target VM. Also, it cannot be assumed that the - * catch location returned here will ever be reached by the throwing - * thread. If there is - * a native frame between the current location and the catch location, - * the exception might be handled and cleared in that native method - * instead. - * - * @return the {@link Location} where the exception will be caught or null if - * the exception is uncaught. - */ - public Location getCatchLocation() { - return ((ExceptionEvent)oneEvent).catchLocation(); - } - - @Override - public void notify(JDIListener listener) { - listener.exception(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/JDIAdapter.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/JDIAdapter.java deleted file mode 100644 index 056cd0933b5..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/JDIAdapter.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -/** - * The adapter which receives JDI event sets. The methods in this - * class are empty; this class is provided as a convenience for - * easily creating listeners by extending this class and overriding - * only the methods of interest. - */ -public class JDIAdapter implements JDIListener { - - @Override - public void accessWatchpoint(AccessWatchpointEventSet e) { - } - - @Override - public void classPrepare(ClassPrepareEventSet e) { - } - - @Override - public void classUnload(ClassUnloadEventSet e) { - } - - @Override - public void exception(ExceptionEventSet e) { - } - - @Override - public void locationTrigger(LocationTriggerEventSet e) { - } - - @Override - public void modificationWatchpoint(ModificationWatchpointEventSet e) { - } - - @Override - public void threadDeath(ThreadDeathEventSet e) { - } - - @Override - public void threadStart(ThreadStartEventSet e) { - } - - @Override - public void vmDeath(VMDeathEventSet e) { - } - - @Override - public void vmDisconnect(VMDisconnectEventSet e) { - } - - @Override - public void vmStart(VMStartEventSet e) { - } - -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/JDIListener.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/JDIListener.java deleted file mode 100644 index 18a37261ee4..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/JDIListener.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import java.util.EventListener; - -public interface JDIListener extends EventListener { - void accessWatchpoint(AccessWatchpointEventSet e); - void classPrepare(ClassPrepareEventSet e); - void classUnload(ClassUnloadEventSet e); - void exception(ExceptionEventSet e); - void locationTrigger(LocationTriggerEventSet e); - void modificationWatchpoint(ModificationWatchpointEventSet e); - void threadDeath(ThreadDeathEventSet e); - void threadStart(ThreadStartEventSet e); - void vmDeath(VMDeathEventSet e); - void vmDisconnect(VMDisconnectEventSet e); - void vmStart(VMStartEventSet e); -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/LocatableEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/LocatableEventSet.java deleted file mode 100644 index 6b4f607009c..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/LocatableEventSet.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -/** - * Abstract event set for events with location and thread. - */ -public abstract class LocatableEventSet extends AbstractEventSet { - - private static final long serialVersionUID = 1027131209997915620L; - - LocatableEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - /** - * Returns the {@link Location} of this mirror. Depending on context - * and on available debug information, this location will have - * varying precision. - * - * @return the {@link Location} of this mirror. - */ - public Location getLocation() { - return ((LocatableEvent)oneEvent).location(); - } - - /** - * Returns the thread in which this event has occurred. - * - * @return a {@link ThreadReference} which mirrors the event's thread in - * the target VM. - */ - public ThreadReference getThread() { - return ((LocatableEvent)oneEvent).thread(); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/LocationTriggerEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/LocationTriggerEventSet.java deleted file mode 100644 index 3d25a573883..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/LocationTriggerEventSet.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.event.*; - -public class LocationTriggerEventSet extends LocatableEventSet { - - private static final long serialVersionUID = -3674631710485872487L; - - LocationTriggerEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - @Override - public void notify(JDIListener listener) { - listener.locationTrigger(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ModificationWatchpointEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ModificationWatchpointEventSet.java deleted file mode 100644 index 41749efa705..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ModificationWatchpointEventSet.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -public class ModificationWatchpointEventSet extends WatchpointEventSet { - - private static final long serialVersionUID = -680889300856154719L; - - ModificationWatchpointEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - /** - * Value that will be assigned to the field when the instruction - * completes. - */ - public Value getValueToBe() { - return ((ModificationWatchpointEvent)oneEvent).valueToBe(); - } - - @Override - public void notify(JDIListener listener) { - listener.modificationWatchpoint(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ThreadDeathEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ThreadDeathEventSet.java deleted file mode 100644 index 893ec73fa97..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ThreadDeathEventSet.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -public class ThreadDeathEventSet extends AbstractEventSet { - - private static final long serialVersionUID = -8801604712308151331L; - - ThreadDeathEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - /** - * Returns the thread which is terminating. - * - * @return a {@link ThreadReference} which mirrors the event's thread in - * the target VM. - */ - public ThreadReference getThread() { - return ((ThreadDeathEvent)oneEvent).thread(); - } - - @Override - public void notify(JDIListener listener) { - listener.threadDeath(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ThreadStartEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ThreadStartEventSet.java deleted file mode 100644 index 657e9633c9c..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/ThreadStartEventSet.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -public class ThreadStartEventSet extends AbstractEventSet { - - private static final long serialVersionUID = -3802096132294933502L; - - ThreadStartEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - /** - * Returns the thread which has started. - * - * @return a {@link ThreadReference} which mirrors the event's thread in - * the target VM. - */ - public ThreadReference getThread() { - return ((ThreadStartEvent)oneEvent).thread(); - } - - @Override - public void notify(JDIListener listener) { - listener.threadStart(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/VMDeathEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/VMDeathEventSet.java deleted file mode 100644 index b6f7eb31843..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/VMDeathEventSet.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.event.*; - -public class VMDeathEventSet extends AbstractEventSet { - - private static final long serialVersionUID = 1163097303940092229L; - - VMDeathEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - @Override - public void notify(JDIListener listener) { - listener.vmDeath(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/VMDisconnectEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/VMDisconnectEventSet.java deleted file mode 100644 index 5b7dc7953ac..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/VMDisconnectEventSet.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.event.*; - -public class VMDisconnectEventSet extends AbstractEventSet { - - private static final long serialVersionUID = 7968123152344675342L; - - VMDisconnectEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - @Override - public void notify(JDIListener listener) { - listener.vmDisconnect(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/VMStartEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/VMStartEventSet.java deleted file mode 100644 index f9381239fc8..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/VMStartEventSet.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -public class VMStartEventSet extends AbstractEventSet { - - private static final long serialVersionUID = -3384957227835478191L; - - VMStartEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - /** - * Returns the initial thread of the VM which has started. - * - * @return a {@link ThreadReference} which mirrors the event's - * thread in the target VM. - */ - public ThreadReference getThread() { - return ((VMStartEvent)oneEvent).thread(); - } - - @Override - public void notify(JDIListener listener) { - listener.vmStart(this); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/WatchpointEventSet.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/WatchpointEventSet.java deleted file mode 100644 index 76be4acf1da..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/event/WatchpointEventSet.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 1999, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.event; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -public abstract class WatchpointEventSet extends LocatableEventSet { - - private static final long serialVersionUID = 5606285209703845409L; - - WatchpointEventSet(EventSet jdiEventSet) { - super(jdiEventSet); - } - - /** - * Returns the field that is about to be accessed/modified. - * - * @return a {@link Field} which mirrors the field - * in the target VM. - */ - public Field getField() { - return ((WatchpointEvent)oneEvent).field(); - } - - /** - * Returns the object whose field is about to be accessed/modified. - * Return null is the access is to a static field. - * - * @return a {@link ObjectReference} which mirrors the event's - * object in the target VM. - */ - public ObjectReference getObject() { - return ((WatchpointEvent)oneEvent).object(); - } - - /** - * Current value of the field. - */ - public Value getValueCurrent() { - return ((WatchpointEvent)oneEvent).valueCurrent(); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ApplicationTool.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ApplicationTool.java deleted file mode 100644 index 717a5b9390e..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ApplicationTool.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; - -import com.sun.tools.example.debug.bdi.*; - -public class ApplicationTool extends JPanel { - - private static final long serialVersionUID = 310966063293205714L; - - private ExecutionManager runtime; - - private TypeScript script; - - private static final String PROMPT = "Input:"; - - public ApplicationTool(Environment env) { - - super(new BorderLayout()); - - this.runtime = env.getExecutionManager(); - - this.script = new TypeScript(PROMPT, false); // No implicit echo. - this.add(script); - - script.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - runtime.sendLineToApplication(script.readln()); - } - }); - - runtime.addApplicationEchoListener(new TypeScriptOutputListener(script)); - runtime.addApplicationOutputListener(new TypeScriptOutputListener(script)); - runtime.addApplicationErrorListener(new TypeScriptOutputListener(script)); - - //### should clean up on exit! - - } - - /****** - public void setFont(Font f) { - script.setFont(f); - } - ******/ - -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ClassManager.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ClassManager.java deleted file mode 100644 index 6e347376769..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ClassManager.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -public class ClassManager { - - // This class is provided primarily for symmetry with - // SourceManager. Currently, it does very little. - // If we add facilities in the future that require that - // class files be read outside of the VM, for example, to - // provide a disassembled view of a class for bytecode-level - // debugging, the required class file management will be done - // here. - - private SearchPath classPath; - - public ClassManager(Environment env) { - this.classPath = new SearchPath(""); - } - - public ClassManager(SearchPath classPath) { - this.classPath = classPath; - } - - /* - * Set path for access to class files. - */ - - public void setClassPath(SearchPath sp) { - classPath = sp; - } - - /* - * Get path for access to class files. - */ - - public SearchPath getClassPath() { - return classPath; - } - -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ClassTreeTool.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ClassTreeTool.java deleted file mode 100644 index 995c414854c..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ClassTreeTool.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -import java.util.*; - -import javax.swing.*; -import javax.swing.tree.*; -import java.awt.*; -import java.awt.event.*; - -import com.sun.jdi.*; -import com.sun.tools.example.debug.event.*; -import com.sun.tools.example.debug.bdi.*; - -public class ClassTreeTool extends JPanel { - - private static final long serialVersionUID = 526178912591739259L; - - private Environment env; - - private ExecutionManager runtime; - private SourceManager sourceManager; - private ClassManager classManager; - - private JTree tree; - private DefaultTreeModel treeModel; - private ClassTreeNode root; -// private SearchPath sourcePath; - - private CommandInterpreter interpreter; - - private static String HEADING = "CLASSES"; - - public ClassTreeTool(Environment env) { - - super(new BorderLayout()); - - this.env = env; - this.runtime = env.getExecutionManager(); - this.sourceManager = env.getSourceManager(); - - this.interpreter = new CommandInterpreter(env); - - root = createClassTree(HEADING); - treeModel = new DefaultTreeModel(root); - - // Create a tree that allows one selection at a time. - - tree = new JTree(treeModel); - tree.setSelectionModel(new SingleLeafTreeSelectionModel()); - - /****** - // Listen for when the selection changes. - tree.addTreeSelectionListener(new TreeSelectionListener() { - public void valueChanged(TreeSelectionEvent e) { - ClassTreeNode node = (ClassTreeNode) - (e.getPath().getLastPathComponent()); - if (node != null) { - interpreter.executeCommand("view " + node.getReferenceTypeName()); - } - } - }); - ******/ - - MouseListener ml = new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - int selRow = tree.getRowForLocation(e.getX(), e.getY()); - TreePath selPath = tree.getPathForLocation(e.getX(), e.getY()); - if(selRow != -1) { - if(e.getClickCount() == 1) { - ClassTreeNode node = - (ClassTreeNode)selPath.getLastPathComponent(); - // If user clicks on leaf, select it, and issue 'view' command. - if (node.isLeaf()) { - tree.setSelectionPath(selPath); - interpreter.executeCommand("view " + node.getReferenceTypeName()); - } - } - } - } - }; - tree.addMouseListener(ml); - - JScrollPane treeView = new JScrollPane(tree); - add(treeView); - - // Create listener. - ClassTreeToolListener listener = new ClassTreeToolListener(); - runtime.addJDIListener(listener); - runtime.addSessionListener(listener); - - //### remove listeners on exit! - } - - private class ClassTreeToolListener extends JDIAdapter - implements JDIListener, SessionListener { - - // SessionListener - - @Override - public void sessionStart(EventObject e) { - // Get system classes and any others loaded before attaching. - try { - for (ReferenceType type : runtime.allClasses()) { - root.addClass(type); - } - } catch (VMDisconnectedException ee) { - // VM terminated unexpectedly. - } catch (NoSessionException ee) { - // Ignore. Should not happen. - } - } - - @Override - public void sessionInterrupt(EventObject e) {} - @Override - public void sessionContinue(EventObject e) {} - - // JDIListener - - @Override - public void classPrepare(ClassPrepareEventSet e) { - root.addClass(e.getReferenceType()); - } - - @Override - public void classUnload(ClassUnloadEventSet e) { - root.removeClass(e.getClassName()); - } - - @Override - public void vmDisconnect(VMDisconnectEventSet e) { - // Clear contents of this view. - root = createClassTree(HEADING); - treeModel = new DefaultTreeModel(root); - tree.setModel(treeModel); - } - } - - ClassTreeNode createClassTree(String label) { - return new ClassTreeNode(label, null); - } - - class ClassTreeNode extends DefaultMutableTreeNode { - - private String name; - private ReferenceType refTy; // null for package - - ClassTreeNode(String name, ReferenceType refTy) { - this.name = name; - this.refTy = refTy; - } - - @Override - public String toString() { - return name; - } - - public ReferenceType getReferenceType() { - return refTy; - } - - public String getReferenceTypeName() { - return refTy.name(); - } - - private boolean isPackage() { - return (refTy == null); - } - - @Override - public boolean isLeaf() { - return !isPackage(); - } - - public void addClass(ReferenceType refTy) { - addClass(refTy.name(), refTy); - } - - private void addClass(String className, ReferenceType refTy) { - if (className.equals("")) { - return; - } - int pos = className.indexOf('.'); - if (pos < 0) { - insertNode(className, refTy); - } else { - String head = className.substring(0, pos); - String tail = className.substring(pos + 1); - ClassTreeNode child = insertNode(head, null); - child.addClass(tail, refTy); - } - } - - private ClassTreeNode insertNode(String name, ReferenceType refTy) { - for (int i = 0; i < getChildCount(); i++) { - ClassTreeNode child = (ClassTreeNode)getChildAt(i); - int cmp = name.compareTo(child.toString()); - if (cmp == 0) { - // like-named node already exists - return child; - } else if (cmp < 0) { - // insert new node before the child - ClassTreeNode newChild = new ClassTreeNode(name, refTy); - treeModel.insertNodeInto(newChild, this, i); - return newChild; - } - } - // insert new node after last child - ClassTreeNode newChild = new ClassTreeNode(name, refTy); - treeModel.insertNodeInto(newChild, this, getChildCount()); - return newChild; - } - - public void removeClass(String className) { - if (className.equals("")) { - return; - } - int pos = className.indexOf('.'); - if (pos < 0) { - ClassTreeNode child = findNode(className); - if (!isPackage()) { - treeModel.removeNodeFromParent(child); - } - } else { - String head = className.substring(0, pos); - String tail = className.substring(pos + 1); - ClassTreeNode child = findNode(head); - child.removeClass(tail); - if (isPackage() && child.getChildCount() < 1) { - // Prune non-leaf nodes with no children. - treeModel.removeNodeFromParent(child); - } - } - } - - private ClassTreeNode findNode(String name) { - for (int i = 0; i < getChildCount(); i++) { - ClassTreeNode child = (ClassTreeNode)getChildAt(i); - int cmp = name.compareTo(child.toString()); - if (cmp == 0) { - return child; - } else if (cmp > 0) { - // not found, since children are sorted - return null; - } - } - return null; - } - - } - -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/CommandInterpreter.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/CommandInterpreter.java deleted file mode 100644 index fbff95b2703..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/CommandInterpreter.java +++ /dev/null @@ -1,1468 +0,0 @@ -/* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -import java.io.*; -import java.util.*; - -import com.sun.jdi.*; -import com.sun.tools.example.debug.bdi.*; - -public class CommandInterpreter { - - boolean echo; - - Environment env; - - private ContextManager context; - private ExecutionManager runtime; - private ClassManager classManager; - private SourceManager sourceManager; - - private OutputSink out; //### Hack! Should be local in each method used. - private String lastCommand = "help"; - - public CommandInterpreter(Environment env) { - this(env, true); - } - - public CommandInterpreter(Environment env, boolean echo) { - this.env = env; - this.echo = echo; - this.runtime = env.getExecutionManager(); - this.context = env.getContextManager(); - this.classManager = env.getClassManager(); - this.sourceManager = env.getSourceManager(); - } - - private ThreadReference[] threads = null; - - /* - * The numbering of threads is relative to the current set of threads, - * and may be affected by the creation and termination of new threads. - * Commands issued using such thread ids will only give reliable behavior - * relative to what was shown earlier in 'list' commands if the VM is interrupted. - * We need a better scheme. - */ - - private ThreadReference[] threads() throws NoSessionException { - if (threads == null) { - ThreadIterator ti = new ThreadIterator(getDefaultThreadGroup()); - List tlist = new ArrayList(); - while (ti.hasNext()) { - tlist.add(ti.nextThread()); - } - threads = tlist.toArray(new ThreadReference[tlist.size()]); - } - return threads; - } - - private ThreadReference findThread(String idToken) throws NoSessionException { - String id; - ThreadReference thread = null; - if (idToken.startsWith("t@")) { - id = idToken.substring(2); - } else { - id = idToken; - } - try { - ThreadReference[] threads = threads(); - long threadID = Long.parseLong(id, 16); - for (ThreadReference thread2 : threads) { - if (thread2.uniqueID() == threadID) { - thread = thread2; - break; - } - } - if (thread == null) { - //env.failure("No thread for id \"" + idToken + "\""); - env.failure("\"" + idToken + "\" is not a valid thread id."); - } - } catch (NumberFormatException e) { - env.error("Thread id \"" + idToken + "\" is ill-formed."); - thread = null; - } - return thread; - } - - private ThreadIterator allThreads() throws NoSessionException { - threads = null; - //### Why not use runtime.allThreads().iterator() ? - return new ThreadIterator(runtime.topLevelThreadGroups()); - } - - private ThreadIterator currentThreadGroupThreads() throws NoSessionException { - threads = null; - return new ThreadIterator(getDefaultThreadGroup()); - } - - private ThreadGroupIterator allThreadGroups() throws NoSessionException { - threads = null; - return new ThreadGroupIterator(runtime.topLevelThreadGroups()); - } - - private ThreadGroupReference defaultThreadGroup; - - private ThreadGroupReference getDefaultThreadGroup() throws NoSessionException { - if (defaultThreadGroup == null) { - defaultThreadGroup = runtime.systemThreadGroup(); - } - return defaultThreadGroup; - } - - private void setDefaultThreadGroup(ThreadGroupReference tg) { - defaultThreadGroup = tg; - } - - /* - * Command handlers. - */ - - // Command: classes - - private void commandClasses() throws NoSessionException { - OutputSink out = env.getOutputSink(); - //out.println("** classes list **"); - for (ReferenceType refType : runtime.allClasses()) { - out.println(refType.name()); - } - out.show(); - } - - - // Command: methods - - private void commandMethods(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - env.error("No class specified."); - return; - } - String idClass = t.nextToken(); - ReferenceType cls = findClass(idClass); - if (cls != null) { - List methods = cls.allMethods(); - OutputSink out = env.getOutputSink(); - for (int i = 0; i < methods.size(); i++) { - Method method = methods.get(i); - out.print(method.declaringType().name() + " " + - method.name() + "("); - Iterator it = method.argumentTypeNames().iterator(); - if (it.hasNext()) { - while (true) { - out.print(it.next()); - if (!it.hasNext()) { - break; - } - out.print(", "); - } - } - out.println(")"); - } - out.show(); - } else { - //### Should validate class name syntax. - env.failure("\"" + idClass + "\" is not a valid id or class name."); - } - } - - private ReferenceType findClass(String pattern) throws NoSessionException { - List results = runtime.findClassesMatchingPattern(pattern); - if (results.size() > 0) { - //### Should handle multiple results sensibly. - return results.get(0); - } - return null; - } - - // Command: threads - - private void commandThreads(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - OutputSink out = env.getOutputSink(); - printThreadGroup(out, getDefaultThreadGroup(), 0); - out.show(); - return; - } - String name = t.nextToken(); - ThreadGroupReference tg = findThreadGroup(name); - if (tg == null) { - env.failure(name + " is not a valid threadgroup name."); - } else { - OutputSink out = env.getOutputSink(); - printThreadGroup(out, tg, 0); - out.show(); - } - } - - private ThreadGroupReference findThreadGroup(String name) throws NoSessionException { - //### Issue: Uniqueness of thread group names is not enforced. - ThreadGroupIterator tgi = allThreadGroups(); - while (tgi.hasNext()) { - ThreadGroupReference tg = tgi.nextThreadGroup(); - if (tg.name().equals(name)) { - return tg; - } - } - return null; - } - - private int printThreadGroup(OutputSink out, ThreadGroupReference tg, int iThread) { - out.println("Group " + tg.name() + ":"); - List tlist = tg.threads(); - int maxId = 0; - int maxName = 0; - for (int i = 0 ; i < tlist.size() ; i++) { - ThreadReference thr = tlist.get(i); - int len = Utils.description(thr).length(); - if (len > maxId) { - maxId = len; - } - String name = thr.name(); - int iDot = name.lastIndexOf('.'); - if (iDot >= 0 && name.length() > iDot) { - name = name.substring(iDot + 1); - } - if (name.length() > maxName) { - maxName = name.length(); - } - } - String maxNumString = String.valueOf(iThread + tlist.size()); - int maxNumDigits = maxNumString.length(); - for (int i = 0 ; i < tlist.size() ; i++) { - ThreadReference thr = tlist.get(i); - char buf[] = new char[80]; - for (int j = 0; j < 79; j++) { - buf[j] = ' '; - } - buf[79] = '\0'; - StringBuilder sbOut = new StringBuilder(); - sbOut.append(buf); - - // Right-justify the thread number at start of output string - String numString = String.valueOf(iThread + i + 1); - sbOut.insert(maxNumDigits - numString.length(), - numString); - sbOut.insert(maxNumDigits, "."); - - int iBuf = maxNumDigits + 2; - sbOut.insert(iBuf, Utils.description(thr)); - iBuf += maxId + 1; - String name = thr.name(); - int iDot = name.lastIndexOf('.'); - if (iDot >= 0 && name.length() > iDot) { - name = name.substring(iDot + 1); - } - sbOut.insert(iBuf, name); - iBuf += maxName + 1; - sbOut.insert(iBuf, Utils.getStatus(thr)); - sbOut.setLength(79); - out.println(sbOut.toString()); - } - for (ThreadGroupReference tg0 : tg.threadGroups()) { - if (!tg.equals(tg0)) { // TODO ref mgt - iThread += printThreadGroup(out, tg0, iThread + tlist.size()); - } - } - return tlist.size(); - } - - // Command: threadgroups - - private void commandThreadGroups() throws NoSessionException { - ThreadGroupIterator it = allThreadGroups(); - int cnt = 0; - OutputSink out = env.getOutputSink(); - while (it.hasNext()) { - ThreadGroupReference tg = it.nextThreadGroup(); - ++cnt; - out.println("" + cnt + ". " + Utils.description(tg) + " " + tg.name()); - } - out.show(); - } - - // Command: thread - - private void commandThread(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - env.error("Thread number not specified."); - return; - } - ThreadReference thread = findThread(t.nextToken()); - if (thread != null) { - //### Should notify user. - context.setCurrentThread(thread); - } - } - - // Command: threadgroup - - private void commandThreadGroup(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - env.error("Threadgroup name not specified."); - return; - } - String name = t.nextToken(); - ThreadGroupReference tg = findThreadGroup(name); - if (tg == null) { - env.failure(name + " is not a valid threadgroup name."); - } else { - //### Should notify user. - setDefaultThreadGroup(tg); - } - } - - // Command: run - - private void commandRun(StringTokenizer t) throws NoSessionException { - if (doLoad(false, t)) { - env.notice("Running ..."); - } - } - - // Command: load - - private void commandLoad(StringTokenizer t) throws NoSessionException { - if (doLoad(true, t)) {} - } - - private boolean doLoad(boolean suspended, - StringTokenizer t) throws NoSessionException { - - String clname; - - if (!t.hasMoreTokens()) { - clname = context.getMainClassName(); - if (!clname.equals("")) { - // Run from prevously-set class name. - try { - String vmArgs = context.getVmArguments(); - runtime.run(suspended, - vmArgs, - clname, - context.getProgramArguments()); - return true; - } catch (VMLaunchFailureException e) { - env.failure("Attempt to launch main class \"" + clname + "\" failed."); - } - } else { - env.failure("No main class specified and no current default defined."); - } - } else { - clname = t.nextToken(); - StringBuilder str = new StringBuilder(); - // Allow VM arguments to be specified here? - while (t.hasMoreTokens()) { - String tok = t.nextToken(); - str.append(tok); - if (t.hasMoreTokens()) { - str.append(' '); - } - } - String args = str.toString(); - try { - String vmArgs = context.getVmArguments(); - runtime.run(suspended, vmArgs, clname, args); - context.setMainClassName(clname); - //context.setVmArguments(vmArgs); - context.setProgramArguments(args); - return true; - } catch (VMLaunchFailureException e) { - env.failure("Attempt to launch main class \"" + clname + "\" failed."); - } - } - return false; - } - - // Command: connect - - private void commandConnect(StringTokenizer t) { - try { - LaunchTool.queryAndLaunchVM(runtime); - } catch (VMLaunchFailureException e) { - env.failure("Attempt to connect failed."); - } - } - - // Command: attach - - private void commandAttach(StringTokenizer t) { - String portName; - if (!t.hasMoreTokens()) { - portName = context.getRemotePort(); - if (!portName.equals("")) { - try { - runtime.attach(portName); - } catch (VMLaunchFailureException e) { - env.failure("Attempt to attach to port \"" + portName + "\" failed."); - } - } else { - env.failure("No port specified and no current default defined."); - } - } else { - portName = t.nextToken(); - try { - runtime.attach(portName); - } catch (VMLaunchFailureException e) { - env.failure("Attempt to attach to port \"" + portName + "\" failed."); - } - context.setRemotePort(portName); - } - } - - // Command: detach - - private void commandDetach(StringTokenizer t) throws NoSessionException { - runtime.detach(); - } - - // Command: interrupt - - private void commandInterrupt(StringTokenizer t) throws NoSessionException { - runtime.interrupt(); - } - - // Command: suspend - - private void commandSuspend(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - // Suspend all threads in the current thread group. - //### Issue: help message says default is all threads. - //### Behavior here agrees with 'jdb', however. - ThreadIterator ti = currentThreadGroupThreads(); - while (ti.hasNext()) { - // TODO - don't suspend debugger threads - ti.nextThread().suspend(); - } - env.notice("All (non-system) threads suspended."); - } else { - while (t.hasMoreTokens()) { - ThreadReference thread = findThread(t.nextToken()); - if (thread != null) { - //thread.suspend(); - runtime.suspendThread(thread); - } - } - } - } - - // Command: resume - - private void commandResume(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - // Suspend all threads in the current thread group. - //### Issue: help message says default is all threads. - //### Behavior here agrees with 'jdb', however. - ThreadIterator ti = currentThreadGroupThreads(); - while (ti.hasNext()) { - // TODO - don't suspend debugger threads - ti.nextThread().resume(); - } - env.notice("All threads resumed."); - } else { - while (t.hasMoreTokens()) { - ThreadReference thread = findThread(t.nextToken()); - if (thread != null) { - //thread.resume(); - runtime.resumeThread(thread); - } - } - } - } - - // Command: cont - - private void commandCont() throws NoSessionException { - try { - runtime.go(); - } catch (VMNotInterruptedException e) { - //### failure? - env.notice("Target VM is already running."); - } - } - - // Command: step - - private void commandStep(StringTokenizer t) throws NoSessionException{ - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.failure("No current thread."); - return; - } - try { - if (t.hasMoreTokens() && - t.nextToken().toLowerCase().equals("up")) { - runtime.stepOut(current); - } else { - runtime.stepIntoLine(current); - } - } catch (AbsentInformationException e) { - env.failure("No linenumber information available -- " + - "Try \"stepi\" to step by instructions."); - } - } - - // Command: stepi - - private void commandStepi() throws NoSessionException { - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.failure("No current thread."); - return; - } - runtime.stepIntoInstruction(current); - } - - // Command: next - - private void commandNext() throws NoSessionException { - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.failure("No current thread."); - return; - } - try { - runtime.stepOverLine(current); - } catch (AbsentInformationException e) { - env.failure("No linenumber information available -- " + - "Try \"nexti\" to step by instructions."); - } - } - - // Command: nexti (NEW) - - private void commandNexti() throws NoSessionException { - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.failure("No current thread."); - return; - } - runtime.stepOverInstruction(current); - } - - // Command: kill - - private void commandKill(StringTokenizer t) throws NoSessionException { - //### Should change the way in which thread ids and threadgroup names - //### are distinguished. - if (!t.hasMoreTokens()) { - env.error("Usage: kill or "); - return; - } - while (t.hasMoreTokens()) { - String idToken = t.nextToken(); - ThreadReference thread = findThread(idToken); - if (thread != null) { - runtime.stopThread(thread); - env.notice("Thread " + thread.name() + " killed."); - return; - } else { - /* Check for threadgroup name, NOT skipping "system". */ - //### Should skip "system"? Classic 'jdb' does this. - //### Should deal with possible non-uniqueness of threadgroup names. - ThreadGroupIterator itg = allThreadGroups(); - while (itg.hasNext()) { - ThreadGroupReference tg = itg.nextThreadGroup(); - if (tg.name().equals(idToken)) { - ThreadIterator it = new ThreadIterator(tg); - while (it.hasNext()) { - runtime.stopThread(it.nextThread()); - } - env.notice("Threadgroup " + tg.name() + "killed."); - return; - } - } - env.failure("\"" + idToken + - "\" is not a valid threadgroup or id."); - } - } - } - - - /************* - // TODO - private void commandCatchException(StringTokenizer t) throws NoSessionException {} - // TODO - private void commandIgnoreException(StringTokenizer t) throws NoSessionException {} - *************/ - - // Command: up - - //### Print current frame after command? - - int readCount(StringTokenizer t) { - int cnt = 1; - if (t.hasMoreTokens()) { - String idToken = t.nextToken(); - try { - cnt = Integer.valueOf(idToken).intValue(); - } catch (NumberFormatException e) { - cnt = -1; - } - } - return cnt; - } - - void commandUp(StringTokenizer t) throws NoSessionException { - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.failure("No current thread."); - return; - } - int nLevels = readCount(t); - if (nLevels <= 0) { - env.error("usage: up [n frames]"); - return; - } - try { - int delta = context.moveCurrentFrameIndex(current, -nLevels); - if (delta == 0) { - env.notice("Already at top of stack."); - } else if (-delta < nLevels) { - env.notice("Moved up " + delta + " frames to top of stack."); - } - } catch (VMNotInterruptedException e) { - env.failure("Target VM must be in interrupted state."); - } - } - - private void commandDown(StringTokenizer t) throws NoSessionException { - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.failure("No current thread."); - return; - } - int nLevels = readCount(t); - if (nLevels <= 0) { - env.error("usage: down [n frames]"); - return; - } - try { - int delta = context.moveCurrentFrameIndex(current, nLevels); - if (delta == 0) { - env.notice("Already at bottom of stack."); - } else if (delta < nLevels) { - env.notice("Moved down " + delta + " frames to bottom of stack."); - } - } catch (VMNotInterruptedException e) { - env.failure("Target VM must be in interrupted state."); - } - } - - // Command: frame - - private void commandFrame(StringTokenizer t) throws NoSessionException { - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.failure("No current thread."); - return; - } - if (!t.hasMoreTokens()) { - env.error("usage: frame "); - return; - } - String idToken = t.nextToken(); - int n; - try { - n = Integer.valueOf(idToken).intValue(); - } catch (NumberFormatException e) { - n = 0; - } - if (n <= 0) { - env.error("use positive frame index"); - return; - } - try { - int delta = context.setCurrentFrameIndex(current, n); - if (delta == 0) { - env.notice("Frame unchanged."); - } else if (delta < 0) { - env.notice("Moved up " + -delta + " frames."); - } else { - env.notice("Moved down " + delta + " frames."); - } - } catch (VMNotInterruptedException e) { - env.failure("Target VM must be in interrupted state."); - } - } - - // Command: where - - //### Should we insist that VM be interrupted here? - //### There is an inconsistency between the 'where' command - //### and 'up' and 'down' in this respect. - - private void commandWhere(StringTokenizer t, boolean showPC) - throws NoSessionException { - ThreadReference current = context.getCurrentThread(); - if (!t.hasMoreTokens()) { - if (current == null) { - env.error("No thread specified."); - return; - } - dumpStack(current, showPC); - } else { - String token = t.nextToken(); - if (token.toLowerCase().equals("all")) { - ThreadIterator it = allThreads(); - while (it.hasNext()) { - ThreadReference thread = it.next(); - out.println(thread.name() + ": "); - dumpStack(thread, showPC); - } - } else { - ThreadReference thread = findThread(t.nextToken()); - //### Do we want to set current thread here? - //### Should notify user of change. - if (thread != null) { - context.setCurrentThread(thread); - } - dumpStack(thread, showPC); - } - } - } - - private void dumpStack(ThreadReference thread, boolean showPC) { - //### Check for these. - //env.failure("Thread no longer exists."); - //env.failure("Target VM must be in interrupted state."); - //env.failure("Current thread isn't suspended."); - //### Should handle extremely long stack traces sensibly for user. - List stack = null; - try { - stack = thread.frames(); - } catch (IncompatibleThreadStateException e) { - env.failure("Thread is not suspended."); - } - //### Fix this! - //### Previously mishandled cases where thread was not current. - //### Now, prints all of the stack regardless of current frame. - int frameIndex = 0; - //int frameIndex = context.getCurrentFrameIndex(); - if (stack == null) { - env.failure("Thread is not running (no stack)."); - } else { - OutputSink out = env.getOutputSink(); - int nFrames = stack.size(); - for (int i = frameIndex; i < nFrames; i++) { - StackFrame frame = stack.get(i); - Location loc = frame.location(); - Method meth = loc.method(); - out.print(" [" + (i + 1) + "] "); - out.print(meth.declaringType().name()); - out.print('.'); - out.print(meth.name()); - out.print(" ("); - if (meth.isNative()) { - out.print("native method"); - } else if (loc.lineNumber() != -1) { - try { - out.print(loc.sourceName()); - } catch (AbsentInformationException e) { - out.print(""); - } - out.print(':'); - out.print(loc.lineNumber()); - } - out.print(')'); - if (showPC) { - long pc = loc.codeIndex(); - if (pc != -1) { - out.print(", pc = " + pc); - } - } - out.println(); - } - out.show(); - } - } - - private void listEventRequests() throws NoSessionException { - // Print set breakpoints - List specs = runtime.eventRequestSpecs(); - if (specs.isEmpty()) { - env.notice("No breakpoints/watchpoints/exceptions set."); - } else { - OutputSink out = env.getOutputSink(); - out.println("Current breakpoints/watchpoints/exceptions set:"); - for (EventRequestSpec bp : specs) { - out.println("\t" + bp); - } - out.show(); - } - } - - private BreakpointSpec parseBreakpointSpec(String bptSpec) { - StringTokenizer t = new StringTokenizer(bptSpec); - BreakpointSpec bpSpec = null; -// try { - String token = t.nextToken("@:( \t\n\r"); - // We can't use hasMoreTokens here because it will cause any leading - // paren to be lost. - String rest; - try { - rest = t.nextToken("").trim(); - } catch (NoSuchElementException e) { - rest = null; - } - if ((rest != null) && rest.startsWith("@")) { - t = new StringTokenizer(rest.substring(1)); - String sourceName = token; - String lineToken = t.nextToken(); - int lineNumber = Integer.valueOf(lineToken).intValue(); - if (t.hasMoreTokens()) { - return null; - } - bpSpec = runtime.createSourceLineBreakpoint(sourceName, - lineNumber); - } else if ((rest != null) && rest.startsWith(":")) { - t = new StringTokenizer(rest.substring(1)); - String classId = token; - String lineToken = t.nextToken(); - int lineNumber = Integer.valueOf(lineToken).intValue(); - if (t.hasMoreTokens()) { - return null; - } - bpSpec = runtime.createClassLineBreakpoint(classId, lineNumber); - } else { - // Try stripping method from class.method token. - int idot = token.lastIndexOf('.'); - if ( (idot <= 0) || /* No dot or dot in first char */ - (idot >= token.length() - 1) ) { /* dot in last char */ - return null; - } - String methodName = token.substring(idot + 1); - String classId = token.substring(0, idot); - List argumentList = null; - if (rest != null) { - if (!rest.startsWith("(") || !rest.endsWith(")")) { - //### Should throw exception with error message - //out.println("Invalid method specification: " - // + methodName + rest); - return null; - } - // Trim the parens - //### What about spaces in arglist? - rest = rest.substring(1, rest.length() - 1); - argumentList = new ArrayList(); - t = new StringTokenizer(rest, ","); - while (t.hasMoreTokens()) { - argumentList.add(t.nextToken()); - } - } - bpSpec = runtime.createMethodBreakpoint(classId, - methodName, - argumentList); - } -// } catch (Exception e) { -// env.error("Exception attempting to create breakpoint: " + e); -// return null; -// } - return bpSpec; - } - - private void commandStop(StringTokenizer t) throws NoSessionException { - String token; - - if (!t.hasMoreTokens()) { - listEventRequests(); - } else { - token = t.nextToken(); - // Ignore optional "at" or "in" token. - // Allowed for backward compatibility. - if (token.equals("at") || token.equals("in")) { - if (t.hasMoreTokens()) { - token = t.nextToken(); - } else { - env.error("Missing breakpoint specification."); - return; - } - } - BreakpointSpec bpSpec = parseBreakpointSpec(token); - if (bpSpec != null) { - //### Add sanity-checks for deferred breakpoint. - runtime.install(bpSpec); - } else { - env.error("Ill-formed breakpoint specification."); - } - } - } - - private void commandClear(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - // Print set breakpoints - listEventRequests(); - return; - } - //### need 'clear all' - BreakpointSpec bpSpec = parseBreakpointSpec(t.nextToken()); - if (bpSpec != null) { - List specs = runtime.eventRequestSpecs(); - - if (specs.isEmpty()) { - env.notice("No breakpoints set."); - } else { - List toDelete = new ArrayList(); - for (EventRequestSpec spec : specs) { - if (spec.equals(bpSpec)) { - toDelete.add(spec); - } - } - // The request used for matching should be found - if (toDelete.size() <= 1) { - env.notice("No matching breakpoint set."); - } - for (EventRequestSpec spec : toDelete) { - runtime.delete(spec); - } - } - } else { - env.error("Ill-formed breakpoint specification."); - } - } - - // Command: list - - private void commandList(StringTokenizer t) throws NoSessionException { - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.error("No thread specified."); - return; - } - Location loc; - try { - StackFrame frame = context.getCurrentFrame(current); - if (frame == null) { - env.failure("Thread has not yet begun execution."); - return; - } - loc = frame.location(); - } catch (VMNotInterruptedException e) { - env.failure("Target VM must be in interrupted state."); - return; - } - SourceModel source = sourceManager.sourceForLocation(loc); - if (source == null) { - if (loc.method().isNative()) { - env.failure("Current method is native."); - return; - } - env.failure("No source available for " + Utils.locationString(loc) + "."); - return; - } - ReferenceType refType = loc.declaringType(); - int lineno = loc.lineNumber(); - if (t.hasMoreTokens()) { - String id = t.nextToken(); - // See if token is a line number. - try { - lineno = Integer.valueOf(id).intValue(); - } catch (NumberFormatException nfe) { - // It isn't -- see if it's a method name. - List meths = refType.methodsByName(id); - if (meths == null || meths.size() == 0) { - env.failure(id + - " is not a valid line number or " + - "method name for class " + - refType.name()); - return; - } else if (meths.size() > 1) { - env.failure(id + - " is an ambiguous method name in" + - refType.name()); - return; - } - loc = meths.get(0).location(); - lineno = loc.lineNumber(); - } - } - int startLine = (lineno > 4) ? lineno - 4 : 1; - int endLine = startLine + 9; - String sourceLine = source.sourceLine(lineno); - if (sourceLine == null) { - env.failure("" + - lineno + - " is an invalid line number for " + - refType.name()); - } else { - OutputSink out = env.getOutputSink(); - for (int i = startLine; i <= endLine; i++) { - sourceLine = source.sourceLine(i); - if (sourceLine == null) { - break; - } - out.print(i); - out.print("\t"); - if (i == lineno) { - out.print("=> "); - } else { - out.print(" "); - } - out.println(sourceLine); - } - out.show(); - } - } - - // Command: use - // Get or set the source file path list. - - private void commandUse(StringTokenizer t) { - if (!t.hasMoreTokens()) { - out.println(sourceManager.getSourcePath().asString()); - } else { - //### Should throw exception for invalid path. - //### E.g., vetoable property change. - sourceManager.setSourcePath(new SearchPath(t.nextToken())); - } - } - - // Command: sourcepath - // Get or set the source file path list. (Alternate to 'use'.) - - private void commandSourcepath(StringTokenizer t) { - if (!t.hasMoreTokens()) { - out.println(sourceManager.getSourcePath().asString()); - } else { - //### Should throw exception for invalid path. - //### E.g., vetoable property change. - sourceManager.setSourcePath(new SearchPath(t.nextToken())); - } - } - - // Command: classpath - // Get or set the class file path list. - - private void commandClasspath(StringTokenizer t) { - if (!t.hasMoreTokens()) { - out.println(classManager.getClassPath().asString()); - } else { - //### Should throw exception for invalid path. - //### E.g., vetoable property change. - classManager.setClassPath(new SearchPath(t.nextToken())); - } - } - - // Command: view - // Display source for source file or class. - - private void commandView(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - env.error("Argument required"); - } else { - String name = t.nextToken(); - if (name.endsWith(".java") || - name.indexOf(File.separatorChar) >= 0) { - env.viewSource(name); - } else { - //### JDI crashes taking line number for class. - /***** - ReferenceType cls = findClass(name); - if (cls != null) { - env.viewLocation(cls.location()); - } else { - env.failure("No such class"); - } - *****/ - String fileName = name.replace('.', File.separatorChar) + ".java"; - env.viewSource(fileName); - } - } - } - - // Command: locals - // Print all local variables in current stack frame. - - private void commandLocals() throws NoSessionException { - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.failure("No default thread specified: " + - "use the \"thread\" command first."); - return; - } - StackFrame frame; - try { - frame = context.getCurrentFrame(current); - if (frame == null) { - env.failure("Thread has not yet created any stack frames."); - return; - } - } catch (VMNotInterruptedException e) { - env.failure("Target VM must be in interrupted state."); - return; - } - - List vars; - try { - vars = frame.visibleVariables(); - if (vars == null || vars.size() == 0) { - env.failure("No local variables"); - return; - } - } catch (AbsentInformationException e) { - env.failure("Local variable information not available." + - " Compile with -g to generate variable information"); - return; - } - - OutputSink out = env.getOutputSink(); - out.println("Method arguments:"); - for (LocalVariable var : vars) { - if (var.isArgument()) { - printVar(out, var, frame); - } - } - out.println("Local variables:"); - for (LocalVariable var : vars) { - if (!var.isArgument()) { - printVar(out, var, frame); - } - } - out.show(); - return; - } - - /** - * Command: monitor - * Monitor an expression - */ - private void commandMonitor(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - env.error("Argument required"); - } else { - env.getMonitorListModel().add(t.nextToken("")); - } - } - - /** - * Command: unmonitor - * Unmonitor an expression - */ - private void commandUnmonitor(StringTokenizer t) throws NoSessionException { - if (!t.hasMoreTokens()) { - env.error("Argument required"); - } else { - env.getMonitorListModel().remove(t.nextToken("")); - } - } - - // Print a stack variable. - - private void printVar(OutputSink out, LocalVariable var, StackFrame frame) { - out.print(" " + var.name()); - if (var.isVisible(frame)) { - Value val = frame.getValue(var); - out.println(" = " + val.toString()); - } else { - out.println(" is not in scope"); - } - } - - // Command: print - // Evaluate an expression. - - private void commandPrint(StringTokenizer t, boolean dumpObject) throws NoSessionException { - if (!t.hasMoreTokens()) { - //### Probably confused if expresion contains whitespace. - env.error("No expression specified."); - return; - } - ThreadReference current = context.getCurrentThread(); - if (current == null) { - env.failure("No default thread specified: " + - "use the \"thread\" command first."); - return; - } - StackFrame frame; - try { - frame = context.getCurrentFrame(current); - if (frame == null) { - env.failure("Thread has not yet created any stack frames."); - return; - } - } catch (VMNotInterruptedException e) { - env.failure("Target VM must be in interrupted state."); - return; - } - while (t.hasMoreTokens()) { - String expr = t.nextToken(""); - Value val = null; - try { - val = runtime.evaluate(frame, expr); - } catch(Exception e) { - env.error("Exception: " + e); - //### Fix this! - } - if (val == null) { - return; // Error message already printed - } - OutputSink out = env.getOutputSink(); - if (dumpObject && (val instanceof ObjectReference) && - !(val instanceof StringReference)) { - ObjectReference obj = (ObjectReference)val; - ReferenceType refType = obj.referenceType(); - out.println(expr + " = " + val.toString() + " {"); - dump(out, obj, refType, refType); - out.println("}"); - } else { - out.println(expr + " = " + val.toString()); - } - out.show(); - } - } - - private void dump(OutputSink out, - ObjectReference obj, ReferenceType refType, - ReferenceType refTypeBase) { - for (Field field : refType.fields()) { - out.print(" "); - if (!refType.equals(refTypeBase)) { - out.print(refType.name() + "."); - } - out.print(field.name() + ": "); - Object o = obj.getValue(field); - out.println((o == null) ? "null" : o.toString()); // Bug ID 4374471 - } - if (refType instanceof ClassType) { - ClassType sup = ((ClassType)refType).superclass(); - if (sup != null) { - dump(out, obj, sup, refTypeBase); - } - } else if (refType instanceof InterfaceType) { - for (InterfaceType sup : ((InterfaceType)refType).superinterfaces()) { - dump(out, obj, sup, refTypeBase); - } - } - } - - /* - * Display help message. - */ - - private void help() { - out.println("** command list **"); - out.println("threads [threadgroup] -- list threads"); - out.println("thread -- set default thread"); - out.println("suspend [thread id(s)] -- suspend threads (default: all)"); - out.println("resume [thread id(s)] -- resume threads (default: all)"); - out.println("where [thread id] | all -- dump a thread's stack"); - out.println("wherei [thread id] | all -- dump a thread's stack, with pc info"); - out.println("threadgroups -- list threadgroups"); - out.println("threadgroup -- set current threadgroup\n"); -// out.println("print -- print value of expression"); - out.println("dump -- print all object information\n"); -// out.println("eval -- evaluate expression (same as print)"); - out.println("locals -- print all local variables in current stack frame\n"); - out.println("classes -- list currently known classes"); - out.println("methods -- list a class's methods\n"); - out.println("stop [in] .[(argument_type,...)] -- set a breakpoint in a method"); - out.println("stop [at] : -- set a breakpoint at a line"); - out.println("up [n frames] -- move up a thread's stack"); - out.println("down [n frames] -- move down a thread's stack"); - out.println("frame -- to a frame"); - out.println("clear .[(argument_type,...)] -- clear a breakpoint in a method"); - out.println("clear : -- clear a breakpoint at a line"); - out.println("clear -- list breakpoints"); - out.println("step -- execute current line"); - out.println("step up -- execute until the current method returns to its caller"); - out.println("stepi -- execute current instruction"); - out.println("next -- step one line (step OVER calls)"); - out.println("nexti -- step one instruction (step OVER calls)"); - out.println("cont -- continue execution from breakpoint\n"); -// out.println("catch -- break for the specified exception"); -// out.println("ignore -- ignore when the specified exception\n"); - out.println("view classname|filename -- display source file"); - out.println("list [line number|method] -- print source code context at line or method"); - out.println("use -- display or change the source path\n"); -//### new - out.println("sourcepath -- display or change the source path\n"); -//### new - out.println("classpath -- display or change the class path\n"); - out.println("monitor -- evaluate an expression each time the program stops\n"); - out.println("unmonitor -- delete a monitor\n"); - out.println("read -- read and execute a command file\n"); -// out.println("memory -- report memory usage"); -// out.println("gc -- free unused objects\n"); - out.println("run [args] -- start execution of a Java class"); - out.println("run -- re-execute last class run"); - out.println("load [args] -- start execution of a Java class, initially suspended"); - out.println("load -- re-execute last class run, initially suspended"); - out.println("attach -- debug existing process\n"); - out.println("detach -- detach from debuggee process\n"); - out.println("kill -- kill a thread or threadgroup\n"); - out.println("!! -- repeat last command"); - out.println("help (or ?) -- list commands"); - out.println("exit (or quit) -- exit debugger"); - } - - /* - * Execute a command. - */ - - public void executeCommand(String command) { - //### Treatment of 'out' here is dirty... - out = env.getOutputSink(); - if (echo) { - out.println(">>> " + command); - } - StringTokenizer t = new StringTokenizer(command); - try { - String cmd; - if (t.hasMoreTokens()) { - cmd = t.nextToken().toLowerCase(); - lastCommand = cmd; - } else { - cmd = lastCommand; - } - if (cmd.equals("print")) { - commandPrint(t, false); - } else if (cmd.equals("eval")) { - commandPrint(t, false); - } else if (cmd.equals("dump")) { - commandPrint(t, true); - } else if (cmd.equals("locals")) { - commandLocals(); - } else if (cmd.equals("classes")) { - commandClasses(); - } else if (cmd.equals("methods")) { - commandMethods(t); - } else if (cmd.equals("threads")) { - commandThreads(t); - } else if (cmd.equals("thread")) { - commandThread(t); - } else if (cmd.equals("suspend")) { - commandSuspend(t); - } else if (cmd.equals("resume")) { - commandResume(t); - } else if (cmd.equals("cont")) { - commandCont(); - } else if (cmd.equals("threadgroups")) { - commandThreadGroups(); - } else if (cmd.equals("threadgroup")) { - commandThreadGroup(t); - } else if (cmd.equals("run")) { - commandRun(t); - } else if (cmd.equals("load")) { - commandLoad(t); - } else if (cmd.equals("connect")) { - commandConnect(t); - } else if (cmd.equals("attach")) { - commandAttach(t); - } else if (cmd.equals("detach")) { - commandDetach(t); - } else if (cmd.equals("interrupt")) { - commandInterrupt(t); -//### Not implemented. -// } else if (cmd.equals("catch")) { -// commandCatchException(t); -//### Not implemented. -// } else if (cmd.equals("ignore")) { -// commandIgnoreException(t); - } else if (cmd.equals("step")) { - commandStep(t); - } else if (cmd.equals("stepi")) { - commandStepi(); - } else if (cmd.equals("next")) { - commandNext(); - } else if (cmd.equals("nexti")) { - commandNexti(); - } else if (cmd.equals("kill")) { - commandKill(t); - } else if (cmd.equals("where")) { - commandWhere(t, false); - } else if (cmd.equals("wherei")) { - commandWhere(t, true); - } else if (cmd.equals("up")) { - commandUp(t); - } else if (cmd.equals("down")) { - commandDown(t); - } else if (cmd.equals("frame")) { - commandFrame(t); - } else if (cmd.equals("stop")) { - commandStop(t); - } else if (cmd.equals("clear")) { - commandClear(t); - } else if (cmd.equals("list")) { - commandList(t); - } else if (cmd.equals("use")) { - commandUse(t); - } else if (cmd.equals("sourcepath")) { - commandSourcepath(t); - } else if (cmd.equals("classpath")) { - commandClasspath(t); - } else if (cmd.equals("monitor")) { - commandMonitor(t); - } else if (cmd.equals("unmonitor")) { - commandUnmonitor(t); - } else if (cmd.equals("view")) { - commandView(t); -// } else if (cmd.equals("read")) { -// readCommand(t); - } else if (cmd.equals("help") || cmd.equals("?")) { - help(); - } else if (cmd.equals("quit") || cmd.equals("exit")) { - try { - runtime.detach(); - } catch (NoSessionException e) { - // ignore - } - env.terminate(); - } else { - //### Dubious repeat-count feature inherited from 'jdb' - if (t.hasMoreTokens()) { - try { - int repeat = Integer.parseInt(cmd); - String subcom = t.nextToken(""); - while (repeat-- > 0) { - executeCommand(subcom); - } - return; - } catch (NumberFormatException exc) { - } - } - out.println("huh? Try help..."); - out.flush(); - } - } catch (NoSessionException e) { - out.println("There is no currently attached VM session."); - out.flush(); - } catch (Exception e) { - out.println("Internal exception: " + e.toString()); - out.flush(); - System.out.println("JDB internal exception: " + e.toString()); - e.printStackTrace(); - } - out.show(); - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/CommandTool.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/CommandTool.java deleted file mode 100644 index d010ec2f56b..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/CommandTool.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -import java.io.*; -import java.util.*; - -import javax.swing.*; -import java.awt.BorderLayout; -import java.awt.event.*; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -import com.sun.tools.example.debug.bdi.*; -import com.sun.tools.example.debug.event.*; - -public class CommandTool extends JPanel { - - private static final long serialVersionUID = 8613516856378346415L; - - private Environment env; - - private ContextManager context; - private ExecutionManager runtime; - private SourceManager sourceManager; - - private TypeScript script; - - private static final String DEFAULT_CMD_PROMPT = "Command:"; - - public CommandTool(Environment env) { - - super(new BorderLayout()); - - this.env = env; - this.context = env.getContextManager(); - this.runtime = env.getExecutionManager(); - this.sourceManager = env.getSourceManager(); - - script = new TypeScript(DEFAULT_CMD_PROMPT, false); //no echo - this.add(script); - - final CommandInterpreter interpreter = - new CommandInterpreter(env); - - // Establish handler for incoming commands. - - script.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - interpreter.executeCommand(script.readln()); - } - }); - - // Establish ourselves as the listener for VM diagnostics. - - OutputListener diagnosticsListener = - new TypeScriptOutputListener(script, true); - runtime.addDiagnosticsListener(diagnosticsListener); - - // Establish ourselves as the shared debugger typescript. - - env.setTypeScript(new PrintWriter(new TypeScriptWriter(script))); - - // Handle VM events. - - TTYDebugListener listener = new TTYDebugListener(diagnosticsListener); - - runtime.addJDIListener(listener); - runtime.addSessionListener(listener); - runtime.addSpecListener(listener); - context.addContextListener(listener); - - //### remove listeners on exit! - - } - - private class TTYDebugListener implements - JDIListener, SessionListener, SpecListener, ContextListener { - - private OutputListener diagnostics; - - TTYDebugListener(OutputListener diagnostics) { - this.diagnostics = diagnostics; - } - - // JDIListener - - @Override - public void accessWatchpoint(AccessWatchpointEventSet e) { - setThread(e); - for (EventIterator it = e.eventIterator(); it.hasNext(); ) { - it.nextEvent(); - diagnostics.putString("Watchpoint hit: " + - locationString(e)); - } - } - - @Override - public void classPrepare(ClassPrepareEventSet e) { - if (context.getVerboseFlag()) { - String name = e.getReferenceType().name(); - diagnostics.putString("Class " + name + " loaded"); - } - } - - @Override - public void classUnload(ClassUnloadEventSet e) { - if (context.getVerboseFlag()) { - diagnostics.putString("Class " + e.getClassName() + - " unloaded."); - } - } - - @Override - public void exception(ExceptionEventSet e) { - setThread(e); - String name = e.getException().referenceType().name(); - diagnostics.putString("Exception: " + name); - } - - @Override - public void locationTrigger(LocationTriggerEventSet e) { - String locString = locationString(e); - setThread(e); - for (EventIterator it = e.eventIterator(); it.hasNext(); ) { - Event evt = it.nextEvent(); - if (evt instanceof BreakpointEvent) { - diagnostics.putString("Breakpoint hit: " + locString); - } else if (evt instanceof StepEvent) { - diagnostics.putString("Step completed: " + locString); - } else if (evt instanceof MethodEntryEvent) { - diagnostics.putString("Method entered: " + locString); - } else if (evt instanceof MethodExitEvent) { - diagnostics.putString("Method exited: " + locString); - } else { - diagnostics.putString("UNKNOWN event: " + e); - } - } - } - - @Override - public void modificationWatchpoint(ModificationWatchpointEventSet e) { - setThread(e); - for (EventIterator it = e.eventIterator(); it.hasNext(); ) { - it.nextEvent(); - diagnostics.putString("Watchpoint hit: " + - locationString(e)); - } - } - - @Override - public void threadDeath(ThreadDeathEventSet e) { - if (context.getVerboseFlag()) { - diagnostics.putString("Thread " + e.getThread() + - " ended."); - } - } - - @Override - public void threadStart(ThreadStartEventSet e) { - if (context.getVerboseFlag()) { - diagnostics.putString("Thread " + e.getThread() + - " started."); - } - } - - @Override - public void vmDeath(VMDeathEventSet e) { - script.setPrompt(DEFAULT_CMD_PROMPT); - diagnostics.putString("VM exited"); - } - - @Override - public void vmDisconnect(VMDisconnectEventSet e) { - script.setPrompt(DEFAULT_CMD_PROMPT); - diagnostics.putString("Disconnected from VM"); - } - - @Override - public void vmStart(VMStartEventSet e) { - script.setPrompt(DEFAULT_CMD_PROMPT); - diagnostics.putString("VM started"); - } - - // SessionListener - - @Override - public void sessionStart(EventObject e) {} - - @Override - public void sessionInterrupt(EventObject e) { - Thread.yield(); // fetch output - diagnostics.putString("VM interrupted by user."); - script.setPrompt(DEFAULT_CMD_PROMPT); - } - - @Override - public void sessionContinue(EventObject e) { - diagnostics.putString("Execution resumed."); - script.setPrompt(DEFAULT_CMD_PROMPT); - } - - // SpecListener - - @Override - public void breakpointSet(SpecEvent e) { - EventRequestSpec spec = e.getEventRequestSpec(); - diagnostics.putString("Breakpoint set at " + spec + "."); - } - @Override - public void breakpointDeferred(SpecEvent e) { - EventRequestSpec spec = e.getEventRequestSpec(); - diagnostics.putString("Breakpoint will be set at " + - spec + " when its class is loaded."); - } - @Override - public void breakpointDeleted(SpecEvent e) { - EventRequestSpec spec = e.getEventRequestSpec(); - diagnostics.putString("Breakpoint at " + spec.toString() + " deleted."); - } - @Override - public void breakpointResolved(SpecEvent e) { - EventRequestSpec spec = e.getEventRequestSpec(); - diagnostics.putString("Breakpoint resolved to " + spec.toString() + "."); - } - @Override - public void breakpointError(SpecErrorEvent e) { - EventRequestSpec spec = e.getEventRequestSpec(); - diagnostics.putString("Deferred breakpoint at " + - spec + " could not be resolved:" + - e.getReason()); - } - -//### Add info for watchpoints and exceptions - - @Override - public void watchpointSet(SpecEvent e) { - } - @Override - public void watchpointDeferred(SpecEvent e) { - } - @Override - public void watchpointDeleted(SpecEvent e) { - } - @Override - public void watchpointResolved(SpecEvent e) { - } - @Override - public void watchpointError(SpecErrorEvent e) { - } - - @Override - public void exceptionInterceptSet(SpecEvent e) { - } - @Override - public void exceptionInterceptDeferred(SpecEvent e) { - } - @Override - public void exceptionInterceptDeleted(SpecEvent e) { - } - @Override - public void exceptionInterceptResolved(SpecEvent e) { - } - @Override - public void exceptionInterceptError(SpecErrorEvent e) { - } - - - // ContextListener. - - // If the user selects a new current thread or frame, update prompt. - - @Override - public void currentFrameChanged(CurrentFrameChangedEvent e) { - // Update prompt only if affect thread is current. - ThreadReference thread = e.getThread(); - if (thread == context.getCurrentThread()) { - script.setPrompt(promptString(thread, e.getIndex())); - } - } - - } - - private String locationString(LocatableEventSet e) { - Location loc = e.getLocation(); - return "thread=\"" + e.getThread().name() + - "\", " + Utils.locationString(loc); - } - - private void setThread(LocatableEventSet e) { - if (!e.suspendedNone()) { - Thread.yield(); // fetch output - script.setPrompt(promptString(e.getThread(), 0)); - //### Current thread should be set elsewhere, e.g., - //### in ContextManager - //### context.setCurrentThread(thread); - } - } - - private String promptString(ThreadReference thread, int frameIndex) { - if (thread == null) { - return DEFAULT_CMD_PROMPT; - } else { - // Frame indices are presented to user as indexed from 1. - return (thread.name() + "[" + (frameIndex + 1) + "]:"); - } - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ContextListener.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ContextListener.java deleted file mode 100644 index 27143fac83a..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ContextListener.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -public interface ContextListener { - void currentFrameChanged(CurrentFrameChangedEvent e); -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ContextManager.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ContextManager.java deleted file mode 100644 index fb2416789e8..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/ContextManager.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -import java.io.*; -import java.util.*; - -import com.sun.jdi.*; -import com.sun.tools.example.debug.event.*; -import com.sun.tools.example.debug.bdi.*; - -public class ContextManager { - - private ClassManager classManager; - private ExecutionManager runtime; - - private String mainClassName; - private String vmArguments; - private String commandArguments; - private String remotePort; - - private ThreadReference currentThread; - - private boolean verbose; - - private ArrayList contextListeners = new ArrayList(); - - public ContextManager(Environment env) { - classManager = env.getClassManager(); - runtime = env.getExecutionManager(); - mainClassName = ""; - vmArguments = ""; - commandArguments = ""; - currentThread = null; - - ContextManagerListener listener = new ContextManagerListener(); - runtime.addJDIListener(listener); - runtime.addSessionListener(listener); - } - - // Program execution defaults. - - //### Should there be change listeners for these? - //### They would be needed if we expected a dialog to be - //### synchronized with command input while it was open. - - public String getMainClassName() { - return mainClassName; - } - - public void setMainClassName(String mainClassName) { - this.mainClassName = mainClassName; - } - - public String getVmArguments() { - return processClasspathDefaults(vmArguments); - } - - public void setVmArguments(String vmArguments) { - this.vmArguments = vmArguments; - } - - public String getProgramArguments() { - return commandArguments; - } - - public void setProgramArguments(String commandArguments) { - this.commandArguments = commandArguments; - } - - public String getRemotePort() { - return remotePort; - } - - public void setRemotePort(String remotePort) { - this.remotePort = remotePort; - - } - - - // Miscellaneous debugger session preferences. - - public boolean getVerboseFlag() { - return verbose; - } - - public void setVerboseFlag(boolean verbose) { - this.verbose = verbose; - } - - - // Thread focus. - - public ThreadReference getCurrentThread() { - return currentThread; - } - - public void setCurrentThread(ThreadReference t) { - if (t != currentThread) { - currentThread = t; - notifyCurrentThreadChanged(t); - } - } - - public void setCurrentThreadInvalidate(ThreadReference t) { - currentThread = t; - notifyCurrentFrameChanged(runtime.threadInfo(t), - 0, true); - } - - public void invalidateCurrentThread() { - notifyCurrentFrameChanged(null, 0, true); - } - - - // If a view is displaying the current thread, it may - // choose to indicate which frame is current in the - // sense of the command-line UI. It may also "warp" the - // selection to that frame when changed by an 'up' or 'down' - // command. Hence, a notifier is provided. - - /****** - public int getCurrentFrameIndex() { - return getCurrentFrameIndex(currentThreadInfo); - } - ******/ - - public int getCurrentFrameIndex(ThreadReference t) { - return getCurrentFrameIndex(runtime.threadInfo(t)); - } - - //### Used in StackTraceTool. - public int getCurrentFrameIndex(ThreadInfo tinfo) { - if (tinfo == null) { - return 0; - } - Integer currentFrame = (Integer)tinfo.getUserObject(); - if (currentFrame == null) { - return 0; - } else { - return currentFrame.intValue(); - } - } - - public int moveCurrentFrameIndex(ThreadReference t, int count) throws VMNotInterruptedException { - return setCurrentFrameIndex(t,count, true); - } - - public int setCurrentFrameIndex(ThreadReference t, int newIndex) throws VMNotInterruptedException { - return setCurrentFrameIndex(t, newIndex, false); - } - - public int setCurrentFrameIndex(int newIndex) throws VMNotInterruptedException { - if (currentThread == null) { - return 0; - } else { - return setCurrentFrameIndex(currentThread, newIndex, false); - } - } - - private int setCurrentFrameIndex(ThreadReference t, int x, boolean relative) throws VMNotInterruptedException { - boolean sameThread = t.equals(currentThread); - ThreadInfo tinfo = runtime.threadInfo(t); - if (tinfo == null) { - return 0; - } - int maxIndex = tinfo.getFrameCount()-1; - int oldIndex = getCurrentFrameIndex(tinfo); - int newIndex = relative? oldIndex + x : x; - if (newIndex > maxIndex) { - newIndex = maxIndex; - } else if (newIndex < 0) { - newIndex = 0; - } - if (!sameThread || newIndex != oldIndex) { // don't recurse - setCurrentFrameIndex(tinfo, newIndex); - } - return newIndex - oldIndex; - } - - private void setCurrentFrameIndex(ThreadInfo tinfo, int index) { - tinfo.setUserObject(index); - //### In fact, the value may not have changed at this point. - //### We need to signal that the user attempted to change it, - //### however, so that the selection can be "warped" to the - //### current location. - notifyCurrentFrameChanged(tinfo.thread(), index); - } - - public StackFrame getCurrentFrame() throws VMNotInterruptedException { - return getCurrentFrame(runtime.threadInfo(currentThread)); - } - - public StackFrame getCurrentFrame(ThreadReference t) throws VMNotInterruptedException { - return getCurrentFrame(runtime.threadInfo(t)); - } - - public StackFrame getCurrentFrame(ThreadInfo tinfo) throws VMNotInterruptedException { - int index = getCurrentFrameIndex(tinfo); - try { - // It is possible, though unlikely, that the VM was interrupted - // before the thread created its Java stack. - return tinfo.getFrame(index); - } catch (FrameIndexOutOfBoundsException e) { - return null; - } - } - - public void addContextListener(ContextListener cl) { - contextListeners.add(cl); - } - - public void removeContextListener(ContextListener cl) { - contextListeners.remove(cl); - } - - //### These notifiers are fired only in response to USER-INITIATED changes - //### to the current thread and current frame. When the current thread is set automatically - //### after a breakpoint hit or step completion, no event is generated. Instead, - //### interested parties are expected to listen for the BreakpointHit and StepCompleted - //### events. This convention is unclean, and I believe that it reflects a defect in - //### in the current architecture. Unfortunately, however, we cannot guarantee the - //### order in which various listeners receive a given event, and the handlers for - //### the very same events that cause automatic changes to the current thread may also - //### need to know the current thread. - - private void notifyCurrentThreadChanged(ThreadReference t) { - ThreadInfo tinfo = null; - int index = 0; - if (t != null) { - tinfo = runtime.threadInfo(t); - index = getCurrentFrameIndex(tinfo); - } - notifyCurrentFrameChanged(tinfo, index, false); - } - - private void notifyCurrentFrameChanged(ThreadReference t, int index) { - notifyCurrentFrameChanged(runtime.threadInfo(t), - index, false); - } - - private void notifyCurrentFrameChanged(ThreadInfo tinfo, int index, - boolean invalidate) { - ArrayList l = new ArrayList(contextListeners); - CurrentFrameChangedEvent evt = - new CurrentFrameChangedEvent(this, tinfo, index, invalidate); - for (int i = 0; i < l.size(); i++) { - l.get(i).currentFrameChanged(evt); - } - } - - private class ContextManagerListener extends JDIAdapter - implements SessionListener, JDIListener { - - // SessionListener - - @Override - public void sessionStart(EventObject e) { - invalidateCurrentThread(); - } - - @Override - public void sessionInterrupt(EventObject e) { - setCurrentThreadInvalidate(currentThread); - } - - @Override - public void sessionContinue(EventObject e) { - invalidateCurrentThread(); - } - - // JDIListener - - @Override - public void locationTrigger(LocationTriggerEventSet e) { - setCurrentThreadInvalidate(e.getThread()); - } - - @Override - public void exception(ExceptionEventSet e) { - setCurrentThreadInvalidate(e.getThread()); - } - - @Override - public void vmDisconnect(VMDisconnectEventSet e) { - invalidateCurrentThread(); - } - - } - - - /** - * Add a -classpath argument to the arguments passed to the exec'ed - * VM with the contents of CLASSPATH environment variable, - * if -classpath was not already specified. - * - * @param javaArgs the arguments to the VM being exec'd that - * potentially has a user specified -classpath argument. - * @return a javaArgs whose -classpath option has been added - */ - - private String processClasspathDefaults(String javaArgs) { - if (javaArgs.indexOf("-classpath ") == -1) { - StringBuilder munged = new StringBuilder(javaArgs); - SearchPath classpath = classManager.getClassPath(); - if (classpath.isEmpty()) { - String envcp = System.getProperty("env.class.path"); - if ((envcp != null) && (envcp.length() > 0)) { - munged.append(" -classpath " + envcp); - } - } else { - munged.append(" -classpath " + classpath.asString()); - } - return munged.toString(); - } else { - return javaArgs; - } - } - - private String appendPath(String path1, String path2) { - if (path1 == null || path1.length() == 0) { - return path2 == null ? "." : path2; - } else if (path2 == null || path2.length() == 0) { - return path1; - } else { - return path1 + File.pathSeparator + path2; - } - } - -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/CurrentFrameChangedEvent.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/CurrentFrameChangedEvent.java deleted file mode 100644 index b933e758f38..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/CurrentFrameChangedEvent.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -import com.sun.jdi.*; -import com.sun.tools.example.debug.bdi.*; -import java.util.EventObject; - -public class CurrentFrameChangedEvent extends EventObject { - - private static final long serialVersionUID = 4214479486546762179L; - private ThreadInfo tinfo; - private int index; - private boolean invalidate; - - public CurrentFrameChangedEvent(Object source, ThreadInfo tinfo, - int index, boolean invalidate) { - super(source); - this.tinfo = tinfo; - this.index = index; - this.invalidate = invalidate; - } - - public ThreadReference getThread() { - return tinfo == null? null : tinfo.thread(); - } - - public ThreadInfo getThreadInfo() { - return tinfo; - } - - public int getIndex() { - return index; - } - - public boolean getInvalidate() { - return invalidate; - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/Environment.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/Environment.java deleted file mode 100644 index b06ae4d6c79..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/Environment.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -import java.io.*; -import com.sun.jdi.*; -import com.sun.tools.example.debug.bdi.*; - -public class Environment { - - private SourceManager sourceManager; - private ClassManager classManager; - private ContextManager contextManager; - private MonitorListModel monitorListModel; - private ExecutionManager runtime; - - private PrintWriter typeScript; - - private boolean verbose; - - public Environment() { - this.classManager = new ClassManager(this); - //### Order of the next three lines is important! (FIX THIS) - this.runtime = new ExecutionManager(); - this.sourceManager = new SourceManager(this); - this.contextManager = new ContextManager(this); - this.monitorListModel = new MonitorListModel(this); - } - - // Services used by debugging tools. - - public SourceManager getSourceManager() { - return sourceManager; - } - - public ClassManager getClassManager() { - return classManager; - } - - public ContextManager getContextManager() { - return contextManager; - } - - public MonitorListModel getMonitorListModel() { - return monitorListModel; - } - - public ExecutionManager getExecutionManager() { - return runtime; - } - - //### TODO: - //### Tools should attach/detach from environment - //### via a property, which should call an 'addTool' - //### method when set to maintain a registry of - //### tools for exit-time cleanup, etc. Tool - //### class constructors should be argument-free, so - //### that they may be instantiated by bean builders. - //### Will also need 'removeTool' in case property - //### value is changed. - // - // public void addTool(Tool t); - // public void removeTool(Tool t); - - public void terminate() { - System.exit(0); - } - - // public void refresh(); // notify all tools to refresh their views - - - // public void addStatusListener(StatusListener l); - // public void removeStatusListener(StatusListener l); - - // public void addOutputListener(OutputListener l); - // public void removeOutputListener(OutputListener l); - - public void setTypeScript(PrintWriter writer) { - typeScript = writer; - } - - public void error(String message) { - if (typeScript != null) { - typeScript.println(message); - } else { - System.out.println(message); - } - } - - public void failure(String message) { - if (typeScript != null) { - typeScript.println(message); - } else { - System.out.println(message); - } - } - - public void notice(String message) { - if (typeScript != null) { - typeScript.println(message); - } else { - System.out.println(message); - } - } - - public OutputSink getOutputSink() { - return new OutputSink(typeScript); - } - - public void viewSource(String fileName) { - //### HACK ### - //### Should use listener here. - com.sun.tools.example.debug.gui.GUI.srcTool.showSourceFile(fileName); - } - - public void viewLocation(Location locn) { - //### HACK ### - //### Should use listener here. - //### Should we use sourceForLocation here? - com.sun.tools.example.debug.gui.GUI.srcTool.showSourceForLocation(locn); - } - - //### Also in 'ContextManager'. Do we need both? - - public boolean getVerboseFlag() { - return verbose; - } - - public void setVerboseFlag(boolean verbose) { - this.verbose = verbose; - } - -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/GUI.java b/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/GUI.java deleted file mode 100644 index eefbcfa7b61..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/debug/gui/GUI.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 1998, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.debug.gui; - -import java.io.*; -import javax.swing.*; -import javax.swing.border.*; -import java.awt.*; -import java.awt.event.*; - -import com.sun.jdi.*; -import com.sun.tools.example.debug.bdi.*; - -public class GUI extends JPanel { - - private static final long serialVersionUID = 3292463234530679091L; - private CommandTool cmdTool; - private ApplicationTool appTool; - //###HACK## - //### There is currently dirty code in Environment that - //### accesses this directly. - //private SourceTool srcTool; - public static SourceTool srcTool; - - private SourceTreeTool sourceTreeTool; - private ClassTreeTool classTreeTool; - private ThreadTreeTool threadTreeTool; - private StackTraceTool stackTool; - private MonitorTool monitorTool; - - public static final String progname = "javadt"; - public static final String version = "1.0Beta"; //### FIX ME. - public static final String windowBanner = "Java(tm) platform Debug Tool"; - - private Font fixedFont = new Font("monospaced", Font.PLAIN, 10); - - private GUI(Environment env) { - setLayout(new BorderLayout()); - - setBorder(new EmptyBorder(5, 5, 5, 5)); - - add(new JDBToolBar(env), BorderLayout.NORTH); - - srcTool = new SourceTool(env); - srcTool.setPreferredSize(new java.awt.Dimension(500, 300)); - srcTool.setTextFont(fixedFont); - - stackTool = new StackTraceTool(env); - stackTool.setPreferredSize(new java.awt.Dimension(500, 100)); - - monitorTool = new MonitorTool(env); - monitorTool.setPreferredSize(new java.awt.Dimension(500, 50)); - - JSplitPane right = new JSplitPane(JSplitPane.VERTICAL_SPLIT, srcTool, - new JSplitPane(JSplitPane.VERTICAL_SPLIT, stackTool, monitorTool)); - - sourceTreeTool = new SourceTreeTool(env); - sourceTreeTool.setPreferredSize(new java.awt.Dimension(200, 450)); - - classTreeTool = new ClassTreeTool(env); - classTreeTool.setPreferredSize(new java.awt.Dimension(200, 450)); - - threadTreeTool = new ThreadTreeTool(env); - threadTreeTool.setPreferredSize(new java.awt.Dimension(200, 450)); - - JTabbedPane treePane = new JTabbedPane(SwingConstants.BOTTOM); - treePane.addTab("Source", null, sourceTreeTool); - treePane.addTab("Classes", null, classTreeTool); - treePane.addTab("Threads", null, threadTreeTool); - - JSplitPane centerTop = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treePane, right); - - cmdTool = new CommandTool(env); - cmdTool.setPreferredSize(new java.awt.Dimension(700, 150)); - - appTool = new ApplicationTool(env); - appTool.setPreferredSize(new java.awt.Dimension(700, 200)); - - JSplitPane centerBottom = new JSplitPane(JSplitPane.VERTICAL_SPLIT, cmdTool, appTool); - // centerBottom.setPreferredSize(new java.awt.Dimension(700, 350)); - - JSplitPane center = new JSplitPane(JSplitPane.VERTICAL_SPLIT, centerTop, centerBottom); - - add(center, BorderLayout.CENTER); - - - } - - private static void usage() { - String separator = File.pathSeparator; - System.out.println("Usage: " + progname + " "); - System.out.println(); - System.out.println("where options include:"); - System.out.println(" -help print out this message and exit"); - System.out.println(" -sourcepath "); - System.out.println(" list directories in which to look for source files"); - System.out.println(" -remote :"); - System.out.println(" host machine and port number of interpreter to attach to"); - System.out.println(" -dbgtrace [flags] print info for debugging " + progname); - System.out.println(); - System.out.println("options forwarded to debuggee process:"); - System.out.println(" -v -verbose[:class|gc|jni]"); - System.out.println(" turn on verbose mode"); - System.out.println(" -D= set a system property"); - System.out.println(" -classpath "); - System.out.println(" list directories in which to look for classes"); - System.out.println(" -X

Example JDI Applications

-This example download contains the source code and -documentation for three applications written using -the JavaTM Debug Interface (JDI) -of the Java Platform Debugger Architecture (JPDA). -They are provided as educational tools and as starting -points for debugger development. -

-In increasing order of complexity: -

    -
  • Trace displays traces -of program execution. It is very simple (less than 600 lines) -yet uses most of the basic JDI functionality. It is a -good starting point. -
  • Jdb is the command line debugger -distributed with the J2SE SDK. -
  • Javadt is the beginnings of -a GUI debugger. -
-

-Trace is in the trace directory. -Jdb and Javadt share a package, and are under the -debug directory. - -

Required Set-up

- -

Where is JPDA?

-New versions of the J2SE SDK have JPDA included. For -older versions JPDA must be separately downloaded. -
-
SDKs with JPDA included -
J2SE SDK v1.3 and later and J2SE SDK for Linux v1.2.2 -
SDKs requiring JPDA download -
J2SE SDK v1.2.1 and v1.2.2 for Solaris and Windows -
Other SDKs -
Check with vendor -
-

-

Set-up for J2SE SDKs with JPDA included

-Your classpath must include the JDI Library code, which is -in tools.jar in the lib directory. -This is needed for both compiling the example code and -executing it. -

-

Set-up for J2SE SDKs without JPDA - Solaris

-Download JPDA v1.0 from -http://java.sun.com/products/jpda. Follow the -Installation Instructions -found there. Pay particular attention to setting the library -path. -

-Your classpath must include the JDI Library code, which is -in jpda_home/lib/tools.jar. -This is needed for both compiling the example code and -executing it. -

-

Set-up for J2SE SDKs without JPDA - Windows

-Download JPDA v1.0 from -http://java.sun.com/products/jpda. Follow the -Installation Instructions -found there. Be sure to add: -
-        jpda_home\bin
-
-to your path. -

-Your classpath must include the JDI Library code, which is -in jpda_home\lib\tools.jar. -This is needed for both compiling the example code and -executing it. -

-


-
java-debugger@java.sun.com
-

-

-

- - - diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/doc/javadt.html b/jdk/src/demo/share/jpda/com/sun/tools/example/doc/javadt.html deleted file mode 100644 index f9d28a166bb..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/doc/javadt.html +++ /dev/null @@ -1,174 +0,0 @@ - - - Release notes for the javadt debugger - - -

Release notes for the javadt debugger

- -

-As a demonstration of the - -JavaTM Platform Debugger Architecture -we are providing source code for -a simple GUI debugging tool - javadt. -It is included as an example and demonstration of - -JDI. It is not a finished or polished debugger and is -missing many features of importance for real debugging work. -

- -

Invoking javadt

-

-javadt can be run by executing: -

-   java com.sun.tools.example.debug.gui.GUI <options>.. <class-name>
-
-where <class-name> is the name you would normally -place on the java command line. -Note: the path to the JDI Library and to -the compiled javadt class files must be on the class path -used to invoke gui.GUI. -

-For example, you can invoke the javadt debugger as follows: -

-   java com.sun.tools.example.debug.gui.GUI -classpath . Hello
-
-Note: this -classpath option controls the -class path for the Hello application. -Once the window appears, you can issue the 'run' command to begin -execution immediately. It is also -possible to give the class name in the 'run' command, in -which case it may be omitted when invoking the debugger from the -shell. -

-The classpath may also be set from within the debugger, using the -'classpath' command. Currently, other arguments to the VM must be -given on the shell command line when the debugger is initially -invoked. The most recently mentioned classpath, VM arguments, main -class name, and program arguments are retained as defaults for later -'run' and 'load' commands. (Unfortunately, at present, the debugger -will likely crash if you attempt to begin another debugging session -with another debuggee process from within the same invocation of the -debugger. You should exit to the shell and start a new debugger -process.) -

- -

Using javadt

-The javadt normally displays context related to the "current thread", -that is, the thread that most recently encountered a breakpoint, threw -an uncaught exception, or was single-stepped by the user. When -program execution is suspended on account of one of these events, a -current thread exists, and the javadt displays the following information -about it: -

-

    -
  • A stack backtrace. - -
  • The source code surrounding the line corresponding to the - instruction counter for the thread, if the source code is - available. -
-

-In addition, a tabbed pane allows the user to view one of three -additional views: -

-

    -
  • A tree of all source files available on the source path. - -
  • A tree of all loaded class files, organized hierarchically - by package. - -
  • A tree of all active threads, organized hierarchically - by thread group. -
-

-By clicking on the name of a source file, the source view can be -directed to display it. Likewise, clicking on a thread will make that -thread the current thread. These features are normally used while the -program is suspended, e.g, at a breakpoint. Upon resumption and -encountering another breakpoint, for example, the current thread will -be automatically reset and the views will be updated. The views tile -the javadt display, and are adjustable in size. -

-The javadt functionality is rather basic, thus a command-line interaction -window is also provided that allows access to functions that are not -yet exposed in the javadt. In particular, it is necessary to use the -command line in order to set breakpoints and examine variables. The -javadt debugger command interpreter implements roughly a subset of the -jdb - functionality, but adds a few commands of its own. The -'help' command lists the complete set of commands and their function. -Shortcuts for a set of the most common commands is provided on a -button-bar at the top of the display. -

-The program to be debugged may be started either as a child of the -debugger, or the debugger can be attached to an existing process, -provided that its VM is prepared to accept the connection. If the -debuggee is started by the debugger as a child, a line-oriented -interface to its standard input, output, and error streams is provided -in an application interaction pane. -

-The debugger expects to find the program source code on its -sourcepath, set with the 'use' or 'sourcepath' command. If you find -that sources are not being displayed because the sourcepath is -incorrect, you may change it at that time, and the source view will be -immediately updated. -

-The message "No current thread" is often encountered when stepping -through a program. This message does not mean that the thread or -the VM has died, merely that a current thread is undefined. This -situation can easily occur unexpectedly when the program being -stepped is waiting, eg., for input. The VM appears to be stopped, -as it would be after the successful completion of a step, but it -is considered to be "running", not "interrupted". The prompt -in the command interaction pane indicates the state by changing -to a thread name and frame number when the VM is interrupted. -When it is running, the prompt "Command:" is displayed. -

-

Source for javadt

-Full source code for javadt is included under the -debug directory of examples.jar. -Note: these directories also include the -source for jdb. -Source code for these example applications is included to provide concrete -examples for debugger developers. Example code may be used, modified -and redistributed by debugger developers providing they adhere to the -terms in the COPYRIGHT notice. -

-javadt uses the following packages (found under the -debug directory): -

-
gui -
User interface code -
bdi -
Debugger core code -
events -
Event Set code -
expr -
Expression processing code -
-

-

Building javadt

-To build the javadt classes from the -provided source files under the debug directory, -you need only to compile them. No special -options are required, aside from those which set your classpath to -include the JDI Library. -

-

-However, if you want to modify the expression parser in the file -Expr.jj, you will need the - -JavaCC parser generator. -It is available free from -Metamata -(now part of WebGain). -

-


-
java-debugger@java.sun.com
-

-

-

- - diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/doc/jdb.html b/jdk/src/demo/share/jpda/com/sun/tools/example/doc/jdb.html deleted file mode 100644 index a8232b0207d..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/doc/jdb.html +++ /dev/null @@ -1,104 +0,0 @@ - - - Release notes for the jdb debugger - - -  - - - - - -
-
-

Release notes for the jdb debugger

-
- -

-Home Page - -

-As a demonstration of the - -JavaTM Platform Debugger Architecture -we are providing source code for the jdb debugger, which was -re-written to use - -JDI. - -

-

jdb man pages

-
-jdb man pages for Windows -

-jdb man pages for Solaris -

-

-

Invoking jdb

-The jdb sample can be started by executing: -
-   java com.sun.tools.example.debug.tty.TTY <options>.. <class-name>
-
-where <class-name> is the name you would normally -place on the java command line. The -help -option provides information on options. -

-

-Note: the path to the JDI Library and to -the compiled jdb class files must be on the class path -used to invoke com.sun.tools.example.debug.tty.TTY. - -

-For more information on invoking and connecting, refer to the - -Connection and Invocation Details section of the - -JPDA documentation, -particularly the section on jdb. -

- - -

Source for jdb

-Full source code for jdb is included under the -debug directory of examples.jar. -Note: these directories also include the -source for javadt. -Source code for these example applications is included to provide concrete -examples for debugger developers. Example code may be used, modified -and redistributed by debugger developers providing they adhere to the -terms in the COPYRIGHT notice. -

-jdb uses the following packages (found under the -debug directory): -

-
tty -
Application code -
expr -
Expression processing code -
- -

-

Building jdb

-To completely rebuild the jdb classes from the -provided source files under the debug directory, -you need only to compile them. No special -options are required, aside from those which set your classpath to -include the JDI Library. -

-

-However, if you want to modify the expression parser in the file -Expr.jj, you will need the - -JavaCC parser generator. -It is available free from -Metamata -(now part of WebGain). -

-


-
java-debugger@java.sun.com
-

-

-

- - diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/doc/trace.html b/jdk/src/demo/share/jpda/com/sun/tools/example/doc/trace.html deleted file mode 100644 index 8cae84dfe1e..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/doc/trace.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - trace example - - -

trace example

- -Trace runs the Java language program passed as an argument and -generates a trace of its execution. Trace is a simple command -line tool that uses the - -Java Debug Interface (JDI). Programs need -not be compiled for debugging since this information is not -used. -

-Trace can be invoked as follows: -

-        java com.sun.tools.example.trace.Trace options class args
-
-Your classpath must include the JDI Library -(see set-up), -the path to the compiled trace class files, -and the path for the application being traced. -

-Available options are: - -

-  -output filename   
-        Set destination for output trace. By default output
-        goes to the terminal.
-
-  -all                 
-        Include system classes in output.  By default
-        java.*, javax.*, sun.* and com.sun.* events are
-        not diplayed.
-
-  -fields
-        Also show assignments into fields.
-
-  -help              
-        Print a help message
-
-
-class is the program to trace. args are the arguments to class. -

- -

Source for trace

-Full source code for trace is included in the -trace directory of examples.jar. -Source code for these example applications is included to provide concrete -examples for debugger developers. Example code may be used, modified -and redistributed by debugger developers providing they adhere to the -terms in the COPYRIGHT notice. - -

-

Building trace

-To completely rebuild the trace classes from the -provided source files in the trace directory, -you need only to compile them. No special -options are required, aside from those which set your classpath to -include the JDI Library. - -

-


-
java-debugger@java.sun.com
-

-

-

- - diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/trace/EventThread.java b/jdk/src/demo/share/jpda/com/sun/tools/example/trace/EventThread.java deleted file mode 100644 index 11084df5dd2..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/trace/EventThread.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (c) 2001, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.trace; - -import com.sun.jdi.*; -import com.sun.jdi.request.*; -import com.sun.jdi.event.*; - -import java.util.*; -import java.io.PrintWriter; - -/** - * This class processes incoming JDI events and displays them - * - * @author Robert Field - */ -public class EventThread extends Thread { - - private final VirtualMachine vm; // Running VM - private final String[] excludes; // Packages to exclude - private final PrintWriter writer; // Where output goes - - static String nextBaseIndent = ""; // Starting indent for next thread - - private boolean connected = true; // Connected to VM - private boolean vmDied = true; // VMDeath occurred - - // Maps ThreadReference to ThreadTrace instances - private Map traceMap = - new HashMap<>(); - - EventThread(VirtualMachine vm, String[] excludes, PrintWriter writer) { - super("event-handler"); - this.vm = vm; - this.excludes = excludes; - this.writer = writer; - } - - /** - * Run the event handling thread. - * As long as we are connected, get event sets off - * the queue and dispatch the events within them. - */ - @Override - public void run() { - EventQueue queue = vm.eventQueue(); - while (connected) { - try { - EventSet eventSet = queue.remove(); - EventIterator it = eventSet.eventIterator(); - while (it.hasNext()) { - handleEvent(it.nextEvent()); - } - eventSet.resume(); - } catch (InterruptedException exc) { - // Ignore - } catch (VMDisconnectedException discExc) { - handleDisconnectedException(); - break; - } - } - } - - /** - * Create the desired event requests, and enable - * them so that we will get events. - * @param excludes Class patterns for which we don't want events - * @param watchFields Do we want to watch assignments to fields - */ - void setEventRequests(boolean watchFields) { - EventRequestManager mgr = vm.eventRequestManager(); - - // want all exceptions - ExceptionRequest excReq = mgr.createExceptionRequest(null, - true, true); - // suspend so we can step - excReq.setSuspendPolicy(EventRequest.SUSPEND_ALL); - excReq.enable(); - - MethodEntryRequest menr = mgr.createMethodEntryRequest(); - for (int i=0; i 0) { - indent.append("| "); - } - - EventRequestManager mgr = vm.eventRequestManager(); - mgr.deleteEventRequest(event.request()); - } - - void threadDeathEvent(ThreadDeathEvent event) { - indent = new StringBuffer(baseIndent); - println("====== " + thread.name() + " end ======"); - } - } - - /** - * Returns the ThreadTrace instance for the specified thread, - * creating one if needed. - */ - ThreadTrace threadTrace(ThreadReference thread) { - ThreadTrace trace = traceMap.get(thread); - if (trace == null) { - trace = new ThreadTrace(thread); - traceMap.put(thread, trace); - } - return trace; - } - - /** - * Dispatch incoming events - */ - private void handleEvent(Event event) { - if (event instanceof ExceptionEvent) { - exceptionEvent((ExceptionEvent)event); - } else if (event instanceof ModificationWatchpointEvent) { - fieldWatchEvent((ModificationWatchpointEvent)event); - } else if (event instanceof MethodEntryEvent) { - methodEntryEvent((MethodEntryEvent)event); - } else if (event instanceof MethodExitEvent) { - methodExitEvent((MethodExitEvent)event); - } else if (event instanceof StepEvent) { - stepEvent((StepEvent)event); - } else if (event instanceof ThreadDeathEvent) { - threadDeathEvent((ThreadDeathEvent)event); - } else if (event instanceof ClassPrepareEvent) { - classPrepareEvent((ClassPrepareEvent)event); - } else if (event instanceof VMStartEvent) { - vmStartEvent((VMStartEvent)event); - } else if (event instanceof VMDeathEvent) { - vmDeathEvent((VMDeathEvent)event); - } else if (event instanceof VMDisconnectEvent) { - vmDisconnectEvent((VMDisconnectEvent)event); - } else { - throw new Error("Unexpected event type"); - } - } - - /*** - * A VMDisconnectedException has happened while dealing with - * another event. We need to flush the event queue, dealing only - * with exit events (VMDeath, VMDisconnect) so that we terminate - * correctly. - */ - synchronized void handleDisconnectedException() { - EventQueue queue = vm.eventQueue(); - while (connected) { - try { - EventSet eventSet = queue.remove(); - EventIterator iter = eventSet.eventIterator(); - while (iter.hasNext()) { - Event event = iter.nextEvent(); - if (event instanceof VMDeathEvent) { - vmDeathEvent((VMDeathEvent)event); - } else if (event instanceof VMDisconnectEvent) { - vmDisconnectEvent((VMDisconnectEvent)event); - } - } - eventSet.resume(); // Resume the VM - } catch (InterruptedException exc) { - // ignore - } - } - } - - private void vmStartEvent(VMStartEvent event) { - writer.println("-- VM Started --"); - } - - // Forward event for thread specific processing - private void methodEntryEvent(MethodEntryEvent event) { - threadTrace(event.thread()).methodEntryEvent(event); - } - - // Forward event for thread specific processing - private void methodExitEvent(MethodExitEvent event) { - threadTrace(event.thread()).methodExitEvent(event); - } - - // Forward event for thread specific processing - private void stepEvent(StepEvent event) { - threadTrace(event.thread()).stepEvent(event); - } - - // Forward event for thread specific processing - private void fieldWatchEvent(ModificationWatchpointEvent event) { - threadTrace(event.thread()).fieldWatchEvent(event); - } - - void threadDeathEvent(ThreadDeathEvent event) { - ThreadTrace trace = traceMap.get(event.thread()); - if (trace != null) { // only want threads we care about - trace.threadDeathEvent(event); // Forward event - } - } - - /** - * A new class has been loaded. - * Set watchpoints on each of its fields - */ - private void classPrepareEvent(ClassPrepareEvent event) { - EventRequestManager mgr = vm.eventRequestManager(); - List fields = event.referenceType().visibleFields(); - for (Field field : fields) { - ModificationWatchpointRequest req = - mgr.createModificationWatchpointRequest(field); - for (int i=0; i= 0) { - out.write(cbuf, 0, count); - } - out.flush(); - } catch(IOException exc) { - System.err.println("Child I/O Transfer - " + exc); - } - } -} diff --git a/jdk/src/demo/share/jpda/com/sun/tools/example/trace/Trace.java b/jdk/src/demo/share/jpda/com/sun/tools/example/trace/Trace.java deleted file mode 100644 index 2ce99f97a01..00000000000 --- a/jdk/src/demo/share/jpda/com/sun/tools/example/trace/Trace.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2001, 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. 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 source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.tools.example.trace; - -import com.sun.jdi.VirtualMachine; -import com.sun.jdi.Bootstrap; -import com.sun.jdi.connect.*; - -import java.util.Map; -import java.util.List; - -import java.io.PrintWriter; -import java.io.FileWriter; -import java.io.IOException; - -/** - * This program traces the execution of another program. - * See "java Trace -help". - * It is a simple example of the use of the Java Debug Interface. - * - * @author Robert Field - */ -public class Trace { - - // Running remote VM - private final VirtualMachine vm; - - // Thread transferring remote error stream to our error stream - private Thread errThread = null; - - // Thread transferring remote output stream to our output stream - private Thread outThread = null; - - // Mode for tracing the Trace program (default= 0 off) - private int debugTraceMode = 0; - - // Do we want to watch assignments to fields - private boolean watchFields = false; - - // Class patterns for which we don't want events - private String[] excludes = {"java.*", "javax.*", "sun.*", - "com.sun.*"}; - - /** - * main - */ - public static void main(String[] args) { - new Trace(args); - } - - /** - * Parse the command line arguments. - * Launch target VM. - * Generate the trace. - */ - Trace(String[] args) { - PrintWriter writer = new PrintWriter(System.out); - int inx; - for (inx = 0; inx < args.length; ++inx) { - String arg = args[inx]; - if (arg.charAt(0) != '-') { - break; - } - if (arg.equals("-output")) { - try { - writer = new PrintWriter(new FileWriter(args[++inx])); - } catch (IOException exc) { - System.err.println("Cannot open output file: " + args[inx] - + " - " + exc); - System.exit(1); - } - } else if (arg.equals("-all")) { - excludes = new String[0]; - } else if (arg.equals("-fields")) { - watchFields = true; - } else if (arg.equals("-dbgtrace")) { - debugTraceMode = Integer.parseInt(args[++inx]); - } else if (arg.equals("-help")) { - usage(); - System.exit(0); - } else { - System.err.println("No option: " + arg); - usage(); - System.exit(1); - } - } - if (inx >= args.length) { - System.err.println(" missing"); - usage(); - System.exit(1); - } - StringBuilder sb = new StringBuilder(); - sb.append(args[inx]); - for (++inx; inx < args.length; ++inx) { - sb.append(' '); - sb.append(args[inx]); - } - vm = launchTarget(sb.toString()); - generateTrace(writer); - } - - - /** - * Generate the trace. - * Enable events, start thread to display events, - * start threads to forward remote error and output streams, - * resume the remote VM, wait for the final event, and shutdown. - */ - void generateTrace(PrintWriter writer) { - vm.setDebugTraceMode(debugTraceMode); - EventThread eventThread = new EventThread(vm, excludes, writer); - eventThread.setEventRequests(watchFields); - eventThread.start(); - redirectOutput(); - vm.resume(); - - // Shutdown begins when event thread terminates - try { - eventThread.join(); - errThread.join(); // Make sure output is forwarded - outThread.join(); // before we exit - } catch (InterruptedException exc) { - // we don't interrupt - } - writer.close(); - } - - /** - * Launch target VM. - * Forward target's output and error. - */ - VirtualMachine launchTarget(String mainArgs) { - LaunchingConnector connector = findLaunchingConnector(); - Map arguments = - connectorArguments(connector, mainArgs); - try { - return connector.launch(arguments); - } catch (IOException exc) { - throw new Error("Unable to launch target VM: " + exc); - } catch (IllegalConnectorArgumentsException exc) { - throw new Error("Internal error: " + exc); - } catch (VMStartException exc) { - throw new Error("Target VM failed to initialize: " + - exc.getMessage()); - } - } - - void redirectOutput() { - Process process = vm.process(); - - // Copy target's output and error to our output and error. - errThread = new StreamRedirectThread("error reader", - process.getErrorStream(), - System.err); - outThread = new StreamRedirectThread("output reader", - process.getInputStream(), - System.out); - errThread.start(); - outThread.start(); - } - - /** - * Find a com.sun.jdi.CommandLineLaunch connector - */ - LaunchingConnector findLaunchingConnector() { - List connectors = Bootstrap.virtualMachineManager().allConnectors(); - for (Connector connector : connectors) { - if (connector.name().equals("com.sun.jdi.CommandLineLaunch")) { - return (LaunchingConnector)connector; - } - } - throw new Error("No launching connector"); - } - - /** - * Return the launching connector's arguments. - */ - Map connectorArguments(LaunchingConnector connector, String mainArgs) { - Map arguments = connector.defaultArguments(); - Connector.Argument mainArg = - (Connector.Argument)arguments.get("main"); - if (mainArg == null) { - throw new Error("Bad launching connector"); - } - mainArg.setValue(mainArgs); - - if (watchFields) { - // We need a VM that supports watchpoints - Connector.Argument optionArg = - (Connector.Argument)arguments.get("options"); - if (optionArg == null) { - throw new Error("Bad launching connector"); - } - optionArg.setValue("-classic"); - } - return arguments; - } - - /** - * Print command line usage help - */ - void usage() { - System.err.println("Usage: java Trace "); - System.err.println(" are:"); - System.err.println( -" -output Output trace to "); - System.err.println( -" -all Include system classes in output"); - System.err.println( -" -help Print this help message"); - System.err.println(" is the program to trace"); - System.err.println(" are the arguments to "); - } -} diff --git a/jdk/src/demo/share/jvmti/hprof/sample.makefile.txt b/jdk/src/demo/share/jvmti/hprof/sample.makefile.txt deleted file mode 100644 index e8f84dc8577..00000000000 --- a/jdk/src/demo/share/jvmti/hprof/sample.makefile.txt +++ /dev/null @@ -1,205 +0,0 @@ -# -# Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# - Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# - Neither the name of Oracle nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -######################################################################## -# -# Sample GNU Makefile for building -# -# Example uses: -# gnumake JDK= OSNAME=solaris [OPT=true] [LIBARCH=sparc] -# gnumake JDK= OSNAME=solaris [OPT=true] [LIBARCH=sparcv9] -# gnumake JDK= OSNAME=linux [OPT=true] -# gnumake JDK= OSNAME=win32 [OPT=true] -# -######################################################################## - -# Source lists -LIBNAME=hprof -SOURCES= \ - debug_malloc.c \ - hprof_blocks.c \ - hprof_class.c \ - hprof_cpu.c \ - hprof_error.c \ - hprof_event.c \ - hprof_frame.c \ - hprof_init.c \ - hprof_io.c \ - hprof_ioname.c \ - hprof_listener.c \ - hprof_loader.c \ - hprof_monitor.c \ - hprof_object.c \ - hprof_reference.c \ - hprof_site.c \ - hprof_stack.c \ - hprof_string.c \ - hprof_table.c \ - hprof_tag.c \ - hprof_tls.c \ - hprof_trace.c \ - hprof_tracker.c \ - hprof_util.c \ - hprof_md.c - -JAVA_SOURCES=Tracker.java - -# Name of jar file that needs to be created -#JARFILE=hprof.jar - -# Solaris Sun C Compiler Version 5.5 -ifeq ($(OSNAME), solaris) - # Sun Solaris Compiler options needed - COMMON_FLAGS=-mt -KPIC - # Options that help find errors - COMMON_FLAGS+= -Xa -v -xstrconst -xc99=%none - # To make hprof logging code available - COMMON_FLAGS+= -DHPROF_LOGGING - # Check LIBARCH for any special compiler options - LIBARCH=$(shell uname -p) - ifeq ($(LIBARCH), sparc) - COMMON_FLAGS+=-xarch=v8 -xregs=no%appl - endif - ifeq ($(LIBARCH), sparcv9) - COMMON_FLAGS+=-xarch=v9 -xregs=no%appl - endif - ifeq ($(OPT), true) - CFLAGS=-xO2 $(COMMON_FLAGS) -DNDEBUG - else - CFLAGS=-g $(COMMON_FLAGS) -DDEBUG - endif - # Object files needed to create library - OBJECTS=$(SOURCES:%.c=%.o) - # Library name and options needed to build it - LIBRARY=lib$(LIBNAME).so - LDFLAGS=-z defs -ztext - # Libraries we are dependent on - LIBRARIES=-lsocket -lnsl -ldl -lc - # Building a shared library - LINK_SHARED=$(LINK.c) -G -o $@ -endif - -# Linux GNU C Compiler -ifeq ($(OSNAME), linux) - # GNU Compiler options needed to build it - COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer - # Options that help find errors - COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses - # To allow access to dladdr() - COMMON_FLAGS+= -D_GNU_SOURCE - # To prevent include of procfs.h - COMMON_FLAGS+= -DLINUX - # To make sure code is reentrant - COMMON_FLAGS+= -D_REENTRANT - # To make hprof logging code available - COMMON_FLAGS+= -DHPROF_LOGGING - ifeq ($(OPT), true) - CFLAGS=-O2 $(COMMON_FLAGS) -DNDEBUG - else - CFLAGS=-g $(COMMON_FLAGS) -DDEBUG - endif - # Object files needed to create library - OBJECTS=$(SOURCES:%.c=%.o) - # Library name and options needed to build it - LIBRARY=lib$(LIBNAME).so - LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc - # Libraries we are dependent on - LIBRARIES= -ldl -lc - # Building a shared library - LINK_SHARED=$(LINK.c) -shared -o $@ -endif - -# Windows Microsoft C/C++ Optimizing Compiler Version 12 -ifeq ($(OSNAME), win32) - CC=cl - # Compiler options needed to build it - COMMON_FLAGS=-Gy -DWIN32 - # Options that help find errors - COMMON_FLAGS+=-W0 -WX - # To make hprof logging code available - COMMON_FLAGS+= -DHPROF_LOGGING - ifeq ($(OPT), true) - CFLAGS= -Ox -Op -Zi $(COMMON_FLAGS) -DNDEBUG - else - CFLAGS= -Od -Zi $(COMMON_FLAGS) -DDEBUG - endif - # Add java_crw_demo source - SOURCES += ../java_crw_demo.c - # Object files needed to create library - OBJECTS=$(SOURCES:%.c=%.obj) - # Library name and options needed to build it - LIBRARY=$(LIBNAME).dll - LDFLAGS= - # Libraries we are dependent on - LIBRARIES=wsock32.lib winmm.lib - # Building a shared library - LINK_SHARED=link -dll -out:$@ -endif - -# Common -I options -CFLAGS += -I. -CFLAGS += -I../java_crw_demo -CFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME) - -# Default rule (build both native library and jar file) -all: hprof_md.c $(LIBRARY) $(JARFILE) - -# Get platform specific hprof_md.c -hprof_md.c: - rm -f $@ - cp $(OSNAME)/hprof_md.c $@ - -# Build native library -$(LIBRARY): $(OBJECTS) - $(LINK_SHARED) $(OBJECTS) $(LIBRARIES) - -# Build jar file -$(JARFILE): $(JAVA_SOURCES) - rm -f -r classes - mkdir -p classes - $(JDK)/bin/javac -d classes $(JAVA_SOURCES) - (cd classes; $(JDK)/bin/jar cf ../$@ *) - -# Cleanup the built bits -clean: - rm -f -r classes - rm -f $(LIBRARY) $(JARFILE) $(OBJECTS) - -# Simple tester -test: all - LD_LIBRARY_PATH=. $(JDK)/bin/java -agentlib:$(LIBNAME) -Xbootclasspath/a:./$(JARFILE) -version - -# Compilation rule only needed on Windows -ifeq ($(OSNAME), win32) -%.obj: %.c - $(COMPILE.c) $< -endif - diff --git a/jdk/src/demo/share/jvmti/index.html b/jdk/src/demo/share/jvmti/index.html index b66ac8d9bfa..4b479c12468 100644 --- a/jdk/src/demo/share/jvmti/index.html +++ b/jdk/src/demo/share/jvmti/index.html @@ -54,17 +54,16 @@ variable (Windows). This is system and platform specific. If you are using 64bit Solaris (e.g. 'java -d64'), you should use LD_LIBRARY_PATH64. -Some agents such as hprof (heap/cpu profiler) and jdwp (debugger backend) +Some agents such as the jdwp (debugger backend) are located inside the primary JDK directories and will always be found in those locations.

The agents that instrument classfiles (i.e. BCI, usually through the java_crw_demo library) -such as hprof, heapTracker, mtrace, and minst, +such as heapTracker, mtrace, and minst, also need to have the Java classes they use available in the bootclasspath. -The one used by hprof is already in the bootclasspath, and the -other agents will make attempts at automatically adding their jar file +The agents will make attempts at automatically adding their jar file (e.g. heapTracker.jar, mtrace.jar, or minst.jar) to the bootclasspath with AddToBootstrapClassLoaderSearch from JVM TI at startup (see the agent_util code). @@ -150,19 +149,6 @@ This is a small agent that gets information about threads waiting on monitors. -

  • -hprof -
    -This is a large agent that does heap and cpu profiling. -This demo agent is actually built into the - -Java Runtime Environment (JRE). -It uses Bytecode Instrumentation (BCI) via the java_crw_demo library. -
    -Note: hprof is NOT a small or simple agent, the other smaller demos -should be looked at first. -
  • - diff --git a/jdk/src/java.base/share/classes/java/io/ByteArrayOutputStream.java b/jdk/src/java.base/share/classes/java/io/ByteArrayOutputStream.java index 71be2db3b47..3d199579249 100644 --- a/jdk/src/java.base/share/classes/java/io/ByteArrayOutputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ByteArrayOutputStream.java @@ -93,6 +93,14 @@ public class ByteArrayOutputStream extends OutputStream { grow(minCapacity); } + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + /** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. @@ -105,14 +113,19 @@ public class ByteArrayOutputStream extends OutputStream { int newCapacity = oldCapacity << 1; if (newCapacity - minCapacity < 0) newCapacity = minCapacity; - if (newCapacity < 0) { - if (minCapacity < 0) // overflow - throw new OutOfMemoryError(); - newCapacity = Integer.MAX_VALUE; - } + if (newCapacity - MAX_ARRAY_SIZE > 0) + newCapacity = hugeCapacity(minCapacity); buf = Arrays.copyOf(buf, newCapacity); } + private static int hugeCapacity(int minCapacity) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return (minCapacity > MAX_ARRAY_SIZE) ? + Integer.MAX_VALUE : + MAX_ARRAY_SIZE; + } + /** * Writes the specified byte to this byte array output stream. * diff --git a/jdk/src/java.base/share/classes/java/io/FileInputStream.java b/jdk/src/java.base/share/classes/java/io/FileInputStream.java index 6f13156bf98..b501b45707f 100644 --- a/jdk/src/java.base/share/classes/java/io/FileInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/FileInputStream.java @@ -184,7 +184,16 @@ class FileInputStream extends InputStream * Opens the specified file for reading. * @param name the name of the file */ - private native void open(String name) throws FileNotFoundException; + private native void open0(String name) throws FileNotFoundException; + + // wrap native call to allow instrumentation + /** + * Opens the specified file for reading. + * @param name the name of the file + */ + private void open(String name) throws FileNotFoundException { + open0(name); + } /** * Reads a byte of data from this input stream. This method blocks diff --git a/jdk/src/java.base/share/classes/java/io/FileOutputStream.java b/jdk/src/java.base/share/classes/java/io/FileOutputStream.java index 1f7cff54cfa..281a695e6df 100644 --- a/jdk/src/java.base/share/classes/java/io/FileOutputStream.java +++ b/jdk/src/java.base/share/classes/java/io/FileOutputStream.java @@ -256,9 +256,20 @@ class FileOutputStream extends OutputStream * @param name name of file to be opened * @param append whether the file is to be opened in append mode */ - private native void open(String name, boolean append) + private native void open0(String name, boolean append) throws FileNotFoundException; + // wrap native call to allow instrumentation + /** + * Opens a file, with the specified name, for overwriting or appending. + * @param name name of file to be opened + * @param append whether the file is to be opened in append mode + */ + private void open(String name, boolean append) + throws FileNotFoundException { + open0(name, append); + } + /** * Writes the specified byte to this file output stream. * diff --git a/jdk/src/java.base/share/classes/java/io/FilePermission.java b/jdk/src/java.base/share/classes/java/io/FilePermission.java index 0744ea28e4a..b008d4f933a 100644 --- a/jdk/src/java.base/share/classes/java/io/FilePermission.java +++ b/jdk/src/java.base/share/classes/java/io/FilePermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -31,6 +31,7 @@ import java.util.List; import java.util.ArrayList; import java.util.Vector; import java.util.Collections; +import java.util.StringJoiner; import sun.security.util.SecurityConstants; /** @@ -556,39 +557,25 @@ public final class FilePermission extends Permission implements Serializable { * @return the canonical string representation of the actions. */ private static String getActions(int mask) { - StringBuilder sb = new StringBuilder(); - boolean comma = false; + StringJoiner sj = new StringJoiner(","); if ((mask & READ) == READ) { - comma = true; - sb.append("read"); + sj.add("read"); } - if ((mask & WRITE) == WRITE) { - if (comma) sb.append(','); - else comma = true; - sb.append("write"); + sj.add("write"); } - if ((mask & EXECUTE) == EXECUTE) { - if (comma) sb.append(','); - else comma = true; - sb.append("execute"); + sj.add("execute"); } - if ((mask & DELETE) == DELETE) { - if (comma) sb.append(','); - else comma = true; - sb.append("delete"); + sj.add("delete"); } - if ((mask & READLINK) == READLINK) { - if (comma) sb.append(','); - else comma = true; - sb.append("readlink"); + sj.add("readlink"); } - return sb.toString(); + return sj.toString(); } /** diff --git a/jdk/src/java.base/share/classes/java/io/ObjectOutputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectOutputStream.java index 7dc6dde469f..e99e0257f31 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectOutputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -32,6 +32,7 @@ import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.StringJoiner; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import static java.io.ObjectStreamClass.processQueue; @@ -2465,15 +2466,11 @@ public class ObjectOutputStream * Returns a string representation of this object */ public String toString() { - StringBuilder buffer = new StringBuilder(); - if (!stack.isEmpty()) { - for(int i = stack.size(); i > 0; i-- ) { - buffer.append(stack.get(i - 1)); - if (i != 1) - buffer.append('\n'); - } + StringJoiner sj = new StringJoiner("\n"); + for (int i = stack.size() - 1; i >= 0; i--) { + sj.add(stack.get(i)); } - return buffer.toString(); + return sj.toString(); } } diff --git a/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java b/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java index ae1e530f168..d6b79b245cd 100644 --- a/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java +++ b/jdk/src/java.base/share/classes/java/io/RandomAccessFile.java @@ -296,9 +296,26 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { * @param mode the mode flags, a combination of the O_ constants * defined above */ - private native void open(String name, int mode) + private native void open0(String name, int mode) throws FileNotFoundException; + // wrap native call to allow instrumentation + /** + * Opens a file and returns the file descriptor. The file is + * opened in read-write mode if the O_RDWR bit in {@code mode} + * is true, else the file is opened as read-only. + * If the {@code name} refers to a directory, an IOException + * is thrown. + * + * @param name the name of the file + * @param mode the mode flags, a combination of the O_ constants + * defined above + */ + private void open(String name, int mode) + throws FileNotFoundException { + open0(name, mode); + } + // 'Read' primitives /** diff --git a/jdk/src/java.base/share/classes/java/lang/Class.java b/jdk/src/java.base/share/classes/java/lang/Class.java index cd26ab11791..2179ee809f5 100644 --- a/jdk/src/java.base/share/classes/java/lang/Class.java +++ b/jdk/src/java.base/share/classes/java/lang/Class.java @@ -54,6 +54,7 @@ import java.util.Set; import java.util.Map; import java.util.HashMap; import java.util.Objects; +import java.util.StringJoiner; import sun.misc.Unsafe; import sun.reflect.CallerSensitive; import sun.reflect.ConstantPool; @@ -1322,7 +1323,7 @@ public final class Class implements java.io.Serializable, // (for anonymous classes): 1 or more digits. // Since getSimpleBinaryName() will strip the binary name of - // the immediatly enclosing class, we are now looking at a + // the immediately enclosing class, we are now looking at a // string that matches the regular expression "\$[0-9]*" // followed by a simple name (considering the simple of an // anonymous class to be the empty string). @@ -3141,19 +3142,14 @@ public final class Class implements java.io.Serializable, private native Class[] getDeclaredClasses0(); private static String argumentTypesToString(Class[] argTypes) { - StringBuilder buf = new StringBuilder(); - buf.append("("); + StringJoiner sj = new StringJoiner(", ", "(", ")"); if (argTypes != null) { for (int i = 0; i < argTypes.length; i++) { - if (i > 0) { - buf.append(", "); - } Class c = argTypes[i]; - buf.append((c == null) ? "null" : c.getName()); + sj.add((c == null) ? "null" : c.getName()); } } - buf.append(")"); - return buf.toString(); + return sj.toString(); } /** use serialVersionUID from JDK 1.1 for interoperability */ diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java index 1652d6cc4eb..1def66a146b 100644 --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java @@ -205,7 +205,7 @@ public abstract class ClassLoader { } /** - * Registers the given class loader type as parallel capabale. + * Registers the given class loader type as parallel capable. * Returns {@code true} is successfully registered; {@code false} if * loader's super class is not registered. */ @@ -832,7 +832,7 @@ public abstract class ClassLoader { { int len = b.remaining(); - // Use byte[] if not a direct ByteBufer: + // Use byte[] if not a direct ByteBuffer: if (!b.isDirect()) { if (b.hasArray()) { return defineClass(name, b.array(), diff --git a/jdk/src/java.base/share/classes/java/lang/StringCoding.java b/jdk/src/java.base/share/classes/java/lang/StringCoding.java index 24ed0c06bbe..a4c71b4cf21 100644 --- a/jdk/src/java.base/share/classes/java/lang/StringCoding.java +++ b/jdk/src/java.base/share/classes/java/lang/StringCoding.java @@ -196,19 +196,19 @@ class StringCoding { static char[] decode(Charset cs, byte[] ba, int off, int len) { // (1)We never cache the "external" cs, the only benefit of creating // an additional StringDe/Encoder object to wrap it is to share the - // de/encode() method. These SD/E objects are short-lifed, the young-gen - // gc should be able to take care of them well. But the best approash + // de/encode() method. These SD/E objects are short-lived, the young-gen + // gc should be able to take care of them well. But the best approach // is still not to generate them if not really necessary. // (2)The defensive copy of the input byte/char[] has a big performance // impact, as well as the outgoing result byte/char[]. Need to do the // optimization check of (sm==null && classLoader0==null) for both. // (3)getClass().getClassLoader0() is expensive // (4)There might be a timing gap in isTrusted setting. getClassLoader0() - // is only chcked (and then isTrusted gets set) when (SM==null). It is + // is only checked (and then isTrusted gets set) when (SM==null). It is // possible that the SM==null for now but then SM is NOT null later // when safeTrim() is invoked...the "safe" way to do is to redundant // check (... && (isTrusted || SM == null || getClassLoader0())) in trim - // but it then can be argued that the SM is null when the opertaion + // but it then can be argued that the SM is null when the operation // is started... CharsetDecoder cd = cs.newDecoder(); int en = scale(len, cd.maxCharsPerByte()); diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java index fbac697c245..345cdae1df7 100644 --- a/jdk/src/java.base/share/classes/java/lang/System.java +++ b/jdk/src/java.base/share/classes/java/lang/System.java @@ -1193,7 +1193,7 @@ public final class System { // Setup Java signal handlers for HUP, TERM, and INT (where available). Terminator.setup(); - // Initialize any miscellenous operating system settings that need to be + // Initialize any miscellaneous operating system settings that need to be // set for the class libraries. Currently this is no-op everywhere except // for Windows where the process-wide error mode is set before the java.io // classes are used. diff --git a/jdk/src/java.base/share/classes/java/lang/Throwable.java b/jdk/src/java.base/share/classes/java/lang/Throwable.java index 396d8e90ecc..d71f9ecdf0d 100644 --- a/jdk/src/java.base/share/classes/java/lang/Throwable.java +++ b/jdk/src/java.base/share/classes/java/lang/Throwable.java @@ -139,7 +139,7 @@ public class Throwable implements Serializable { * {@linkplain #setStackTrace(StackTraceElement[]) Setting the * stack trace} to a one-element array containing this sentinel * value indicates future attempts to set the stack trace will be - * ignored. The sentinal is equal to the result of calling:
    + * ignored. The sentinel is equal to the result of calling:
    * {@code new StackTraceElement("", "", null, Integer.MIN_VALUE)} */ public static final StackTraceElement STACK_TRACE_ELEMENT_SENTINEL = diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 752c0976d9e..9d8db4eef78 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -98,7 +98,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; private final String implMethodClassName; // Name of type containing implementation "CC" private final String implMethodName; // Name of implementation method "impl" private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;" - private final Class implMethodReturnClass; // class for implementaion method return type "Ljava/lang/String;" + private final Class implMethodReturnClass; // class for implementation method return type "Ljava/lang/String;" private final MethodType constructorType; // Generated class constructor type "(CC)void" private final ClassWriter cw; // ASM class writer private final String[] argNames; // Generated names for the constructor arguments diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 3ab5d9c4dcf..58e56dd246a 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -209,7 +209,7 @@ class InvokerBytecodeGenerator { throw new InternalError("observed CP placeholder twice: " + cpPlaceholder); } // insert placeholder in CP and remember the patch - int index = cw.newConst((Object) cpPlaceholder); // TODO check if aready in the constant pool + int index = cw.newConst((Object) cpPlaceholder); // TODO check if already in the constant pool cpPatches.put(cpPlaceholder, new CpPatch(index, cpPlaceholder, arg)); return cpPlaceholder; } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java index b9c18b548bd..d3116d12963 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java @@ -37,7 +37,7 @@ import static java.lang.invoke.LambdaForm.*; * @author jrose */ class Invokers { - // exact type (sans leading taget MH) for the outgoing call + // exact type (sans leading target MH) for the outgoing call private final MethodType targetType; // FIXME: Get rid of the invokers that are not useful. diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java index 9cc901eea7a..75b26be4e0c 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -59,7 +59,7 @@ import java.util.Objects; * and properly use the named member. *

    * When resolved, a member name's internal implementation may include references to JVM metadata. - * This representation is stateless and only decriptive. + * This representation is stateless and only descriptive. * It provides no private information and no capability to use the member. *

    * By contrast, a {@linkplain java.lang.reflect.Method} contains fuller information diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index 19664528f26..5ed091e408f 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -679,7 +679,7 @@ public abstract class MethodHandle { * This method provides the crucial behavioral difference between * {@link #invokeExact invokeExact} and plain, inexact {@link #invoke invoke}. * The two methods - * perform the same steps when the caller's type descriptor exactly m atches + * perform the same steps when the caller's type descriptor exactly matches * the callee's, but when the types differ, plain {@link #invoke invoke} * also calls {@code asType} (or some internal equivalent) in order * to match up the caller's and callee's types. diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index abd8999aeaa..3e4ee65e161 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -621,7 +621,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } /** - * The LambaForm shape for catchException combinator is the following: + * The LambdaForm shape for catchException combinator is the following: *

    {@code
          *  guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{
          *    t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L);
    @@ -702,7 +702,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
             MethodType type = target.type();
             LambdaForm form = makeGuardWithCatchForm(type.basicType());
     
    -        // Prepare auxiliary method handles used during LambdaForm interpreation.
    +        // Prepare auxiliary method handles used during LambdaForm interpretation.
             // Box arguments and wrap them into Object[]: ValueConversions.array().
             MethodType varargsType = type.changeReturnType(Object[].class);
             MethodHandle collectArgs = ValueConversions.varargsArray(type.parameterCount())
    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 0f5169e95e2..01c3b33001d 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
    @@ -509,7 +509,7 @@ class MethodHandleNatives {
     
         /**
          * Is this method a caller-sensitive method?
    -     * I.e., does it call Reflection.getCallerClass or a similer method
    +     * I.e., does it call Reflection.getCallerClass or a similar method
          * to ask about the identity of its caller?
          */
         static boolean isCallerSensitive(MemberName mem) {
    diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java
    index c26460048b0..2b20ae71935 100644
    --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java
    +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java
    @@ -33,6 +33,7 @@ import java.util.Arrays;
     import java.util.Collections;
     import java.util.List;
     import java.util.Objects;
    +import java.util.StringJoiner;
     import java.util.concurrent.ConcurrentMap;
     import java.util.concurrent.ConcurrentHashMap;
     import sun.invoke.util.BytecodeDescriptor;
    @@ -717,15 +718,12 @@ class MethodType implements java.io.Serializable {
          */
         @Override
         public String toString() {
    -        StringBuilder sb = new StringBuilder();
    -        sb.append("(");
    +        StringJoiner sj = new StringJoiner(",", "(",
    +                ")" + rtype.getSimpleName());
             for (int i = 0; i < ptypes.length; i++) {
    -            if (i > 0)  sb.append(",");
    -            sb.append(ptypes[i].getSimpleName());
    +            sj.add(ptypes[i].getSimpleName());
             }
    -        sb.append(")");
    -        sb.append(rtype.getSimpleName());
    -        return sb.toString();
    +        return sj.toString();
         }
     
     
    diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
    index f85ab432388..01a074f36e0 100644
    --- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
    +++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
    @@ -78,7 +78,7 @@ public class AccessibleObject implements AnnotatedElement {
          * object is a {@link Constructor} object for the class {@link
          * java.lang.Class}).  In the event of such a SecurityException, the
          * accessibility of objects is set to {@code flag} for array elements
    -     * upto (and excluding) the element for which the exception occurred; the
    +     * up to (and excluding) the element for which the exception occurred; the
          * accessibility of elements beyond (and including) the element for which
          * the exception occurred is unchanged.
          *
    diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java
    index f424deec74a..4b112bf16b3 100644
    --- a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java
    +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java
    @@ -544,15 +544,33 @@ public final class Constructor extends Executable {
          */
         @Override
         public AnnotatedType getAnnotatedReceiverType() {
    -        if (getDeclaringClass().getEnclosingClass() == null)
    -            return super.getAnnotatedReceiverType();
    +        Class thisDeclClass = getDeclaringClass();
    +        Class enclosingClass = thisDeclClass.getEnclosingClass();
     
    +        if (enclosingClass == null) {
    +            // A Constructor for a top-level class
    +            return null;
    +        }
    +
    +        Class outerDeclaringClass = thisDeclClass.getDeclaringClass();
    +        if (outerDeclaringClass == null) {
    +            // A constructor for a local or anonymous class
    +            return null;
    +        }
    +
    +        // Either static nested or inner class
    +        if (Modifier.isStatic(thisDeclClass.getModifiers())) {
    +            // static nested
    +            return null;
    +        }
    +
    +        // A Constructor for an inner class
             return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(),
                     sun.misc.SharedSecrets.getJavaLangAccess().
    -                        getConstantPool(getDeclaringClass()),
    +                    getConstantPool(thisDeclClass),
                     this,
    -                getDeclaringClass(),
    -                getDeclaringClass().getEnclosingClass(),
    +                thisDeclClass,
    +                enclosingClass,
                     TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER);
         }
     }
    diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java b/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java
    index 8493d10eaa4..99eb1eb8b90 100644
    --- a/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java
    +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java
    @@ -585,21 +585,24 @@ public abstract class Executable extends AccessibleObject
         /**
          * Returns an {@code AnnotatedType} object that represents the use of a
          * type to specify the receiver type of the method/constructor represented
    -     * by this Executable object. The receiver type of a method/constructor is
    -     * available only if the method/constructor has a receiver
    -     * parameter (JLS 8.4.1).
    +     * by this {@code Executable} object.
          *
    -     * If this {@code Executable} object represents a constructor or instance
    -     * method that does not have a receiver parameter, or has a receiver
    -     * parameter with no annotations on its type, then the return value is an
    -     * {@code AnnotatedType} object representing an element with no
    +     * The receiver type of a method/constructor is available only if the
    +     * method/constructor has a receiver parameter (JLS 8.4.1). If this {@code
    +     * Executable} object represents an instance method or represents a
    +     * constructor of an inner member class, and the
    +     * method/constructor either has no receiver parameter or has a
    +     * receiver parameter with no annotations on its type, then the return
    +     * value is an {@code AnnotatedType} object representing an element with no
          * annotations.
          *
    -     * If this {@code Executable} object represents a static method, then the
    -     * return value is null.
    +     * If this {@code Executable} object represents a static method or
    +     * represents a constructor of a top level, static member, local, or
    +     * anoymous class, then the return value is null.
          *
          * @return an object representing the receiver type of the method or
    -     * constructor represented by this {@code Executable}
    +     * constructor represented by this {@code Executable} or {@code null} if
    +     * this {@code Executable} can not have a receiver parameter
          */
         public AnnotatedType getAnnotatedReceiverType() {
             if (Modifier.isStatic(this.getModifiers()))
    diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java b/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java
    index f035b8e5e73..69c568f09fe 100644
    --- a/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java
    +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java
    @@ -173,7 +173,7 @@ public final class Parameter implements AnnotatedElement {
          *         a name.
          */
         public String getName() {
    -        // Note: empty strings as paramete names are now outlawed.
    +        // Note: empty strings as parameter names are now outlawed.
             // The .equals("") is for compatibility with current JVM
             // behavior.  It may be removed at some point.
             if(name == null || name.equals(""))
    diff --git a/jdk/src/java.base/share/classes/java/net/InetAddress.java b/jdk/src/java.base/share/classes/java/net/InetAddress.java
    index 09b645d4d85..eb72c091285 100644
    --- a/jdk/src/java.base/share/classes/java/net/InetAddress.java
    +++ b/jdk/src/java.base/share/classes/java/net/InetAddress.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1995, 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
    @@ -25,11 +25,8 @@
     
     package java.net;
     
    -import java.util.HashMap;
    -import java.util.LinkedHashMap;
    -import java.util.Random;
    +import java.util.NavigableSet;
     import java.util.Iterator;
    -import java.util.LinkedList;
     import java.util.List;
     import java.util.ArrayList;
     import java.util.ServiceLoader;
    @@ -41,6 +38,11 @@ import java.io.ObjectInputStream;
     import java.io.ObjectInputStream.GetField;
     import java.io.ObjectOutputStream;
     import java.io.ObjectOutputStream.PutField;
    +import java.util.concurrent.ConcurrentHashMap;
    +import java.util.concurrent.ConcurrentMap;
    +import java.util.concurrent.ConcurrentSkipListSet;
    +import java.util.concurrent.atomic.AtomicLong;
    +
     import sun.security.action.*;
     import sun.net.InetAddressCachePolicy;
     import sun.net.util.IPAddressUtil;
    @@ -705,195 +707,130 @@ class InetAddress implements java.io.Serializable {
                 + "/" + getHostAddress();
         }
     
    -    /*
    -     * Cached addresses - our own litle nis, not!
    -     */
    -    private static Cache addressCache = new Cache(Cache.Type.Positive);
    +    // mapping from host name to Addresses - either NameServiceAddresses (while
    +    // still being looked-up by NameService(s)) or CachedAddresses when cached
    +    private static final ConcurrentMap cache =
    +        new ConcurrentHashMap<>();
     
    -    private static Cache negativeCache = new Cache(Cache.Type.Negative);
    +    // CachedAddresses that have to expire are kept ordered in this NavigableSet
    +    // which is scanned on each access
    +    private static final NavigableSet expirySet =
    +        new ConcurrentSkipListSet<>();
     
    -    private static boolean addressCacheInit = false;
    +    // common interface
    +    private interface Addresses {
    +        InetAddress[] get() throws UnknownHostException;
    +    }
     
    -    static InetAddress[]    unknown_array; // put THIS in cache
    +    // a holder for cached addresses with required metadata
    +    private static final class CachedAddresses  implements Addresses, Comparable {
    +        private static final AtomicLong seq = new AtomicLong();
    +        final String host;
    +        final InetAddress[] inetAddresses;
    +        final long expiryTime; // time of expiry (in terms of System.nanoTime())
    +        final long id = seq.incrementAndGet(); // each instance is unique
    +
    +        CachedAddresses(String host, InetAddress[] inetAddresses, long expiryTime) {
    +            this.host = host;
    +            this.inetAddresses = inetAddresses;
    +            this.expiryTime = expiryTime;
    +        }
    +
    +        @Override
    +        public InetAddress[] get() throws UnknownHostException {
    +            if (inetAddresses == null) {
    +                throw new UnknownHostException(host);
    +            }
    +            return inetAddresses;
    +        }
    +
    +        @Override
    +        public int compareTo(CachedAddresses other) {
    +            // natural order is expiry time -
    +            // compare difference of expiry times rather than
    +            // expiry times directly, to avoid possible overflow.
    +            // (see System.nanoTime() recommendations...)
    +            long diff = this.expiryTime - other.expiryTime;
    +            if (diff < 0L) return -1;
    +            if (diff > 0L) return 1;
    +            // ties are broken using unique id
    +            return Long.compare(this.id, other.id);
    +        }
    +    }
    +
    +    // a name service lookup based Addresses implementation which replaces itself
    +    // in cache when the result is obtained
    +    private static final class NameServiceAddresses implements Addresses {
    +        private final String host;
    +        private final InetAddress reqAddr;
    +
    +        NameServiceAddresses(String host, InetAddress reqAddr) {
    +            this.host = host;
    +            this.reqAddr = reqAddr;
    +        }
    +
    +        @Override
    +        public InetAddress[] get() throws UnknownHostException {
    +            Addresses addresses;
    +            // only one thread is doing lookup to name service
    +            // for particular host at any time.
    +            synchronized (this) {
    +                // re-check that we are still us + re-install us if slot empty
    +                addresses = cache.putIfAbsent(host, this);
    +                if (addresses == null) {
    +                    // this can happen when we were replaced by CachedAddresses in
    +                    // some other thread, then CachedAddresses expired and were
    +                    // removed from cache while we were waiting for lock...
    +                    addresses = this;
    +                }
    +                // still us ?
    +                if (addresses == this) {
    +                    // lookup name services
    +                    InetAddress[] inetAddresses;
    +                    UnknownHostException ex;
    +                    int cachePolicy;
    +                    try {
    +                        inetAddresses = getAddressesFromNameService(host, reqAddr);
    +                        ex = null;
    +                        cachePolicy = InetAddressCachePolicy.get();
    +                    } catch (UnknownHostException uhe) {
    +                        inetAddresses = null;
    +                        ex = uhe;
    +                        cachePolicy = InetAddressCachePolicy.getNegative();
    +                    }
    +                    // remove or replace us with cached addresses according to cachePolicy
    +                    if (cachePolicy == InetAddressCachePolicy.NEVER) {
    +                        cache.remove(host, this);
    +                    } else {
    +                        CachedAddresses cachedAddresses = new CachedAddresses(
    +                            host,
    +                            inetAddresses,
    +                            cachePolicy == InetAddressCachePolicy.FOREVER
    +                            ? 0L
    +                            // cachePolicy is in [s] - we need [ns]
    +                            : System.nanoTime() + 1000_000_000L * cachePolicy
    +                        );
    +                        if (cache.replace(host, this, cachedAddresses) &&
    +                            cachePolicy != InetAddressCachePolicy.FOREVER) {
    +                            // schedule expiry
    +                            expirySet.add(cachedAddresses);
    +                        }
    +                    }
    +                    if (inetAddresses == null) {
    +                        throw ex == null ? new UnknownHostException(host) : ex;
    +                    }
    +                    return inetAddresses;
    +                }
    +                // else addresses != this
    +            }
    +            // delegate to different addresses when we are already replaced
    +            // but outside of synchronized block to avoid any chance of dead-locking
    +            return addresses.get();
    +        }
    +    }
     
         static InetAddressImpl  impl;
     
    -    private static final HashMap lookupTable = new HashMap<>();
    -
    -    /**
    -     * Represents a cache entry
    -     */
    -    static final class CacheEntry {
    -
    -        CacheEntry(InetAddress[] addresses, long expiration) {
    -            this.addresses = addresses;
    -            this.expiration = expiration;
    -        }
    -
    -        InetAddress[] addresses;
    -        long expiration;
    -    }
    -
    -    /**
    -     * A cache that manages entries based on a policy specified
    -     * at creation time.
    -     */
    -    static final class Cache {
    -        private LinkedHashMap cache;
    -        private Type type;
    -
    -        enum Type {Positive, Negative};
    -
    -        /**
    -         * Create cache
    -         */
    -        public Cache(Type type) {
    -            this.type = type;
    -            cache = new LinkedHashMap();
    -        }
    -
    -        private int getPolicy() {
    -            if (type == Type.Positive) {
    -                return InetAddressCachePolicy.get();
    -            } else {
    -                return InetAddressCachePolicy.getNegative();
    -            }
    -        }
    -
    -        /**
    -         * Add an entry to the cache. If there's already an
    -         * entry then for this host then the entry will be
    -         * replaced.
    -         */
    -        public Cache put(String host, InetAddress[] addresses) {
    -            int policy = getPolicy();
    -            if (policy == InetAddressCachePolicy.NEVER) {
    -                return this;
    -            }
    -
    -            // purge any expired entries
    -
    -            if (policy != InetAddressCachePolicy.FOREVER) {
    -
    -                // As we iterate in insertion order we can
    -                // terminate when a non-expired entry is found.
    -                LinkedList expired = new LinkedList<>();
    -                long now = System.currentTimeMillis();
    -                for (String key : cache.keySet()) {
    -                    CacheEntry entry = cache.get(key);
    -
    -                    if (entry.expiration >= 0 && entry.expiration < now) {
    -                        expired.add(key);
    -                    } else {
    -                        break;
    -                    }
    -                }
    -
    -                for (String key : expired) {
    -                    cache.remove(key);
    -                }
    -            }
    -
    -            // create new entry and add it to the cache
    -            // -- as a HashMap replaces existing entries we
    -            //    don't need to explicitly check if there is
    -            //    already an entry for this host.
    -            long expiration;
    -            if (policy == InetAddressCachePolicy.FOREVER) {
    -                expiration = -1;
    -            } else {
    -                expiration = System.currentTimeMillis() + (policy * 1000);
    -            }
    -            CacheEntry entry = new CacheEntry(addresses, expiration);
    -            cache.put(host, entry);
    -            return this;
    -        }
    -
    -        /**
    -         * Query the cache for the specific host. If found then
    -         * return its CacheEntry, or null if not found.
    -         */
    -        public CacheEntry get(String host) {
    -            int policy = getPolicy();
    -            if (policy == InetAddressCachePolicy.NEVER) {
    -                return null;
    -            }
    -            CacheEntry entry = cache.get(host);
    -
    -            // check if entry has expired
    -            if (entry != null && policy != InetAddressCachePolicy.FOREVER) {
    -                if (entry.expiration >= 0 &&
    -                    entry.expiration < System.currentTimeMillis()) {
    -                    cache.remove(host);
    -                    entry = null;
    -                }
    -            }
    -
    -            return entry;
    -        }
    -    }
    -
    -    /*
    -     * Initialize cache and insert anyLocalAddress into the
    -     * unknown array with no expiry.
    -     */
    -    private static void cacheInitIfNeeded() {
    -        assert Thread.holdsLock(addressCache);
    -        if (addressCacheInit) {
    -            return;
    -        }
    -        unknown_array = new InetAddress[1];
    -        unknown_array[0] = impl.anyLocalAddress();
    -
    -        addressCache.put(impl.anyLocalAddress().getHostName(),
    -                         unknown_array);
    -
    -        addressCacheInit = true;
    -    }
    -
    -    /*
    -     * Cache the given hostname and addresses.
    -     */
    -    private static void cacheAddresses(String hostname,
    -                                       InetAddress[] addresses,
    -                                       boolean success) {
    -        hostname = hostname.toLowerCase();
    -        synchronized (addressCache) {
    -            cacheInitIfNeeded();
    -            if (success) {
    -                addressCache.put(hostname, addresses);
    -            } else {
    -                negativeCache.put(hostname, addresses);
    -            }
    -        }
    -    }
    -
    -    /*
    -     * Lookup hostname in cache (positive & negative cache). If
    -     * found return addresses, null if not found.
    -     */
    -    private static InetAddress[] getCachedAddresses(String hostname) {
    -        hostname = hostname.toLowerCase();
    -
    -        // search both positive & negative caches
    -
    -        synchronized (addressCache) {
    -            cacheInitIfNeeded();
    -
    -            CacheEntry entry = addressCache.get(hostname);
    -            if (entry == null) {
    -                entry = negativeCache.get(hostname);
    -            }
    -
    -            if (entry != null) {
    -                return entry.addresses;
    -            }
    -        }
    -
    -        // not found
    -        return null;
    -    }
    -
         private static NameService createNSProvider(String provider) {
             if (provider == null)
                 return null;
    @@ -1168,7 +1105,7 @@ class InetAddress implements java.io.Serializable {
                 // We were expecting an IPv6 Litteral, but got something else
                 throw new UnknownHostException("["+host+"]");
             }
    -        return getAllByName0(host, reqAddr, true);
    +        return getAllByName0(host, reqAddr, true, true);
         }
     
         /**
    @@ -1229,14 +1166,27 @@ class InetAddress implements java.io.Serializable {
          */
         static InetAddress[] getAllByName0 (String host, boolean check)
             throws UnknownHostException  {
    -        return getAllByName0 (host, null, check);
    +        return getAllByName0 (host, null, check, true);
         }
     
    -    private static InetAddress[] getAllByName0 (String host, InetAddress reqAddr, boolean check)
    +    /**
    +     * Designated lookup method.
    +     *
    +     * @param host host name to look up
    +     * @param reqAddr requested address to be the 1st in returned array
    +     * @param check perform security check
    +     * @param useCache use cached value if not expired else always
    +     *                 perform name service lookup (and cache the result)
    +     * @return array of InetAddress(es)
    +     * @throws UnknownHostException if host name is not found
    +     */
    +    private static InetAddress[] getAllByName0(String host,
    +                                               InetAddress reqAddr,
    +                                               boolean check,
    +                                               boolean useCache)
             throws UnknownHostException  {
     
             /* If it gets here it is presumed to be a hostname */
    -        /* Cache.get can return: null, unknownAddress, or InetAddress[] */
     
             /* make sure the connection to the host is allowed, before we
              * give out a hostname
    @@ -1248,155 +1198,106 @@ class InetAddress implements java.io.Serializable {
                 }
             }
     
    -        InetAddress[] addresses = getCachedAddresses(host);
    -
    -        /* If no entry in cache, then do the host lookup */
    -        if (addresses == null) {
    -            addresses = getAddressesFromNameService(host, reqAddr);
    +        // remove expired addresses from cache - expirySet keeps them ordered
    +        // by expiry time so we only need to iterate the prefix of the NavigableSet...
    +        long now = System.nanoTime();
    +        for (CachedAddresses caddrs : expirySet) {
    +            // compare difference of time instants rather than
    +            // time instants directly, to avoid possible overflow.
    +            // (see System.nanoTime() recommendations...)
    +            if ((caddrs.expiryTime - now) < 0L) {
    +                // ConcurrentSkipListSet uses weakly consistent iterator,
    +                // so removing while iterating is OK...
    +                if (expirySet.remove(caddrs)) {
    +                    // ... remove from cache
    +                    cache.remove(caddrs.host, caddrs);
    +                }
    +            } else {
    +                // we encountered 1st element that expires in future
    +                break;
    +            }
             }
     
    -        if (addresses == unknown_array)
    -            throw new UnknownHostException(host);
    +        // look-up or remove from cache
    +        Addresses addrs;
    +        if (useCache) {
    +            addrs = cache.get(host);
    +        } else {
    +            addrs = cache.remove(host);
    +            if (addrs != null) {
    +                if (addrs instanceof CachedAddresses) {
    +                    // try removing from expirySet too if CachedAddresses
    +                    expirySet.remove(addrs);
    +                }
    +                addrs = null;
    +            }
    +        }
     
    -        return addresses.clone();
    +        if (addrs == null) {
    +            // create a NameServiceAddresses instance which will look up
    +            // the name service and install it within cache...
    +            Addresses oldAddrs = cache.putIfAbsent(
    +                host,
    +                addrs = new NameServiceAddresses(host, reqAddr)
    +            );
    +            if (oldAddrs != null) { // lost putIfAbsent race
    +                addrs = oldAddrs;
    +            }
    +        }
    +
    +        // ask Addresses to get an array of InetAddress(es) and clone it
    +        return addrs.get().clone();
         }
     
    -    private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
    +    static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
             throws UnknownHostException
         {
             InetAddress[] addresses = null;
    -        boolean success = false;
             UnknownHostException ex = null;
     
    -        // Check whether the host is in the lookupTable.
    -        // 1) If the host isn't in the lookupTable when
    -        //    checkLookupTable() is called, checkLookupTable()
    -        //    would add the host in the lookupTable and
    -        //    return null. So we will do the lookup.
    -        // 2) If the host is in the lookupTable when
    -        //    checkLookupTable() is called, the current thread
    -        //    would be blocked until the host is removed
    -        //    from the lookupTable. Then this thread
    -        //    should try to look up the addressCache.
    -        //     i) if it found the addresses in the
    -        //        addressCache, checkLookupTable()  would
    -        //        return the addresses.
    -        //     ii) if it didn't find the addresses in the
    -        //         addressCache for any reason,
    -        //         it should add the host in the
    -        //         lookupTable and return null so the
    -        //         following code would do  a lookup itself.
    -        if ((addresses = checkLookupTable(host)) == null) {
    +        for (NameService nameService : nameServices) {
                 try {
    -                // This is the first thread which looks up the addresses
    -                // this host or the cache entry for this host has been
    -                // expired so this thread should do the lookup.
    -                for (NameService nameService : nameServices) {
    -                    try {
    -                        /*
    -                         * Do not put the call to lookup() inside the
    -                         * constructor.  if you do you will still be
    -                         * allocating space when the lookup fails.
    -                         */
    -
    -                        addresses = nameService.lookupAllHostAddr(host);
    -                        success = true;
    -                        break;
    -                    } catch (UnknownHostException uhe) {
    -                        if (host.equalsIgnoreCase("localhost")) {
    -                            InetAddress[] local = new InetAddress[] { impl.loopbackAddress() };
    -                            addresses = local;
    -                            success = true;
    -                            break;
    -                        }
    -                        else {
    -                            addresses = unknown_array;
    -                            success = false;
    -                            ex = uhe;
    -                        }
    -                    }
    +                addresses = nameService.lookupAllHostAddr(host);
    +                break;
    +            } catch (UnknownHostException uhe) {
    +                if (host.equalsIgnoreCase("localhost")) {
    +                    addresses = new InetAddress[] { impl.loopbackAddress() };
    +                    break;
                     }
    -
    -                // More to do?
    -                if (reqAddr != null && addresses.length > 1 && !addresses[0].equals(reqAddr)) {
    -                    // Find it?
    -                    int i = 1;
    -                    for (; i < addresses.length; i++) {
    -                        if (addresses[i].equals(reqAddr)) {
    -                            break;
    -                        }
    -                    }
    -                    // Rotate
    -                    if (i < addresses.length) {
    -                        InetAddress tmp, tmp2 = reqAddr;
    -                        for (int j = 0; j < i; j++) {
    -                            tmp = addresses[j];
    -                            addresses[j] = tmp2;
    -                            tmp2 = tmp;
    -                        }
    -                        addresses[i] = tmp2;
    -                    }
    -                }
    -                // Cache the address.
    -                cacheAddresses(host, addresses, success);
    -
    -                if (!success && ex != null)
    -                    throw ex;
    -
    -            } finally {
    -                // Delete host from the lookupTable and notify
    -                // all threads waiting on the lookupTable monitor.
    -                updateLookupTable(host);
    -            }
    -        }
    -
    -        return addresses;
    -    }
    -
    -
    -    private static InetAddress[] checkLookupTable(String host) {
    -        synchronized (lookupTable) {
    -            // If the host isn't in the lookupTable, add it in the
    -            // lookuptable and return null. The caller should do
    -            // the lookup.
    -            if (lookupTable.containsKey(host) == false) {
    -                lookupTable.put(host, null);
    -                return null;
    -            }
    -
    -            // If the host is in the lookupTable, it means that another
    -            // thread is trying to look up the addresses of this host.
    -            // This thread should wait.
    -            while (lookupTable.containsKey(host)) {
    -                try {
    -                    lookupTable.wait();
    -                } catch (InterruptedException e) {
    +                else {
    +                    ex = uhe;
                     }
                 }
             }
     
    -        // The other thread has finished looking up the addresses of
    -        // the host. This thread should retry to get the addresses
    -        // from the addressCache. If it doesn't get the addresses from
    -        // the cache, it will try to look up the addresses itself.
    -        InetAddress[] addresses = getCachedAddresses(host);
             if (addresses == null) {
    -            synchronized (lookupTable) {
    -                lookupTable.put(host, null);
    -                return null;
    +            throw ex == null ? new UnknownHostException(host) : ex;
    +        }
    +
    +        // More to do?
    +        if (reqAddr != null && addresses.length > 1 && !addresses[0].equals(reqAddr)) {
    +            // Find it?
    +            int i = 1;
    +            for (; i < addresses.length; i++) {
    +                if (addresses[i].equals(reqAddr)) {
    +                    break;
    +                }
    +            }
    +            // Rotate
    +            if (i < addresses.length) {
    +                InetAddress tmp, tmp2 = reqAddr;
    +                for (int j = 0; j < i; j++) {
    +                    tmp = addresses[j];
    +                    addresses[j] = tmp2;
    +                    tmp2 = tmp;
    +                }
    +                addresses[i] = tmp2;
                 }
             }
     
             return addresses;
         }
     
    -    private static void updateLookupTable(String host) {
    -        synchronized (lookupTable) {
    -            lookupTable.remove(host);
    -            lookupTable.notifyAll();
    -        }
    -    }
    -
         /**
          * Returns an {@code InetAddress} object given the raw IP address .
          * The argument is in network byte order: the highest order
    @@ -1418,10 +1319,18 @@ class InetAddress implements java.io.Serializable {
             return getByAddress(null, addr);
         }
     
    -    private static InetAddress cachedLocalHost = null;
    -    private static long cacheTime = 0;
    -    private static final long maxCacheTime = 5000L;
    -    private static final Object cacheLock = new Object();
    +    private static final class CachedLocalHost {
    +        final String host;
    +        final InetAddress addr;
    +        final long expiryTime = System.nanoTime() + 5000_000_000L; // now + 5s;
    +
    +        CachedLocalHost(String host, InetAddress addr) {
    +            this.host = host;
    +            this.addr = addr;
    +        }
    +    }
    +
    +    private static volatile CachedLocalHost cachedLocalHost;
     
         /**
          * Returns the address of the local host. This is achieved by retrieving
    @@ -1450,47 +1359,41 @@ class InetAddress implements java.io.Serializable {
     
             SecurityManager security = System.getSecurityManager();
             try {
    +            // is cached data still valid?
    +            CachedLocalHost clh = cachedLocalHost;
    +            if (clh != null && (clh.expiryTime - System.nanoTime()) >= 0L) {
    +                if (security != null) {
    +                    security.checkConnect(clh.host, -1);
    +                }
    +                return clh.addr;
    +            }
    +
                 String local = impl.getLocalHostName();
     
                 if (security != null) {
                     security.checkConnect(local, -1);
                 }
     
    +            InetAddress localAddr;
                 if (local.equals("localhost")) {
    -                return impl.loopbackAddress();
    -            }
    -
    -            InetAddress ret = null;
    -            synchronized (cacheLock) {
    -                long now = System.currentTimeMillis();
    -                if (cachedLocalHost != null) {
    -                    if ((now - cacheTime) < maxCacheTime) // Less than 5s old?
    -                        ret = cachedLocalHost;
    -                    else
    -                        cachedLocalHost = null;
    -                }
    -
    -                // we are calling getAddressesFromNameService directly
    -                // to avoid getting localHost from cache
    -                if (ret == null) {
    -                    InetAddress[] localAddrs;
    -                    try {
    -                        localAddrs =
    -                            InetAddress.getAddressesFromNameService(local, null);
    -                    } catch (UnknownHostException uhe) {
    -                        // Rethrow with a more informative error message.
    -                        UnknownHostException uhe2 =
    -                            new UnknownHostException(local + ": " +
    -                                                     uhe.getMessage());
    -                        uhe2.initCause(uhe);
    -                        throw uhe2;
    -                    }
    -                    cachedLocalHost = localAddrs[0];
    -                    cacheTime = now;
    -                    ret = localAddrs[0];
    +                // shortcut for "localhost" host name
    +                localAddr = impl.loopbackAddress();
    +            } else {
    +                // call getAllByName0 without security checks and
    +                // without using cached data
    +                try {
    +                    localAddr = getAllByName0(local, null, false, false)[0];
    +                } catch (UnknownHostException uhe) {
    +                    // Rethrow with a more informative error message.
    +                    UnknownHostException uhe2 =
    +                        new UnknownHostException(local + ": " +
    +                                                 uhe.getMessage());
    +                    uhe2.initCause(uhe);
    +                    throw uhe2;
                     }
                 }
    -            return ret;
    +            cachedLocalHost = new CachedLocalHost(local, localAddr);
    +            return localAddr;
             } catch (java.lang.SecurityException e) {
                 return impl.loopbackAddress();
             }
    diff --git a/jdk/src/java.base/share/classes/java/net/NetPermission.java b/jdk/src/java.base/share/classes/java/net/NetPermission.java
    index 9178f348723..dad3fb99f32 100644
    --- a/jdk/src/java.base/share/classes/java/net/NetPermission.java
    +++ b/jdk/src/java.base/share/classes/java/net/NetPermission.java
    @@ -72,10 +72,10 @@ import java.util.StringTokenizer;
      *   
      *
      * 
    - *  getNetworkInformation
    - *  The ability to retrieve all information about local network interfaces.
    - *  Malicious code can read information about network hardware such as
    - *  MAC addresses, which could be used to construct local IPv6 addresses.
    + *   getNetworkInformation
    + *   The ability to retrieve all information about local network interfaces.
    + *   Malicious code can read information about network hardware such as
    + *   MAC addresses, which could be used to construct local IPv6 addresses.
      * 
      *
      * 
    @@ -98,8 +98,8 @@ import java.util.StringTokenizer;
      * 
      *   requestPasswordAuthentication
      *   The ability
    - * to ask the authenticator registered with the system for
    - * a password
    + *   to ask the authenticator registered with the system for
    + *   a password
      *   Malicious code may steal this password.
      * 
      *
    @@ -116,11 +116,11 @@ import java.util.StringTokenizer;
      * 
      *   setDefaultAuthenticator
      *   The ability to set the
    - * way authentication information is retrieved when
    - * a proxy or HTTP server asks for authentication
    + *   way authentication information is retrieved when
    + *   a proxy or HTTP server asks for authentication
      *   Malicious
    - * code can set an authenticator that monitors and steals user
    - * authentication input as it retrieves the input from the user.
    + *   code can set an authenticator that monitors and steals user
    + *   authentication input as it retrieves the input from the user.
      * 
      *
      * 
    @@ -143,13 +143,13 @@ import java.util.StringTokenizer;
      * 
      *   specifyStreamHandler
      *   The ability
    - * to specify a stream handler when constructing a URL
    + *   to specify a stream handler when constructing a URL
      *   Malicious code may create a URL with resources that it would
    -normally not have access to (like file:/foo/fum/), specifying a
    -stream handler that gets the actual bytes from someplace it does
    -have access to. Thus it might be able to trick the system into
    -creating a ProtectionDomain/CodeSource for a class even though
    -that class really didn't come from that location.
    + *   normally not have access to (like file:/foo/fum/), specifying a
    + *   stream handler that gets the actual bytes from someplace it does
    + *   have access to. Thus it might be able to trick the system into
    + *   creating a ProtectionDomain/CodeSource for a class even though
    + *   that class really didn't come from that location.
      * 
      * 
      *
    diff --git a/jdk/src/java.base/share/classes/java/net/SocketInputStream.java b/jdk/src/java.base/share/classes/java/net/SocketInputStream.java
    index 224051ff608..41b18bdc7e0 100644
    --- a/jdk/src/java.base/share/classes/java/net/SocketInputStream.java
    +++ b/jdk/src/java.base/share/classes/java/net/SocketInputStream.java
    @@ -96,6 +96,26 @@ class SocketInputStream extends FileInputStream
                                        int timeout)
             throws IOException;
     
    +    // wrap native call to allow instrumentation
    +    /**
    +     * Reads into an array of bytes at the specified offset using
    +     * the received socket primitive.
    +     * @param fd the FileDescriptor
    +     * @param b the buffer into which the data is read
    +     * @param off the start offset of the data
    +     * @param len the maximum number of bytes read
    +     * @param timeout the read timeout in ms
    +     * @return the actual number of bytes read, -1 is
    +     *          returned when the end of the stream is reached.
    +     * @exception IOException If an I/O error has occurred.
    +     */
    +    private int socketRead(FileDescriptor fd,
    +                           byte b[], int off, int len,
    +                           int timeout)
    +        throws IOException {
    +        return socketRead0(fd, b, off, len, timeout);
    +    }
    +
         /**
          * Reads into a byte array data from the socket.
          * @param b the buffer into which the data is read
    @@ -147,7 +167,7 @@ class SocketInputStream extends FileInputStream
             // acquire file descriptor and do the read
             FileDescriptor fd = impl.acquireFD();
             try {
    -            n = socketRead0(fd, b, off, length, timeout);
    +            n = socketRead(fd, b, off, length, timeout);
                 if (n > 0) {
                     return n;
                 }
    @@ -165,7 +185,7 @@ class SocketInputStream extends FileInputStream
                 impl.setConnectionResetPending();
                 impl.acquireFD();
                 try {
    -                n = socketRead0(fd, b, off, length, timeout);
    +                n = socketRead(fd, b, off, length, timeout);
                     if (n > 0) {
                         return n;
                     }
    diff --git a/jdk/src/java.base/share/classes/java/net/SocketPermission.java b/jdk/src/java.base/share/classes/java/net/SocketPermission.java
    index 1f3248077be..8894152512b 100644
    --- a/jdk/src/java.base/share/classes/java/net/SocketPermission.java
    +++ b/jdk/src/java.base/share/classes/java/net/SocketPermission.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2013, 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
    @@ -30,6 +30,7 @@ import java.util.Vector;
     import java.util.List;
     import java.util.ArrayList;
     import java.util.Collections;
    +import java.util.StringJoiner;
     import java.util.StringTokenizer;
     import java.net.InetAddress;
     import java.security.Permission;
    @@ -1112,36 +1113,21 @@ public final class SocketPermission extends Permission
          * @param mask a specific integer action mask to translate into a string
          * @return the canonical string representation of the actions
          */
    -    private static String getActions(int mask)
    -    {
    -        StringBuilder sb = new StringBuilder();
    -        boolean comma = false;
    -
    +    private static String getActions(int mask) {
    +        StringJoiner sj = new StringJoiner(",");
             if ((mask & CONNECT) == CONNECT) {
    -            comma = true;
    -            sb.append("connect");
    +            sj.add("connect");
             }
    -
             if ((mask & LISTEN) == LISTEN) {
    -            if (comma) sb.append(',');
    -            else comma = true;
    -            sb.append("listen");
    +            sj.add("listen");
             }
    -
             if ((mask & ACCEPT) == ACCEPT) {
    -            if (comma) sb.append(',');
    -            else comma = true;
    -            sb.append("accept");
    +            sj.add("accept");
             }
    -
    -
             if ((mask & RESOLVE) == RESOLVE) {
    -            if (comma) sb.append(',');
    -            else comma = true;
    -            sb.append("resolve");
    +            sj.add("resolve");
             }
    -
    -        return sb.toString();
    +        return sj.toString();
         }
     
         /**
    diff --git a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java
    index e448a120bdc..6f4691404c3 100644
    --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java
    +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2013, 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
    @@ -407,6 +407,29 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
             return pkg;
         }
     
    +    // Also called by VM to define Package for classes loaded from the CDS
    +    // archive
    +    private void definePackageInternal(String pkgname, Manifest man, URL url)
    +    {
    +        if (getAndVerifyPackage(pkgname, man, url) == null) {
    +            try {
    +                if (man != null) {
    +                    definePackage(pkgname, man, url);
    +                } else {
    +                    definePackage(pkgname, null, null, null, null, null, null, null);
    +                }
    +            } catch (IllegalArgumentException iae) {
    +                // parallel-capable class loaders: re-verify in case of a
    +                // race condition
    +                if (getAndVerifyPackage(pkgname, man, url) == null) {
    +                    // Should never happen
    +                    throw new AssertionError("Cannot find package " +
    +                                             pkgname);
    +                }
    +            }
    +        }
    +    }
    +
         /*
          * Defines a Class using the class bytes obtained from the specified
          * Resource. The resulting Class must be resolved before it can be
    @@ -420,23 +443,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
                 String pkgname = name.substring(0, i);
                 // Check if package already loaded.
                 Manifest man = res.getManifest();
    -            if (getAndVerifyPackage(pkgname, man, url) == null) {
    -                try {
    -                    if (man != null) {
    -                        definePackage(pkgname, man, url);
    -                    } else {
    -                        definePackage(pkgname, null, null, null, null, null, null, null);
    -                    }
    -                } catch (IllegalArgumentException iae) {
    -                    // parallel-capable class loaders: re-verify in case of a
    -                    // race condition
    -                    if (getAndVerifyPackage(pkgname, man, url) == null) {
    -                        // Should never happen
    -                        throw new AssertionError("Cannot find package " +
    -                                                 pkgname);
    -                    }
    -                }
    -            }
    +            definePackageInternal(pkgname, man, url);
             }
             // Now read the class bytes and define the class
             java.nio.ByteBuffer bb = res.getByteBuffer();
    diff --git a/jdk/src/java.base/share/classes/java/security/SecureRandom.java b/jdk/src/java.base/share/classes/java/security/SecureRandom.java
    index b9ae7220b38..0accb4cc7a4 100644
    --- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java
    +++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1996, 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
    @@ -39,15 +39,16 @@ import sun.security.jca.GetInstance.Instance;
      *
      * 

    A cryptographically strong random number * minimally complies with the statistical random number generator tests - * specified in + * specified in + * * FIPS 140-2, Security Requirements for Cryptographic Modules, * section 4.9.1. * Additionally, SecureRandom must produce non-deterministic output. * Therefore any seed material passed to a SecureRandom object must be * unpredictable, and all SecureRandom output sequences must be * cryptographically strong, as described in - * - * RFC 1750: Randomness Recommendations for Security. + * + * RFC 4086: Randomness Requirements for Security. * *

    A caller obtains a SecureRandom instance via the * no-argument constructor or one of the {@code getInstance} methods: diff --git a/jdk/src/java.base/share/classes/java/text/CalendarBuilder.java b/jdk/src/java.base/share/classes/java/text/CalendarBuilder.java index a8246b676ca..cb30a358ea4 100644 --- a/jdk/src/java.base/share/classes/java/text/CalendarBuilder.java +++ b/jdk/src/java.base/share/classes/java/text/CalendarBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -26,6 +26,7 @@ package java.text; import java.util.Calendar; +import java.util.StringJoiner; import static java.util.GregorianCalendar.*; /** @@ -146,19 +147,13 @@ class CalendarBuilder { } public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("CalendarBuilder:["); + StringJoiner sj = new StringJoiner(",", "CalendarBuilder:[", "]"); for (int i = 0; i < field.length; i++) { if (isSet(i)) { - sb.append(i).append('=').append(field[MAX_FIELD + i]).append(','); + sj.add(i + "=" + field[MAX_FIELD + i]); } } - int lastIndex = sb.length() - 1; - if (sb.charAt(lastIndex) == ',') { - sb.setLength(lastIndex); - } - sb.append(']'); - return sb.toString(); + return sj.toString(); } static int toISODayOfWeek(int calendarDayOfWeek) { diff --git a/jdk/src/java.base/share/classes/java/time/Duration.java b/jdk/src/java.base/share/classes/java/time/Duration.java index cb672c4d3b4..30d146dbf64 100644 --- a/jdk/src/java.base/share/classes/java/time/Duration.java +++ b/jdk/src/java.base/share/classes/java/time/Duration.java @@ -388,19 +388,21 @@ public final class Duration Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { // check for letter T but no time sections - if ("T".equals(matcher.group(3)) == false) { - boolean negate = "-".equals(matcher.group(1)); - String dayMatch = matcher.group(2); - String hourMatch = matcher.group(4); - String minuteMatch = matcher.group(5); - String secondMatch = matcher.group(6); - String fractionMatch = matcher.group(7); - if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) { - long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days"); - long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours"); - long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes"); - long seconds = parseNumber(text, secondMatch, 1, "seconds"); - int nanos = parseFraction(text, fractionMatch, seconds < 0 ? -1 : 1); + if (!charMatch(text, matcher.start(3), matcher.end(3), 'T')) { + boolean negate = charMatch(text, matcher.start(1), matcher.end(1), '-'); + + int dayStart = matcher.start(2), dayEnd = matcher.end(2); + int hourStart = matcher.start(4), hourEnd = matcher.end(4); + int minuteStart = matcher.start(5), minuteEnd = matcher.end(5); + int secondStart = matcher.start(6), secondEnd = matcher.end(6); + int fractionStart = matcher.start(7), fractionEnd = matcher.end(7); + + if (dayStart >= 0 || hourStart >= 0 || minuteStart >= 0 || secondStart >= 0) { + long daysAsSecs = parseNumber(text, dayStart, dayEnd, SECONDS_PER_DAY, "days"); + long hoursAsSecs = parseNumber(text, hourStart, hourEnd, SECONDS_PER_HOUR, "hours"); + long minsAsSecs = parseNumber(text, minuteStart, minuteEnd, SECONDS_PER_MINUTE, "minutes"); + long seconds = parseNumber(text, secondStart, secondEnd, 1, "seconds"); + int nanos = parseFraction(text, fractionStart, fractionEnd, seconds < 0 ? -1 : 1); try { return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos); } catch (ArithmeticException ex) { @@ -412,27 +414,37 @@ public final class Duration throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0); } - private static long parseNumber(CharSequence text, String parsed, int multiplier, String errorText) { + private static boolean charMatch(CharSequence text, int start, int end, char c) { + return (start >= 0 && end == start + 1 && text.charAt(start) == c); + } + + private static long parseNumber(CharSequence text, int start, int end, int multiplier, String errorText) { // regex limits to [-+]?[0-9]+ - if (parsed == null) { + if (start < 0 || end < 0) { return 0; } try { - long val = Long.parseLong(parsed); + long val = Long.parseLong(text, 10, start, end); return Math.multiplyExact(val, multiplier); } catch (NumberFormatException | ArithmeticException ex) { throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex); } } - private static int parseFraction(CharSequence text, String parsed, int negate) { + private static int parseFraction(CharSequence text, int start, int end, int negate) { // regex limits to [0-9]{0,9} - if (parsed == null || parsed.length() == 0) { + if (start < 0 || end < 0 || end - start == 0) { return 0; } try { - parsed = (parsed + "000000000").substring(0, 9); - return Integer.parseInt(parsed) * negate; + int fraction = Integer.parseInt(text, 10, start, end); + + // for number strings smaller than 9 digits, interpret as if there + // were trailing zeros + for (int i = end - start; i < 9; i++) { + fraction *= 10; + } + return fraction * negate; } catch (NumberFormatException | ArithmeticException ex) { throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex); } diff --git a/jdk/src/java.base/share/classes/java/time/Period.java b/jdk/src/java.base/share/classes/java/time/Period.java index 5d808a42b41..88adb958fa0 100644 --- a/jdk/src/java.base/share/classes/java/time/Period.java +++ b/jdk/src/java.base/share/classes/java/time/Period.java @@ -329,17 +329,17 @@ public final class Period Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { - int negate = ("-".equals(matcher.group(1)) ? -1 : 1); - String yearMatch = matcher.group(2); - String monthMatch = matcher.group(3); - String weekMatch = matcher.group(4); - String dayMatch = matcher.group(5); - if (yearMatch != null || monthMatch != null || dayMatch != null || weekMatch != null) { + int negate = (charMatch(text, matcher.start(1), matcher.end(1), '-') ? -1 : 1); + int yearStart = matcher.start(2), yearEnd = matcher.end(2); + int monthStart = matcher.start(3), monthEnd = matcher.end(3); + int weekStart = matcher.start(4), weekEnd = matcher.end(4); + int dayStart = matcher.start(5), dayEnd = matcher.end(5); + if (yearStart >= 0 || monthStart >= 0 || weekStart >= 0 || dayStart >= 0) { try { - int years = parseNumber(text, yearMatch, negate); - int months = parseNumber(text, monthMatch, negate); - int weeks = parseNumber(text, weekMatch, negate); - int days = parseNumber(text, dayMatch, negate); + int years = parseNumber(text, yearStart, yearEnd, negate); + int months = parseNumber(text, monthStart, monthEnd, negate); + int weeks = parseNumber(text, weekStart, weekEnd, negate); + int days = parseNumber(text, dayStart, dayEnd, negate); days = Math.addExact(days, Math.multiplyExact(weeks, 7)); return create(years, months, days); } catch (NumberFormatException ex) { @@ -350,11 +350,15 @@ public final class Period throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0); } - private static int parseNumber(CharSequence text, String str, int negate) { - if (str == null) { + private static boolean charMatch(CharSequence text, int start, int end, char c) { + return (start >= 0 && end == start + 1 && text.charAt(start) == c); + } + + private static int parseNumber(CharSequence text, int start, int end, int negate) { + if (start < 0 || end < 0) { return 0; } - int val = Integer.parseInt(str); + int val = Integer.parseInt(text, 10, start, end); try { return Math.multiplyExact(val, negate); } catch (ArithmeticException ex) { diff --git a/jdk/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java b/jdk/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java index e37374af15f..81b769af01f 100644 --- a/jdk/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java +++ b/jdk/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -38,20 +38,20 @@ import sun.util.calendar.LocalGregorianCalendar; import sun.util.calendar.ZoneInfo; /** - * JapaneseImperialCalendar implements a Japanese + * {@code JapaneseImperialCalendar} implements a Japanese * calendar system in which the imperial era-based year numbering is * supported from the Meiji era. The following are the eras supported * by this calendar system. - *

    
    + * 
    {@code
      * ERA value   Era name    Since (in Gregorian)
      * ------------------------------------------------------
      *     0       N/A         N/A
    - *     1       Meiji       1868-01-01 midnight local time
    - *     2       Taisho      1912-07-30 midnight local time
    - *     3       Showa       1926-12-25 midnight local time
    - *     4       Heisei      1989-01-08 midnight local time
    + *     1       Meiji       1868-01-01T00:00:00 local time
    + *     2       Taisho      1912-07-30T00:00:00 local time
    + *     3       Showa       1926-12-25T00:00:00 local time
    + *     4       Heisei      1989-01-08T00:00:00 local time
      * ------------------------------------------------------
    - * 
    + * }
    * *

    ERA value 0 specifies the years before Meiji and * the Gregorian year values are used. Unlike {@link @@ -63,6 +63,31 @@ import sun.util.calendar.ZoneInfo; * with time differences for applying the era transitions. This * calendar implementation assumes local time for all transitions. * + *

    A new era can be specified using property + * jdk.calendar.japanese.supplemental.era. The new era is added to the + * predefined eras. The syntax of the property is as follows. + *

    + *   {@code name=,abbr=,since=}
    + * 
    + * where + *
    + *
    {@code :}
    the full name of the new era (non-ASCII characters allowed) + *
    {@code :}
    the abbreviation of the new era (non-ASCII characters allowed) + *
    {@code :}
    the start time of the new era represented by + * milliseconds from 1970-01-01T00:00:00 local time or UTC if {@code 'u'} is + * appended to the milliseconds value. (ASCII digits only) + *
    + * + *

    If the given era is invalid, such as the since value before the + * beginning of the last predefined era, the given era will be + * ignored. + * + *

    The following is an example of the property usage. + *

    + *   java -Djdk.calendar.japanese.supplemental.era="name=NewEra,abbr=N,since=253374307200000"
    + * 
    + * The property specifies an era change to NewEra at 9999-02-11T00:00:00 local time. + * * @author Masayoshi Okutsu * @since 1.6 */ @@ -102,7 +127,6 @@ class JapaneseImperialCalendar extends Calendar { public static final int HEISEI = 4; private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian) - private static final int EPOCH_YEAR = 1970; // Useful millisecond constants. Although ONE_DAY and ONE_WEEK can fit // into ints, they must be longs in order to prevent arithmetic overflow @@ -111,7 +135,6 @@ class JapaneseImperialCalendar extends Calendar { private static final int ONE_MINUTE = 60*ONE_SECOND; private static final int ONE_HOUR = 60*ONE_MINUTE; private static final long ONE_DAY = 24*ONE_HOUR; - private static final long ONE_WEEK = 7*ONE_DAY; // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton). private static final LocalGregorianCalendar jcal @@ -217,6 +240,7 @@ class JapaneseImperialCalendar extends Calendar { }; // Proclaim serialization compatibility with JDK 1.6 + @SuppressWarnings("FieldNameHidesFieldInSuperclass") private static final long serialVersionUID = -3364572813905467929L; static { @@ -340,6 +364,7 @@ class JapaneseImperialCalendar extends Calendar { * false otherwise. * @see Calendar#compareTo(Calendar) */ + @Override public boolean equals(Object obj) { return obj instanceof JapaneseImperialCalendar && super.equals(obj); @@ -349,6 +374,7 @@ class JapaneseImperialCalendar extends Calendar { * Generates the hash code for this * JapaneseImperialCalendar object. */ + @Override public int hashCode() { return super.hashCode() ^ jdate.hashCode(); } @@ -381,6 +407,7 @@ class JapaneseImperialCalendar extends Calendar { * or if any calendar fields have out-of-range values in * non-lenient mode. */ + @Override public void add(int field, int amount) { // If amount == 0, do nothing even the given field is out of // range. This is tested by JCK. @@ -509,6 +536,7 @@ class JapaneseImperialCalendar extends Calendar { } } + @Override public void roll(int field, boolean up) { roll(field, up ? +1 : -1); } @@ -533,6 +561,7 @@ class JapaneseImperialCalendar extends Calendar { * @see #add(int,int) * @see #set(int,int) */ + @Override public void roll(int field, int amount) { // If amount == 0, do nothing even the given field is out of // range. This is tested by JCK. diff --git a/jdk/src/java.base/share/classes/java/util/Locale.java b/jdk/src/java.base/share/classes/java/util/Locale.java index fbcb2f75e66..cf29686e693 100644 --- a/jdk/src/java.base/share/classes/java/util/Locale.java +++ b/jdk/src/java.base/share/classes/java/util/Locale.java @@ -2059,14 +2059,11 @@ public final class Locale implements Cloneable, Serializable { // If we have no list patterns, compose the list in a simple, // non-localized way. if (listPattern == null || listCompositionPattern == null) { - StringBuilder result = new StringBuilder(); + StringJoiner sj = new StringJoiner(","); for (int i = 0; i < stringList.length; ++i) { - if (i > 0) { - result.append(','); - } - result.append(stringList[i]); + sj.add(stringList[i]); } - return result.toString(); + return sj.toString(); } // Compose the list down to three elements if necessary diff --git a/jdk/src/java.base/share/classes/java/util/PropertyPermission.java b/jdk/src/java.base/share/classes/java/util/PropertyPermission.java index d532bddabf6..7e818a90b64 100644 --- a/jdk/src/java.base/share/classes/java/util/PropertyPermission.java +++ b/jdk/src/java.base/share/classes/java/util/PropertyPermission.java @@ -324,20 +324,16 @@ public final class PropertyPermission extends BasicPermission { * @return the canonical string representation of the actions. */ static String getActions(int mask) { - StringBuilder sb = new StringBuilder(); - boolean comma = false; - - if ((mask & READ) == READ) { - comma = true; - sb.append("read"); + switch (mask & (READ|WRITE)) { + case READ: + return SecurityConstants.PROPERTY_READ_ACTION; + case WRITE: + return SecurityConstants.PROPERTY_WRITE_ACTION; + case READ|WRITE: + return SecurityConstants.PROPERTY_RW_ACTION; + default: + return ""; } - - if ((mask & WRITE) == WRITE) { - if (comma) sb.append(','); - else comma = true; - sb.append("write"); - } - return sb.toString(); } /** diff --git a/jdk/src/java.base/share/classes/java/util/StringJoiner.java b/jdk/src/java.base/share/classes/java/util/StringJoiner.java index b6ba84c5df8..b08a2f9b711 100644 --- a/jdk/src/java.base/share/classes/java/util/StringJoiner.java +++ b/jdk/src/java.base/share/classes/java/util/StringJoiner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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,6 +24,9 @@ */ package java.util; +import sun.misc.JavaLangAccess; +import sun.misc.SharedSecrets; + /** * {@code StringJoiner} is used to construct a sequence of characters separated * by a delimiter and optionally starting with a supplied prefix @@ -67,22 +70,24 @@ public final class StringJoiner { private final String delimiter; private final String suffix; - /* - * StringBuilder value -- at any time, the characters constructed from the - * prefix, the added element separated by the delimiter, but without the - * suffix, so that we can more easily add elements without having to jigger - * the suffix each time. - */ - private StringBuilder value; + /** Contains all the string components added so far. */ + private String[] elts; - /* - * By default, the string consisting of prefix+suffix, returned by - * toString(), or properties of value, when no elements have yet been added, - * i.e. when it is empty. This may be overridden by the user to be some - * other value including the empty String. + /** The number of string components added so far. */ + private int size; + + /** Total length in chars so far, excluding prefix and suffix. */ + private int len; + + /** + * When overriden by the user to be non-null via {@link setEmptyValue}, the + * string returned by toString() when no elements have yet been added. + * When null, prefix + suffix is used as the empty value. */ private String emptyValue; + private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + /** * Constructs a {@code StringJoiner} with no characters in it, with no * {@code prefix} or {@code suffix}, and a copy of the supplied @@ -125,7 +130,6 @@ public final class StringJoiner { this.prefix = prefix.toString(); this.delimiter = delimiter.toString(); this.suffix = suffix.toString(); - this.emptyValue = this.prefix + this.suffix; } /** @@ -148,29 +152,44 @@ public final class StringJoiner { return this; } + private static int getChars(String s, char[] chars, int start) { + int len = s.length(); + s.getChars(0, len, chars, start); + return len; + } + /** * Returns the current value, consisting of the {@code prefix}, the values * added so far separated by the {@code delimiter}, and the {@code suffix}, * unless no elements have been added in which case, the - * {@code prefix + suffix} or the {@code emptyValue} characters are returned + * {@code prefix + suffix} or the {@code emptyValue} characters are returned. * * @return the string representation of this {@code StringJoiner} */ @Override public String toString() { - if (value == null) { + final String[] elts = this.elts; + if (elts == null && emptyValue != null) { return emptyValue; - } else { - if (suffix.equals("")) { - return value.toString(); - } else { - int initialLength = value.length(); - String result = value.append(suffix).toString(); - // reset value to pre-append initialLength - value.setLength(initialLength); - return result; + } + final int size = this.size; + final int addLen = prefix.length() + suffix.length(); + if (addLen == 0) { + compactElts(); + return size == 0 ? "" : elts[0]; + } + final String delimiter = this.delimiter; + final char[] chars = new char[len + addLen]; + int k = getChars(prefix, chars, 0); + if (size > 0) { + k += getChars(elts[0], chars, k); + for (int i = 1; i < size; i++) { + k += getChars(delimiter, chars, k); + k += getChars(elts[i], chars, k); } } + k += getChars(suffix, chars, k); + return jla.newStringUnsafe(chars); } /** @@ -182,7 +201,16 @@ public final class StringJoiner { * @return a reference to this {@code StringJoiner} */ public StringJoiner add(CharSequence newElement) { - prepareBuilder().append(newElement); + final String elt = String.valueOf(newElement); + if (elts == null) { + elts = new String[8]; + } else { + if (size == elts.length) + elts = Arrays.copyOf(elts, 2 * size); + len += delimiter.length(); + } + len += elt.length(); + elts[size++] = elt; return this; } @@ -207,24 +235,25 @@ public final class StringJoiner { */ public StringJoiner merge(StringJoiner other) { Objects.requireNonNull(other); - if (other.value != null) { - final int length = other.value.length(); - // lock the length so that we can seize the data to be appended - // before initiate copying to avoid interference, especially when - // merge 'this' - StringBuilder builder = prepareBuilder(); - builder.append(other.value, other.prefix.length(), length); + if (other.elts == null) { + return this; } - return this; + other.compactElts(); + return add(other.elts[0]); } - private StringBuilder prepareBuilder() { - if (value != null) { - value.append(delimiter); - } else { - value = new StringBuilder().append(prefix); + private void compactElts() { + if (size > 1) { + final char[] chars = new char[len]; + int i = 1, k = getChars(elts[0], chars, 0); + do { + k += getChars(delimiter, chars, k); + k += getChars(elts[i], chars, k); + elts[i] = null; + } while (++i < size); + size = 1; + elts[0] = jla.newStringUnsafe(chars); } - return value; } /** @@ -238,10 +267,7 @@ public final class StringJoiner { * @return the length of the current value of {@code StringJoiner} */ public int length() { - // Remember that we never actually append the suffix unless we return - // the full (present) value or some sub-string or length of it, so that - // we can add on more if we need to. - return (value != null ? value.length() + suffix.length() : - emptyValue.length()); + return (size == 0 && emptyValue != null) ? emptyValue.length() : + len + prefix.length() + suffix.length(); } } diff --git a/jdk/src/java.base/share/classes/javax/security/auth/Subject.java b/jdk/src/java.base/share/classes/javax/security/auth/Subject.java index e8ce12c9eee..0eee83c6083 100644 --- a/jdk/src/java.base/share/classes/javax/security/auth/Subject.java +++ b/jdk/src/java.base/share/classes/javax/security/auth/Subject.java @@ -182,21 +182,20 @@ public final class Subject implements java.io.Serializable { * {@code AuthPermission("modifyPublicCredentials")}. * To modify the private credential Set, the caller must have * {@code AuthPermission("modifyPrivateCredentials")}. - *

    * * @param readOnly true if the {@code Subject} is to be read-only, - * and false otherwise.

    + * and false otherwise. * * @param principals the {@code Set} of Principals - * to be associated with this {@code Subject}.

    + * to be associated with this {@code Subject}. * * @param pubCredentials the {@code Set} of public credentials - * to be associated with this {@code Subject}.

    + * to be associated with this {@code Subject}. * * @param privCredentials the {@code Set} of private credentials * to be associated with this {@code Subject}. * - * @exception NullPointerException if the specified + * @throws NullPointerException if the specified * {@code principals}, {@code pubCredentials}, * or {@code privCredentials} are {@code null}, * or a null value exists within any of these three @@ -233,10 +232,11 @@ public final class Subject implements java.io.Serializable { * Also, once a {@code Subject} is read-only, * it can not be reset to being writable again. * - *

    - * - * @exception SecurityException if the caller does not have permission - * to set this {@code Subject} to be read-only. + * @throws SecurityException if a security manager is installed and the + * caller does not have an + * {@link AuthPermission#AuthPermission(String) + * AuthPermission("setReadOnly")} permission to set this + * {@code Subject} to be read-only. */ public void setReadOnly() { java.lang.SecurityManager sm = System.getSecurityManager(); @@ -250,8 +250,6 @@ public final class Subject implements java.io.Serializable { /** * Query whether this {@code Subject} is read-only. * - *

    - * * @return true if this {@code Subject} is read-only, false otherwise. */ public boolean isReadOnly() { @@ -267,8 +265,6 @@ public final class Subject implements java.io.Serializable { * In this situation, the most recent {@code Subject} associated * with the {@code AccessControlContext} is returned. * - *

    - * * @param acc the {@code AccessControlContext} from which to retrieve * the {@code Subject}. * @@ -277,10 +273,13 @@ public final class Subject implements java.io.Serializable { * if no {@code Subject} is associated * with the provided {@code AccessControlContext}. * - * @exception SecurityException if the caller does not have permission - * to get the {@code Subject}.

    + * @throws SecurityException if a security manager is installed and the + * caller does not have an + * {@link AuthPermission#AuthPermission(String) + * AuthPermission("getSubject")} permission to get the + * {@code Subject}. * - * @exception NullPointerException if the provided + * @throws NullPointerException if the provided * {@code AccessControlContext} is {@code null}. */ public static Subject getSubject(final AccessControlContext acc) { @@ -321,26 +320,27 @@ public final class Subject implements java.io.Serializable { * passing it the provided {@code PrivilegedAction}, * as well as the newly constructed {@code AccessControlContext}. * - *

    - * * @param subject the {@code Subject} that the specified * {@code action} will run as. This parameter - * may be {@code null}.

    + * may be {@code null}. * * @param the type of the value returned by the PrivilegedAction's * {@code run} method. * * @param action the code to be run as the specified - * {@code Subject}.

    + * {@code Subject}. * * @return the value returned by the PrivilegedAction's * {@code run} method. * - * @exception NullPointerException if the {@code PrivilegedAction} - * is {@code null}.

    + * @throws NullPointerException if the {@code PrivilegedAction} + * is {@code null}. * - * @exception SecurityException if the caller does not have permission - * to invoke this method. + * @throws SecurityException if a security manager is installed and the + * caller does not have an + * {@link AuthPermission#AuthPermission(String) + * AuthPermission("doAs")} permission to invoke this + * method. */ public static T doAs(final Subject subject, final java.security.PrivilegedAction action) { @@ -377,31 +377,32 @@ public final class Subject implements java.io.Serializable { * passing it the provided {@code PrivilegedExceptionAction}, * as well as the newly constructed {@code AccessControlContext}. * - *

    - * * @param subject the {@code Subject} that the specified * {@code action} will run as. This parameter - * may be {@code null}.

    + * may be {@code null}. * * @param the type of the value returned by the * PrivilegedExceptionAction's {@code run} method. * * @param action the code to be run as the specified - * {@code Subject}.

    + * {@code Subject}. * * @return the value returned by the * PrivilegedExceptionAction's {@code run} method. * - * @exception PrivilegedActionException if the + * @throws PrivilegedActionException if the * {@code PrivilegedExceptionAction.run} - * method throws a checked exception.

    + * method throws a checked exception. * - * @exception NullPointerException if the specified + * @throws NullPointerException if the specified * {@code PrivilegedExceptionAction} is - * {@code null}.

    + * {@code null}. * - * @exception SecurityException if the caller does not have permission - * to invoke this method. + * @throws SecurityException if a security manager is installed and the + * caller does not have an + * {@link AuthPermission#AuthPermission(String) + * AuthPermission("doAs")} permission to invoke this + * method. */ public static T doAs(final Subject subject, final java.security.PrivilegedExceptionAction action) @@ -435,29 +436,30 @@ public final class Subject implements java.io.Serializable { * this method instantiates a new {@code AccessControlContext} * with an empty collection of ProtectionDomains. * - *

    - * * @param subject the {@code Subject} that the specified * {@code action} will run as. This parameter - * may be {@code null}.

    + * may be {@code null}. * * @param the type of the value returned by the PrivilegedAction's * {@code run} method. * * @param action the code to be run as the specified - * {@code Subject}.

    + * {@code Subject}. * * @param acc the {@code AccessControlContext} to be tied to the - * specified subject and action.

    + * specified subject and action. * * @return the value returned by the PrivilegedAction's * {@code run} method. * - * @exception NullPointerException if the {@code PrivilegedAction} - * is {@code null}.

    + * @throws NullPointerException if the {@code PrivilegedAction} + * is {@code null}. * - * @exception SecurityException if the caller does not have permission - * to invoke this method. + * @throws SecurityException if a security manager is installed and the + * caller does not have a + * {@link AuthPermission#AuthPermission(String) + * AuthPermission("doAsPrivileged")} permission to invoke + * this method. */ public static T doAsPrivileged(final Subject subject, final java.security.PrivilegedAction action, @@ -495,34 +497,35 @@ public final class Subject implements java.io.Serializable { * this method instantiates a new {@code AccessControlContext} * with an empty collection of ProtectionDomains. * - *

    - * * @param subject the {@code Subject} that the specified * {@code action} will run as. This parameter - * may be {@code null}.

    + * may be {@code null}. * * @param the type of the value returned by the * PrivilegedExceptionAction's {@code run} method. * * @param action the code to be run as the specified - * {@code Subject}.

    + * {@code Subject}. * * @param acc the {@code AccessControlContext} to be tied to the - * specified subject and action.

    + * specified subject and action. * * @return the value returned by the * PrivilegedExceptionAction's {@code run} method. * - * @exception PrivilegedActionException if the + * @throws PrivilegedActionException if the * {@code PrivilegedExceptionAction.run} - * method throws a checked exception.

    + * method throws a checked exception. * - * @exception NullPointerException if the specified + * @throws NullPointerException if the specified * {@code PrivilegedExceptionAction} is - * {@code null}.

    + * {@code null}. * - * @exception SecurityException if the caller does not have permission - * to invoke this method. + * @throws SecurityException if a security manager is installed and the + * caller does not have a + * {@link AuthPermission#AuthPermission(String) + * AuthPermission("doAsPrivileged")} permission to invoke + * this method. */ public static T doAsPrivileged(final Subject subject, final java.security.PrivilegedExceptionAction action, @@ -577,9 +580,12 @@ public final class Subject implements java.io.Serializable { * to the returned {@code Set} affects the internal * {@code Principal} {@code Set} as well. * - *

    + *

    If a security manager is installed, the caller must have a + * {@link AuthPermission#AuthPermission(String) + * AuthPermission("modifyPrincipals")} permission to modify + * the returned set, or a {@code SecurityException} will be thrown. * - * @return The {@code Set} of Principals associated with this + * @return the {@code Set} of Principals associated with this * {@code Subject}. */ public Set getPrincipals() { @@ -600,8 +606,6 @@ public final class Subject implements java.io.Serializable { * Modifications to the returned {@code Set} * will not affect the internal {@code Principal} {@code Set}. * - *

    - * * @param the type of the class modeled by {@code c} * * @param c the returned {@code Set} of Principals will all be @@ -610,8 +614,8 @@ public final class Subject implements java.io.Serializable { * @return a {@code Set} of Principals that are instances of the * specified {@code Class}. * - * @exception NullPointerException if the specified {@code Class} - * is {@code null}. + * @throws NullPointerException if the specified {@code Class} + * is {@code null}. */ public Set getPrincipals(Class c) { @@ -632,9 +636,12 @@ public final class Subject implements java.io.Serializable { * to the returned {@code Set} affects the internal public * Credential {@code Set} as well. * - *

    + *

    If a security manager is installed, the caller must have a + * {@link AuthPermission#AuthPermission(String) + * AuthPermission("modifyPublicCredentials")} permission to modify + * the returned set, or a {@code SecurityException} will be thrown. * - * @return A {@code Set} of public credentials held by this + * @return a {@code Set} of public credentials held by this * {@code Subject}. */ public Set getPublicCredentials() { @@ -653,20 +660,18 @@ public final class Subject implements java.io.Serializable { * to the returned {@code Set} affects the internal private * Credential {@code Set} as well. * - *

    A caller requires permissions to access the Credentials - * in the returned {@code Set}, or to modify the - * {@code Set} itself. A {@code SecurityException} - * is thrown if the caller does not have the proper permissions. + *

    If a security manager is installed, the caller must have a + * {@link AuthPermission#AuthPermission(String) + * AuthPermission("modifyPrivateCredentials")} permission to modify + * the returned set, or a {@code SecurityException} will be thrown. * *

    While iterating through the {@code Set}, - * a {@code SecurityException} is thrown - * if the caller does not have permission to access a - * particular Credential. The {@code Iterator} - * is nevertheless advanced to next element in the {@code Set}. + * a {@code SecurityException} is thrown if a security manager is installed + * and the caller does not have a {@link PrivateCredentialPermission} + * to access a particular Credential. The {@code Iterator} + * is nevertheless advanced to the next element in the {@code Set}. * - *

    - * - * @return A {@code Set} of private credentials held by this + * @return a {@code Set} of private credentials held by this * {@code Subject}. */ public Set getPrivateCredentials() { @@ -695,8 +700,6 @@ public final class Subject implements java.io.Serializable { * Modifications to the returned {@code Set} * will not affect the internal public Credential {@code Set}. * - *

    - * * @param the type of the class modeled by {@code c} * * @param c the returned {@code Set} of public credentials will all be @@ -705,7 +708,7 @@ public final class Subject implements java.io.Serializable { * @return a {@code Set} of public credentials that are instances * of the specified {@code Class}. * - * @exception NullPointerException if the specified {@code Class} + * @throws NullPointerException if the specified {@code Class} * is {@code null}. */ public Set getPublicCredentials(Class c) { @@ -723,9 +726,9 @@ public final class Subject implements java.io.Serializable { * {@code Subject} that are instances or subclasses of the specified * {@code Class}. * - *

    The caller must have permission to access all of the - * requested Credentials, or a {@code SecurityException} - * will be thrown. + *

    If a security manager is installed, the caller must have a + * {@link PrivateCredentialPermission} to access all of the requested + * Credentials, or a {@code SecurityException} will be thrown. * *

    The returned {@code Set} is not backed by this Subject's * internal private Credential {@code Set}. A new @@ -733,8 +736,6 @@ public final class Subject implements java.io.Serializable { * Modifications to the returned {@code Set} * will not affect the internal private Credential {@code Set}. * - *

    - * * @param the type of the class modeled by {@code c} * * @param c the returned {@code Set} of private credentials will all be @@ -743,7 +744,7 @@ public final class Subject implements java.io.Serializable { * @return a {@code Set} of private credentials that are instances * of the specified {@code Class}. * - * @exception NullPointerException if the specified {@code Class} + * @throws NullPointerException if the specified {@code Class} * is {@code null}. */ public Set getPrivateCredentials(Class c) { @@ -772,19 +773,18 @@ public final class Subject implements java.io.Serializable { * equal if their {@code Principal} and {@code Credential} * Sets are equal. * - *

    - * * @param o Object to be compared for equality with this * {@code Subject}. * * @return true if the specified Object is equal to this * {@code Subject}. * - * @exception SecurityException if the caller does not have permission - * to access the private credentials for this {@code Subject}, - * or if the caller does not have permission to access the - * private credentials for the provided {@code Subject}. + * @throws SecurityException if a security manager is installed and the + * caller does not have a {@link PrivateCredentialPermission} + * permission to access the private credentials for this + * {@code Subject} or the provided {@code Subject}. */ + @Override public boolean equals(Object o) { if (o == null) { @@ -834,10 +834,9 @@ public final class Subject implements java.io.Serializable { /** * Return the String representation of this {@code Subject}. * - *

    - * * @return the String representation of this {@code Subject}. */ + @Override public String toString() { return toString(true); } @@ -895,13 +894,13 @@ public final class Subject implements java.io.Serializable { /** * Returns a hashcode for this {@code Subject}. * - *

    - * * @return a hashcode for this {@code Subject}. * - * @exception SecurityException if the caller does not have permission - * to access this Subject's private credentials. + * @throws SecurityException if a security manager is installed and the + * caller does not have a {@link PrivateCredentialPermission} + * permission to access this Subject's private credentials. */ + @Override public int hashCode() { /** @@ -996,7 +995,7 @@ public final class Subject implements java.io.Serializable { * * @param coll A {@code Collection} to be tested for null references * - * @exception NullPointerException if the specified collection is either + * @throws NullPointerException if the specified collection is either * {@code null} or contains a {@code null} element */ private static void collectionNullClean(Collection coll) { @@ -1546,7 +1545,7 @@ public final class Subject implements java.io.Serializable { } } - static class AuthPermissionHolder { + static final class AuthPermissionHolder { static final AuthPermission DO_AS_PERMISSION = new AuthPermission("doAs"); diff --git a/jdk/src/java.base/share/classes/sun/net/InetAddressCachePolicy.java b/jdk/src/java.base/share/classes/sun/net/InetAddressCachePolicy.java index 31578b50d78..f20feec8ae0 100644 --- a/jdk/src/java.base/share/classes/sun/net/InetAddressCachePolicy.java +++ b/jdk/src/java.base/share/classes/sun/net/InetAddressCachePolicy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -56,7 +56,7 @@ public final class InetAddressCachePolicy { * caching. For security reasons, this caching is made forever when * a security manager is set. */ - private static int cachePolicy = FOREVER; + private static volatile int cachePolicy = FOREVER; /* The Java-level namelookup cache policy for negative lookups: * @@ -66,7 +66,7 @@ public final class InetAddressCachePolicy { * default value is 0. It can be set to some other value for * performance reasons. */ - private static int negativeCachePolicy = NEVER; + private static volatile int negativeCachePolicy = NEVER; /* * Whether or not the cache policy for successful lookups was set @@ -110,10 +110,7 @@ public final class InetAddressCachePolicy { }); if (tmp != null) { - cachePolicy = tmp.intValue(); - if (cachePolicy < 0) { - cachePolicy = FOREVER; - } + cachePolicy = tmp < 0 ? FOREVER : tmp; propertySet = true; } else { /* No properties defined for positive caching. If there is no @@ -148,19 +145,16 @@ public final class InetAddressCachePolicy { }); if (tmp != null) { - negativeCachePolicy = tmp.intValue(); - if (negativeCachePolicy < 0) { - negativeCachePolicy = FOREVER; - } + negativeCachePolicy = tmp < 0 ? FOREVER : tmp; propertyNegativeSet = true; } } - public static synchronized int get() { + public static int get() { return cachePolicy; } - public static synchronized int getNegative() { + public static int getNegative() { return negativeCachePolicy; } @@ -190,7 +184,7 @@ public final class InetAddressCachePolicy { * @param newPolicy the value in seconds for how long the lookup * should be cached */ - public static synchronized void setNegativeIfNotSet(int newPolicy) { + public static void setNegativeIfNotSet(int newPolicy) { /* * When setting the new value we may want to signal that the * cache should be flushed, though this doesn't seem strictly @@ -200,7 +194,8 @@ public final class InetAddressCachePolicy { // Negative caching does not seem to have any security // implications. // checkValue(newPolicy, negativeCachePolicy); - negativeCachePolicy = newPolicy; + // but we should normalize negative policy + negativeCachePolicy = newPolicy < 0 ? FOREVER : newPolicy; } } diff --git a/jdk/src/java.base/share/classes/sun/net/www/MimeEntry.java b/jdk/src/java.base/share/classes/sun/net/www/MimeEntry.java index 7a7bcce453c..f96953a42d4 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/MimeEntry.java +++ b/jdk/src/java.base/share/classes/sun/net/www/MimeEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -26,6 +26,7 @@ package sun.net.www; import java.net.URL; import java.io.*; +import java.util.StringJoiner; import java.util.StringTokenizer; public class MimeEntry implements Cloneable { @@ -281,52 +282,34 @@ public class MimeEntry implements Cloneable { } public synchronized String toProperty() { - StringBuilder sb = new StringBuilder(); - - String separator = "; "; - boolean needSeparator = false; + StringJoiner sj = new StringJoiner("; "); int action = getAction(); if (action != MimeEntry.UNKNOWN) { - sb.append("action=" + actionKeywords[action]); - needSeparator = true; + sj.add("action=" + actionKeywords[action]); } String command = getLaunchString(); if (command != null && command.length() > 0) { - if (needSeparator) { - sb.append(separator); - } - sb.append("application=" + command); - needSeparator = true; + sj.add("application=" + command); } - if (getImageFileName() != null) { - if (needSeparator) { - sb.append(separator); - } - sb.append("icon=" + getImageFileName()); - needSeparator = true; + String image = getImageFileName(); + if (image != null) { + sj.add("icon=" + image); } String extensions = getExtensionsAsList(); if (extensions.length() > 0) { - if (needSeparator) { - sb.append(separator); - } - sb.append("file_extensions=" + extensions); - needSeparator = true; + sj.add("file_extensions=" + extensions); } String description = getDescription(); if (description != null && !description.equals(getType())) { - if (needSeparator) { - sb.append(separator); - } - sb.append("description=" + description); + sj.add("description=" + description); } - return sb.toString(); + return sj.toString(); } public String toString() { diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 781f772c1ab..f4ade7e3dfd 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -64,6 +64,7 @@ import java.util.Iterator; import java.util.HashSet; import java.util.HashMap; import java.util.Set; +import java.util.StringJoiner; import sun.net.*; import sun.net.www.*; import sun.net.www.http.HttpClient; @@ -1386,16 +1387,11 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } List l = entry.getValue(); if (l != null && !l.isEmpty()) { - StringBuilder cookieValue = new StringBuilder(); + StringJoiner cookieValue = new StringJoiner("; "); for (String value : l) { - cookieValue.append(value).append("; "); - } - // strip off the trailing '; ' - try { - requests.add(key, cookieValue.substring(0, cookieValue.length() - 2)); - } catch (StringIndexOutOfBoundsException ignored) { - // no-op + cookieValue.add(value); } + requests.add(key, cookieValue.toString()); } } } @@ -2870,20 +2866,14 @@ public class HttpURLConnection extends java.net.HttpURLConnection { sun.misc.JavaNetHttpCookieAccess access = sun.misc.SharedSecrets.getJavaNetHttpCookieAccess(); - StringBuilder retValue = new StringBuilder(); + StringJoiner retValue = new StringJoiner(","); // RFC 2965, comma separated List cookies = access.parse(value); - boolean multipleCookies = false; for (HttpCookie cookie : cookies) { // skip HttpOnly cookies - if (cookie.isHttpOnly()) - continue; - if (multipleCookies) - retValue.append(','); // RFC 2965, comma separated - retValue.append(access.header(cookie)); - multipleCookies = true; + if (!cookie.isHttpOnly()) + retValue.add(access.header(cookie)); } - - return retValue.length() == 0 ? "" : retValue.toString(); + return retValue.toString(); } return value; diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java index 1ec1700ea67..c3067c044e0 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java @@ -501,7 +501,8 @@ public class HttpsURLConnectionImpl } public boolean equals(Object obj) { - return delegate.equals(obj); + return this == obj || ((obj instanceof HttpsURLConnectionImpl) && + delegate.equals(((HttpsURLConnectionImpl)obj).delegate)); } public int hashCode() { diff --git a/jdk/src/java.base/share/classes/sun/util/calendar/Era.java b/jdk/src/java.base/share/classes/sun/util/calendar/Era.java index a013c57afd2..3ab04110075 100644 --- a/jdk/src/java.base/share/classes/sun/util/calendar/Era.java +++ b/jdk/src/java.base/share/classes/sun/util/calendar/Era.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -41,20 +41,15 @@ import java.util.TimeZone; * CalendarDate. * *

    The following era names are defined in this release. - * - *

    
    + * 
    {@code
      *   Calendar system         Era name         Since (in Gregorian)
      *   -----------------------------------------------------------------------
    - *   Japanese calendar       Meiji            1868-01-01 midnight local time
    - *                           Taisho           1912-07-30 midnight local time
    - *                           Showa            1926-12-26 midnight local time
    - *                           Heisei           1989-01-08 midnight local time
    - *   Julian calendar         BeforeCommonEra  -292275055-05-16T16:47:04.192Z
    - *                           CommonEra        0000-12-30 midnight local time
    - *   Taiwanese calendar      MinGuo           1911-01-01 midnight local time
    - *   Thai Buddhist calendar  BuddhistEra      -543-01-01 midnight local time
    + *   Japanese calendar       Meiji            1868-01-01T00:00:00 local time
    + *                           Taisho           1912-07-30T00:00:00 local time
    + *                           Showa            1926-12-25T00:00:00 local time
    + *                           Heisei           1989-01-08T00:00:00 local time
      *   -----------------------------------------------------------------------
    - * 
    + * }
    * * @author Masayoshi Okutsu * @since 1.5 diff --git a/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java b/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java index 9a9b6637471..10cbbdceee1 100644 --- a/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java +++ b/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -25,11 +25,7 @@ package sun.util.calendar; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.StringTokenizer; +import java.security.AccessController; import java.util.TimeZone; /** @@ -39,6 +35,28 @@ import java.util.TimeZone; */ public class LocalGregorianCalendar extends BaseCalendar { + private static final Era[] JAPANESE_ERAS = { + new Era("Meiji", "M", -3218832000000L, true), + new Era("Taisho", "T", -1812153600000L, true), + new Era("Showa", "S", -1357603200000L, true), + new Era("Heisei", "H", 600220800000L, true), + }; + + private static boolean isValidEra(Era newEra, Era[] eras) { + Era last = eras[eras.length - 1]; + if (last.getSinceDate().getYear() >= newEra.getSinceDate().getYear()) { + return false; + } + // The new era name should be unique. Its abbr may not. + String newName = newEra.getName(); + for (Era era : eras) { + if (era.getName().equals(newName)) { + return false; + } + } + return true; + } + private String name; private Era[] eras; @@ -118,58 +136,70 @@ public class LocalGregorianCalendar extends BaseCalendar { } static LocalGregorianCalendar getLocalGregorianCalendar(String name) { - Properties calendarProps; - try { - calendarProps = CalendarSystem.getCalendarProperties(); - } catch (IOException | IllegalArgumentException e) { - throw new InternalError(e); - } - // Parse calendar.*.eras - String props = calendarProps.getProperty("calendar." + name + ".eras"); - if (props == null) { + // Only the Japanese calendar is supported. + if (!"japanese".equals(name)) { return null; } - List eras = new ArrayList<>(); - StringTokenizer eraTokens = new StringTokenizer(props, ";"); - while (eraTokens.hasMoreTokens()) { - String items = eraTokens.nextToken().trim(); - StringTokenizer itemTokens = new StringTokenizer(items, ","); - String eraName = null; - boolean localTime = true; - long since = 0; - String abbr = null; - while (itemTokens.hasMoreTokens()) { - String item = itemTokens.nextToken(); - int index = item.indexOf('='); - // it must be in the key=value form. - if (index == -1) { - return null; - } - String key = item.substring(0, index); - String value = item.substring(index + 1); - if ("name".equals(key)) { - eraName = value; - } else if ("since".equals(key)) { - if (value.endsWith("u")) { - localTime = false; - since = Long.parseLong(value.substring(0, value.length() - 1)); - } else { - since = Long.parseLong(value); - } - } else if ("abbr".equals(key)) { - abbr = value; - } else { - throw new RuntimeException("Unknown key word: " + key); + // Append an era to the predefined eras if it's given by the property. + String prop = AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("jdk.calendar.japanese.supplemental.era")); + if (prop != null) { + Era era = parseEraEntry(prop); + if (era != null) { + if (isValidEra(era, JAPANESE_ERAS)) { + int length = JAPANESE_ERAS.length; + Era[] eras = new Era[length + 1]; + System.arraycopy(JAPANESE_ERAS, 0, eras, 0, length); + eras[length] = era; + return new LocalGregorianCalendar(name, eras); } } - Era era = new Era(eraName, abbr, since, localTime); - eras.add(era); } - Era[] eraArray = new Era[eras.size()]; - eras.toArray(eraArray); + return new LocalGregorianCalendar(name, JAPANESE_ERAS); + } - return new LocalGregorianCalendar(name, eraArray); + private static Era parseEraEntry(String entry) { + String[] keyValuePairs = entry.split(","); + String eraName = null; + boolean localTime = true; + long since = 0; + String abbr = null; + + for (String item : keyValuePairs) { + String[] keyvalue = item.split("="); + if (keyvalue.length != 2) { + return null; + } + String key = keyvalue[0].trim(); + String value = keyvalue[1].trim(); + switch (key) { + case "name": + eraName = value; + break; + case "since": + if (value.endsWith("u")) { + localTime = false; + value = value.substring(0, value.length() - 1); + } + try { + since = Long.parseLong(value); + } catch (NumberFormatException e) { + return null; + } + break; + case "abbr": + abbr = value; + break; + default: + return null; + } + } + if (eraName == null || eraName.isEmpty() + || abbr == null || abbr.isEmpty()) { + return null; + } + return new Era(eraName, abbr, since, localTime); } private LocalGregorianCalendar(String name, Era[] eras) { @@ -262,9 +292,8 @@ public class LocalGregorianCalendar extends BaseCalendar { } private boolean validateEra(Era era) { - // Validate the era - for (int i = 0; i < eras.length; i++) { - if (era == eras[i]) { + for (Era era1 : eras) { + if (era == era1) { return true; } } @@ -333,6 +362,7 @@ public class LocalGregorianCalendar extends BaseCalendar { } if (i >= 0) { ldate.setLocalEra(era); + @SuppressWarnings("null") int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1; ldate.setLocalYear(y); } else { diff --git a/jdk/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java b/jdk/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java index 77f7b843d64..bda94f63bec 100644 --- a/jdk/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java +++ b/jdk/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 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 @@ -30,6 +30,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.text.spi.BreakIteratorProvider; import java.text.spi.CollatorProvider; +import java.util.Collections; import java.util.HashSet; import java.util.Locale; import java.util.ResourceBundle; @@ -102,6 +103,9 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { @Override protected Set createLanguageTagSet(String category) { ResourceBundle rb = ResourceBundle.getBundle("sun.util.cldr.CLDRLocaleDataMetaInfo", Locale.ROOT); + if (rb.containsKey(category)) { + return Collections.emptySet(); + } String supportedLocaleString = rb.getString(category); Set tagset = new HashSet<>(); StringTokenizer tokens = new StringTokenizer(supportedLocaleString); diff --git a/jdk/src/java.base/share/classes/sun/util/locale/BaseLocale.java b/jdk/src/java.base/share/classes/sun/util/locale/BaseLocale.java index 6eee5829095..137fd82f7dd 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/BaseLocale.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/BaseLocale.java @@ -32,6 +32,7 @@ package sun.util.locale; +import java.util.StringJoiner; public final class BaseLocale { @@ -120,33 +121,20 @@ public final class BaseLocale { @Override public String toString() { - StringBuilder buf = new StringBuilder(); + StringJoiner sj = new StringJoiner(", "); if (language.length() > 0) { - buf.append("language="); - buf.append(language); + sj.add("language=" + language); } if (script.length() > 0) { - if (buf.length() > 0) { - buf.append(", "); - } - buf.append("script="); - buf.append(script); + sj.add("script=" + script); } if (region.length() > 0) { - if (buf.length() > 0) { - buf.append(", "); - } - buf.append("region="); - buf.append(region); + sj.add("region=" + region); } if (variant.length() > 0) { - if (buf.length() > 0) { - buf.append(", "); - } - buf.append("variant="); - buf.append(variant); + sj.add("variant=" + variant); } - return buf.toString(); + return sj.toString(); } @Override diff --git a/jdk/src/java.base/share/classes/sun/util/locale/LanguageTag.java b/jdk/src/java.base/share/classes/sun/util/locale/LanguageTag.java index 2247398c400..3fd7f7dbe5e 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/LanguageTag.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/LanguageTag.java @@ -37,6 +37,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.StringJoiner; public class LanguageTag { // @@ -473,21 +474,18 @@ public class LanguageTag { } if (!varitr.isDone()) { // ill-formed variant subtags - StringBuilder buf = new StringBuilder(); + StringJoiner sj = new StringJoiner(SEP); while (!varitr.isDone()) { String prvv = varitr.current(); if (!isPrivateuseSubtag(prvv)) { // cannot use private use subtag - truncated break; } - if (buf.length() > 0) { - buf.append(SEP); - } - buf.append(prvv); + sj.add(prvv); varitr.next(); } - if (buf.length() > 0) { - privuseVar = buf.toString(); + if (sj.length() > 0) { + privuseVar = sj.toString(); } } } diff --git a/jdk/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java b/jdk/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java index cc5a5685cd0..51a723aea25 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -38,6 +38,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; +import java.util.StringJoiner; public class UnicodeLocaleExtension extends Extension { public static final char SINGLETON = 'u'; @@ -70,20 +71,20 @@ public class UnicodeLocaleExtension extends Extension { } if (!this.attributes.isEmpty() || !this.keywords.isEmpty()) { - StringBuilder sb = new StringBuilder(); + StringJoiner sj = new StringJoiner(LanguageTag.SEP); for (String attribute : this.attributes) { - sb.append(LanguageTag.SEP).append(attribute); + sj.add(attribute); } for (Entry keyword : this.keywords.entrySet()) { String key = keyword.getKey(); String value = keyword.getValue(); - sb.append(LanguageTag.SEP).append(key); + sj.add(key); if (value.length() > 0) { - sb.append(LanguageTag.SEP).append(value); + sj.add(value); } } - setValue(sb.substring(1)); // skip leading '-' + setValue(sj.toString()); } } diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index 50473cde715..f07d793a88d 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -34,6 +34,7 @@ import java.text.spi.DateFormatProvider; import java.text.spi.DateFormatSymbolsProvider; import java.text.spi.DecimalFormatSymbolsProvider; import java.text.spi.NumberFormatProvider; +import java.util.Collections; import java.util.HashSet; import java.util.Locale; import java.util.Set; @@ -356,6 +357,9 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements R protected Set createLanguageTagSet(String category) { String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString(category); + if (supportedLocaleString == null) { + return Collections.emptySet(); + } Set tagset = new HashSet<>(); StringTokenizer tokens = new StringTokenizer(supportedLocaleString); while (tokens.hasMoreTokens()) { diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template index 17d9af65817..52ac29de777 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -57,6 +57,12 @@ public class LocaleDataMetaInfo { resourceNameToLocales.put("CollationData", " #CollationData_ENLocales# | #CollationData_NonENLocales# "); + resourceNameToLocales.put("BreakIteratorInfo", + " #BreakIteratorInfo_ENLocales# | #BreakIteratorInfo_NonENLocales# "); + + resourceNameToLocales.put("BreakIteratorRules", + " #BreakIteratorRules_ENLocales# | #BreakIteratorRules_NonENLocales# "); + resourceNameToLocales.put("TimeZoneNames", " #TimeZoneNames_ENLocales# | #TimeZoneNames_NonENLocales# "); diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index b7ba7361d2b..3f7222172d7 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -295,7 +295,7 @@ public abstract class LocaleProviderAdapter { * A utility method for implementing the default LocaleServiceProvider.isSupportedLocale * for the JRE, CLDR, and FALLBACK adapters. */ - static boolean isSupportedLocale(Locale locale, LocaleProviderAdapter.Type type, Set langtags) { + public static boolean isSupportedLocale(Locale locale, LocaleProviderAdapter.Type type, Set langtags) { assert type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK; if (Locale.ROOT.equals(locale)) { return true; diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java index f8c68fa35c2..a1962e463da 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java @@ -547,12 +547,7 @@ class RuleBasedBreakIterator extends BreakIterator { */ @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append('['); - sb.append("checksum=0x"); - sb.append(Long.toHexString(checksum)); - sb.append(']'); - return sb.toString(); + return "[checksum=0x" + Long.toHexString(checksum) + ']'; } /** diff --git a/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java b/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java index 00ba6dec959..679baf6ebbb 100644 --- a/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java +++ b/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -48,8 +48,11 @@ import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; +import java.util.Set; +import sun.util.locale.provider.JRELocaleProviderAdapter; import sun.util.locale.provider.LocaleDataMetaInfo; import sun.util.locale.provider.LocaleProviderAdapter; +import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR; import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE; /** @@ -204,35 +207,23 @@ public class LocaleData { @Override public List getCandidateLocales(String baseName, Locale locale) { List candidates = super.getCandidateLocales(baseName, locale); - /* Get the locale string list from LocaleDataMetaInfo class. */ - String localeString = LocaleDataMetaInfo.getSupportedLocaleString(baseName); - - if (localeString != null && localeString.length() != 0) { - for (Iterator l = candidates.iterator(); l.hasNext();) { - Locale loc = l.next(); - String lstr; - if (loc.getScript().length() > 0) { - lstr = loc.toLanguageTag().replace('-', '_'); - } else { - lstr = loc.toString(); - int idx = lstr.indexOf("_#"); - if (idx >= 0) { - lstr = lstr.substring(0, idx); - } - } - /* Every locale string in the locale string list returned from - the above getSupportedLocaleString is enclosed - within two white spaces so that we could check some locale - such as "en". - */ - if (lstr.length() != 0 && localeString.indexOf(" " + lstr + " ") == -1) { - l.remove(); + // Weed out Locales which are known to have no resource bundles + int lastDot = baseName.lastIndexOf('.'); + String category = (lastDot >= 0) ? baseName.substring(lastDot + 1) : baseName; + LocaleProviderAdapter.Type type = baseName.contains(DOTCLDR) ? CLDR : JRE; + LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); + Set langtags = ((JRELocaleProviderAdapter)adapter).getLanguageTagSet(category); + if (!langtags.isEmpty()) { + for (Iterator itr = candidates.iterator(); itr.hasNext();) { + if (!LocaleProviderAdapter.isSupportedLocale(itr.next(), type, langtags)) { + itr.remove(); } } } + // Force fallback to Locale.ENGLISH for CLDR time zone names support if (locale.getLanguage() != "en" - && baseName.contains(CLDR) && baseName.endsWith("TimeZoneNames")) { + && type == CLDR && category.equals("TimeZoneNames")) { candidates.add(candidates.size() - 1, Locale.ENGLISH); } return candidates; @@ -254,7 +245,7 @@ public class LocaleData { return null; } - private static final String CLDR = ".cldr"; + private static final String DOTCLDR = ".cldr"; /** * Changes baseName to its per-language package name and @@ -275,8 +266,8 @@ public class LocaleData { assert JRE.getUtilResourcesPackage().length() == JRE.getTextResourcesPackage().length(); int index = JRE.getUtilResourcesPackage().length(); - if (baseName.indexOf(CLDR, index) > 0) { - index += CLDR.length(); + if (baseName.indexOf(DOTCLDR, index) > 0) { + index += DOTCLDR.length(); } newBaseName = baseName.substring(0, index + 1) + lang + baseName.substring(index); diff --git a/jdk/src/java.base/share/conf/calendars.properties b/jdk/src/java.base/share/conf/calendars.properties index 49f68aca492..46bb0e2bd60 100644 --- a/jdk/src/java.base/share/conf/calendars.properties +++ b/jdk/src/java.base/share/conf/calendars.properties @@ -1,4 +1,4 @@ -# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 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 @@ -22,37 +22,6 @@ # questions. # -# -# Japanese imperial calendar -# -# Meiji since 1868-01-01 00:00:00 local time (Gregorian) -# Taisho since 1912-07-30 00:00:00 local time (Gregorian) -# Showa since 1926-12-25 00:00:00 local time (Gregorian) -# Heisei since 1989-01-08 00:00:00 local time (Gregorian) -calendar.japanese.type: LocalGregorianCalendar -calendar.japanese.eras: \ - name=Meiji,abbr=M,since=-3218832000000; \ - name=Taisho,abbr=T,since=-1812153600000; \ - name=Showa,abbr=S,since=-1357603200000; \ - name=Heisei,abbr=H,since=600220800000 - -# -# Taiwanese calendar -# Minguo since 1911-01-01 00:00:00 local time (Gregorian) -calendar.taiwanese.type: LocalGregorianCalendar -calendar.taiwanese.eras: \ - name=MinGuo,since=-1830384000000 - -# -# Thai Buddhist calendar -# Buddhist Era since -542-01-01 00:00:00 local time (Gregorian) -calendar.thai-buddhist.type: LocalGregorianCalendar -calendar.thai-buddhist.eras: \ - name=BuddhistEra,abbr=B.E.,since=-79302585600000 -calendar.thai-buddhist.year-boundary: \ - day1=4-1,since=-79302585600000; \ - day1=1-1,since=-915148800000 - # # Hijrah calendars # diff --git a/jdk/src/java.base/share/conf/security/java.security-windows b/jdk/src/java.base/share/conf/security/java.security similarity index 94% rename from jdk/src/java.base/share/conf/security/java.security-windows rename to jdk/src/java.base/share/conf/security/java.security index bd34766c653..7f7bc9c383d 100644 --- a/jdk/src/java.base/share/conf/security/java.security-windows +++ b/jdk/src/java.base/share/conf/security/java.security @@ -65,16 +65,25 @@ # # List of providers and their preference orders (see above): # -security.provider.1=sun.security.provider.Sun -security.provider.2=sun.security.rsa.SunRsaSign -security.provider.3=sun.security.ec.SunEC -security.provider.4=com.sun.net.ssl.internal.ssl.Provider -security.provider.5=com.sun.crypto.provider.SunJCE -security.provider.6=sun.security.jgss.SunProvider -security.provider.7=com.sun.security.sasl.Provider -security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI -security.provider.9=sun.security.smartcardio.SunPCSC -security.provider.10=sun.security.mscapi.SunMSCAPI +#ifdef solaris +security.provider.tbd=com.oracle.security.ucrypto.UcryptoProvider ${java.home}/lib/security/ucrypto-solaris.cfg +security.provider.tbd=sun.security.pkcs11.SunPKCS11 ${java.home}/lib/security/sunpkcs11-solaris.cfg +#endif +security.provider.tbd=sun.security.provider.Sun +security.provider.tbd=sun.security.rsa.SunRsaSign +security.provider.tbd=sun.security.ec.SunEC +security.provider.tbd=com.sun.net.ssl.internal.ssl.Provider +security.provider.tbd=com.sun.crypto.provider.SunJCE +security.provider.tbd=sun.security.jgss.SunProvider +security.provider.tbd=com.sun.security.sasl.Provider +security.provider.tbd=org.jcp.xml.dsig.internal.dom.XMLDSigRI +security.provider.tbd=sun.security.smartcardio.SunPCSC +#ifdef windows +security.provider.tbd=sun.security.mscapi.SunMSCAPI +#endif +#ifdef macosx +security.provider.tbd=apple.security.AppleProvider +#endif # # Sun Provider SecureRandom seed source. @@ -127,7 +136,12 @@ securerandom.source=file:/dev/random # This is a comma-separated list of algorithm and/or algorithm:provider # entries. # +#ifdef windows securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI,SHA1PRNG:SUN +#endif +#ifndef windows +securerandom.strongAlgorithms=NativePRNGBlocking:SUN +#endif # # Class to instantiate as the javax.security.auth.login.Configuration @@ -212,7 +226,9 @@ package.access=sun.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools.,\ com.sun.activation.registries.,\ - com.sun.java.accessibility. +#ifdef macosx + apple.,\ +#endif # # List of comma-separated packages that start with or equal this string @@ -259,7 +275,9 @@ package.definition=sun.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools.,\ com.sun.activation.registries.,\ - com.sun.java.accessibility. +#ifdef macosx + apple.,\ +#endif # # Determines whether this properties file can be appended to diff --git a/jdk/src/java.base/share/conf/security/java.security-aix b/jdk/src/java.base/share/conf/security/java.security-aix deleted file mode 100644 index 77540a3e506..00000000000 --- a/jdk/src/java.base/share/conf/security/java.security-aix +++ /dev/null @@ -1,496 +0,0 @@ -# -# This is the "master security properties file". -# -# An alternate java.security properties file may be specified -# from the command line via the system property -# -# -Djava.security.properties= -# -# This properties file appends to the master security properties file. -# If both properties files specify values for the same key, the value -# from the command-line properties file is selected, as it is the last -# one loaded. -# -# Also, if you specify -# -# -Djava.security.properties== (2 equals), -# -# then that properties file completely overrides the master security -# properties file. -# -# To disable the ability to specify an additional properties file from -# the command line, set the key security.overridePropertiesFile -# to false in the master security properties file. It is set to true -# by default. - -# In this file, various security properties are set for use by -# java.security classes. This is where users can statically register -# Cryptography Package Providers ("providers" for short). The term -# "provider" refers to a package or set of packages that supply a -# concrete implementation of a subset of the cryptography aspects of -# the Java Security API. A provider may, for example, implement one or -# more digital signature algorithms or message digest algorithms. -# -# Each provider must implement a subclass of the Provider class. -# To register a provider in this master security properties file, -# specify the Provider subclass name and priority in the format -# -# security.provider.= -# -# This declares a provider, and specifies its preference -# order n. The preference order is the order in which providers are -# searched for requested algorithms (when no specific provider is -# requested). The order is 1-based; 1 is the most preferred, followed -# by 2, and so on. -# -# must specify the subclass of the Provider class whose -# constructor sets the values of various properties that are required -# for the Java Security API to look up the algorithms or other -# facilities implemented by the provider. -# -# There must be at least one provider specification in java.security. -# There is a default provider that comes standard with the JDK. It -# is called the "SUN" provider, and its Provider subclass -# named Sun appears in the sun.security.provider package. Thus, the -# "SUN" provider is registered via the following: -# -# security.provider.1=sun.security.provider.Sun -# -# (The number 1 is used for the default provider.) -# -# Note: Providers can be dynamically registered instead by calls to -# either the addProvider or insertProviderAt method in the Security -# class. - -# -# List of providers and their preference orders (see above): -# -security.provider.1=sun.security.provider.Sun -security.provider.2=sun.security.rsa.SunRsaSign -security.provider.3=sun.security.ec.SunEC -security.provider.4=com.sun.net.ssl.internal.ssl.Provider -security.provider.5=com.sun.crypto.provider.SunJCE -security.provider.6=sun.security.jgss.SunProvider -security.provider.7=com.sun.security.sasl.Provider -security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI -security.provider.9=sun.security.smartcardio.SunPCSC - -# -# Sun Provider SecureRandom seed source. -# -# Select the primary source of seed data for the "SHA1PRNG" and -# "NativePRNG" SecureRandom implementations in the "Sun" provider. -# (Other SecureRandom implementations might also use this property.) -# -# On Unix-like systems (for example, Solaris/Linux/MacOS), the -# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from -# special device files such as file:/dev/random. -# -# On Windows systems, specifying the URLs "file:/dev/random" or -# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding -# mechanism for SHA1PRNG. -# -# By default, an attempt is made to use the entropy gathering device -# specified by the "securerandom.source" Security property. If an -# exception occurs while accessing the specified URL: -# -# SHA1PRNG: -# the traditional system/thread activity algorithm will be used. -# -# NativePRNG: -# a default value of /dev/random will be used. If neither -# are available, the implementation will be disabled. -# "file" is the only currently supported protocol type. -# -# The entropy gathering device can also be specified with the System -# property "java.security.egd". For example: -# -# % java -Djava.security.egd=file:/dev/random MainClass -# -# Specifying this System property will override the -# "securerandom.source" Security property. -# -# In addition, if "file:/dev/random" or "file:/dev/urandom" is -# specified, the "NativePRNG" implementation will be more preferred than -# SHA1PRNG in the Sun provider. -# -securerandom.source=file:/dev/random - -# -# A list of known strong SecureRandom implementations. -# -# To help guide applications in selecting a suitable strong -# java.security.SecureRandom implementation, Java distributions should -# indicate a list of known strong implementations using the property. -# -# This is a comma-separated list of algorithm and/or algorithm:provider -# entries. -# -securerandom.strongAlgorithms=NativePRNGBlocking:SUN - -# -# Class to instantiate as the javax.security.auth.login.Configuration -# provider. -# -login.configuration.provider=sun.security.provider.ConfigFile - -# -# Default login configuration file -# -#login.config.url.1=file:${user.home}/.java.login.config - -# -# Class to instantiate as the system Policy. This is the name of the class -# that will be used as the Policy object. -# -policy.provider=sun.security.provider.PolicyFile - -# The default is to have a single system-wide policy file, -# and a policy file in the user's home directory. -policy.url.1=file:${java.home}/lib/security/java.policy -policy.url.2=file:${user.home}/.java.policy - -# whether or not we expand properties in the policy file -# if this is set to false, properties (${...}) will not be expanded in policy -# files. -policy.expandProperties=true - -# whether or not we allow an extra policy to be passed on the command line -# with -Djava.security.policy=somefile. Comment out this line to disable -# this feature. -policy.allowSystemProperty=true - -# whether or not we look into the IdentityScope for trusted Identities -# when encountering a 1.1 signed JAR file. If the identity is found -# and is trusted, we grant it AllPermission. -policy.ignoreIdentityScope=false - -# -# Default keystore type. -# -keystore.type=jks - -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageAccess unless the -# corresponding RuntimePermission ("accessClassInPackage."+package) has -# been granted. -package.access=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ - com.sun.istack.internal.,\ - com.sun.jmx.,\ - com.sun.media.sound.,\ - com.sun.naming.internal.,\ - com.sun.proxy.,\ - com.sun.corba.se.,\ - com.sun.org.apache.bcel.internal.,\ - com.sun.org.apache.regexp.internal.,\ - com.sun.org.apache.xerces.internal.,\ - com.sun.org.apache.xpath.internal.,\ - com.sun.org.apache.xalan.internal.extensions.,\ - com.sun.org.apache.xalan.internal.lib.,\ - com.sun.org.apache.xalan.internal.res.,\ - com.sun.org.apache.xalan.internal.templates.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.apache.xalan.internal.xslt.,\ - com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ - com.sun.org.apache.xalan.internal.xsltc.compiler.,\ - com.sun.org.apache.xalan.internal.xsltc.trax.,\ - com.sun.org.apache.xalan.internal.xsltc.util.,\ - com.sun.org.apache.xml.internal.res.,\ - com.sun.org.apache.xml.internal.security.,\ - com.sun.org.apache.xml.internal.serializer.utils.,\ - com.sun.org.apache.xml.internal.utils.,\ - com.sun.org.glassfish.,\ - com.oracle.xmlns.internal.,\ - com.oracle.webservices.internal.,\ - org.jcp.xml.dsig.internal.,\ - jdk.internal.,\ - jdk.nashorn.internal.,\ - jdk.nashorn.tools. - - -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageDefinition unless the -# corresponding RuntimePermission ("defineClassInPackage."+package) has -# been granted. -# -# by default, none of the class loaders supplied with the JDK call -# checkPackageDefinition. -# -package.definition=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ - com.sun.istack.internal.,\ - com.sun.jmx.,\ - com.sun.media.sound.,\ - com.sun.naming.internal.,\ - com.sun.proxy.,\ - com.sun.corba.se.,\ - com.sun.org.apache.bcel.internal.,\ - com.sun.org.apache.regexp.internal.,\ - com.sun.org.apache.xerces.internal.,\ - com.sun.org.apache.xpath.internal.,\ - com.sun.org.apache.xalan.internal.extensions.,\ - com.sun.org.apache.xalan.internal.lib.,\ - com.sun.org.apache.xalan.internal.res.,\ - com.sun.org.apache.xalan.internal.templates.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.apache.xalan.internal.xslt.,\ - com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ - com.sun.org.apache.xalan.internal.xsltc.compiler.,\ - com.sun.org.apache.xalan.internal.xsltc.trax.,\ - com.sun.org.apache.xalan.internal.xsltc.util.,\ - com.sun.org.apache.xml.internal.res.,\ - com.sun.org.apache.xml.internal.security.,\ - com.sun.org.apache.xml.internal.serializer.utils.,\ - com.sun.org.apache.xml.internal.utils.,\ - com.sun.org.glassfish.,\ - com.oracle.xmlns.internal.,\ - com.oracle.webservices.internal.,\ - org.jcp.xml.dsig.internal.,\ - jdk.internal.,\ - jdk.nashorn.internal.,\ - jdk.nashorn.tools. - - -# -# Determines whether this properties file can be appended to -# or overridden on the command line via -Djava.security.properties -# -security.overridePropertiesFile=true - -# -# Determines the default key and trust manager factory algorithms for -# the javax.net.ssl package. -# -ssl.KeyManagerFactory.algorithm=SunX509 -ssl.TrustManagerFactory.algorithm=PKIX - -# -# The Java-level namelookup cache policy for successful lookups: -# -# any negative value: caching forever -# any positive value: the number of seconds to cache an address for -# zero: do not cache -# -# default value is forever (FOREVER). For security reasons, this -# caching is made forever when a security manager is set. When a security -# manager is not set, the default behavior in this implementation -# is to cache for 30 seconds. -# -# NOTE: setting this to anything other than the default value can have -# serious security implications. Do not set it unless -# you are sure you are not exposed to DNS spoofing attack. -# -#networkaddress.cache.ttl=-1 - -# The Java-level namelookup cache policy for failed lookups: -# -# any negative value: cache forever -# any positive value: the number of seconds to cache negative lookup results -# zero: do not cache -# -# In some Microsoft Windows networking environments that employ -# the WINS name service in addition to DNS, name service lookups -# that fail may take a noticeably long time to return (approx. 5 seconds). -# For this reason the default caching policy is to maintain these -# results for 10 seconds. -# -# -networkaddress.cache.negative.ttl=10 - -# -# Properties to configure OCSP for certificate revocation checking -# - -# Enable OCSP -# -# By default, OCSP is not used for certificate revocation checking. -# This property enables the use of OCSP when set to the value "true". -# -# NOTE: SocketPermission is required to connect to an OCSP responder. -# -# Example, -# ocsp.enable=true - -# -# Location of the OCSP responder -# -# By default, the location of the OCSP responder is determined implicitly -# from the certificate being validated. This property explicitly specifies -# the location of the OCSP responder. The property is used when the -# Authority Information Access extension (defined in RFC 3280) is absent -# from the certificate or when it requires overriding. -# -# Example, -# ocsp.responderURL=http://ocsp.example.net:80 - -# -# Subject name of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. In cases where -# the subject name alone is not sufficient to uniquely identify the certificate -# then both the "ocsp.responderCertIssuerName" and -# "ocsp.responderCertSerialNumber" properties must be used instead. When this -# property is set then those two properties are ignored. -# -# Example, -# ocsp.responderCertSubjectName="CN=OCSP Responder, O=XYZ Corp" - -# -# Issuer name of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. When this -# property is set then the "ocsp.responderCertSerialNumber" property must also -# be set. When the "ocsp.responderCertSubjectName" property is set then this -# property is ignored. -# -# Example, -# ocsp.responderCertIssuerName="CN=Enterprise CA, O=XYZ Corp" - -# -# Serial number of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# of hexadecimal digits (colon or space separators may be present) which -# identifies a certificate in the set of certificates supplied during cert path -# validation. When this property is set then the "ocsp.responderCertIssuerName" -# property must also be set. When the "ocsp.responderCertSubjectName" property -# is set then this property is ignored. -# -# Example, -# ocsp.responderCertSerialNumber=2A:FF:00 - -# -# Policy for failed Kerberos KDC lookups: -# -# When a KDC is unavailable (network error, service failure, etc), it is -# put inside a blacklist and accessed less often for future requests. The -# value (case-insensitive) for this policy can be: -# -# tryLast -# KDCs in the blacklist are always tried after those not on the list. -# -# tryLess[:max_retries,timeout] -# KDCs in the blacklist are still tried by their order in the configuration, -# but with smaller max_retries and timeout values. max_retries and timeout -# are optional numerical parameters (default 1 and 5000, which means once -# and 5 seconds). Please notes that if any of the values defined here is -# more than what is defined in krb5.conf, it will be ignored. -# -# Whenever a KDC is detected as available, it is removed from the blacklist. -# The blacklist is reset when krb5.conf is reloaded. You can add -# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is -# reloaded whenever a JAAS authentication is attempted. -# -# Example, -# krb5.kdc.bad.policy = tryLast -# krb5.kdc.bad.policy = tryLess:2,2000 -krb5.kdc.bad.policy = tryLast - -# Algorithm restrictions for certification path (CertPath) processing -# -# In some environments, certain algorithms or key lengths may be undesirable -# for certification path building and validation. For example, "MD2" is -# generally no longer considered to be a secure hash algorithm. This section -# describes the mechanism for disabling algorithms based on algorithm name -# and/or key length. This includes algorithms used in certificates, as well -# as revocation information such as CRLs and signed OCSP Responses. -# -# The syntax of the disabled algorithm string is described as this Java -# BNF-style: -# DisabledAlgorithms: -# " DisabledAlgorithm { , DisabledAlgorithm } " -# -# DisabledAlgorithm: -# AlgorithmName [Constraint] -# -# AlgorithmName: -# (see below) -# -# Constraint: -# KeySizeConstraint -# -# KeySizeConstraint: -# keySize Operator DecimalInteger -# -# Operator: -# <= | < | == | != | >= | > -# -# DecimalInteger: -# DecimalDigits -# -# DecimalDigits: -# DecimalDigit {DecimalDigit} -# -# DecimalDigit: one of -# 1 2 3 4 5 6 7 8 9 0 -# -# The "AlgorithmName" is the standard algorithm name of the disabled -# algorithm. See "Java Cryptography Architecture Standard Algorithm Name -# Documentation" for information about Standard Algorithm Names. Matching -# is performed using a case-insensitive sub-element matching rule. (For -# example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and -# "ECDSA" for signatures.) If the assertion "AlgorithmName" is a -# sub-element of the certificate algorithm name, the algorithm will be -# rejected during certification path building and validation. For example, -# the assertion algorithm name "DSA" will disable all certificate algorithms -# that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion -# will not disable algorithms related to "ECDSA". -# -# A "Constraint" provides further guidance for the algorithm being specified. -# The "KeySizeConstraint" requires a key of a valid size range if the -# "AlgorithmName" is of a key algorithm. The "DecimalInteger" indicates the -# key size specified in number of bits. For example, "RSA keySize <= 1024" -# indicates that any RSA key with key size less than or equal to 1024 bits -# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates -# that any RSA key with key size less than 1024 or greater than 2048 should -# be disabled. Note that the "KeySizeConstraint" only makes sense to key -# algorithms. -# -# Note: This property is currently used by Oracle's PKIX implementation. It -# is not guaranteed to be examined and used by other implementations. -# -# Example: -# jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 -# -# -jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024 - -# Algorithm restrictions for Secure Socket Layer/Transport Layer Security -# (SSL/TLS) processing -# -# In some environments, certain algorithms or key lengths may be undesirable -# when using SSL/TLS. This section describes the mechanism for disabling -# algorithms during SSL/TLS security parameters negotiation, including cipher -# suites selection, peer authentication and key exchange mechanisms. -# -# For PKI-based peer authentication and key exchange mechanisms, this list -# of disabled algorithms will also be checked during certification path -# building and validation, including algorithms used in certificates, as -# well as revocation information such as CRLs and signed OCSP Responses. -# This is in addition to the jdk.certpath.disabledAlgorithms property above. -# -# See the specification of "jdk.certpath.disabledAlgorithms" for the -# syntax of the disabled algorithm string. -# -# Note: This property is currently used by Oracle's JSSE implementation. -# It is not guaranteed to be examined and used by other implementations. -# -# Example: -# jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 diff --git a/jdk/src/java.base/share/conf/security/java.security-linux b/jdk/src/java.base/share/conf/security/java.security-linux deleted file mode 100644 index 6f4204cf791..00000000000 --- a/jdk/src/java.base/share/conf/security/java.security-linux +++ /dev/null @@ -1,496 +0,0 @@ -# -# This is the "master security properties file". -# -# An alternate java.security properties file may be specified -# from the command line via the system property -# -# -Djava.security.properties= -# -# This properties file appends to the master security properties file. -# If both properties files specify values for the same key, the value -# from the command-line properties file is selected, as it is the last -# one loaded. -# -# Also, if you specify -# -# -Djava.security.properties== (2 equals), -# -# then that properties file completely overrides the master security -# properties file. -# -# To disable the ability to specify an additional properties file from -# the command line, set the key security.overridePropertiesFile -# to false in the master security properties file. It is set to true -# by default. - -# In this file, various security properties are set for use by -# java.security classes. This is where users can statically register -# Cryptography Package Providers ("providers" for short). The term -# "provider" refers to a package or set of packages that supply a -# concrete implementation of a subset of the cryptography aspects of -# the Java Security API. A provider may, for example, implement one or -# more digital signature algorithms or message digest algorithms. -# -# Each provider must implement a subclass of the Provider class. -# To register a provider in this master security properties file, -# specify the Provider subclass name and priority in the format -# -# security.provider.= -# -# This declares a provider, and specifies its preference -# order n. The preference order is the order in which providers are -# searched for requested algorithms (when no specific provider is -# requested). The order is 1-based; 1 is the most preferred, followed -# by 2, and so on. -# -# must specify the subclass of the Provider class whose -# constructor sets the values of various properties that are required -# for the Java Security API to look up the algorithms or other -# facilities implemented by the provider. -# -# There must be at least one provider specification in java.security. -# There is a default provider that comes standard with the JDK. It -# is called the "SUN" provider, and its Provider subclass -# named Sun appears in the sun.security.provider package. Thus, the -# "SUN" provider is registered via the following: -# -# security.provider.1=sun.security.provider.Sun -# -# (The number 1 is used for the default provider.) -# -# Note: Providers can be dynamically registered instead by calls to -# either the addProvider or insertProviderAt method in the Security -# class. - -# -# List of providers and their preference orders (see above): -# -security.provider.1=sun.security.provider.Sun -security.provider.2=sun.security.rsa.SunRsaSign -security.provider.3=sun.security.ec.SunEC -security.provider.4=com.sun.net.ssl.internal.ssl.Provider -security.provider.5=com.sun.crypto.provider.SunJCE -security.provider.6=sun.security.jgss.SunProvider -security.provider.7=com.sun.security.sasl.Provider -security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI -security.provider.9=sun.security.smartcardio.SunPCSC - -# -# Sun Provider SecureRandom seed source. -# -# Select the primary source of seed data for the "SHA1PRNG" and -# "NativePRNG" SecureRandom implementations in the "Sun" provider. -# (Other SecureRandom implementations might also use this property.) -# -# On Unix-like systems (for example, Solaris/Linux/MacOS), the -# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from -# special device files such as file:/dev/random. -# -# On Windows systems, specifying the URLs "file:/dev/random" or -# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding -# mechanism for SHA1PRNG. -# -# By default, an attempt is made to use the entropy gathering device -# specified by the "securerandom.source" Security property. If an -# exception occurs while accessing the specified URL: -# -# SHA1PRNG: -# the traditional system/thread activity algorithm will be used. -# -# NativePRNG: -# a default value of /dev/random will be used. If neither -# are available, the implementation will be disabled. -# "file" is the only currently supported protocol type. -# -# The entropy gathering device can also be specified with the System -# property "java.security.egd". For example: -# -# % java -Djava.security.egd=file:/dev/random MainClass -# -# Specifying this System property will override the -# "securerandom.source" Security property. -# -# In addition, if "file:/dev/random" or "file:/dev/urandom" is -# specified, the "NativePRNG" implementation will be more preferred than -# SHA1PRNG in the Sun provider. -# -securerandom.source=file:/dev/random - -# -# A list of known strong SecureRandom implementations. -# -# To help guide applications in selecting a suitable strong -# java.security.SecureRandom implementation, Java distributions should -# indicate a list of known strong implementations using the property. -# -# This is a comma-separated list of algorithm and/or algorithm:provider -# entries. -# -securerandom.strongAlgorithms=NativePRNGBlocking:SUN - -# -# Class to instantiate as the javax.security.auth.login.Configuration -# provider. -# -login.configuration.provider=sun.security.provider.ConfigFile - -# -# Default login configuration file -# -#login.config.url.1=file:${user.home}/.java.login.config - -# -# Class to instantiate as the system Policy. This is the name of the class -# that will be used as the Policy object. -# -policy.provider=sun.security.provider.PolicyFile - -# The default is to have a single system-wide policy file, -# and a policy file in the user's home directory. -policy.url.1=file:${java.home}/lib/security/java.policy -policy.url.2=file:${user.home}/.java.policy - -# whether or not we expand properties in the policy file -# if this is set to false, properties (${...}) will not be expanded in policy -# files. -policy.expandProperties=true - -# whether or not we allow an extra policy to be passed on the command line -# with -Djava.security.policy=somefile. Comment out this line to disable -# this feature. -policy.allowSystemProperty=true - -# whether or not we look into the IdentityScope for trusted Identities -# when encountering a 1.1 signed JAR file. If the identity is found -# and is trusted, we grant it AllPermission. -policy.ignoreIdentityScope=false - -# -# Default keystore type. -# -keystore.type=jks - -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageAccess unless the -# corresponding RuntimePermission ("accessClassInPackage."+package) has -# been granted. -package.access=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ - com.sun.istack.internal.,\ - com.sun.jmx.,\ - com.sun.media.sound.,\ - com.sun.naming.internal.,\ - com.sun.proxy.,\ - com.sun.corba.se.,\ - com.sun.org.apache.bcel.internal.,\ - com.sun.org.apache.regexp.internal.,\ - com.sun.org.apache.xerces.internal.,\ - com.sun.org.apache.xpath.internal.,\ - com.sun.org.apache.xalan.internal.extensions.,\ - com.sun.org.apache.xalan.internal.lib.,\ - com.sun.org.apache.xalan.internal.res.,\ - com.sun.org.apache.xalan.internal.templates.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.apache.xalan.internal.xslt.,\ - com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ - com.sun.org.apache.xalan.internal.xsltc.compiler.,\ - com.sun.org.apache.xalan.internal.xsltc.trax.,\ - com.sun.org.apache.xalan.internal.xsltc.util.,\ - com.sun.org.apache.xml.internal.res.,\ - com.sun.org.apache.xml.internal.security.,\ - com.sun.org.apache.xml.internal.serializer.utils.,\ - com.sun.org.apache.xml.internal.utils.,\ - com.sun.org.glassfish.,\ - com.oracle.xmlns.internal.,\ - com.oracle.webservices.internal.,\ - org.jcp.xml.dsig.internal.,\ - jdk.internal.,\ - jdk.nashorn.internal.,\ - jdk.nashorn.tools.,\ - com.sun.activation.registries. - -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageDefinition unless the -# corresponding RuntimePermission ("defineClassInPackage."+package) has -# been granted. -# -# by default, none of the class loaders supplied with the JDK call -# checkPackageDefinition. -# -package.definition=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ - com.sun.istack.internal.,\ - com.sun.jmx.,\ - com.sun.media.sound.,\ - com.sun.naming.internal.,\ - com.sun.proxy.,\ - com.sun.corba.se.,\ - com.sun.org.apache.bcel.internal.,\ - com.sun.org.apache.regexp.internal.,\ - com.sun.org.apache.xerces.internal.,\ - com.sun.org.apache.xpath.internal.,\ - com.sun.org.apache.xalan.internal.extensions.,\ - com.sun.org.apache.xalan.internal.lib.,\ - com.sun.org.apache.xalan.internal.res.,\ - com.sun.org.apache.xalan.internal.templates.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.apache.xalan.internal.xslt.,\ - com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ - com.sun.org.apache.xalan.internal.xsltc.compiler.,\ - com.sun.org.apache.xalan.internal.xsltc.trax.,\ - com.sun.org.apache.xalan.internal.xsltc.util.,\ - com.sun.org.apache.xml.internal.res.,\ - com.sun.org.apache.xml.internal.security.,\ - com.sun.org.apache.xml.internal.serializer.utils.,\ - com.sun.org.apache.xml.internal.utils.,\ - com.sun.org.glassfish.,\ - com.oracle.xmlns.internal.,\ - com.oracle.webservices.internal.,\ - org.jcp.xml.dsig.internal.,\ - jdk.internal.,\ - jdk.nashorn.internal.,\ - jdk.nashorn.tools.,\ - com.sun.activation.registries. - -# -# Determines whether this properties file can be appended to -# or overridden on the command line via -Djava.security.properties -# -security.overridePropertiesFile=true - -# -# Determines the default key and trust manager factory algorithms for -# the javax.net.ssl package. -# -ssl.KeyManagerFactory.algorithm=SunX509 -ssl.TrustManagerFactory.algorithm=PKIX - -# -# The Java-level namelookup cache policy for successful lookups: -# -# any negative value: caching forever -# any positive value: the number of seconds to cache an address for -# zero: do not cache -# -# default value is forever (FOREVER). For security reasons, this -# caching is made forever when a security manager is set. When a security -# manager is not set, the default behavior in this implementation -# is to cache for 30 seconds. -# -# NOTE: setting this to anything other than the default value can have -# serious security implications. Do not set it unless -# you are sure you are not exposed to DNS spoofing attack. -# -#networkaddress.cache.ttl=-1 - -# The Java-level namelookup cache policy for failed lookups: -# -# any negative value: cache forever -# any positive value: the number of seconds to cache negative lookup results -# zero: do not cache -# -# In some Microsoft Windows networking environments that employ -# the WINS name service in addition to DNS, name service lookups -# that fail may take a noticeably long time to return (approx. 5 seconds). -# For this reason the default caching policy is to maintain these -# results for 10 seconds. -# -# -networkaddress.cache.negative.ttl=10 - -# -# Properties to configure OCSP for certificate revocation checking -# - -# Enable OCSP -# -# By default, OCSP is not used for certificate revocation checking. -# This property enables the use of OCSP when set to the value "true". -# -# NOTE: SocketPermission is required to connect to an OCSP responder. -# -# Example, -# ocsp.enable=true - -# -# Location of the OCSP responder -# -# By default, the location of the OCSP responder is determined implicitly -# from the certificate being validated. This property explicitly specifies -# the location of the OCSP responder. The property is used when the -# Authority Information Access extension (defined in RFC 3280) is absent -# from the certificate or when it requires overriding. -# -# Example, -# ocsp.responderURL=http://ocsp.example.net:80 - -# -# Subject name of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. In cases where -# the subject name alone is not sufficient to uniquely identify the certificate -# then both the "ocsp.responderCertIssuerName" and -# "ocsp.responderCertSerialNumber" properties must be used instead. When this -# property is set then those two properties are ignored. -# -# Example, -# ocsp.responderCertSubjectName="CN=OCSP Responder, O=XYZ Corp" - -# -# Issuer name of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. When this -# property is set then the "ocsp.responderCertSerialNumber" property must also -# be set. When the "ocsp.responderCertSubjectName" property is set then this -# property is ignored. -# -# Example, -# ocsp.responderCertIssuerName="CN=Enterprise CA, O=XYZ Corp" - -# -# Serial number of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# of hexadecimal digits (colon or space separators may be present) which -# identifies a certificate in the set of certificates supplied during cert path -# validation. When this property is set then the "ocsp.responderCertIssuerName" -# property must also be set. When the "ocsp.responderCertSubjectName" property -# is set then this property is ignored. -# -# Example, -# ocsp.responderCertSerialNumber=2A:FF:00 - -# -# Policy for failed Kerberos KDC lookups: -# -# When a KDC is unavailable (network error, service failure, etc), it is -# put inside a blacklist and accessed less often for future requests. The -# value (case-insensitive) for this policy can be: -# -# tryLast -# KDCs in the blacklist are always tried after those not on the list. -# -# tryLess[:max_retries,timeout] -# KDCs in the blacklist are still tried by their order in the configuration, -# but with smaller max_retries and timeout values. max_retries and timeout -# are optional numerical parameters (default 1 and 5000, which means once -# and 5 seconds). Please notes that if any of the values defined here is -# more than what is defined in krb5.conf, it will be ignored. -# -# Whenever a KDC is detected as available, it is removed from the blacklist. -# The blacklist is reset when krb5.conf is reloaded. You can add -# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is -# reloaded whenever a JAAS authentication is attempted. -# -# Example, -# krb5.kdc.bad.policy = tryLast -# krb5.kdc.bad.policy = tryLess:2,2000 -krb5.kdc.bad.policy = tryLast - -# Algorithm restrictions for certification path (CertPath) processing -# -# In some environments, certain algorithms or key lengths may be undesirable -# for certification path building and validation. For example, "MD2" is -# generally no longer considered to be a secure hash algorithm. This section -# describes the mechanism for disabling algorithms based on algorithm name -# and/or key length. This includes algorithms used in certificates, as well -# as revocation information such as CRLs and signed OCSP Responses. -# -# The syntax of the disabled algorithm string is described as this Java -# BNF-style: -# DisabledAlgorithms: -# " DisabledAlgorithm { , DisabledAlgorithm } " -# -# DisabledAlgorithm: -# AlgorithmName [Constraint] -# -# AlgorithmName: -# (see below) -# -# Constraint: -# KeySizeConstraint -# -# KeySizeConstraint: -# keySize Operator DecimalInteger -# -# Operator: -# <= | < | == | != | >= | > -# -# DecimalInteger: -# DecimalDigits -# -# DecimalDigits: -# DecimalDigit {DecimalDigit} -# -# DecimalDigit: one of -# 1 2 3 4 5 6 7 8 9 0 -# -# The "AlgorithmName" is the standard algorithm name of the disabled -# algorithm. See "Java Cryptography Architecture Standard Algorithm Name -# Documentation" for information about Standard Algorithm Names. Matching -# is performed using a case-insensitive sub-element matching rule. (For -# example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and -# "ECDSA" for signatures.) If the assertion "AlgorithmName" is a -# sub-element of the certificate algorithm name, the algorithm will be -# rejected during certification path building and validation. For example, -# the assertion algorithm name "DSA" will disable all certificate algorithms -# that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion -# will not disable algorithms related to "ECDSA". -# -# A "Constraint" provides further guidance for the algorithm being specified. -# The "KeySizeConstraint" requires a key of a valid size range if the -# "AlgorithmName" is of a key algorithm. The "DecimalInteger" indicates the -# key size specified in number of bits. For example, "RSA keySize <= 1024" -# indicates that any RSA key with key size less than or equal to 1024 bits -# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates -# that any RSA key with key size less than 1024 or greater than 2048 should -# be disabled. Note that the "KeySizeConstraint" only makes sense to key -# algorithms. -# -# Note: This property is currently used by Oracle's PKIX implementation. It -# is not guaranteed to be examined and used by other implementations. -# -# Example: -# jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 -# -# -jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024 - -# Algorithm restrictions for Secure Socket Layer/Transport Layer Security -# (SSL/TLS) processing -# -# In some environments, certain algorithms or key lengths may be undesirable -# when using SSL/TLS. This section describes the mechanism for disabling -# algorithms during SSL/TLS security parameters negotiation, including cipher -# suites selection, peer authentication and key exchange mechanisms. -# -# For PKI-based peer authentication and key exchange mechanisms, this list -# of disabled algorithms will also be checked during certification path -# building and validation, including algorithms used in certificates, as -# well as revocation information such as CRLs and signed OCSP Responses. -# This is in addition to the jdk.certpath.disabledAlgorithms property above. -# -# See the specification of "jdk.certpath.disabledAlgorithms" for the -# syntax of the disabled algorithm string. -# -# Note: This property is currently used by Oracle's JSSE implementation. -# It is not guaranteed to be examined and used by other implementations. -# -# Example: -# jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 diff --git a/jdk/src/java.base/share/conf/security/java.security-macosx b/jdk/src/java.base/share/conf/security/java.security-macosx deleted file mode 100644 index ff726991c56..00000000000 --- a/jdk/src/java.base/share/conf/security/java.security-macosx +++ /dev/null @@ -1,499 +0,0 @@ -# -# This is the "master security properties file". -# -# An alternate java.security properties file may be specified -# from the command line via the system property -# -# -Djava.security.properties= -# -# This properties file appends to the master security properties file. -# If both properties files specify values for the same key, the value -# from the command-line properties file is selected, as it is the last -# one loaded. -# -# Also, if you specify -# -# -Djava.security.properties== (2 equals), -# -# then that properties file completely overrides the master security -# properties file. -# -# To disable the ability to specify an additional properties file from -# the command line, set the key security.overridePropertiesFile -# to false in the master security properties file. It is set to true -# by default. - -# In this file, various security properties are set for use by -# java.security classes. This is where users can statically register -# Cryptography Package Providers ("providers" for short). The term -# "provider" refers to a package or set of packages that supply a -# concrete implementation of a subset of the cryptography aspects of -# the Java Security API. A provider may, for example, implement one or -# more digital signature algorithms or message digest algorithms. -# -# Each provider must implement a subclass of the Provider class. -# To register a provider in this master security properties file, -# specify the Provider subclass name and priority in the format -# -# security.provider.= -# -# This declares a provider, and specifies its preference -# order n. The preference order is the order in which providers are -# searched for requested algorithms (when no specific provider is -# requested). The order is 1-based; 1 is the most preferred, followed -# by 2, and so on. -# -# must specify the subclass of the Provider class whose -# constructor sets the values of various properties that are required -# for the Java Security API to look up the algorithms or other -# facilities implemented by the provider. -# -# There must be at least one provider specification in java.security. -# There is a default provider that comes standard with the JDK. It -# is called the "SUN" provider, and its Provider subclass -# named Sun appears in the sun.security.provider package. Thus, the -# "SUN" provider is registered via the following: -# -# security.provider.1=sun.security.provider.Sun -# -# (The number 1 is used for the default provider.) -# -# Note: Providers can be dynamically registered instead by calls to -# either the addProvider or insertProviderAt method in the Security -# class. - -# -# List of providers and their preference orders (see above): -# -security.provider.1=sun.security.provider.Sun -security.provider.2=sun.security.rsa.SunRsaSign -security.provider.3=sun.security.ec.SunEC -security.provider.4=com.sun.net.ssl.internal.ssl.Provider -security.provider.5=com.sun.crypto.provider.SunJCE -security.provider.6=sun.security.jgss.SunProvider -security.provider.7=com.sun.security.sasl.Provider -security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI -security.provider.9=sun.security.smartcardio.SunPCSC -security.provider.10=apple.security.AppleProvider - -# -# Sun Provider SecureRandom seed source. -# -# Select the primary source of seed data for the "SHA1PRNG" and -# "NativePRNG" SecureRandom implementations in the "Sun" provider. -# (Other SecureRandom implementations might also use this property.) -# -# On Unix-like systems (for example, Solaris/Linux/MacOS), the -# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from -# special device files such as file:/dev/random. -# -# On Windows systems, specifying the URLs "file:/dev/random" or -# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding -# mechanism for SHA1PRNG. -# -# By default, an attempt is made to use the entropy gathering device -# specified by the "securerandom.source" Security property. If an -# exception occurs while accessing the specified URL: -# -# SHA1PRNG: -# the traditional system/thread activity algorithm will be used. -# -# NativePRNG: -# a default value of /dev/random will be used. If neither -# are available, the implementation will be disabled. -# "file" is the only currently supported protocol type. -# -# The entropy gathering device can also be specified with the System -# property "java.security.egd". For example: -# -# % java -Djava.security.egd=file:/dev/random MainClass -# -# Specifying this System property will override the -# "securerandom.source" Security property. -# -# In addition, if "file:/dev/random" or "file:/dev/urandom" is -# specified, the "NativePRNG" implementation will be more preferred than -# SHA1PRNG in the Sun provider. -# -securerandom.source=file:/dev/random - -# -# A list of known strong SecureRandom implementations. -# -# To help guide applications in selecting a suitable strong -# java.security.SecureRandom implementation, Java distributions should -# indicate a list of known strong implementations using the property. -# -# This is a comma-separated list of algorithm and/or algorithm:provider -# entries. -# -securerandom.strongAlgorithms=NativePRNGBlocking:SUN - -# -# Class to instantiate as the javax.security.auth.login.Configuration -# provider. -# -login.configuration.provider=sun.security.provider.ConfigFile - -# -# Default login configuration file -# -#login.config.url.1=file:${user.home}/.java.login.config - -# -# Class to instantiate as the system Policy. This is the name of the class -# that will be used as the Policy object. -# -policy.provider=sun.security.provider.PolicyFile - -# The default is to have a single system-wide policy file, -# and a policy file in the user's home directory. -policy.url.1=file:${java.home}/lib/security/java.policy -policy.url.2=file:${user.home}/.java.policy - -# whether or not we expand properties in the policy file -# if this is set to false, properties (${...}) will not be expanded in policy -# files. -policy.expandProperties=true - -# whether or not we allow an extra policy to be passed on the command line -# with -Djava.security.policy=somefile. Comment out this line to disable -# this feature. -policy.allowSystemProperty=true - -# whether or not we look into the IdentityScope for trusted Identities -# when encountering a 1.1 signed JAR file. If the identity is found -# and is trusted, we grant it AllPermission. -policy.ignoreIdentityScope=false - -# -# Default keystore type. -# -keystore.type=jks - -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageAccess unless the -# corresponding RuntimePermission ("accessClassInPackage."+package) has -# been granted. -package.access=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ - com.sun.istack.internal.,\ - com.sun.jmx.,\ - com.sun.media.sound.,\ - com.sun.naming.internal.,\ - com.sun.proxy.,\ - com.sun.corba.se.,\ - com.sun.org.apache.bcel.internal.,\ - com.sun.org.apache.regexp.internal.,\ - com.sun.org.apache.xerces.internal.,\ - com.sun.org.apache.xpath.internal.,\ - com.sun.org.apache.xalan.internal.extensions.,\ - com.sun.org.apache.xalan.internal.lib.,\ - com.sun.org.apache.xalan.internal.res.,\ - com.sun.org.apache.xalan.internal.templates.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.apache.xalan.internal.xslt.,\ - com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ - com.sun.org.apache.xalan.internal.xsltc.compiler.,\ - com.sun.org.apache.xalan.internal.xsltc.trax.,\ - com.sun.org.apache.xalan.internal.xsltc.util.,\ - com.sun.org.apache.xml.internal.res.,\ - com.sun.org.apache.xml.internal.security.,\ - com.sun.org.apache.xml.internal.serializer.utils.,\ - com.sun.org.apache.xml.internal.utils.,\ - com.sun.org.glassfish.,\ - com.oracle.xmlns.internal.,\ - com.oracle.webservices.internal.,\ - org.jcp.xml.dsig.internal.,\ - jdk.internal.,\ - jdk.nashorn.internal.,\ - jdk.nashorn.tools.,\ - com.sun.activation.registries.,\ - apple. - -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageDefinition unless the -# corresponding RuntimePermission ("defineClassInPackage."+package) has -# been granted. -# -# by default, none of the class loaders supplied with the JDK call -# checkPackageDefinition. -# -package.definition=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ - com.sun.istack.internal.,\ - com.sun.jmx.,\ - com.sun.media.sound.,\ - com.sun.naming.internal.,\ - com.sun.proxy.,\ - com.sun.corba.se.,\ - com.sun.org.apache.bcel.internal.,\ - com.sun.org.apache.regexp.internal.,\ - com.sun.org.apache.xerces.internal.,\ - com.sun.org.apache.xpath.internal.,\ - com.sun.org.apache.xalan.internal.extensions.,\ - com.sun.org.apache.xalan.internal.lib.,\ - com.sun.org.apache.xalan.internal.res.,\ - com.sun.org.apache.xalan.internal.templates.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.apache.xalan.internal.xslt.,\ - com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ - com.sun.org.apache.xalan.internal.xsltc.compiler.,\ - com.sun.org.apache.xalan.internal.xsltc.trax.,\ - com.sun.org.apache.xalan.internal.xsltc.util.,\ - com.sun.org.apache.xml.internal.res.,\ - com.sun.org.apache.xml.internal.security.,\ - com.sun.org.apache.xml.internal.serializer.utils.,\ - com.sun.org.apache.xml.internal.utils.,\ - com.sun.org.glassfish.,\ - com.oracle.xmlns.internal.,\ - com.oracle.webservices.internal.,\ - org.jcp.xml.dsig.internal.,\ - jdk.internal.,\ - jdk.nashorn.internal.,\ - jdk.nashorn.tools.,\ - com.sun.activation.registries.,\ - apple. - -# -# Determines whether this properties file can be appended to -# or overridden on the command line via -Djava.security.properties -# -security.overridePropertiesFile=true - -# -# Determines the default key and trust manager factory algorithms for -# the javax.net.ssl package. -# -ssl.KeyManagerFactory.algorithm=SunX509 -ssl.TrustManagerFactory.algorithm=PKIX - -# -# The Java-level namelookup cache policy for successful lookups: -# -# any negative value: caching forever -# any positive value: the number of seconds to cache an address for -# zero: do not cache -# -# default value is forever (FOREVER). For security reasons, this -# caching is made forever when a security manager is set. When a security -# manager is not set, the default behavior in this implementation -# is to cache for 30 seconds. -# -# NOTE: setting this to anything other than the default value can have -# serious security implications. Do not set it unless -# you are sure you are not exposed to DNS spoofing attack. -# -#networkaddress.cache.ttl=-1 - -# The Java-level namelookup cache policy for failed lookups: -# -# any negative value: cache forever -# any positive value: the number of seconds to cache negative lookup results -# zero: do not cache -# -# In some Microsoft Windows networking environments that employ -# the WINS name service in addition to DNS, name service lookups -# that fail may take a noticeably long time to return (approx. 5 seconds). -# For this reason the default caching policy is to maintain these -# results for 10 seconds. -# -# -networkaddress.cache.negative.ttl=10 - -# -# Properties to configure OCSP for certificate revocation checking -# - -# Enable OCSP -# -# By default, OCSP is not used for certificate revocation checking. -# This property enables the use of OCSP when set to the value "true". -# -# NOTE: SocketPermission is required to connect to an OCSP responder. -# -# Example, -# ocsp.enable=true - -# -# Location of the OCSP responder -# -# By default, the location of the OCSP responder is determined implicitly -# from the certificate being validated. This property explicitly specifies -# the location of the OCSP responder. The property is used when the -# Authority Information Access extension (defined in RFC 3280) is absent -# from the certificate or when it requires overriding. -# -# Example, -# ocsp.responderURL=http://ocsp.example.net:80 - -# -# Subject name of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. In cases where -# the subject name alone is not sufficient to uniquely identify the certificate -# then both the "ocsp.responderCertIssuerName" and -# "ocsp.responderCertSerialNumber" properties must be used instead. When this -# property is set then those two properties are ignored. -# -# Example, -# ocsp.responderCertSubjectName="CN=OCSP Responder, O=XYZ Corp" - -# -# Issuer name of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. When this -# property is set then the "ocsp.responderCertSerialNumber" property must also -# be set. When the "ocsp.responderCertSubjectName" property is set then this -# property is ignored. -# -# Example, -# ocsp.responderCertIssuerName="CN=Enterprise CA, O=XYZ Corp" - -# -# Serial number of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# of hexadecimal digits (colon or space separators may be present) which -# identifies a certificate in the set of certificates supplied during cert path -# validation. When this property is set then the "ocsp.responderCertIssuerName" -# property must also be set. When the "ocsp.responderCertSubjectName" property -# is set then this property is ignored. -# -# Example, -# ocsp.responderCertSerialNumber=2A:FF:00 - -# -# Policy for failed Kerberos KDC lookups: -# -# When a KDC is unavailable (network error, service failure, etc), it is -# put inside a blacklist and accessed less often for future requests. The -# value (case-insensitive) for this policy can be: -# -# tryLast -# KDCs in the blacklist are always tried after those not on the list. -# -# tryLess[:max_retries,timeout] -# KDCs in the blacklist are still tried by their order in the configuration, -# but with smaller max_retries and timeout values. max_retries and timeout -# are optional numerical parameters (default 1 and 5000, which means once -# and 5 seconds). Please notes that if any of the values defined here is -# more than what is defined in krb5.conf, it will be ignored. -# -# Whenever a KDC is detected as available, it is removed from the blacklist. -# The blacklist is reset when krb5.conf is reloaded. You can add -# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is -# reloaded whenever a JAAS authentication is attempted. -# -# Example, -# krb5.kdc.bad.policy = tryLast -# krb5.kdc.bad.policy = tryLess:2,2000 -krb5.kdc.bad.policy = tryLast - -# Algorithm restrictions for certification path (CertPath) processing -# -# In some environments, certain algorithms or key lengths may be undesirable -# for certification path building and validation. For example, "MD2" is -# generally no longer considered to be a secure hash algorithm. This section -# describes the mechanism for disabling algorithms based on algorithm name -# and/or key length. This includes algorithms used in certificates, as well -# as revocation information such as CRLs and signed OCSP Responses. -# -# The syntax of the disabled algorithm string is described as this Java -# BNF-style: -# DisabledAlgorithms: -# " DisabledAlgorithm { , DisabledAlgorithm } " -# -# DisabledAlgorithm: -# AlgorithmName [Constraint] -# -# AlgorithmName: -# (see below) -# -# Constraint: -# KeySizeConstraint -# -# KeySizeConstraint: -# keySize Operator DecimalInteger -# -# Operator: -# <= | < | == | != | >= | > -# -# DecimalInteger: -# DecimalDigits -# -# DecimalDigits: -# DecimalDigit {DecimalDigit} -# -# DecimalDigit: one of -# 1 2 3 4 5 6 7 8 9 0 -# -# The "AlgorithmName" is the standard algorithm name of the disabled -# algorithm. See "Java Cryptography Architecture Standard Algorithm Name -# Documentation" for information about Standard Algorithm Names. Matching -# is performed using a case-insensitive sub-element matching rule. (For -# example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and -# "ECDSA" for signatures.) If the assertion "AlgorithmName" is a -# sub-element of the certificate algorithm name, the algorithm will be -# rejected during certification path building and validation. For example, -# the assertion algorithm name "DSA" will disable all certificate algorithms -# that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion -# will not disable algorithms related to "ECDSA". -# -# A "Constraint" provides further guidance for the algorithm being specified. -# The "KeySizeConstraint" requires a key of a valid size range if the -# "AlgorithmName" is of a key algorithm. The "DecimalInteger" indicates the -# key size specified in number of bits. For example, "RSA keySize <= 1024" -# indicates that any RSA key with key size less than or equal to 1024 bits -# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates -# that any RSA key with key size less than 1024 or greater than 2048 should -# be disabled. Note that the "KeySizeConstraint" only makes sense to key -# algorithms. -# -# Note: This property is currently used by Oracle's PKIX implementation. It -# is not guaranteed to be examined and used by other implementations. -# -# Example: -# jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 -# -# -jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024 - -# Algorithm restrictions for Secure Socket Layer/Transport Layer Security -# (SSL/TLS) processing -# -# In some environments, certain algorithms or key lengths may be undesirable -# when using SSL/TLS. This section describes the mechanism for disabling -# algorithms during SSL/TLS security parameters negotiation, including cipher -# suites selection, peer authentication and key exchange mechanisms. -# -# For PKI-based peer authentication and key exchange mechanisms, this list -# of disabled algorithms will also be checked during certification path -# building and validation, including algorithms used in certificates, as -# well as revocation information such as CRLs and signed OCSP Responses. -# This is in addition to the jdk.certpath.disabledAlgorithms property above. -# -# See the specification of "jdk.certpath.disabledAlgorithms" for the -# syntax of the disabled algorithm string. -# -# Note: This property is currently used by Oracle's JSSE implementation. -# It is not guaranteed to be examined and used by other implementations. -# -# Example: -# jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 diff --git a/jdk/src/java.base/share/conf/security/java.security-solaris b/jdk/src/java.base/share/conf/security/java.security-solaris deleted file mode 100644 index e26ff143141..00000000000 --- a/jdk/src/java.base/share/conf/security/java.security-solaris +++ /dev/null @@ -1,498 +0,0 @@ -# -# This is the "master security properties file". -# -# An alternate java.security properties file may be specified -# from the command line via the system property -# -# -Djava.security.properties= -# -# This properties file appends to the master security properties file. -# If both properties files specify values for the same key, the value -# from the command-line properties file is selected, as it is the last -# one loaded. -# -# Also, if you specify -# -# -Djava.security.properties== (2 equals), -# -# then that properties file completely overrides the master security -# properties file. -# -# To disable the ability to specify an additional properties file from -# the command line, set the key security.overridePropertiesFile -# to false in the master security properties file. It is set to true -# by default. - -# In this file, various security properties are set for use by -# java.security classes. This is where users can statically register -# Cryptography Package Providers ("providers" for short). The term -# "provider" refers to a package or set of packages that supply a -# concrete implementation of a subset of the cryptography aspects of -# the Java Security API. A provider may, for example, implement one or -# more digital signature algorithms or message digest algorithms. -# -# Each provider must implement a subclass of the Provider class. -# To register a provider in this master security properties file, -# specify the Provider subclass name and priority in the format -# -# security.provider.= -# -# This declares a provider, and specifies its preference -# order n. The preference order is the order in which providers are -# searched for requested algorithms (when no specific provider is -# requested). The order is 1-based; 1 is the most preferred, followed -# by 2, and so on. -# -# must specify the subclass of the Provider class whose -# constructor sets the values of various properties that are required -# for the Java Security API to look up the algorithms or other -# facilities implemented by the provider. -# -# There must be at least one provider specification in java.security. -# There is a default provider that comes standard with the JDK. It -# is called the "SUN" provider, and its Provider subclass -# named Sun appears in the sun.security.provider package. Thus, the -# "SUN" provider is registered via the following: -# -# security.provider.1=sun.security.provider.Sun -# -# (The number 1 is used for the default provider.) -# -# Note: Providers can be dynamically registered instead by calls to -# either the addProvider or insertProviderAt method in the Security -# class. - -# -# List of providers and their preference orders (see above): -# -security.provider.1=com.oracle.security.ucrypto.UcryptoProvider ${java.home}/lib/security/ucrypto-solaris.cfg -security.provider.2=sun.security.pkcs11.SunPKCS11 ${java.home}/lib/security/sunpkcs11-solaris.cfg -security.provider.3=sun.security.provider.Sun -security.provider.4=sun.security.rsa.SunRsaSign -security.provider.5=sun.security.ec.SunEC -security.provider.6=com.sun.net.ssl.internal.ssl.Provider -security.provider.7=com.sun.crypto.provider.SunJCE -security.provider.8=sun.security.jgss.SunProvider -security.provider.9=com.sun.security.sasl.Provider -security.provider.10=org.jcp.xml.dsig.internal.dom.XMLDSigRI -security.provider.11=sun.security.smartcardio.SunPCSC - -# -# Sun Provider SecureRandom seed source. -# -# Select the primary source of seed data for the "SHA1PRNG" and -# "NativePRNG" SecureRandom implementations in the "Sun" provider. -# (Other SecureRandom implementations might also use this property.) -# -# On Unix-like systems (for example, Solaris/Linux/MacOS), the -# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from -# special device files such as file:/dev/random. -# -# On Windows systems, specifying the URLs "file:/dev/random" or -# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding -# mechanism for SHA1PRNG. -# -# By default, an attempt is made to use the entropy gathering device -# specified by the "securerandom.source" Security property. If an -# exception occurs while accessing the specified URL: -# -# SHA1PRNG: -# the traditional system/thread activity algorithm will be used. -# -# NativePRNG: -# a default value of /dev/random will be used. If neither -# are available, the implementation will be disabled. -# "file" is the only currently supported protocol type. -# -# The entropy gathering device can also be specified with the System -# property "java.security.egd". For example: -# -# % java -Djava.security.egd=file:/dev/random MainClass -# -# Specifying this System property will override the -# "securerandom.source" Security property. -# -# In addition, if "file:/dev/random" or "file:/dev/urandom" is -# specified, the "NativePRNG" implementation will be more preferred than -# SHA1PRNG in the Sun provider. -# -securerandom.source=file:/dev/random - -# -# A list of known strong SecureRandom implementations. -# -# To help guide applications in selecting a suitable strong -# java.security.SecureRandom implementation, Java distributions should -# indicate a list of known strong implementations using the property. -# -# This is a comma-separated list of algorithm and/or algorithm:provider -# entries. -# -securerandom.strongAlgorithms=NativePRNGBlocking:SUN - -# -# Class to instantiate as the javax.security.auth.login.Configuration -# provider. -# -login.configuration.provider=sun.security.provider.ConfigFile - -# -# Default login configuration file -# -#login.config.url.1=file:${user.home}/.java.login.config - -# -# Class to instantiate as the system Policy. This is the name of the class -# that will be used as the Policy object. -# -policy.provider=sun.security.provider.PolicyFile - -# The default is to have a single system-wide policy file, -# and a policy file in the user's home directory. -policy.url.1=file:${java.home}/lib/security/java.policy -policy.url.2=file:${user.home}/.java.policy - -# whether or not we expand properties in the policy file -# if this is set to false, properties (${...}) will not be expanded in policy -# files. -policy.expandProperties=true - -# whether or not we allow an extra policy to be passed on the command line -# with -Djava.security.policy=somefile. Comment out this line to disable -# this feature. -policy.allowSystemProperty=true - -# whether or not we look into the IdentityScope for trusted Identities -# when encountering a 1.1 signed JAR file. If the identity is found -# and is trusted, we grant it AllPermission. -policy.ignoreIdentityScope=false - -# -# Default keystore type. -# -keystore.type=jks - -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageAccess unless the -# corresponding RuntimePermission ("accessClassInPackage."+package) has -# been granted. -package.access=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ - com.sun.istack.internal.,\ - com.sun.jmx.,\ - com.sun.media.sound.,\ - com.sun.naming.internal.,\ - com.sun.proxy.,\ - com.sun.corba.se.,\ - com.sun.org.apache.bcel.internal.,\ - com.sun.org.apache.regexp.internal.,\ - com.sun.org.apache.xerces.internal.,\ - com.sun.org.apache.xpath.internal.,\ - com.sun.org.apache.xalan.internal.extensions.,\ - com.sun.org.apache.xalan.internal.lib.,\ - com.sun.org.apache.xalan.internal.res.,\ - com.sun.org.apache.xalan.internal.templates.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.apache.xalan.internal.xslt.,\ - com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ - com.sun.org.apache.xalan.internal.xsltc.compiler.,\ - com.sun.org.apache.xalan.internal.xsltc.trax.,\ - com.sun.org.apache.xalan.internal.xsltc.util.,\ - com.sun.org.apache.xml.internal.res.,\ - com.sun.org.apache.xml.internal.security.,\ - com.sun.org.apache.xml.internal.serializer.utils.,\ - com.sun.org.apache.xml.internal.utils.,\ - com.sun.org.glassfish.,\ - com.oracle.xmlns.internal.,\ - com.oracle.webservices.internal.,\ - org.jcp.xml.dsig.internal.,\ - jdk.internal.,\ - jdk.nashorn.internal.,\ - jdk.nashorn.tools.,\ - com.sun.activation.registries. - -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageDefinition unless the -# corresponding RuntimePermission ("defineClassInPackage."+package) has -# been granted. -# -# by default, none of the class loaders supplied with the JDK call -# checkPackageDefinition. -# -package.definition=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ - com.sun.istack.internal.,\ - com.sun.jmx.,\ - com.sun.media.sound.,\ - com.sun.naming.internal.,\ - com.sun.proxy.,\ - com.sun.corba.se.,\ - com.sun.org.apache.bcel.internal.,\ - com.sun.org.apache.regexp.internal.,\ - com.sun.org.apache.xerces.internal.,\ - com.sun.org.apache.xpath.internal.,\ - com.sun.org.apache.xalan.internal.extensions.,\ - com.sun.org.apache.xalan.internal.lib.,\ - com.sun.org.apache.xalan.internal.res.,\ - com.sun.org.apache.xalan.internal.templates.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.apache.xalan.internal.xslt.,\ - com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ - com.sun.org.apache.xalan.internal.xsltc.compiler.,\ - com.sun.org.apache.xalan.internal.xsltc.trax.,\ - com.sun.org.apache.xalan.internal.xsltc.util.,\ - com.sun.org.apache.xml.internal.res.,\ - com.sun.org.apache.xml.internal.security.,\ - com.sun.org.apache.xml.internal.serializer.utils.,\ - com.sun.org.apache.xml.internal.utils.,\ - com.sun.org.glassfish.,\ - com.oracle.xmlns.internal.,\ - com.oracle.webservices.internal.,\ - org.jcp.xml.dsig.internal.,\ - jdk.internal.,\ - jdk.nashorn.internal.,\ - jdk.nashorn.tools.,\ - com.sun.activation.registries. - -# -# Determines whether this properties file can be appended to -# or overridden on the command line via -Djava.security.properties -# -security.overridePropertiesFile=true - -# -# Determines the default key and trust manager factory algorithms for -# the javax.net.ssl package. -# -ssl.KeyManagerFactory.algorithm=SunX509 -ssl.TrustManagerFactory.algorithm=PKIX - -# -# The Java-level namelookup cache policy for successful lookups: -# -# any negative value: caching forever -# any positive value: the number of seconds to cache an address for -# zero: do not cache -# -# default value is forever (FOREVER). For security reasons, this -# caching is made forever when a security manager is set. When a security -# manager is not set, the default behavior in this implementation -# is to cache for 30 seconds. -# -# NOTE: setting this to anything other than the default value can have -# serious security implications. Do not set it unless -# you are sure you are not exposed to DNS spoofing attack. -# -#networkaddress.cache.ttl=-1 - -# The Java-level namelookup cache policy for failed lookups: -# -# any negative value: cache forever -# any positive value: the number of seconds to cache negative lookup results -# zero: do not cache -# -# In some Microsoft Windows networking environments that employ -# the WINS name service in addition to DNS, name service lookups -# that fail may take a noticeably long time to return (approx. 5 seconds). -# For this reason the default caching policy is to maintain these -# results for 10 seconds. -# -# -networkaddress.cache.negative.ttl=10 - -# -# Properties to configure OCSP for certificate revocation checking -# - -# Enable OCSP -# -# By default, OCSP is not used for certificate revocation checking. -# This property enables the use of OCSP when set to the value "true". -# -# NOTE: SocketPermission is required to connect to an OCSP responder. -# -# Example, -# ocsp.enable=true - -# -# Location of the OCSP responder -# -# By default, the location of the OCSP responder is determined implicitly -# from the certificate being validated. This property explicitly specifies -# the location of the OCSP responder. The property is used when the -# Authority Information Access extension (defined in RFC 3280) is absent -# from the certificate or when it requires overriding. -# -# Example, -# ocsp.responderURL=http://ocsp.example.net:80 - -# -# Subject name of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. In cases where -# the subject name alone is not sufficient to uniquely identify the certificate -# then both the "ocsp.responderCertIssuerName" and -# "ocsp.responderCertSerialNumber" properties must be used instead. When this -# property is set then those two properties are ignored. -# -# Example, -# ocsp.responderCertSubjectName="CN=OCSP Responder, O=XYZ Corp" - -# -# Issuer name of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. When this -# property is set then the "ocsp.responderCertSerialNumber" property must also -# be set. When the "ocsp.responderCertSubjectName" property is set then this -# property is ignored. -# -# Example, -# ocsp.responderCertIssuerName="CN=Enterprise CA, O=XYZ Corp" - -# -# Serial number of the OCSP responder's certificate -# -# By default, the certificate of the OCSP responder is that of the issuer -# of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# of hexadecimal digits (colon or space separators may be present) which -# identifies a certificate in the set of certificates supplied during cert path -# validation. When this property is set then the "ocsp.responderCertIssuerName" -# property must also be set. When the "ocsp.responderCertSubjectName" property -# is set then this property is ignored. -# -# Example, -# ocsp.responderCertSerialNumber=2A:FF:00 - -# -# Policy for failed Kerberos KDC lookups: -# -# When a KDC is unavailable (network error, service failure, etc), it is -# put inside a blacklist and accessed less often for future requests. The -# value (case-insensitive) for this policy can be: -# -# tryLast -# KDCs in the blacklist are always tried after those not on the list. -# -# tryLess[:max_retries,timeout] -# KDCs in the blacklist are still tried by their order in the configuration, -# but with smaller max_retries and timeout values. max_retries and timeout -# are optional numerical parameters (default 1 and 5000, which means once -# and 5 seconds). Please notes that if any of the values defined here is -# more than what is defined in krb5.conf, it will be ignored. -# -# Whenever a KDC is detected as available, it is removed from the blacklist. -# The blacklist is reset when krb5.conf is reloaded. You can add -# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is -# reloaded whenever a JAAS authentication is attempted. -# -# Example, -# krb5.kdc.bad.policy = tryLast -# krb5.kdc.bad.policy = tryLess:2,2000 -krb5.kdc.bad.policy = tryLast - -# Algorithm restrictions for certification path (CertPath) processing -# -# In some environments, certain algorithms or key lengths may be undesirable -# for certification path building and validation. For example, "MD2" is -# generally no longer considered to be a secure hash algorithm. This section -# describes the mechanism for disabling algorithms based on algorithm name -# and/or key length. This includes algorithms used in certificates, as well -# as revocation information such as CRLs and signed OCSP Responses. -# -# The syntax of the disabled algorithm string is described as this Java -# BNF-style: -# DisabledAlgorithms: -# " DisabledAlgorithm { , DisabledAlgorithm } " -# -# DisabledAlgorithm: -# AlgorithmName [Constraint] -# -# AlgorithmName: -# (see below) -# -# Constraint: -# KeySizeConstraint -# -# KeySizeConstraint: -# keySize Operator DecimalInteger -# -# Operator: -# <= | < | == | != | >= | > -# -# DecimalInteger: -# DecimalDigits -# -# DecimalDigits: -# DecimalDigit {DecimalDigit} -# -# DecimalDigit: one of -# 1 2 3 4 5 6 7 8 9 0 -# -# The "AlgorithmName" is the standard algorithm name of the disabled -# algorithm. See "Java Cryptography Architecture Standard Algorithm Name -# Documentation" for information about Standard Algorithm Names. Matching -# is performed using a case-insensitive sub-element matching rule. (For -# example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and -# "ECDSA" for signatures.) If the assertion "AlgorithmName" is a -# sub-element of the certificate algorithm name, the algorithm will be -# rejected during certification path building and validation. For example, -# the assertion algorithm name "DSA" will disable all certificate algorithms -# that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion -# will not disable algorithms related to "ECDSA". -# -# A "Constraint" provides further guidance for the algorithm being specified. -# The "KeySizeConstraint" requires a key of a valid size range if the -# "AlgorithmName" is of a key algorithm. The "DecimalInteger" indicates the -# key size specified in number of bits. For example, "RSA keySize <= 1024" -# indicates that any RSA key with key size less than or equal to 1024 bits -# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates -# that any RSA key with key size less than 1024 or greater than 2048 should -# be disabled. Note that the "KeySizeConstraint" only makes sense to key -# algorithms. -# -# Note: This property is currently used by Oracle's PKIX implementation. It -# is not guaranteed to be examined and used by other implementations. -# -# Example: -# jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 -# -# -jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024 - -# Algorithm restrictions for Secure Socket Layer/Transport Layer Security -# (SSL/TLS) processing -# -# In some environments, certain algorithms or key lengths may be undesirable -# when using SSL/TLS. This section describes the mechanism for disabling -# algorithms during SSL/TLS security parameters negotiation, including cipher -# suites selection, peer authentication and key exchange mechanisms. -# -# For PKI-based peer authentication and key exchange mechanisms, this list -# of disabled algorithms will also be checked during certification path -# building and validation, including algorithms used in certificates, as -# well as revocation information such as CRLs and signed OCSP Responses. -# This is in addition to the jdk.certpath.disabledAlgorithms property above. -# -# See the specification of "jdk.certpath.disabledAlgorithms" for the -# syntax of the disabled algorithm string. -# -# Note: This property is currently used by Oracle's JSSE implementation. -# It is not guaranteed to be examined and used by other implementations. -# -# Example: -# jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 diff --git a/jdk/src/java.base/share/native/libjava/FileInputStream.c b/jdk/src/java.base/share/native/libjava/FileInputStream.c index 092ddbf6f1f..dc1aea5cd64 100644 --- a/jdk/src/java.base/share/native/libjava/FileInputStream.c +++ b/jdk/src/java.base/share/native/libjava/FileInputStream.c @@ -57,7 +57,7 @@ Java_java_io_FileInputStream_initIDs(JNIEnv *env, jclass fdClass) { */ JNIEXPORT void JNICALL -Java_java_io_FileInputStream_open(JNIEnv *env, jobject this, jstring path) { +Java_java_io_FileInputStream_open0(JNIEnv *env, jobject this, jstring path) { fileOpen(env, this, path, fis_fd, O_RDONLY); } diff --git a/jdk/src/java.base/share/native/libjava/RandomAccessFile.c b/jdk/src/java.base/share/native/libjava/RandomAccessFile.c index 53b5f1aac1f..a44d8f39681 100644 --- a/jdk/src/java.base/share/native/libjava/RandomAccessFile.c +++ b/jdk/src/java.base/share/native/libjava/RandomAccessFile.c @@ -47,8 +47,8 @@ Java_java_io_RandomAccessFile_initIDs(JNIEnv *env, jclass fdClass) { JNIEXPORT void JNICALL -Java_java_io_RandomAccessFile_open(JNIEnv *env, - jobject this, jstring path, jint mode) +Java_java_io_RandomAccessFile_open0(JNIEnv *env, + jobject this, jstring path, jint mode) { int flags = 0; if (mode & java_io_RandomAccessFile_O_RDONLY) diff --git a/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java b/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java index e696d3eba07..2bb712e7867 100644 --- a/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java +++ b/jdk/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java @@ -226,6 +226,7 @@ class InheritedChannel { // -- Native methods -- + private static native void initIDs(); private static native int dup(int fd) throws IOException; private static native void dup2(int fd, int fd2) throws IOException; private static native int open0(String path, int oflag) throws IOException; @@ -236,5 +237,6 @@ class InheritedChannel { static { IOUtil.load(); + initIDs(); } } diff --git a/jdk/src/java.base/unix/native/libjava/FileOutputStream_md.c b/jdk/src/java.base/unix/native/libjava/FileOutputStream_md.c index efd5864cd9c..22d80a22663 100644 --- a/jdk/src/java.base/unix/native/libjava/FileOutputStream_md.c +++ b/jdk/src/java.base/unix/native/libjava/FileOutputStream_md.c @@ -53,8 +53,8 @@ Java_java_io_FileOutputStream_initIDs(JNIEnv *env, jclass fdClass) { */ JNIEXPORT void JNICALL -Java_java_io_FileOutputStream_open(JNIEnv *env, jobject this, - jstring path, jboolean append) { +Java_java_io_FileOutputStream_open0(JNIEnv *env, jobject this, + jstring path, jboolean append) { fileOpen(env, this, path, fos_fd, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC)); } diff --git a/jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c b/jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c index da5be2257d0..18dee4ddd41 100644 --- a/jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c +++ b/jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c @@ -599,9 +599,9 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env, */ assert(prog != NULL && argBlock != NULL); if ((phelperpath = getBytes(env, helperpath)) == NULL) goto Catch; - if ((pprog = getBytes(env, prog)) == NULL) goto Catch; - if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch; - if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch; + if ((pprog = getBytes(env, prog)) == NULL) goto Catch; + if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch; + if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch; c->argv[0] = pprog; c->argc = argc + 2; initVectorFromBlock(c->argv+1, pargBlock, argc); @@ -690,10 +690,11 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env, closeSafely(childenv[0]); closeSafely(childenv[1]); - releaseBytes(env, prog, pprog); - releaseBytes(env, argBlock, pargBlock); - releaseBytes(env, envBlock, penvBlock); - releaseBytes(env, dir, c->pdir); + releaseBytes(env, helperpath, phelperpath); + releaseBytes(env, prog, pprog); + releaseBytes(env, argBlock, pargBlock); + releaseBytes(env, envBlock, penvBlock); + releaseBytes(env, dir, c->pdir); free(c->argv); free(c->envv); diff --git a/jdk/src/java.base/unix/native/libnio/ch/IOUtil.c b/jdk/src/java.base/unix/native/libnio/ch/IOUtil.c index d8bbe849252..438bf41ddea 100644 --- a/jdk/src/java.base/unix/native/libnio/ch/IOUtil.c +++ b/jdk/src/java.base/unix/native/libnio/ch/IOUtil.c @@ -35,7 +35,6 @@ #include "java_lang_Integer.h" #include "nio.h" #include "nio_util.h" -#include "net_util.h" static jfieldID fd_fdID; /* for jint 'fd' in java.io.FileDescriptor */ @@ -45,7 +44,6 @@ Java_sun_nio_ch_IOUtil_initIDs(JNIEnv *env, jclass clazz) { CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor")); CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, clazz, "fd", "I")); - initInetAddressIDs(env); } JNIEXPORT jboolean JNICALL diff --git a/jdk/src/java.base/unix/native/libnio/ch/InheritedChannel.c b/jdk/src/java.base/unix/native/libnio/ch/InheritedChannel.c index 986348e5320..86d1b05baa2 100644 --- a/jdk/src/java.base/unix/native/libnio/ch/InheritedChannel.c +++ b/jdk/src/java.base/unix/native/libnio/ch/InheritedChannel.c @@ -47,6 +47,13 @@ static int matchFamily(struct sockaddr *sa) { return (family == AF_INET); } +JNIEXPORT void JNICALL +Java_sun_nio_ch_InheritedChannel_initIDs(JNIEnv *env, jclass cla) +{ + /* Initialize InetAddress IDs before later use of NET_XXX functions */ + initInetAddressIDs(env); +} + JNIEXPORT jobject JNICALL Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd) { diff --git a/jdk/src/java.base/unix/native/libnio/ch/Net.c b/jdk/src/java.base/unix/native/libnio/ch/Net.c index 8887f59109c..197b23a7285 100644 --- a/jdk/src/java.base/unix/native/libnio/ch/Net.c +++ b/jdk/src/java.base/unix/native/libnio/ch/Net.c @@ -151,7 +151,7 @@ static jboolean isSourceFilterSupported(){ JNIEXPORT void JNICALL Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) { - /* Here because Windows native code does need to init IDs */ + initInetAddressIDs(env); } JNIEXPORT jboolean JNICALL diff --git a/jdk/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/jdk/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index d3ee3279e54..e8a1623a87d 100644 --- a/jdk/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/jdk/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -333,7 +333,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) { int res = -1; RESTARTABLE(dup((int)fd), res); - if (fd == -1) { + if (res == -1) { throwUnixException(env, errno); } return (jint)res; @@ -361,13 +361,14 @@ Java_sun_nio_fs_UnixNativeDispatcher_fopen0(JNIEnv* env, jclass this, JNIEXPORT void JNICALL Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stream) { - int res; FILE* fp = jlong_to_ptr(stream); - do { - res = fclose(fp); - } while (res == EOF && errno == EINTR); - if (res == EOF) { + /* NOTE: fclose() wrapper is only used with read-only streams. + * If it ever is used with write streams, it might be better to add + * RESTARTABLE(fflush(fp)) before closing, to make sure the stream + * is completely written even if fclose() failed. + */ + if (fclose(fp) == EOF && errno != EINTR) { throwUnixException(env, errno); } } @@ -675,11 +676,9 @@ Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd JNIEXPORT void JNICALL Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) { - int err; DIR* dirp = jlong_to_ptr(dir); - RESTARTABLE(closedir(dirp), err); - if (errno == -1) { + if (closedir(dirp) == -1 && errno != EINTR) { throwUnixException(env, errno); } } diff --git a/jdk/src/java.base/windows/native/libjava/FileOutputStream_md.c b/jdk/src/java.base/windows/native/libjava/FileOutputStream_md.c index 567ebaa0c83..02ea15e89cb 100644 --- a/jdk/src/java.base/windows/native/libjava/FileOutputStream_md.c +++ b/jdk/src/java.base/windows/native/libjava/FileOutputStream_md.c @@ -54,8 +54,8 @@ Java_java_io_FileOutputStream_initIDs(JNIEnv *env, jclass fosClass) { */ JNIEXPORT void JNICALL -Java_java_io_FileOutputStream_open(JNIEnv *env, jobject this, - jstring path, jboolean append) { +Java_java_io_FileOutputStream_open0(JNIEnv *env, jobject this, + jstring path, jboolean append) { fileOpen(env, this, path, fos_fd, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC)); } diff --git a/jdk/src/java.base/windows/native/libjava/WinNTFileSystem_md.c b/jdk/src/java.base/windows/native/libjava/WinNTFileSystem_md.c index 6ecf818d3ff..3c280c0c9b4 100644 --- a/jdk/src/java.base/windows/native/libjava/WinNTFileSystem_md.c +++ b/jdk/src/java.base/windows/native/libjava/WinNTFileSystem_md.c @@ -572,10 +572,10 @@ Java_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls, SetLastError(error); JNU_ThrowIOExceptionWithLastError(env, "Could not open file"); } - } - free(pathbuf); - return JNI_FALSE; } + free(pathbuf); + return JNI_FALSE; + } free(pathbuf); CloseHandle(h); return JNI_TRUE; @@ -636,7 +636,7 @@ Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file) if (search_path == 0) { free (pathbuf); errno = ENOMEM; - JNU_ThrowOutOfMemoryError(env, "native memory allocation faiuled"); + JNU_ThrowOutOfMemoryError(env, "native memory allocation failed"); return NULL; } wcscpy(search_path, pathbuf); @@ -652,7 +652,7 @@ Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file) /* Remove trailing space chars from directory name */ len = (int)wcslen(search_path); - while (search_path[len-1] == ' ') { + while (search_path[len-1] == L' ') { len--; } search_path[len] = 0; @@ -713,13 +713,15 @@ Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file) return NULL; // error FindClose(handle); - /* Copy the final results into an appropriately-sized array */ - old = rv; - rv = (*env)->NewObjectArray(env, len, str_class, NULL); - if (rv == NULL) - return NULL; /* error */ - if (JNU_CopyObjectArray(env, rv, old, len) < 0) - return NULL; /* error */ + if (len < maxlen) { + /* Copy the final results into an appropriately-sized array */ + old = rv; + rv = (*env)->NewObjectArray(env, len, str_class, NULL); + if (rv == NULL) + return NULL; /* error */ + if (JNU_CopyObjectArray(env, rv, old, len) < 0) + return NULL; /* error */ + } return rv; } @@ -753,9 +755,7 @@ Java_java_io_WinNTFileSystem_rename0(JNIEnv *env, jobject this, jobject from, jboolean rv = JNI_FALSE; WCHAR *frompath = fileToNTPath(env, from, ids.path); WCHAR *topath = fileToNTPath(env, to, ids.path); - if (frompath == NULL || topath == NULL) - return JNI_FALSE; - if (_wrename(frompath, topath) == 0) { + if (frompath != NULL && topath != NULL && _wrename(frompath, topath) == 0) { rv = JNI_TRUE; } free(frompath); diff --git a/jdk/src/java.base/windows/native/libnio/ch/IOUtil.c b/jdk/src/java.base/windows/native/libnio/ch/IOUtil.c index 49de1eb89d7..5c33ac4de23 100644 --- a/jdk/src/java.base/windows/native/libnio/ch/IOUtil.c +++ b/jdk/src/java.base/windows/native/libnio/ch/IOUtil.c @@ -56,7 +56,6 @@ Java_sun_nio_ch_IOUtil_initIDs(JNIEnv *env, jclass clazz) CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor")); CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, clazz, "fd", "I")); CHECK_NULL(handle_fdID = (*env)->GetFieldID(env, clazz, "handle", "J")); - initInetAddressIDs(env); } /************************************************************** diff --git a/jdk/src/java.base/windows/native/libnio/ch/Net.c b/jdk/src/java.base/windows/native/libnio/ch/Net.c index fb0faa87b84..b92e63ac11b 100644 --- a/jdk/src/java.base/windows/native/libnio/ch/Net.c +++ b/jdk/src/java.base/windows/native/libnio/ch/Net.c @@ -81,7 +81,7 @@ static void setConnectionReset(SOCKET s, BOOL enable) { JNIEXPORT void JNICALL Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) { - /* nothing to do */ + initInetAddressIDs(env); } JNIEXPORT jboolean JNICALL diff --git a/jdk/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java b/jdk/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java index 28df9def412..eeed61d3798 100644 --- a/jdk/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java +++ b/jdk/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java @@ -114,7 +114,7 @@ public final class JRSUIControl { changes.putAll(other.changes); } - protected synchronized final void finalize() throws Throwable { + protected synchronized void finalize() throws Throwable { if (cfDictionaryPtr == 0) return; disposeCFDictionary(cfDictionaryPtr); cfDictionaryPtr = 0; diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameUI.java index 90ce8ca5b80..2ba95f6af05 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameUI.java @@ -938,7 +938,11 @@ public class AquaInternalFrameUI extends BasicInternalFrameUI implements SwingCo final Point pt = new Point(); final Component c = getComponentToForwardTo(e, pt); if (c == null) return; - c.dispatchEvent(new MouseWheelEvent(c, e.getID(), e.getWhen(), e.getModifiers(), pt.x, pt.y, e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation())); + c.dispatchEvent(new MouseWheelEvent(c, e.getID(), e.getWhen(), + e.getModifiers(), pt.x, pt.y, e.getXOnScreen(), e.getYOnScreen(), + e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), + e.getScrollAmount(), e.getWheelRotation(), + e.getPreciseWheelRotation())); } public void componentResized(final ComponentEvent e) { diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java index 8dd4fa60d2d..3e40b843449 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java @@ -3307,7 +3307,7 @@ public class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements Swing pane.repaint(); } else if (name == "indexForTitle") { calculatedBaseline = false; - updateHtmlViews((Integer) e.getNewValue()); + updateHtmlViews((Integer) e.getNewValue(), false); } else if (name == "tabLayoutPolicy") { AquaTabbedPaneCopyFromBasicUI.this.uninstallUI(pane); AquaTabbedPaneCopyFromBasicUI.this.installUI(pane); @@ -3345,7 +3345,7 @@ public class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements Swing calculatedBaseline = false; } else if (name == "indexForNullComponent") { isRunsDirty = true; - updateHtmlViews((Integer) e.getNewValue()); + updateHtmlViews((Integer) e.getNewValue(), true); } else if (name == "font") { calculatedBaseline = false; } @@ -3464,10 +3464,10 @@ public class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements Swing return; } isRunsDirty = true; - updateHtmlViews(tp.indexOfComponent(child)); + updateHtmlViews(tp.indexOfComponent(child), true); } - private void updateHtmlViews(int index) { + private void updateHtmlViews(int index, boolean inserted) { final String title = tabPane.getTitleAt(index); final boolean isHTML = BasicHTML.isHTMLString(title); if (isHTML) { @@ -3475,16 +3475,24 @@ public class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements Swing htmlViews = createHTMLVector(); } else { // Vector already exists final View v = BasicHTML.createHTMLView(tabPane, title); - htmlViews.insertElementAt(v, index); + setHtmlView(v, inserted, index); } } else { // Not HTML if (htmlViews != null) { // Add placeholder - htmlViews.insertElementAt(null, index); + setHtmlView(null, inserted, index); } // else nada! } updateMnemonics(); } + private void setHtmlView(View v, boolean inserted, int index) { + if (inserted || index >= htmlViews.size()) { + htmlViews.insertElementAt(v, index); + } else { + htmlViews.setElementAt(v, index); + } + } + public void componentRemoved(final ContainerEvent e) { final JTabbedPane tp = (JTabbedPane)e.getContainer(); final Component child = e.getChild(); diff --git a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java index 8e1cead53c2..28c59712fe7 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java @@ -43,7 +43,7 @@ import sun.awt.HeadlessToolkit; import sun.awt.util.ThreadGroupUtils; import sun.lwawt.macosx.*; -public class CFontManager extends SunFontManager { +public final class CFontManager extends SunFontManager { private FontConfigManager fcManager = null; private static Hashtable genericFonts = new Hashtable(); @@ -61,20 +61,14 @@ public class CFontManager extends SunFontManager { return new CFontConfiguration(this, preferLocaleFonts, preferPropFonts); } - private static String[] defaultPlatformFont = null; - /* * Returns an array of two strings. The first element is the * name of the font. The second element is the file name. */ @Override - public synchronized String[] getDefaultPlatformFont() { - if (defaultPlatformFont == null) { - defaultPlatformFont = new String[2]; - defaultPlatformFont[0] = "Lucida Grande"; - defaultPlatformFont[1] = "/System/Library/Fonts/LucidaGrande.ttc"; - } - return defaultPlatformFont; + protected String[] getDefaultPlatformFont() { + return new String[]{"Lucida Grande", + "/System/Library/Fonts/LucidaGrande.ttc"}; } // This is a way to register any kind of Font2D, not just files and composites. diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java index 408862f7746..ca731ba3a72 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java @@ -1233,11 +1233,13 @@ public abstract class LWComponentPeer delegate, me.getID(), me.getWhen(), me.getModifiers(), me.getX(), me.getY(), + me.getXOnScreen(), me.getYOnScreen(), me.getClickCount(), me.isPopupTrigger(), me.getScrollType(), me.getScrollAmount(), - me.getWheelRotation()); + me.getWheelRotation(), + me.getPreciseWheelRotation()); } else if (e instanceof MouseEvent) { MouseEvent me = (MouseEvent) e; diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java index b72ef77d876..4655d2bcfca 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java @@ -105,6 +105,8 @@ public class LWWindowPeer private final SecurityWarningWindow warningWindow; + private volatile boolean targetFocusable; + /** * Current modal blocker or null. * @@ -240,13 +242,12 @@ public class LWWindowPeer if (!visible && warningWindow != null) { warningWindow.setVisible(false, false); } - + updateFocusableWindowState(); super.setVisibleImpl(visible); // TODO: update graphicsConfig, see 4868278 platformWindow.setVisible(visible); if (isSimpleWindow()) { KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance(); - if (visible) { if (!getTarget().isAutoRequestFocus()) { return; @@ -397,6 +398,7 @@ public class LWWindowPeer @Override public void updateFocusableWindowState() { + targetFocusable = getTarget().isFocusableWindow(); platformWindow.updateFocusableWindowState(); } @@ -1220,13 +1222,13 @@ public class LWWindowPeer } private boolean isFocusableWindow() { - boolean focusable = getTarget().isFocusableWindow(); + boolean focusable = targetFocusable; if (isSimpleWindow()) { LWWindowPeer ownerPeer = getOwnerFrameDialog(this); if (ownerPeer == null) { return false; } - return focusable && ownerPeer.getTarget().isFocusableWindow(); + return focusable && ownerPeer.targetFocusable; } return focusable; } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java index c241aae3cc0..7618bbec2a4 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java @@ -38,7 +38,8 @@ public class CEmbeddedFrame extends EmbeddedFrame { private CPlatformResponder responder; private static final Object classLock = new Object(); - private static volatile CEmbeddedFrame focusedWindow; + private static volatile CEmbeddedFrame globalFocusedWindow; + private CEmbeddedFrame browserWindowFocusedApplet; private boolean parentWindowActive = true; public CEmbeddedFrame() { @@ -111,10 +112,10 @@ public class CEmbeddedFrame extends EmbeddedFrame { synchronized (classLock) { // In some cases an applet may not receive the focus lost event // from the parent window (see 8012330) - focusedWindow = (focused) ? this - : ((focusedWindow == this) ? null : focusedWindow); + globalFocusedWindow = (focused) ? this + : ((globalFocusedWindow == this) ? null : globalFocusedWindow); } - if (focusedWindow == this) { + if (globalFocusedWindow == this) { // see bug 8010925 // we can't put this to handleWindowFocusEvent because // it won't be invoced if focuse is moved to a html element @@ -145,9 +146,23 @@ public class CEmbeddedFrame extends EmbeddedFrame { // non-focused applet. This method can be called from different threads. public void handleWindowFocusEvent(boolean parentWindowActive) { this.parentWindowActive = parentWindowActive; + // If several applets are running in different browser's windows, it is necessary to + // detect the switching between the parent windows and update globalFocusedWindow accordingly. + synchronized (classLock) { + if (!parentWindowActive) { + this.browserWindowFocusedApplet = globalFocusedWindow; + } + if (parentWindowActive && globalFocusedWindow != this && isParentWindowChanged()) { + // It looks like we have switched to another browser window, let's restore focus to + // the previously focused applet in this window. If no applets were focused in the + // window, we will set focus to the first applet in the window. + globalFocusedWindow = (this.browserWindowFocusedApplet != null) ? this.browserWindowFocusedApplet + : this; + } + } // ignore focus "lost" native request as it may mistakenly // deactivate active window (see 8001161) - if (focusedWindow == this && parentWindowActive) { + if (globalFocusedWindow == this && parentWindowActive) { responder.handleWindowFocusEvent(parentWindowActive, null); } } @@ -155,4 +170,10 @@ public class CEmbeddedFrame extends EmbeddedFrame { public boolean isParentWindowActive() { return parentWindowActive; } + + private boolean isParentWindowChanged() { + // If globalFocusedWindow is located at inactive parent window or null, we have swithed to + // another window. + return globalFocusedWindow != null ? !globalFocusedWindow.isParentWindowActive() : true; + } } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java index 16bada2688c..7a33fdf22e2 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java @@ -54,11 +54,11 @@ public final class NSPrintInfo implements PrintJobAttribute, PrintRequestAttribu return "" + fNSPrintInfo; } - public final Class getCategory() { + public Class getCategory() { return NSPrintInfo.class; } - public final String getName() { + public String getName() { return "nsPrintInfo"; } } diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/sun/awt/JavaComponentAccessibility.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/sun/awt/JavaComponentAccessibility.m index e0de79524e8..1b3ec43a9fe 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/sun/awt/JavaComponentAccessibility.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/sun/awt/JavaComponentAccessibility.m @@ -1108,7 +1108,10 @@ static NSObject *sAttributeNamesLOCK = nil; JNIEnv *env = [ThreadUtilities getJNIEnv]; id value = nil; + NSWindow* hostWindow = [[self->fView window] retain]; jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop) + [hostWindow release]; + if (focused != NULL) { if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) { value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView]; diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/FFT.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/FFT.java index b378c8cc65d..8b1436736c0 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/FFT.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/FFT.java @@ -68,7 +68,7 @@ public final class FFT { calc(fftFrameSize, data, sign, w); } - private final static double[] computeTwiddleFactors(int fftFrameSize, + private static double[] computeTwiddleFactors(int fftFrameSize, int sign) { int imax = (int) (Math.log(fftFrameSize) / Math.log(2.)); @@ -122,7 +122,7 @@ public final class FFT { return warray; } - private final static void calc(int fftFrameSize, double[] data, int sign, + private static void calc(int fftFrameSize, double[] data, int sign, double[] w) { final int fftFrameSize2 = fftFrameSize << 1; @@ -139,7 +139,7 @@ public final class FFT { } - private final static void calcF2E(int fftFrameSize, double[] data, int i, + private static void calcF2E(int fftFrameSize, double[] data, int i, int nstep, double[] w) { int jmax = nstep; for (int n = 0; n < jmax; n += 2) { @@ -163,7 +163,7 @@ public final class FFT { // Perform Factor-4 Decomposition with 3 * complex operators and 8 +/- // complex operators - private final static void calcF4F(int fftFrameSize, double[] data, int i, + private static void calcF4F(int fftFrameSize, double[] data, int i, int nstep, double[] w) { final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize; // Factor-4 Decomposition @@ -331,7 +331,7 @@ public final class FFT { // Perform Factor-4 Decomposition with 3 * complex operators and 8 +/- // complex operators - private final static void calcF4I(int fftFrameSize, double[] data, int i, + private static void calcF4I(int fftFrameSize, double[] data, int i, int nstep, double[] w) { final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize; // Factor-4 Decomposition @@ -499,7 +499,7 @@ public final class FFT { // Perform Factor-4 Decomposition with 3 * complex operators and 8 +/- // complex operators - private final static void calcF4FE(int fftFrameSize, double[] data, int i, + private static void calcF4FE(int fftFrameSize, double[] data, int i, int nstep, double[] w) { final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize; // Factor-4 Decomposition @@ -593,7 +593,7 @@ public final class FFT { // Perform Factor-4 Decomposition with 3 * complex operators and 8 +/- // complex operators - private final static void calcF4IE(int fftFrameSize, double[] data, int i, + private static void calcF4IE(int fftFrameSize, double[] data, int i, int nstep, double[] w) { final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize; // Factor-4 Decomposition @@ -685,7 +685,7 @@ public final class FFT { } - private final void bitreversal(double[] data) { + private void bitreversal(double[] data) { if (fftFrameSize < 4) return; diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JDK13Services.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JDK13Services.java index 9c93d06dc23..3805bb8848c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JDK13Services.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JDK13Services.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -25,6 +25,8 @@ package com.sun.media.sound; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -176,11 +178,11 @@ public final class JDK13Services { && !Sequencer.class.equals(typeClass)) { return null; } - String value; - String propertyName = typeClass.getName(); - value = JSSecurityManager.getProperty(propertyName); + String name = typeClass.getName(); + String value = AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty(name)); if (value == null) { - value = getProperties().getProperty(propertyName); + value = getProperties().getProperty(name); } if ("".equals(value)) { value = null; diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java index 60549a77ea4..6614b088cf3 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -73,33 +73,6 @@ final class JSSecurityManager { } } - static String getProperty(final String propertyName) { - String propertyValue; - if (hasSecurityManager()) { - if(Printer.debug) Printer.debug("using JDK 1.2 security to get property"); - try{ - PrivilegedAction action = new PrivilegedAction() { - public String run() { - try { - return System.getProperty(propertyName); - } catch (Throwable t) { - return null; - } - } - }; - propertyValue = AccessController.doPrivileged(action); - } catch( Exception e ) { - if(Printer.debug) Printer.debug("not using JDK 1.2 security to get properties"); - propertyValue = System.getProperty(propertyName); - } - } else { - if(Printer.debug) Printer.debug("not using JDK 1.2 security to get properties"); - propertyValue = System.getProperty(propertyName); - } - return propertyValue; - } - - /** Load properties from a file. This method tries to load properties from the filename give into the passed properties object. diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/Platform.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/Platform.java index 766e485f120..493aa7e0bd5 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/Platform.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -74,17 +74,6 @@ final class Platform { // intel is little-endian. sparc is big-endian. private static boolean bigEndian; - // this is the value of the "java.home" system property. i am looking it up here - // for use when trying to load the soundbank, just so - // that all the privileged code is localized in this file.... - private static String javahome; - - // this is the value of the "java.class.path" system property - private static String classpath; - - - - static { if(Printer.trace)Printer.trace(">> Platform.java: static"); @@ -129,26 +118,6 @@ final class Platform { return signed8; } - - /** - * Obtain javahome. - * $$kk: 04.16.99: this is *bad*!! - */ - static String getJavahome() { - - return javahome; - } - - /** - * Obtain classpath. - * $$jb: 04.21.99: this is *bad* too!! - */ - static String getClasspath() { - - return classpath; - } - - // PRIVATE METHODS /** @@ -157,21 +126,13 @@ final class Platform { private static void loadLibraries() { if(Printer.trace)Printer.trace(">>Platform.loadLibraries"); - try { - // load the main library - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - System.loadLibrary(libNameMain); - return null; - } - }); - // just for the heck of it... - loadedLibs |= LIB_MAIN; - } catch (SecurityException e) { - if(Printer.err)Printer.err("Security exception loading main native library. JavaSound requires access to these resources."); - throw(e); - } + // load the main library + AccessController.doPrivileged((PrivilegedAction) () -> { + System.loadLibrary(libNameMain); + return null; + }); + // just for the heck of it... + loadedLibs |= LIB_MAIN; // now try to load extra libs. They are defined at compile time in the Makefile // with the define EXTRA_SOUND_JNI_LIBS @@ -181,12 +142,9 @@ final class Platform { while (st.hasMoreTokens()) { final String lib = st.nextToken(); try { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - System.loadLibrary(lib); - return null; - } + AccessController.doPrivileged((PrivilegedAction) () -> { + System.loadLibrary(lib); + return null; }); if (lib.equals(libNameALSA)) { @@ -239,7 +197,5 @@ final class Platform { // $$fb 2002-03-06: implement check for endianness in native. Facilitates porting ! bigEndian = nIsBigEndian(); signed8 = nIsSigned8(); // Solaris on Sparc: signed, all others unsigned - javahome = JSSecurityManager.getProperty("java.home"); - classpath = JSSecurityManager.getProperty("java.class.path"); } } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/RIFFReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/RIFFReader.java index 7969a5d4fce..9849fbcb961 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/RIFFReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/RIFFReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,21 +39,20 @@ public final class RIFFReader extends InputStream { private long filepointer = 0; private final String fourcc; private String riff_type = null; - private long ckSize = 0; + private long ckSize = Integer.MAX_VALUE; private InputStream stream; - private long avail; + private long avail = Integer.MAX_VALUE; private RIFFReader lastiterator = null; public RIFFReader(InputStream stream) throws IOException { - if (stream instanceof RIFFReader) - root = ((RIFFReader)stream).root; - else + if (stream instanceof RIFFReader) { + root = ((RIFFReader) stream).root; + } else { root = this; + } this.stream = stream; - avail = Integer.MAX_VALUE; - ckSize = Integer.MAX_VALUE; // Check for RIFF null paddings, int b; @@ -76,10 +75,12 @@ public final class RIFFReader extends InputStream { readFully(fourcc, 1, 3); this.fourcc = new String(fourcc, "ascii"); ckSize = readUnsignedInt(); - - avail = this.ckSize; + avail = ckSize; if (getFormat().equals("RIFF") || getFormat().equals("LIST")) { + if (avail > Integer.MAX_VALUE) { + throw new RIFFInvalidDataException("Chunk size too big"); + } byte[] format = new byte[4]; readFully(format); this.riff_type = new String(format, "ascii"); @@ -118,19 +119,23 @@ public final class RIFFReader extends InputStream { } public int read() throws IOException { - if (avail == 0) + if (avail == 0) { return -1; + } int b = stream.read(); - if (b == -1) + if (b == -1) { + avail = 0; return -1; + } avail--; filepointer++; return b; } public int read(byte[] b, int offset, int len) throws IOException { - if (avail == 0) + if (avail == 0) { return -1; + } if (len > avail) { int rlen = stream.read(b, offset, (int)avail); if (rlen != -1) @@ -139,19 +144,21 @@ public final class RIFFReader extends InputStream { return rlen; } else { int ret = stream.read(b, offset, len); - if (ret == -1) + if (ret == -1) { + avail = 0; return -1; + } avail -= ret; filepointer += ret; return ret; } } - public final void readFully(byte b[]) throws IOException { + public void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } - public final void readFully(byte b[], int off, int len) throws IOException { + public void readFully(byte b[], int off, int len) throws IOException { if (len < 0) throw new IndexOutOfBoundsException(); while (len > 0) { @@ -165,7 +172,7 @@ public final class RIFFReader extends InputStream { } } - public final long skipBytes(long n) throws IOException { + public long skipBytes(long n) throws IOException { if (n < 0) return 0; long skipped = 0; @@ -191,8 +198,10 @@ public final class RIFFReader extends InputStream { return len; } else { long ret = stream.skip(n); - if (ret == -1) + if (ret == -1) { + avail = 0; return -1; + } avail -= ret; filepointer += ret; return ret; @@ -210,8 +219,13 @@ public final class RIFFReader extends InputStream { } // Read ASCII chars from stream - public String readString(int len) throws IOException { - byte[] buff = new byte[len]; + public String readString(final int len) throws IOException { + final byte[] buff; + try { + buff = new byte[len]; + } catch (final OutOfMemoryError oom) { + throw new IOException("Length too big", oom); + } readFully(buff); for (int i = 0; i < buff.length; i++) { if (buff[i] == 0) { diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SF2Soundbank.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SF2Soundbank.java index 83c8848b4f9..d45d50162bb 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SF2Soundbank.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SF2Soundbank.java @@ -276,6 +276,9 @@ public final class SF2Soundbank implements Soundbank { count--; } + if (presets_bagNdx.isEmpty()) { + throw new RIFFInvalidDataException(); + } int offset = presets_bagNdx.get(0); // Offset should be 0 (but just case) for (int i = 0; i < offset; i++) { @@ -360,6 +363,9 @@ public final class SF2Soundbank implements Soundbank { count--; } + if (instruments_bagNdx.isEmpty()) { + throw new RIFFInvalidDataException(); + } int offset = instruments_bagNdx.get(0); // Offset should be 0 (but just case) for (int i = 0; i < offset; i++) { @@ -401,6 +407,9 @@ public final class SF2Soundbank implements Soundbank { modulator.amount = chunk.readShort(); modulator.amountSourceOperator = chunk.readUnsignedShort(); modulator.transportOperator = chunk.readUnsignedShort(); + if (i < 0 || i >= instruments_splits_gen.size()) { + throw new RIFFInvalidDataException(); + } SF2LayerRegion split = instruments_splits_gen.get(i); if (split != null) split.modulators.add(modulator); @@ -424,7 +433,8 @@ public final class SF2Soundbank implements Soundbank { sample.name = chunk.readString(20); long start = chunk.readUnsignedInt(); long end = chunk.readUnsignedInt(); - sample.data = sampleData.subbuffer(start * 2, end * 2, true); + if (sampleData != null) + sample.data = sampleData.subbuffer(start * 2, end * 2, true); if (sampleData24 != null) sample.data24 = sampleData24.subbuffer(start, end, true); /* @@ -462,6 +472,9 @@ public final class SF2Soundbank implements Soundbank { int sampleid = split.generators.get( SF2LayerRegion.GENERATOR_SAMPLEID); split.generators.remove(SF2LayerRegion.GENERATOR_SAMPLEID); + if (sampleid < 0 || sampleid >= samples.size()) { + throw new RIFFInvalidDataException(); + } split.sample = samples.get(sampleid); } else { globalsplit = split; @@ -488,6 +501,9 @@ public final class SF2Soundbank implements Soundbank { int instrumentid = split.generators.get( SF2InstrumentRegion.GENERATOR_INSTRUMENT); split.generators.remove(SF2LayerRegion.GENERATOR_INSTRUMENT); + if (instrumentid < 0 || instrumentid >= layers.size()) { + throw new RIFFInvalidDataException(); + } split.layer = layers.get(instrumentid); } else { globalsplit = split; diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMidiAudioFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMidiAudioFileReader.java index 48ae72fcb02..5089a87199a 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMidiAudioFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMidiAudioFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,6 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.media.sound; import java.io.File; @@ -39,14 +40,14 @@ import javax.sound.midi.Receiver; import javax.sound.midi.Sequence; import javax.sound.midi.Track; import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFileFormat.Type; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.UnsupportedAudioFileException; -import javax.sound.sampled.AudioFileFormat.Type; import javax.sound.sampled.spi.AudioFileReader; /** - * MIDI File Audio Renderer/Reader + * MIDI File Audio Renderer/Reader. * * @author Karl Helgason */ @@ -109,6 +110,9 @@ public final class SoftMidiAudioFileReader extends AudioFileReader { if (divtype == Sequence.PPQ) { if (((MetaMessage) msg).getType() == 0x51) { byte[] data = ((MetaMessage) msg).getData(); + if (data.length < 3) { + throw new UnsupportedAudioFileException(); + } mpq = ((data[0] & 0xff) << 16) | ((data[1] & 0xff) << 8) | (data[2] & 0xff); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java index 2c6dff99fea..e895ead074f 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -28,6 +28,7 @@ package com.sun.media.sound; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -732,31 +733,28 @@ public final class SoftSynthesizer implements AudioSynthesizer, * Save generated soundbank to disk for faster future use. */ OutputStream out = AccessController - .doPrivileged(new PrivilegedAction() { - public OutputStream run() { - try { - File userhome = new File(System - .getProperty("user.home"), - ".gervill"); - if (!userhome.exists()) - userhome.mkdirs(); - File emg_soundbank_file = new File( - userhome, "soundbank-emg.sf2"); - if (emg_soundbank_file.exists()) - return null; - return new FileOutputStream( - emg_soundbank_file); - } catch (IOException e) { - } catch (SecurityException e) { + .doPrivileged((PrivilegedAction) () -> { + try { + File userhome = new File(System + .getProperty("user.home"), ".gervill"); + if (!userhome.exists()) { + userhome.mkdirs(); } - return null; + File emg_soundbank_file = new File( + userhome, "soundbank-emg.sf2"); + if (emg_soundbank_file.exists()) { + return null; + } + return new FileOutputStream(emg_soundbank_file); + } catch (final FileNotFoundException ignored) { } + return null; }); if (out != null) { try { ((SF2Soundbank) defaultSoundBank).save(out); out.close(); - } catch (IOException e) { + } catch (final IOException ignored) { } } } @@ -846,26 +844,24 @@ public final class SoftSynthesizer implements AudioSynthesizer, private Properties getStoredProperties() { return AccessController - .doPrivileged(new PrivilegedAction() { - public Properties run() { - Properties p = new Properties(); - String notePath = "/com/sun/media/sound/softsynthesizer"; - try { - Preferences prefroot = Preferences.userRoot(); - if (prefroot.nodeExists(notePath)) { - Preferences prefs = prefroot.node(notePath); - String[] prefs_keys = prefs.keys(); - for (String prefs_key : prefs_keys) { - String val = prefs.get(prefs_key, null); - if (val != null) - p.setProperty(prefs_key, val); + .doPrivileged((PrivilegedAction) () -> { + Properties p = new Properties(); + String notePath = "/com/sun/media/sound/softsynthesizer"; + try { + Preferences prefroot = Preferences.userRoot(); + if (prefroot.nodeExists(notePath)) { + Preferences prefs = prefroot.node(notePath); + String[] prefs_keys = prefs.keys(); + for (String prefs_key : prefs_keys) { + String val = prefs.get(prefs_key, null); + if (val != null) { + p.setProperty(prefs_key, val); } } - } catch (BackingStoreException e) { - } catch (SecurityException e) { } - return p; + } catch (final BackingStoreException ignored) { } + return p; }); } @@ -1044,7 +1040,6 @@ public final class SoftSynthesizer implements AudioSynthesizer, return; } synchronized (control_mutex) { - Throwable causeException = null; try { if (line != null) { // can throw IllegalArgumentException @@ -1117,24 +1112,17 @@ public final class SoftSynthesizer implements AudioSynthesizer, weakstream.sourceDataLine = sourceDataLine; } - } catch (LineUnavailableException e) { - causeException = e; - } catch (IllegalArgumentException e) { - causeException = e; - } catch (SecurityException e) { - causeException = e; - } - - if (causeException != null) { - if (isOpen()) + } catch (final LineUnavailableException | SecurityException + | IllegalArgumentException e) { + if (isOpen()) { close(); + } // am: need MidiUnavailableException(Throwable) ctor! MidiUnavailableException ex = new MidiUnavailableException( "Can not open line"); - ex.initCause(causeException); + ex.initCause(e); throw ex; } - } } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java index 1dbd72a262a..fd960395b1f 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -25,27 +25,25 @@ package com.sun.media.sound; +import java.io.BufferedInputStream; import java.io.DataInputStream; +import java.io.EOFException; import java.io.File; import java.io.FileInputStream; -import java.io.InputStream; import java.io.IOException; -import java.io.EOFException; -import java.io.BufferedInputStream; +import java.io.InputStream; import java.net.URL; -import javax.sound.midi.MidiFileFormat; import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MetaMessage; import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiFileFormat; import javax.sound.midi.MidiMessage; import javax.sound.midi.Sequence; import javax.sound.midi.SysexMessage; import javax.sound.midi.Track; import javax.sound.midi.spi.MidiFileReader; - - /** * MIDI file reader. * @@ -53,19 +51,23 @@ import javax.sound.midi.spi.MidiFileReader; * @author Jan Borgersen * @author Florian Bomers */ - public final class StandardMidiFileReader extends MidiFileReader { private static final int MThd_MAGIC = 0x4d546864; // 'MThd' private static final int bisBufferSize = 1024; // buffer size in buffered input streams - public MidiFileFormat getMidiFileFormat(InputStream stream) throws InvalidMidiDataException, IOException { + public MidiFileFormat getMidiFileFormat(InputStream stream) + throws InvalidMidiDataException, IOException { return getMidiFileFormatFromStream(stream, MidiFileFormat.UNKNOWN_LENGTH, null); } - // $$fb 2002-04-17: part of fix for 4635286: MidiSystem.getMidiFileFormat() returns format having invalid length - private MidiFileFormat getMidiFileFormatFromStream(InputStream stream, int fileLength, SMFParser smfParser) throws InvalidMidiDataException, IOException { + // $$fb 2002-04-17: part of fix for 4635286: MidiSystem.getMidiFileFormat() + // returns format having invalid length + private MidiFileFormat getMidiFileFormatFromStream(InputStream stream, + int fileLength, + SMFParser smfParser) + throws InvalidMidiDataException, IOException{ int maxReadLength = 16; int duration = MidiFileFormat.UNKNOWN_LENGTH; DataInputStream dis; @@ -230,7 +232,7 @@ public final class StandardMidiFileReader extends MidiFileReader { //============================================================================================================= /** - * State variables during parsing of a MIDI file + * State variables during parsing of a MIDI file. */ final class SMFParser { private static final int MTrk_MAGIC = 0x4d54726b; // 'MTrk' @@ -297,7 +299,11 @@ final class SMFParser { } } // now read track in a byte array - trackData = new byte[trackLength]; + try { + trackData = new byte[trackLength]; + } catch (final OutOfMemoryError oom) { + throw new IOException("Track length too big", oom); + } try { // $$fb 2003-08-20: fix for 4910986: MIDI file parser breaks up on http connection stream.readFully(trackData); @@ -386,8 +392,13 @@ final class SMFParser { // meta int metaType = readUnsigned(); int metaLength = (int) readVarInt(); + final byte[] metaData; + try { + metaData = new byte[metaLength]; + } catch (final OutOfMemoryError oom) { + throw new IOException("Meta length too big", oom); + } - byte[] metaData = new byte[metaLength]; read(metaData); MetaMessage metaMessage = new MetaMessage(); @@ -413,5 +424,4 @@ final class SMFParser { throw new EOFException("invalid MIDI file"); } } - } diff --git a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/Clipboard.java b/jdk/src/java.desktop/share/classes/java/awt/datatransfer/Clipboard.java index 210c700941e..6211692d5c9 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/Clipboard.java +++ b/jdk/src/java.desktop/share/classes/java/awt/datatransfer/Clipboard.java @@ -25,7 +25,7 @@ package java.awt.datatransfer; -import java.awt.EventQueue; +import sun.datatransfer.DataFlavorUtil; import java.util.Objects; import java.util.Set; @@ -130,7 +130,8 @@ public class Clipboard { this.contents = contents; if (oldOwner != null && oldOwner != owner) { - EventQueue.invokeLater(() -> oldOwner.lostOwnership(Clipboard.this, oldContents)); + DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> + oldOwner.lostOwnership(Clipboard.this, oldContents)); } fireFlavorsChanged(); } @@ -324,7 +325,7 @@ public class Clipboard { return; } flavorListeners.forEach(listener -> - EventQueue.invokeLater(() -> + DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> listener.flavorsChanged(new FlavorEvent(Clipboard.this)))); } diff --git a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/DataFlavor.java b/jdk/src/java.desktop/share/classes/java/awt/datatransfer/DataFlavor.java index 57132f2f53e..84b18fc332a 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/DataFlavor.java +++ b/jdk/src/java.desktop/share/classes/java/awt/datatransfer/DataFlavor.java @@ -25,7 +25,7 @@ package java.awt.datatransfer; -import sun.awt.datatransfer.DataTransferer; +import sun.datatransfer.DataFlavorUtil; import sun.reflect.misc.ReflectUtil; import java.io.ByteArrayInputStream; @@ -44,7 +44,6 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.Arrays; import java.util.Collections; -import java.util.Comparator; import java.util.Objects; import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; @@ -582,12 +581,12 @@ public class DataFlavor implements Externalizable, Cloneable { } else { params += representationClass.getName(); } - if (DataTransferer.isFlavorCharsetTextType(this) && + if (DataFlavorUtil.isFlavorCharsetTextType(this) && (isRepresentationClassInputStream() || isRepresentationClassByteBuffer() || byte[].class.equals(representationClass))) { - params += ";charset=" + DataTransferer.getTextCharset(this); + params += ";charset=" + DataFlavorUtil.getTextCharset(this); } return params; } @@ -609,13 +608,8 @@ public class DataFlavor implements Externalizable, Cloneable { * @since 1.3 */ public static final DataFlavor getTextPlainUnicodeFlavor() { - String encoding = null; - DataTransferer transferer = DataTransferer.getInstance(); - if (transferer != null) { - encoding = transferer.getDefaultUnicodeEncoding(); - } return new DataFlavor( - "text/plain;charset="+encoding + "text/plain;charset=" + DataFlavorUtil.getDesktopService().getDefaultUnicodeEncoding() +";class=java.io.InputStream", "Plain Text"); } @@ -741,12 +735,8 @@ public class DataFlavor implements Externalizable, Cloneable { return null; } - if (textFlavorComparator == null) { - textFlavorComparator = new TextFlavorComparator(); - } - DataFlavor bestFlavor = Collections.max(Arrays.asList(availableFlavors), - textFlavorComparator); + DataFlavorUtil.getTextFlavorComparator()); if (!bestFlavor.isFlavorTextType()) { return null; @@ -755,46 +745,6 @@ public class DataFlavor implements Externalizable, Cloneable { return bestFlavor; } - private static Comparator textFlavorComparator; - - static class TextFlavorComparator - extends DataTransferer.DataFlavorComparator { - - /** - * Compares two DataFlavor objects. Returns a negative - * integer, zero, or a positive integer as the first - * DataFlavor is worse than, equal to, or better than the - * second. - *

    - * DataFlavors are ordered according to the rules outlined - * for selectBestTextFlavor. - * - * @param flavor1 the first DataFlavor to be compared - * @param flavor2 the second DataFlavor to be compared - * @return a negative integer, zero, or a positive integer as the first - * argument is worse, equal to, or better than the second - * @throws ClassCastException if either of the arguments is not an - * instance of DataFlavor - * @throws NullPointerException if either of the arguments is - * null - * - * @see #selectBestTextFlavor - */ - public int compare(DataFlavor flavor1, DataFlavor flavor2) { - if (flavor1.isFlavorTextType()) { - if (flavor2.isFlavorTextType()) { - return super.compare(flavor1, flavor2); - } else { - return 1; - } - } else if (flavor2.isFlavorTextType()) { - return -1; - } else { - return 0; - } - } - } - /** * Gets a Reader for a text flavor, decoded, if necessary, for the expected * charset (encoding). The supported representation classes are @@ -1015,13 +965,13 @@ public class DataFlavor implements Externalizable, Cloneable { } if ("text".equals(getPrimaryType())) { - if (DataTransferer.doesSubtypeSupportCharset(this) + if (DataFlavorUtil.doesSubtypeSupportCharset(this) && representationClass != null && !isStandardTextRepresentationClass()) { String thisCharset = - DataTransferer.canonicalName(this.getParameter("charset")); + DataFlavorUtil.canonicalName(this.getParameter("charset")); String thatCharset = - DataTransferer.canonicalName(that.getParameter("charset")); + DataFlavorUtil.canonicalName(that.getParameter("charset")); if (!Objects.equals(thisCharset, thatCharset)) { return false; } @@ -1088,10 +1038,10 @@ public class DataFlavor implements Externalizable, Cloneable { // subTypes is '*', regardless of the other subType. if ("text".equals(primaryType)) { - if (DataTransferer.doesSubtypeSupportCharset(this) + if (DataFlavorUtil.doesSubtypeSupportCharset(this) && representationClass != null && !isStandardTextRepresentationClass()) { - String charset = DataTransferer.canonicalName(getParameter("charset")); + String charset = DataFlavorUtil.canonicalName(getParameter("charset")); if (charset != null) { total += charset.hashCode(); } @@ -1280,9 +1230,8 @@ public class DataFlavor implements Externalizable, Cloneable { * Returns true if the representation class is Remote. * @return true if the representation class is Remote */ - public boolean isRepresentationClassRemote() { - return DataTransferer.isRemote(representationClass); + return DataFlavorUtil.RMI.isRemote(representationClass); } /** @@ -1356,8 +1305,8 @@ public class DataFlavor implements Externalizable, Cloneable { * @since 1.4 */ public boolean isFlavorTextType() { - return (DataTransferer.isFlavorCharsetTextType(this) || - DataTransferer.isFlavorNoncharsetTextType(this)); + return (DataFlavorUtil.isFlavorCharsetTextType(this) || + DataFlavorUtil.isFlavorNoncharsetTextType(this)); } /** diff --git a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/SystemFlavorMap.java b/jdk/src/java.desktop/share/classes/java/awt/datatransfer/SystemFlavorMap.java index e799020110a..8bd47fe5f45 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/SystemFlavorMap.java +++ b/jdk/src/java.desktop/share/classes/java/awt/datatransfer/SystemFlavorMap.java @@ -25,22 +25,15 @@ package java.awt.datatransfer; -import java.awt.Toolkit; - -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.lang.ref.SoftReference; +import sun.datatransfer.DataFlavorUtil; +import sun.datatransfer.DesktopDatatransferService; import java.io.BufferedReader; -import java.io.File; -import java.io.InputStreamReader; import java.io.IOException; - -import java.net.URL; -import java.net.MalformedURLException; - +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.ref.SoftReference; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -48,12 +41,8 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Properties; import java.util.Set; -import sun.awt.AppContext; -import sun.awt.datatransfer.DataTransferer; - /** * The SystemFlavorMap is a configurable map between "natives" (Strings), which * correspond to platform-specific data formats, and "flavors" (DataFlavors), @@ -73,13 +62,6 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { private static final Object FLAVOR_MAP_KEY = new Object(); - /** - * Copied from java.util.Properties. - */ - private static final String keyValueSeparators = "=: \t\r\n\f"; - private static final String strictKeyValueSeparators = "=:"; - private static final String whiteSpaceChars = " \t\r\n\f"; - /** * The list of valid, decoded text flavor representation classes, in order * from best to worst. @@ -198,16 +180,11 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { /** * Returns the default FlavorMap for this thread's ClassLoader. + * * @return the default FlavorMap for this thread's ClassLoader */ public static FlavorMap getDefaultFlavorMap() { - AppContext context = AppContext.getAppContext(); - FlavorMap fm = (FlavorMap) context.get(FLAVOR_MAP_KEY); - if (fm == null) { - fm = new SystemFlavorMap(); - context.put(FLAVOR_MAP_KEY, fm); - } - return fm; + return DataFlavorUtil.getDesktopService().getFlavorMap(SystemFlavorMap::new); } private SystemFlavorMap() { @@ -223,7 +200,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { } isMapInitialized = true; - InputStream is = SystemFlavorMap.class.getResourceAsStream("/sun/awt/datatransfer/flavormap.properties"); + InputStream is = SystemFlavorMap.class.getResourceAsStream("/sun/datatransfer/resources/flavormap.properties"); if (is == null) { throw new InternalError("Default flavor mapping not found"); } @@ -238,22 +215,25 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { line = line.substring(0, line.length() - 1) + reader.readLine().trim(); } int delimiterPosition = line.indexOf('='); - String key = line.substring(0, delimiterPosition).replace("\\ ", " "); + String key = line.substring(0, delimiterPosition).replaceAll("\\ ", " "); String[] values = line.substring(delimiterPosition + 1, line.length()).split(","); for (String value : values) { try { + value = loadConvert(value); MimeType mime = new MimeType(value); if ("text".equals(mime.getPrimaryType())) { String charset = mime.getParameter("charset"); - if (DataTransferer.doesSubtypeSupportCharset(mime.getSubType(), charset)) + if (DataFlavorUtil.doesSubtypeSupportCharset(mime.getSubType(), charset)) { // We need to store the charset and eoln // parameters, if any, so that the // DataTransferer will have this information // for conversion into the native format. - DataTransferer transferer = DataTransferer.getInstance(); - if (transferer != null) { - transferer.registerTextFlavorProperties(key, charset, + DesktopDatatransferService desktopService = + DataFlavorUtil.getDesktopService(); + if (desktopService.isDesktopPresent()) { + desktopService.registerTextFlavorProperties( + key, charset, mime.getParameter("eoln"), mime.getParameter("terminators")); } @@ -305,6 +285,63 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { } } + // Copied from java.util.Properties + private static String loadConvert(String theString) { + char aChar; + int len = theString.length(); + StringBuilder outBuffer = new StringBuilder(len); + + for (int x = 0; x < len; ) { + aChar = theString.charAt(x++); + if (aChar == '\\') { + aChar = theString.charAt(x++); + if (aChar == 'u') { + // Read the xxxx + int value = 0; + for (int i = 0; i < 4; i++) { + aChar = theString.charAt(x++); + switch (aChar) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + value = (value << 4) + aChar - '0'; + break; + } + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': { + value = (value << 4) + 10 + aChar - 'a'; + break; + } + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': { + value = (value << 4) + 10 + aChar - 'A'; + break; + } + default: { + throw new IllegalArgumentException( + "Malformed \\uxxxx encoding."); + } + } + } + outBuffer.append((char)value); + } else { + if (aChar == 't') { + aChar = '\t'; + } else if (aChar == 'r') { + aChar = '\r'; + } else if (aChar == 'n') { + aChar = '\n'; + } else if (aChar == 'f') { + aChar = '\f'; + } + outBuffer.append(aChar); + } + } else { + outBuffer.append(aChar); + } + } + return outBuffer.toString(); + } + /** * Stores the listed object under the specified hash key in map. Unlike a * standard map, the listed object will not replace any object already at @@ -332,10 +369,10 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { LinkedHashSet flavors = getNativeToFlavor().get(nat); if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { - DataTransferer transferer = DataTransferer.getInstance(); - if (transferer != null) { + DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService(); + if (desktopService.isDesktopPresent()) { LinkedHashSet platformFlavors = - transferer.getPlatformMappingsForNative(nat); + desktopService.getPlatformMappingsForNative(nat); if (!platformFlavors.isEmpty()) { if (flavors != null) { // Prepending the platform-specific mappings ensures @@ -395,10 +432,10 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { LinkedHashSet natives = getFlavorToNative().get(flav); if (flav != null && !disabledMappingGenerationKeys.contains(flav)) { - DataTransferer transferer = DataTransferer.getInstance(); - if (transferer != null) { + DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService(); + if (desktopService.isDesktopPresent()) { LinkedHashSet platformNatives = - transferer.getPlatformMappingsForFlavor(flav); + desktopService.getPlatformMappingsForFlavor(flav); if (!platformNatives.isEmpty()) { if (natives != null) { // Prepend the platform-specific mappings to ensure @@ -474,7 +511,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { // In this case we shouldn't synthesize a native for this flavor, // since its mappings were explicitly specified. retval = flavorToNativeLookup(flav, false); - } else if (DataTransferer.isFlavorCharsetTextType(flav)) { + } else if (DataFlavorUtil.isFlavorCharsetTextType(flav)) { retval = new LinkedHashSet<>(0); // For text/* flavors, flavor-to-native mappings specified in @@ -502,7 +539,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { // addUnencodedNativeForFlavor(), so they have lower priority. retval.addAll(flavorToNativeLookup(flav, false)); } - } else if (DataTransferer.isFlavorNoncharsetTextType(flav)) { + } else if (DataFlavorUtil.isFlavorNoncharsetTextType(flav)) { retval = getTextTypeToNative().get(flav.mimeType.getBaseType()); if (retval == null || retval.isEmpty()) { @@ -602,7 +639,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { // on load from flavormap.properties. } - if (DataTransferer.doesSubtypeSupportCharset(subType, null)) { + if (DataFlavorUtil.doesSubtypeSupportCharset(subType, null)) { if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) { returnValue.add(DataFlavor.stringFlavor); @@ -624,7 +661,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { } } - for (String charset : DataTransferer.standardEncodings()) { + for (String charset : DataFlavorUtil.standardEncodings()) { for (String encodedTextClass : ENCODED_TEXT_CLASSES) { final String mimeType = diff --git a/jdk/src/java.desktop/share/classes/java/awt/font/TextLayout.java b/jdk/src/java.desktop/share/classes/java/awt/font/TextLayout.java index 45da5af89c6..f86779c161b 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/font/TextLayout.java +++ b/jdk/src/java.desktop/share/classes/java/awt/font/TextLayout.java @@ -1811,7 +1811,7 @@ public final class TextLayout implements Cloneable { * should be logical or visual counterparts. They are not * checked for validity. */ - private final TextHitInfo getStrongHit(TextHitInfo hit1, TextHitInfo hit2) { + private TextHitInfo getStrongHit(TextHitInfo hit1, TextHitInfo hit2) { // right now we're using the following rule for strong hits: // A hit on a character with a lower level diff --git a/jdk/src/java.desktop/share/classes/java/beans/PropertyChangeSupport.java b/jdk/src/java.desktop/share/classes/java/beans/PropertyChangeSupport.java index 40e58ae1e5d..532fdea1edc 100644 --- a/jdk/src/java.desktop/share/classes/java/beans/PropertyChangeSupport.java +++ b/jdk/src/java.desktop/share/classes/java/beans/PropertyChangeSupport.java @@ -544,7 +544,7 @@ public class PropertyChangeSupport implements Serializable { /** * {@inheritDoc} */ - public final PropertyChangeListener extract(PropertyChangeListener listener) { + public PropertyChangeListener extract(PropertyChangeListener listener) { while (listener instanceof PropertyChangeListenerProxy) { listener = ((PropertyChangeListenerProxy) listener).getListener(); } diff --git a/jdk/src/java.desktop/share/classes/java/beans/VetoableChangeSupport.java b/jdk/src/java.desktop/share/classes/java/beans/VetoableChangeSupport.java index 14902cc6276..6f211378991 100644 --- a/jdk/src/java.desktop/share/classes/java/beans/VetoableChangeSupport.java +++ b/jdk/src/java.desktop/share/classes/java/beans/VetoableChangeSupport.java @@ -533,7 +533,7 @@ public class VetoableChangeSupport implements Serializable { /** * {@inheritDoc} */ - public final VetoableChangeListener extract(VetoableChangeListener listener) { + public VetoableChangeListener extract(VetoableChangeListener listener) { while (listener instanceof VetoableChangeListenerProxy) { listener = ((VetoableChangeListenerProxy) listener).getListener(); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/ControllerEventListener.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/ControllerEventListener.java index c9666bc2df8..dba4e80c54d 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/ControllerEventListener.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/ControllerEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2002, 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 @@ -27,38 +27,35 @@ package javax.sound.midi; import java.util.EventListener; - /** - * The ControllerEventListener interface should be implemented - * by classes whose instances need to be notified when a Sequencer - * has processed a requested type of MIDI control-change event. - * To register a ControllerEventListener object to receive such - * notifications, invoke the + * The {@code ControllerEventListener} interface should be implemented by + * classes whose instances need to be notified when a {@link Sequencer} has + * processed a requested type of MIDI control-change event. To register a + * {@code ControllerEventListener} object to receive such notifications, invoke + * the * {@link Sequencer#addControllerEventListener(ControllerEventListener, int[]) - * addControllerEventListener} method of Sequencer, - * specifying the types of MIDI controllers about which you are interested in - * getting control-change notifications. - * - * @see MidiChannel#controlChange(int, int) + * addControllerEventListener} method of {@code Sequencer}, specifying the types + * of MIDI controllers about which you are interested in getting control-change + * notifications. * * @author Kara Kytle + * @see MidiChannel#controlChange(int, int) */ public interface ControllerEventListener extends EventListener { /** - * Invoked when a Sequencer has encountered and processed - * a control-change event of interest to this listener. The event passed - * in is a ShortMessage whose first data byte indicates - * the controller number and whose second data byte is the value to which - * the controller was set. - * - * @param event the control-change event that the sequencer encountered in - * the sequence it is processing + * Invoked when a {@link Sequencer} has encountered and processed a + * control-change event of interest to this listener. The event passed in is + * a {@code ShortMessage} whose first data byte indicates the controller + * number and whose second data byte is the value to which the controller + * was set. * + * @param event the control-change event that the sequencer encountered in + * the sequence it is processing * @see Sequencer#addControllerEventListener(ControllerEventListener, int[]) * @see MidiChannel#controlChange(int, int) * @see ShortMessage#getData1 * @see ShortMessage#getData2 */ - public void controlChange(ShortMessage event); + void controlChange(ShortMessage event); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/Instrument.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/Instrument.java index 3255aeff033..8bda9676df2 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/Instrument.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/Instrument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2004, 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 @@ -25,49 +25,41 @@ package javax.sound.midi; -import java.net.URL; - - - /** - * An instrument is a sound-synthesis algorithm with certain parameter - * settings, usually designed to emulate a specific real-world - * musical instrument or to achieve a specific sort of sound effect. - * Instruments are typically stored in collections called soundbanks. - * Before the instrument can be used to play notes, it must first be loaded - * onto a synthesizer, and then it must be selected for use on - * one or more channels, via a program-change command. MIDI notes - * that are subsequently received on those channels will be played using + * An instrument is a sound-synthesis algorithm with certain parameter settings, + * usually designed to emulate a specific real-world musical instrument or to + * achieve a specific sort of sound effect. Instruments are typically stored in + * collections called soundbanks. Before the instrument can be used to play + * notes, it must first be loaded onto a synthesizer, and then it must be + * selected for use on one or more channels, via a program-change command. MIDI + * notes that are subsequently received on those channels will be played using * the sound of the selected instrument. * + * @author Kara Kytle * @see Soundbank * @see Soundbank#getInstruments * @see Patch * @see Synthesizer#loadInstrument(Instrument) * @see MidiChannel#programChange(int, int) - * @author Kara Kytle */ - public abstract class Instrument extends SoundbankResource { - /** - * Instrument patch + * Instrument patch. */ private final Patch patch; - /** - * Constructs a new MIDI instrument from the specified Patch. - * When a subsequent request is made to load the - * instrument, the sound bank will search its contents for this instrument's Patch, - * and the instrument will be loaded into the synthesizer at the - * bank and program location indicated by the Patch object. - * @param soundbank sound bank containing the instrument - * @param patch the patch of this instrument - * @param name the name of this instrument - * @param dataClass the class used to represent the sample's data. + * Constructs a new MIDI instrument from the specified {@code Patch}. When a + * subsequent request is made to load the instrument, the sound bank will + * search its contents for this instrument's {@code Patch}, and the + * instrument will be loaded into the synthesizer at the bank and program + * location indicated by the {@code Patch} object. * + * @param soundbank sound bank containing the instrument + * @param patch the patch of this instrument + * @param name the name of this instrument + * @param dataClass the class used to represent the sample's data * @see Synthesizer#loadInstrument(Instrument) */ protected Instrument(Soundbank soundbank, Patch patch, String name, Class dataClass) { @@ -76,10 +68,10 @@ public abstract class Instrument extends SoundbankResource { this.patch = patch; } - /** - * Obtains the Patch object that indicates the bank and program + * Obtains the {@code Patch} object that indicates the bank and program * numbers where this instrument is to be stored in the synthesizer. + * * @return this instrument's patch */ public Patch getPatch() { diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/InvalidMidiDataException.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/InvalidMidiDataException.java index ed20121fab8..28a75deefc4 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/InvalidMidiDataException.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/InvalidMidiDataException.java @@ -25,25 +25,25 @@ package javax.sound.midi; - /** - * An InvalidMidiDataException indicates that inappropriate MIDI - * data was encountered. This often means that the data is invalid in and of - * itself, from the perspective of the MIDI specification. An example would - * be an undefined status byte. However, the exception might simply - * mean that the data was invalid in the context it was used, or that - * the object to which the data was given was unable to parse or use it. - * For example, a file reader might not be able to parse a Type 2 MIDI file, even - * though that format is defined in the MIDI specification. + * An {@code InvalidMidiDataException} indicates that inappropriate MIDI data + * was encountered. This often means that the data is invalid in and of itself, + * from the perspective of the MIDI specification. An example would be an + * undefined status byte. However, the exception might simply mean that the data + * was invalid in the context it was used, or that the object to which the data + * was given was unable to parse or use it. For example, a file reader might not + * be able to parse a Type 2 MIDI file, even though that format is defined in + * the MIDI specification. * * @author Kara Kytle */ public class InvalidMidiDataException extends Exception { + private static final long serialVersionUID = 2780771756789932067L; /** - * Constructs an InvalidMidiDataException with - * null for its error detail message. + * Constructs an {@code InvalidMidiDataException} with {@code null} for its + * error detail message. */ public InvalidMidiDataException() { @@ -51,10 +51,10 @@ public class InvalidMidiDataException extends Exception { } /** - * Constructs an InvalidMidiDataException with the - * specified detail message. + * Constructs an {@code InvalidMidiDataException} with the specified detail + * message. * - * @param message the string to display as an error detail message + * @param message the string to display as an error detail message */ public InvalidMidiDataException(String message) { diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MetaEventListener.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MetaEventListener.java index 94fe3d8044f..6f431bf22c9 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MetaEventListener.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MetaEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2002, 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 @@ -27,24 +27,23 @@ package javax.sound.midi; import java.util.EventListener; - /** - * The MetaEventListener interface should be implemented - * by classes whose instances need to be notified when a {@link Sequencer} - * has processed a {@link MetaMessage}. - * To register a MetaEventListener object to receive such - * notifications, pass it as the argument to the - * {@link Sequencer#addMetaEventListener(MetaEventListener) addMetaEventListener} - * method of Sequencer. + * The {@code MetaEventListener} interface should be implemented by classes + * whose instances need to be notified when a {@link Sequencer} has processed a + * {@link MetaMessage}. To register a {@code MetaEventListener} object to + * receive such notifications, pass it as the argument to the + * {@link Sequencer#addMetaEventListener(MetaEventListener) + * addMetaEventListener} method of {@code Sequencer}. * * @author Kara Kytle */ public interface MetaEventListener extends EventListener { /** - * Invoked when a {@link Sequencer} has encountered and processed - * a MetaMessage in the {@link Sequence} it is processing. - * @param meta the meta-message that the sequencer encountered + * Invoked when a {@link Sequencer} has encountered and processed a + * {@code MetaMessage} in the {@code Sequence} it is processing. + * + * @param meta the meta-message that the sequencer encountered */ - public void meta(MetaMessage meta); + void meta(MetaMessage meta); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MetaMessage.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MetaMessage.java index 6378435acc7..2e73cc37ddf 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MetaMessage.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MetaMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -25,65 +25,54 @@ package javax.sound.midi; - /** - * A MetaMessage is a {@link MidiMessage} that is not meaningful to synthesizers, but - * that can be stored in a MIDI file and interpreted by a sequencer program. - * (See the discussion in the MidiMessage - * class description.) The Standard MIDI Files specification defines - * various types of meta-events, such as sequence number, lyric, cue point, - * and set tempo. There are also meta-events - * for such information as lyrics, copyrights, tempo indications, time and key - * signatures, markers, etc. For more information, see the Standard MIDI Files 1.0 - * specification, which is part of the Complete MIDI 1.0 Detailed Specification - * published by the MIDI Manufacturer's Association + * A {@code MetaMessage} is a {@link MidiMessage} that is not meaningful to + * synthesizers, but that can be stored in a MIDI file and interpreted by a + * sequencer program. (See the discussion in the {@code MidiMessage} class + * description.) The Standard MIDI Files specification defines various types of + * meta-events, such as sequence number, lyric, cue point, and set tempo. There + * are also meta-events for such information as lyrics, copyrights, tempo + * indications, time and key signatures, markers, etc. For more information, see + * the Standard MIDI Files 1.0 specification, which is part of the Complete MIDI + * 1.0 Detailed Specification published by the MIDI Manufacturer's Association * (http://www.midi.org). - * *

    - * When data is being transported using MIDI wire protocol, - * a {@link ShortMessage} with the status value 0xFF represents - * a system reset message. In MIDI files, this same status value denotes a MetaMessage. - * The types of meta-message are distinguished from each other by the first byte - * that follows the status byte 0xFF. The subsequent bytes are data - * bytes. As with system exclusive messages, there are an arbitrary number of - * data bytes, depending on the type of MetaMessage. - * - * @see MetaEventListener + * When data is being transported using MIDI wire protocol, a + * {@link ShortMessage} with the status value {@code 0xFF} represents a system + * reset message. In MIDI files, this same status value denotes a + * {@code MetaMessage}. The types of meta-message are distinguished from each + * other by the first byte that follows the status byte {@code 0xFF}. The + * subsequent bytes are data bytes. As with system exclusive messages, there are + * an arbitrary number of data bytes, depending on the type of + * {@code MetaMessage}. * * @author David Rivas * @author Kara Kytle + * @see MetaEventListener */ - public class MetaMessage extends MidiMessage { - - // Status byte defines - /** - * Status byte for MetaMessage (0xFF, or 255), which is used - * in MIDI files. It has the same value as SYSTEM_RESET, which - * is used in the real-time "MIDI wire" protocol. + * Status byte for {@code MetaMessage} (0xFF, or 255), which is used in MIDI + * files. It has the same value as SYSTEM_RESET, which is used in the + * real-time "MIDI wire" protocol. + * * @see MidiMessage#getStatus */ public static final int META = 0xFF; // 255 - // Instance variables - /** - * The length of the actual message in the data array. - * This is used to determine how many bytes of the data array - * is the message, and how many are the status byte, the - * type byte, and the variable-length-int describing the - * length of the message. + * The length of the actual message in the data array. This is used to + * determine how many bytes of the data array is the message, and how many + * are the status byte, the type byte, and the variable-length-int + * describing the length of the message. */ private int dataLength = 0; - /** - * Constructs a new MetaMessage. The contents of - * the message are not set here; use - * {@link #setMessage(int, byte[], int) setMessage} - * to set them subsequently. + * Constructs a new {@code MetaMessage}. The contents of the message are not + * set here; use {@link #setMessage(int, byte[], int) setMessage} to set + * them subsequently. */ public MetaMessage() { // Default meta message data: just the META status byte value @@ -91,17 +80,17 @@ public class MetaMessage extends MidiMessage { } /** - * Constructs a new {@code MetaMessage} and sets the message parameters. - * The contents of the message can be changed by using - * the {@code setMessage} method. + * Constructs a new {@code MetaMessage} and sets the message parameters. The + * contents of the message can be changed by using the {@code setMessage} + * method. * - * @param type meta-message type (must be less than 128) - * @param data the data bytes in the MIDI message - * @param length an amount of bytes in the {@code data} byte array; - * it should be non-negative and less than or equal to - * {@code data.length} - * @throws InvalidMidiDataException if the parameter values do not specify - * a valid MIDI meta message + * @param type meta-message type (must be less than 128) + * @param data the data bytes in the MIDI message + * @param length an amount of bytes in the {@code data} byte array; it + * should be non-negative and less than or equal to + * {@code data.length} + * @throws InvalidMidiDataException if the parameter values do not specify a + * valid MIDI meta message * @see #setMessage(int, byte[], int) * @see #getType() * @see #getData() @@ -113,12 +102,11 @@ public class MetaMessage extends MidiMessage { setMessage(type, data, length); // can throw InvalidMidiDataException } - /** - * Constructs a new MetaMessage. - * @param data an array of bytes containing the complete message. - * The message data may be changed using the setMessage - * method. + * Constructs a new {@code MetaMessage}. + * + * @param data an array of bytes containing the complete message. The + * message data may be changed using the {@code setMessage} method. * @see #setMessage */ protected MetaMessage(byte[] data) { @@ -133,24 +121,24 @@ public class MetaMessage extends MidiMessage { } } - /** - * Sets the message parameters for a MetaMessage. - * Since only one status byte value, 0xFF, is allowed for meta-messages, - * it does not need to be specified here. Calls to {@link MidiMessage#getStatus getStatus} return - * 0xFF for all meta-messages. + * Sets the message parameters for a {@code MetaMessage}. Since only one + * status byte value, {@code 0xFF}, is allowed for meta-messages, it does + * not need to be specified here. Calls to + * {@link MidiMessage#getStatus getStatus} return {@code 0xFF} for all + * meta-messages. *

    - * The type argument should be a valid value for the byte that - * follows the status byte in the MetaMessage. The data argument - * should contain all the subsequent bytes of the MetaMessage. In other words, - * the byte that specifies the type of MetaMessage is not considered a data byte. + * The {@code type} argument should be a valid value for the byte that + * follows the status byte in the {@code MetaMessage}. The {@code data} + * argument should contain all the subsequent bytes of the + * {@code MetaMessage}. In other words, the byte that specifies the type of + * {@code MetaMessage} is not considered a data byte. * - * @param type meta-message type (must be less than 128) - * @param data the data bytes in the MIDI message - * @param length the number of bytes in the data - * byte array - * @throws InvalidMidiDataException if the - * parameter values do not specify a valid MIDI meta message + * @param type meta-message type (must be less than 128) + * @param data the data bytes in the MIDI message + * @param length the number of bytes in the {@code data} byte array + * @throws InvalidMidiDataException if the parameter values do not specify a + * valid MIDI meta message */ public void setMessage(int type, byte[] data, int length) throws InvalidMidiDataException { @@ -172,10 +160,10 @@ public class MetaMessage extends MidiMessage { } } - /** - * Obtains the type of the MetaMessage. - * @return an integer representing the MetaMessage type + * Obtains the type of the {@code MetaMessage}. + * + * @return an integer representing the {@code MetaMessage} type */ public int getType() { if (length>=2) { @@ -184,16 +172,15 @@ public class MetaMessage extends MidiMessage { return 0; } - - /** - * Obtains a copy of the data for the meta message. The returned - * array of bytes does not include the status byte or the message - * length data. The length of the data for the meta message is - * the length of the array. Note that the length of the entire - * message includes the status byte and the meta message type - * byte, and therefore may be longer than the returned array. - * @return array containing the meta message data. + * Obtains a copy of the data for the meta message. The returned array of + * bytes does not include the status byte or the message length data. The + * length of the data for the meta message is the length of the array. Note + * that the length of the entire message includes the status byte and the + * meta message type byte, and therefore may be longer than the returned + * array. + * + * @return array containing the meta message data * @see MidiMessage#getLength */ public byte[] getData() { @@ -202,10 +189,10 @@ public class MetaMessage extends MidiMessage { return returnedArray; } - /** - * Creates a new object of the same class and with the same contents - * as this object. + * Creates a new object of the same class and with the same contents as this + * object. + * * @return a clone of this instance */ public Object clone() { @@ -240,5 +227,4 @@ public class MetaMessage extends MidiMessage { } data[off] = (byte) (value & mask); } - } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiChannel.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiChannel.java index e2f37676304..6db7055ec83 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiChannel.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiChannel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -25,513 +25,450 @@ package javax.sound.midi; - /** - * A MidiChannel object represents a single MIDI channel. - * Generally, each MidiChannel method processes a like-named MIDI - * "channel voice" or "channel mode" message as defined by the MIDI specification. However, - * MidiChannel adds some "get" methods that retrieve the value - * most recently set by one of the standard MIDI channel messages. Similarly, - * methods for per-channel solo and mute have been added. + * A {@code MidiChannel} object represents a single MIDI channel. Generally, + * each {@code MidiChannel} method processes a like-named MIDI "channel voice" + * or "channel mode" message as defined by the MIDI specification. However, + * {@code MidiChannel} adds some "get" methods that retrieve the value most + * recently set by one of the standard MIDI channel messages. Similarly, methods + * for per-channel solo and mute have been added. *

    - * A {@link Synthesizer} object has a collection - * of MidiChannels, usually one for each of the 16 channels - * prescribed by the MIDI 1.0 specification. The Synthesizer - * generates sound when its MidiChannels receive - * noteOn messages. + * A {@link Synthesizer} object has a collection of {@code MidiChannels}, + * usually one for each of the 16 channels prescribed by the MIDI 1.0 + * specification. The {@code Synthesizer} generates sound when its + * {@code MidiChannels} receive {@code noteOn} messages. *

    * See the MIDI 1.0 Specification for more information about the prescribed - * behavior of the MIDI channel messages, which are not exhaustively - * documented here. The specification is titled MIDI Reference: - * The Complete MIDI 1.0 Detailed Specification, and is published by - * the MIDI Manufacturer's Association ( - * http://www.midi.org). + * behavior of the MIDI channel messages, which are not exhaustively documented + * here. The specification is titled + * {@code MIDI Reference: The Complete MIDI 1.0 Detailed Specification}, and is + * published by the MIDI Manufacturer's Association + * (http://www.midi.org). *

    * MIDI was originally a protocol for reporting the gestures of a keyboard - * musician. This genesis is visible in the MidiChannel API, which + * musician. This genesis is visible in the {@code MidiChannel} API, which * preserves such MIDI concepts as key number, key velocity, and key pressure. * It should be understood that the MIDI data does not necessarily originate * with a keyboard player (the source could be a different kind of musician, or - * software). Some devices might generate constant values for velocity - * and pressure, regardless of how the note was performed. - * Also, the MIDI specification often leaves it up to the - * synthesizer to use the data in the way the implementor sees fit. For - * example, velocity data need not always be mapped to volume and/or brightness. - * - * @see Synthesizer#getChannels + * software). Some devices might generate constant values for velocity and + * pressure, regardless of how the note was performed. Also, the MIDI + * specification often leaves it up to the synthesizer to use the data in the + * way the implementor sees fit. For example, velocity data need not always be + * mapped to volume and/or brightness. * * @author David Rivas * @author Kara Kytle + * @see Synthesizer#getChannels */ - public interface MidiChannel { /** - * Starts the specified note sounding. The key-down velocity - * usually controls the note's volume and/or brightness. - * If velocity is zero, this method instead acts like - * {@link #noteOff(int)}, terminating the note. - * - * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) - * @param velocity the speed with which the key was depressed + * Starts the specified note sounding. The key-down velocity usually + * controls the note's volume and/or brightness. If {@code velocity} is + * zero, this method instead acts like {@link #noteOff(int)}, terminating + * the note. * + * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) + * @param velocity the speed with which the key was depressed * @see #noteOff(int, int) */ - public void noteOn(int noteNumber, int velocity); + void noteOn(int noteNumber, int velocity); /** - * Turns the specified note off. The key-up velocity, if not ignored, can - * be used to affect how quickly the note decays. - * In any case, the note might not die away instantaneously; its decay - * rate is determined by the internals of the Instrument. - * If the Hold Pedal (a controller; see - * {@link #controlChange(int, int) controlChange}) - * is down, the effect of this method is deferred until the pedal is - * released. - * - * - * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) - * @param velocity the speed with which the key was released + * Turns the specified note off. The key-up velocity, if not ignored, can be + * used to affect how quickly the note decays. In any case, the note might + * not die away instantaneously; its decay rate is determined by the + * internals of the {@code Instrument}. If the Hold Pedal (a controller; see + * {@link #controlChange(int, int) controlChange}) is down, the effect of + * this method is deferred until the pedal is released. * + * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) + * @param velocity the speed with which the key was released * @see #noteOff(int) * @see #noteOn * @see #allNotesOff * @see #allSoundOff */ - public void noteOff(int noteNumber, int velocity); + void noteOff(int noteNumber, int velocity); /** * Turns the specified note off. * - * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) - * + * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) * @see #noteOff(int, int) */ - public void noteOff(int noteNumber); + void noteOff(int noteNumber); /** - * Reacts to a change in the specified note's key pressure. - * Polyphonic key pressure - * allows a keyboard player to press multiple keys simultaneously, each - * with a different amount of pressure. The pressure, if not ignored, - * is typically used to vary such features as the volume, brightness, - * or vibrato of the note. - * - * It is possible that the underlying synthesizer - * does not support this MIDI message. In order - * to verify that setPolyPressure - * was successful, use getPolyPressure. - * - * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) - * @param pressure value for the specified key, from 0 to 127 (127 = - * maximum pressure) + * Reacts to a change in the specified note's key pressure. Polyphonic key + * pressure allows a keyboard player to press multiple keys simultaneously, + * each with a different amount of pressure. The pressure, if not ignored, + * is typically used to vary such features as the volume, brightness, or + * vibrato of the note. + *

    + * It is possible that the underlying synthesizer does not support this MIDI + * message. In order to verify that {@code setPolyPressure} was successful, + * use {@code getPolyPressure}. * + * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) + * @param pressure value for the specified key, from 0 to 127 + * (127 = maximum pressure) * @see #getPolyPressure(int) */ - public void setPolyPressure(int noteNumber, int pressure); + void setPolyPressure(int noteNumber, int pressure); /** * Obtains the pressure with which the specified key is being depressed. + *

    + * If the device does not support setting poly pressure, this method always + * returns 0. Calling {@code setPolyPressure} will have no effect then. * - * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) - * - * If the device does not support setting poly pressure, - * this method always returns 0. Calling - * setPolyPressure will have no effect then. - * + * @param noteNumber the MIDI note number, from 0 to 127 (60 = Middle C) * @return the amount of pressure for that note, from 0 to 127 - * (127 = maximum pressure) - * + * (127 = maximum pressure) * @see #setPolyPressure(int, int) */ - public int getPolyPressure(int noteNumber); + int getPolyPressure(int noteNumber); /** - * Reacts to a change in the keyboard pressure. Channel - * pressure indicates how hard the keyboard player is depressing - * the entire keyboard. This can be the maximum or - * average of the per-key pressure-sensor values, as set by - * setPolyPressure. More commonly, it is a measurement of - * a single sensor on a device that doesn't implement polyphonic key - * pressure. Pressure can be used to control various aspects of the sound, - * as described under {@link #setPolyPressure(int, int) setPolyPressure}. + * Reacts to a change in the keyboard pressure. Channel pressure indicates + * how hard the keyboard player is depressing the entire keyboard. This can + * be the maximum or average of the per-key pressure-sensor values, as set + * by {@code setPolyPressure}. More commonly, it is a measurement of a + * single sensor on a device that doesn't implement polyphonic key pressure. + * Pressure can be used to control various aspects of the sound, as + * described under {@link #setPolyPressure(int, int) setPolyPressure}. + *

    + * It is possible that the underlying synthesizer does not support this MIDI + * message. In order to verify that {@code setChannelPressure} was + * successful, use {@code getChannelPressure}. * - * It is possible that the underlying synthesizer - * does not support this MIDI message. In order - * to verify that setChannelPressure - * was successful, use getChannelPressure. - * - * @param pressure the pressure with which the keyboard is being depressed, - * from 0 to 127 (127 = maximum pressure) + * @param pressure the pressure with which the keyboard is being depressed, + * from 0 to 127 (127 = maximum pressure) * @see #setPolyPressure(int, int) * @see #getChannelPressure */ - public void setChannelPressure(int pressure); + void setChannelPressure(int pressure); /** * Obtains the channel's keyboard pressure. - * If the device does not support setting channel pressure, - * this method always returns 0. Calling - * setChannelPressure will have no effect then. - * - * @return the amount of pressure for that note, - * from 0 to 127 (127 = maximum pressure) + *

    + * If the device does not support setting channel pressure, this method + * always returns 0. Calling {@code setChannelPressure} will have no effect + * then. * + * @return the amount of pressure for that note, from 0 to 127 + * (127 = maximum pressure) * @see #setChannelPressure(int) */ - public int getChannelPressure(); + int getChannelPressure(); /** - * Reacts to a change in the specified controller's value. A controller - * is some control other than a keyboard key, such as a - * switch, slider, pedal, wheel, or breath-pressure sensor. - * The MIDI 1.0 Specification provides standard numbers for typical - * controllers on MIDI devices, and describes the intended effect - * for some of the controllers. - * The way in which an - * Instrument reacts to a controller change may be - * specific to the Instrument. + * Reacts to a change in the specified controller's value. A controller is + * some control other than a keyboard key, such as a switch, slider, pedal, + * wheel, or breath-pressure sensor. The MIDI 1.0 Specification provides + * standard numbers for typical controllers on MIDI devices, and describes + * the intended effect for some of the controllers. The way in which an + * {@code Instrument} reacts to a controller change may be specific to the + * {@code Instrument}. *

    - * The MIDI 1.0 Specification defines both 7-bit controllers - * and 14-bit controllers. Continuous controllers, such - * as wheels and sliders, typically have 14 bits (two MIDI bytes), - * while discrete controllers, such as switches, typically have 7 bits - * (one MIDI byte). Refer to the specification to see the - * expected resolution for each type of control. + * The MIDI 1.0 Specification defines both 7-bit controllers and 14-bit + * controllers. Continuous controllers, such as wheels and sliders, + * typically have 14 bits (two MIDI bytes), while discrete controllers, such + * as switches, typically have 7 bits (one MIDI byte). Refer to the + * specification to see the expected resolution for each type of control. *

    - * Controllers 64 through 95 (0x40 - 0x5F) allow 7-bit precision. - * The value of a 7-bit controller is set completely by the - * value argument. An additional set of controllers - * provide 14-bit precision by using two controller numbers, one - * for the most significant 7 bits and another for the least significant - * 7 bits. Controller numbers 0 through 31 (0x00 - 0x1F) control the - * most significant 7 bits of 14-bit controllers; controller numbers - * 32 through 63 (0x20 - 0x3F) control the least significant 7 bits of - * these controllers. For example, controller number 7 (0x07) controls - * the upper 7 bits of the channel volume controller, and controller - * number 39 (0x27) controls the lower 7 bits. - * The value of a 14-bit controller is determined - * by the interaction of the two halves. When the most significant 7 bits - * of a controller are set (using controller numbers 0 through 31), the - * lower 7 bits are automatically set to 0. The corresponding controller - * number for the lower 7 bits may then be used to further modulate the - * controller value. - * - * It is possible that the underlying synthesizer - * does not support a specific controller message. In order - * to verify that a call to controlChange - * was successful, use getController. - * - * @param controller the controller number (0 to 127; see the MIDI - * 1.0 Specification for the interpretation) - * @param value the value to which the specified controller is changed (0 to 127) + * Controllers 64 through 95 (0x40 - 0x5F) allow 7-bit precision. The value + * of a 7-bit controller is set completely by the {@code value} argument. An + * additional set of controllers provide 14-bit precision by using two + * controller numbers, one for the most significant 7 bits and another for + * the least significant 7 bits. Controller numbers 0 through 31 + * (0x00 - 0x1F) control the most significant 7 bits of 14-bit controllers; + * controller numbers 32 through 63 (0x20 - 0x3F) control the least + * significant 7 bits of these controllers. For example, controller number 7 + * (0x07) controls the upper 7 bits of the channel volume controller, and + * controller number 39 (0x27) controls the lower 7 bits. The value of a + * 14-bit controller is determined by the interaction of the two halves. + * When the most significant 7 bits of a controller are set (using + * controller numbers 0 through 31), the lower 7 bits are automatically set + * to 0. The corresponding controller number for the lower 7 bits may then + * be used to further modulate the controller value. + *

    + * It is possible that the underlying synthesizer does not support a + * specific controller message. In order to verify that a call to + * {@code controlChange} was successful, use {@code getController}. * + * @param controller the controller number (0 to 127; see the MIDI 1.0 + * Specification for the interpretation) + * @param value the value to which the specified controller is changed + * (0 to 127) * @see #getController(int) */ - public void controlChange(int controller, int value); + void controlChange(int controller, int value); /** - * Obtains the current value of the specified controller. The return - * value is represented with 7 bits. For 14-bit controllers, the MSB and - * LSB controller value needs to be obtained separately. For example, - * the 14-bit value of the volume controller can be calculated by - * multiplying the value of controller 7 (0x07, channel volume MSB) - * with 128 and adding the - * value of controller 39 (0x27, channel volume LSB). - * - * If the device does not support setting a specific controller, - * this method returns 0 for that controller. - * Calling controlChange will have no effect then. - * - * @param controller the number of the controller whose value is desired. - * The allowed range is 0-127; see the MIDI - * 1.0 Specification for the interpretation. + * Obtains the current value of the specified controller. The return value + * is represented with 7 bits. For 14-bit controllers, the MSB and LSB + * controller value needs to be obtained separately. For example, the 14-bit + * value of the volume controller can be calculated by multiplying the value + * of controller 7 (0x07, channel volume MSB) with 128 and adding the value + * of controller 39 (0x27, channel volume LSB). + *

    + * If the device does not support setting a specific controller, this method + * returns 0 for that controller. Calling {@code controlChange} will have no + * effect then. * + * @param controller the number of the controller whose value is desired. + * The allowed range is 0-127; see the MIDI 1.0 Specification for + * the interpretation. * @return the current value of the specified controller (0 to 127) - * * @see #controlChange(int, int) */ - public int getController(int controller); + int getController(int controller); /** - * Changes a program (patch). This selects a specific - * instrument from the currently selected bank of instruments. + * Changes a program (patch). This selects a specific instrument from the + * currently selected bank of instruments. *

    - * The MIDI specification does not - * dictate whether notes that are already sounding should switch - * to the new instrument (timbre) or continue with their original timbre - * until terminated by a note-off. + * The MIDI specification does not dictate whether notes that are already + * sounding should switch to the new instrument (timbre) or continue with + * their original timbre until terminated by a note-off. *

    - * The program number is zero-based (expressed from 0 to 127). - * Note that MIDI hardware displays and literature about MIDI - * typically use the range 1 to 128 instead. - * - * It is possible that the underlying synthesizer - * does not support a specific program. In order - * to verify that a call to programChange - * was successful, use getProgram. - * - * @param program the program number to switch to (0 to 127) + * The program number is zero-based (expressed from 0 to 127). Note that + * MIDI hardware displays and literature about MIDI typically use the range + * 1 to 128 instead. + *

    + * It is possible that the underlying synthesizer does not support a + * specific program. In order to verify that a call to {@code programChange} + * was successful, use {@code getProgram}. * + * @param program the program number to switch to (0 to 127) * @see #programChange(int, int) * @see #getProgram() */ - public void programChange(int program); + void programChange(int program); /** * Changes the program using bank and program (patch) numbers. - * - * It is possible that the underlying synthesizer - * does not support a specific bank, or program. In order - * to verify that a call to programChange - * was successful, use getProgram and - * getController. - * Since banks are changed by way of control changes, - * you can verify the current bank with the following - * statement: + *

    + * It is possible that the underlying synthesizer does not support a + * specific bank, or program. In order to verify that a call to + * {@code programChange} was successful, use {@code getProgram} and + * {@code getController}. Since banks are changed by way of control changes, + * you can verify the current bank with the following statement: *

    -     *   int bank = (getController(0) * 128)
    -     *              + getController(32);
    +     *   int bank = (getController(0) * 128) + getController(32);
          * 
    * - * @param bank the bank number to switch to (0 to 16383) - * @param program the program (patch) to use in the specified bank (0 to 127) + * @param bank the bank number to switch to (0 to 16383) + * @param program the program (patch) to use in the specified bank + * (0 to 127) * @see #programChange(int) * @see #getProgram() */ - public void programChange(int bank, int program); + void programChange(int bank, int program); /** * Obtains the current program number for this channel. + * * @return the program number of the currently selected patch * @see Patch#getProgram * @see Synthesizer#loadInstrument * @see #programChange(int) */ - public int getProgram(); + int getProgram(); /** - * Changes the pitch offset for all notes on this channel. - * This affects all currently sounding notes as well as subsequent ones. - * (For pitch bend to cease, the value needs to be reset to the - * center position.) - *

    The MIDI specification - * stipulates that pitch bend be a 14-bit value, where zero - * is maximum downward bend, 16383 is maximum upward bend, and - * 8192 is the center (no pitch bend). The actual - * amount of pitch change is not specified; it can be changed by - * a pitch-bend sensitivity setting. However, the General MIDI - * specification says that the default range should be two semitones - * up and down from center. - * - * It is possible that the underlying synthesizer - * does not support this MIDI message. In order - * to verify that setPitchBend - * was successful, use getPitchBend. - * - * @param bend the amount of pitch change, as a nonnegative 14-bit value - * (8192 = no bend) + * Changes the pitch offset for all notes on this channel. This affects all + * currently sounding notes as well as subsequent ones. (For pitch bend to + * cease, the value needs to be reset to the center position.) + *

    + * The MIDI specification stipulates that pitch bend be a 14-bit value, + * where zero is maximum downward bend, 16383 is maximum upward bend, and + * 8192 is the center (no pitch bend). The actual amount of pitch change is + * not specified; it can be changed by a pitch-bend sensitivity setting. + * However, the General MIDI specification says that the default range + * should be two semitones up and down from center. + *

    + * It is possible that the underlying synthesizer does not support this MIDI + * message. In order to verify that {@code setPitchBend} was successful, use + * {@code getPitchBend}. * + * @param bend the amount of pitch change, as a nonnegative 14-bit value + * (8192 = no bend) * @see #getPitchBend */ - public void setPitchBend(int bend); + void setPitchBend(int bend); /** - * Obtains the upward or downward pitch offset for this channel. - * If the device does not support setting pitch bend, - * this method always returns 8192. Calling - * setPitchBend will have no effect then. + * Obtains the upward or downward pitch offset for this channel. If the + * device does not support setting pitch bend, this method always returns + * 8192. Calling {@code setPitchBend} will have no effect then. * * @return bend amount, as a nonnegative 14-bit value (8192 = no bend) - * * @see #setPitchBend(int) */ - public int getPitchBend(); + int getPitchBend(); /** * Resets all the implemented controllers to their default values. * * @see #controlChange(int, int) */ - public void resetAllControllers(); + void resetAllControllers(); /** - * Turns off all notes that are currently sounding on this channel. - * The notes might not die away instantaneously; their decay - * rate is determined by the internals of the Instrument. - * If the Hold Pedal controller (see - * {@link #controlChange(int, int) controlChange}) - * is down, the effect of this method is deferred until the pedal is - * released. + * Turns off all notes that are currently sounding on this channel. The + * notes might not die away instantaneously; their decay rate is determined + * by the internals of the {@code Instrument}. If the Hold Pedal controller + * (see {@link #controlChange(int, int) controlChange}) is down, the effect + * of this method is deferred until the pedal is released. * * @see #allSoundOff * @see #noteOff(int) */ - public void allNotesOff(); + void allNotesOff(); /** * Immediately turns off all sounding notes on this channel, ignoring the * state of the Hold Pedal and the internal decay rate of the current - * Instrument. + * {@code Instrument}. * * @see #allNotesOff */ - public void allSoundOff(); + void allSoundOff(); /** - * Turns local control on or off. The default is for local control - * to be on. The "on" setting means that if a device is capable - * of both synthesizing sound and transmitting MIDI messages, - * it will synthesize sound in response to the note-on and - * note-off messages that it itself transmits. It will also respond - * to messages received from other transmitting devices. - * The "off" setting means that the synthesizer will ignore its - * own transmitted MIDI messages, but not those received from other devices. - * - * It is possible that the underlying synthesizer - * does not support local control. In order - * to verify that a call to localControl - * was successful, check the return value. - * - * @param on true to turn local control on, false - * to turn local control off - * @return the new local-control value, or false - * if local control is not supported - * - */ - public boolean localControl(boolean on); - - /** - * Turns mono mode on or off. In mono mode, the channel synthesizes - * only one note at a time. In poly mode (identical to mono mode off), - * the channel can synthesize multiple notes simultaneously. - * The default is mono off (poly mode on). + * Turns local control on or off. The default is for local control to be on. + * The "on" setting means that if a device is capable of both synthesizing + * sound and transmitting MIDI messages, it will synthesize sound in + * response to the note-on and note-off messages that it itself transmits. + * It will also respond to messages received from other transmitting + * devices. The "off" setting means that the synthesizer will ignore its own + * transmitted MIDI messages, but not those received from other devices. *

    - * "Mono" is short for the word "monophonic," which in this context - * is opposed to the word "polyphonic" and refers to a single synthesizer - * voice per MIDI channel. It - * has nothing to do with how many audio channels there might be - * (as in "monophonic" versus "stereophonic" recordings). + * It is possible that the underlying synthesizer does not support local + * control. In order to verify that a call to {@code localControl} was + * successful, check the return value. * - * It is possible that the underlying synthesizer - * does not support mono mode. In order - * to verify that a call to setMono - * was successful, use getMono. - * - * @param on true to turn mono mode on, false to - * turn it off (which means turning poly mode on). + * @param on {@code true} to turn local control on, {@code false} to turn + * local control off + * @return the new local-control value, or false if local control is not + * supported + */ + boolean localControl(boolean on); + + /** + * Turns mono mode on or off. In mono mode, the channel synthesizes only one + * note at a time. In poly mode (identical to mono mode off), the channel + * can synthesize multiple notes simultaneously. The default is mono off + * (poly mode on). + *

    + * "Mono" is short for the word "monophonic," which in this context is + * opposed to the word "polyphonic" and refers to a single synthesizer voice + * per MIDI channel. It has nothing to do with how many audio channels there + * might be (as in "monophonic" versus "stereophonic" recordings). + *

    + * It is possible that the underlying synthesizer does not support mono + * mode. In order to verify that a call to {@code setMono} was successful, + * use {@code getMono}. * + * @param on {@code true} to turn mono mode on, {@code false} to turn it + * off (which means turning poly mode on) * @see #getMono * @see VoiceStatus */ - public void setMono(boolean on); + void setMono(boolean on); /** - * Obtains the current mono/poly mode. - * Synthesizers that do not allow changing mono/poly mode - * will always return the same value, regardless - * of calls to setMono. - * @return true if mono mode is on, otherwise - * false (meaning poly mode is on). + * Obtains the current mono/poly mode. Synthesizers that do not allow + * changing mono/poly mode will always return the same value, regardless of + * calls to {@code setMono}. * + * @return {@code true} if mono mode is on, otherwise {@code false} (meaning + * poly mode is on) * @see #setMono(boolean) */ - public boolean getMono(); + boolean getMono(); /** - * Turns omni mode on or off. In omni mode, the channel responds - * to messages sent on all channels. When omni is off, the channel - * responds only to messages sent on its channel number. - * The default is omni off. - * - * It is possible that the underlying synthesizer - * does not support omni mode. In order - * to verify that setOmni - * was successful, use getOmni. - * - * @param on true to turn omni mode on, false to - * turn it off. + * Turns omni mode on or off. In omni mode, the channel responds to messages + * sent on all channels. When omni is off, the channel responds only to + * messages sent on its channel number. The default is omni off. + *

    + * It is possible that the underlying synthesizer does not support omni + * mode. In order to verify that {@code setOmni} was successful, use + * {@code getOmni}. * + * @param on {@code true} to turn omni mode on, {@code false} to turn it + * off * @see #getOmni * @see VoiceStatus */ - public void setOmni(boolean on); + void setOmni(boolean on); /** - * Obtains the current omni mode. - * Synthesizers that do not allow changing the omni mode - * will always return the same value, regardless - * of calls to setOmni. - * @return true if omni mode is on, otherwise - * false (meaning omni mode is off). + * Obtains the current omni mode. Synthesizers that do not allow changing + * the omni mode will always return the same value, regardless of calls to + * {@code setOmni}. * + * @return {@code true} if omni mode is on, otherwise {@code false} (meaning + * omni mode is off) * @see #setOmni(boolean) */ - public boolean getOmni(); + boolean getOmni(); /** - * Sets the mute state for this channel. A value of - * true means the channel is to be muted, false - * means the channel can sound (if other channels are not soloed). + * Sets the mute state for this channel. A value of {@code true} means the + * channel is to be muted, {@code false} means the channel can sound (if + * other channels are not soloed). *

    - * Unlike {@link #allSoundOff()}, this method - * applies to only a specific channel, not to all channels. Further, it - * silences not only currently sounding notes, but also subsequently - * received notes. - * - * It is possible that the underlying synthesizer - * does not support muting channels. In order - * to verify that a call to setMute - * was successful, use getMute. - * - * @param mute the new mute state + * Unlike {@link #allSoundOff()}, this method applies to only a specific + * channel, not to all channels. Further, it silences not only currently + * sounding notes, but also subsequently received notes. + *

    + * It is possible that the underlying synthesizer does not support muting + * channels. In order to verify that a call to {@code setMute} was + * successful, use {@code getMute}. * + * @param mute the new mute state * @see #getMute * @see #setSolo(boolean) */ - public void setMute(boolean mute); + void setMute(boolean mute); /** - * Obtains the current mute state for this channel. - * If the underlying synthesizer does not support - * muting this channel, this method always returns - * false. - * - * @return true the channel is muted, - * or false if not + * Obtains the current mute state for this channel. If the underlying + * synthesizer does not support muting this channel, this method always + * returns {@code false}. * + * @return {@code true} the channel is muted, or {@code false} if not * @see #setMute(boolean) */ - public boolean getMute(); + boolean getMute(); /** - * Sets the solo state for this channel. - * If solo is true only this channel - * and other soloed channels will sound. If solo - * is false then only other soloed channels will - * sound, unless no channels are soloed, in which case all - * unmuted channels will sound. + * Sets the solo state for this channel. If {@code solo} is {@code true} + * only this channel and other soloed channels will sound. If {@code solo} + * is {@code false} then only other soloed channels will sound, unless no + * channels are soloed, in which case all unmuted channels will sound. + *

    + * It is possible that the underlying synthesizer does not support solo + * channels. In order to verify that a call to {@code setSolo} was + * successful, use {@code getSolo}. * - * It is possible that the underlying synthesizer - * does not support solo channels. In order - * to verify that a call to setSolo - * was successful, use getSolo. - * - * @param soloState new solo state for the channel + * @param soloState new solo state for the channel * @see #getSolo() */ - public void setSolo(boolean soloState); + void setSolo(boolean soloState); /** - * Obtains the current solo state for this channel. - * If the underlying synthesizer does not support - * solo on this channel, this method always returns - * false. - * - * @return true the channel is solo, - * or false if not + * Obtains the current solo state for this channel. If the underlying + * synthesizer does not support solo on this channel, this method always + * returns {@code false}. * + * @return {@code true} the channel is solo, or {@code false} if not * @see #setSolo(boolean) */ - public boolean getSolo(); + boolean getSolo(); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDevice.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDevice.java index f53d4ff3e2f..43c82932f6a 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDevice.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDevice.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -27,64 +27,52 @@ package javax.sound.midi; import java.util.List; - /** - * MidiDevice is the base interface for all MIDI devices. - * Common devices include synthesizers, sequencers, MIDI input ports, and MIDI - * output ports. - * - *

    A MidiDevice can be a transmitter or a receiver of - * MIDI events, or both. Therefore, it can provide {@link Transmitter} - * or {@link Receiver} instances (or both). Typically, MIDI IN ports - * provide transmitters, MIDI OUT ports and synthesizers provide - * receivers. A Sequencer typically provides transmitters for playback - * and receivers for recording. - * - *

    A MidiDevice can be opened and closed explicitly as - * well as implicitly. Explicit opening is accomplished by calling - * {@link #open}, explicit closing is done by calling {@link - * #close} on the MidiDevice instance. - * If an application opens a MidiDevice - * explicitly, it has to close it explicitly to free system resources - * and enable the application to exit cleanly. Implicit opening is - * done by calling {@link javax.sound.midi.MidiSystem#getReceiver - * MidiSystem.getReceiver} and {@link - * javax.sound.midi.MidiSystem#getTransmitter - * MidiSystem.getTransmitter}. The MidiDevice used by - * MidiSystem.getReceiver and - * MidiSystem.getTransmitter is implementation-dependant - * unless the properties javax.sound.midi.Receiver - * and javax.sound.midi.Transmitter are used (see the - * description of properties to select default providers in - * {@link javax.sound.midi.MidiSystem}). A MidiDevice - * that was opened implicitly, is closed implicitly by closing the - * Receiver or Transmitter that resulted in - * opening it. If more than one implicitly opening - * Receiver or Transmitter were obtained by - * the application, the device is closed after the last - * Receiver or Transmitter has been - * closed. On the other hand, calling getReceiver or - * getTransmitter on the device instance directly does - * not open the device implicitly. Closing these - * Transmitters and Receivers does not close - * the device implicitly. To use a device with Receivers - * or Transmitters obtained this way, the device has to - * be opened and closed explicitly. - * - *

    If implicit and explicit opening and closing are mixed on the - * same MidiDevice instance, the following rules apply: +/** + * {@code MidiDevice} is the base interface for all MIDI devices. Common devices + * include synthesizers, sequencers, MIDI input ports, and MIDI output ports. + *

    + * A {@code MidiDevice} can be a transmitter or a receiver of MIDI events, or + * both. Therefore, it can provide {@link Transmitter} or {@link Receiver} + * instances (or both). Typically, MIDI IN ports provide transmitters, MIDI OUT + * ports and synthesizers provide receivers. A Sequencer typically provides + * transmitters for playback and receivers for recording. + *

    + * A {@code MidiDevice} can be opened and closed explicitly as well as + * implicitly. Explicit opening is accomplished by calling {@link #open}, + * explicit closing is done by calling {@link #close} on the {@code MidiDevice} + * instance. If an application opens a {@code MidiDevice} explicitly, it has to + * close it explicitly to free system resources and enable the application to + * exit cleanly. Implicit opening is done by calling + * {@link MidiSystem#getReceiver} and {@link MidiSystem#getTransmitter}. The + * {@code MidiDevice} used by {@code MidiSystem.getReceiver} and + * {@code MidiSystem.getTransmitter} is implementation-dependant unless the + * properties {@code javax.sound.midi.Receiver} and + * {@code javax.sound.midi.Transmitter} are used (see the description of + * properties to select default providers in {@link MidiSystem}). A + * {@code MidiDevice} that was opened implicitly, is closed implicitly by + * closing the {@code Receiver} or {@code Transmitter} that resulted in opening + * it. If more than one implicitly opening {@code Receiver} or + * {@code Transmitter} were obtained by the application, the device is closed + * after the last {@code Receiver} or {@code Transmitter} has been closed. On + * the other hand, calling {@code getReceiver} or {@code getTransmitter} on the + * device instance directly does not open the device implicitly. Closing these + * {@code Transmitter}s and {@code Receiver}s does not close the device + * implicitly. To use a device with {@code Receiver}s or {@code Transmitter}s + * obtained this way, the device has to be opened and closed explicitly. + *

    + * If implicit and explicit opening and closing are mixed on the same + * {@code MidiDevice} instance, the following rules apply: * *

      - *
    • After an explicit open (either before or after implicit - * opens), the device will not be closed by implicit closing. The only - * way to close an explicitly opened device is an explicit close.
    • - * - *
    • An explicit close always closes the device, even if it also has - * been opened implicitly. A subsequent implicit close has no further - * effect.
    • + *
    • After an explicit open (either before or after implicit opens), the + * device will not be closed by implicit closing. The only way to close an + * explicitly opened device is an explicit close.
    • + *
    • An explicit close always closes the device, even if it also has been + * opened implicitly. A subsequent implicit close has no further effect.
    • *
    * - * To detect if a MidiDevice represents a hardware MIDI port, the - * following programming technique can be used: + * To detect if a MidiDevice represents a hardware MIDI port, the following + * programming technique can be used: * *
    {@code
      * MidiDevice device = ...;
    @@ -95,193 +83,171 @@ import java.util.List;
      * }
    * *

    - * A MidiDevice includes a {@link MidiDevice.Info} object - * to provide manufacturer information and so on. + * A {@code MidiDevice} includes a {@link Info} object to provide manufacturer + * information and so on. * + * @author Kara Kytle + * @author Florian Bomers * @see Synthesizer * @see Sequencer * @see Receiver * @see Transmitter - * - * @author Kara Kytle - * @author Florian Bomers */ - public interface MidiDevice extends AutoCloseable { - /** * Obtains information about the device, including its Java class and - * Strings containing its name, vendor, and description. + * {@code Strings} containing its name, vendor, and description. * * @return device info */ - public Info getDeviceInfo(); - + Info getDeviceInfo(); /** - * Opens the device, indicating that it should now acquire any - * system resources it requires and become operational. - * - *

    An application opening a device explicitly with this call - * has to close the device by calling {@link #close}. This is - * necessary to release system resources and allow applications to - * exit cleanly. - * + * Opens the device, indicating that it should now acquire any system + * resources it requires and become operational. *

    - * Note that some devices, once closed, cannot be reopened. Attempts - * to reopen such a device will always result in a MidiUnavailableException. - * - * @throws MidiUnavailableException thrown if the device cannot be - * opened due to resource restrictions. - * @throws SecurityException thrown if the device cannot be - * opened due to security restrictions. + * An application opening a device explicitly with this call has to close + * the device by calling {@link #close}. This is necessary to release system + * resources and allow applications to exit cleanly. + *

    + * Note that some devices, once closed, cannot be reopened. Attempts to + * reopen such a device will always result in a MidiUnavailableException. * + * @throws MidiUnavailableException thrown if the device cannot be opened + * due to resource restrictions + * @throws SecurityException thrown if the device cannot be opened due to + * security restrictions * @see #close * @see #isOpen */ - public void open() throws MidiUnavailableException; - + void open() throws MidiUnavailableException; /** - * Closes the device, indicating that the device should now release - * any system resources it is using. - * - *

    All Receiver and Transmitter instances - * open from this device are closed. This includes instances retrieved - * via MidiSystem. + * Closes the device, indicating that the device should now release any + * system resources it is using. + *

    + * All {@code Receiver} and {@code Transmitter} instances open from this + * device are closed. This includes instances retrieved via + * {@code MidiSystem}. * * @see #open * @see #isOpen */ - public void close(); - + void close(); /** * Reports whether the device is open. * - * @return true if the device is open, otherwise - * false + * @return {@code true} if the device is open, otherwise {@code false} * @see #open * @see #close */ - public boolean isOpen(); - + boolean isOpen(); /** - * Obtains the current time-stamp of the device, in microseconds. - * If a device supports time-stamps, it should start counting at - * 0 when the device is opened and continue incrementing its - * time-stamp in microseconds until the device is closed. - * If it does not support time-stamps, it should always return - * -1. - * @return the current time-stamp of the device in microseconds, - * or -1 if time-stamping is not supported by the device. - */ - public long getMicrosecondPosition(); - - - /** - * Obtains the maximum number of MIDI IN connections available on this - * MIDI device for receiving MIDI data. - * @return maximum number of MIDI IN connections, - * or -1 if an unlimited number of connections is available. - */ - public int getMaxReceivers(); - - - /** - * Obtains the maximum number of MIDI OUT connections available on this - * MIDI device for transmitting MIDI data. - * @return maximum number of MIDI OUT connections, - * or -1 if an unlimited number of connections is available. - */ - public int getMaxTransmitters(); - - - /** - * Obtains a MIDI IN receiver through which the MIDI device may receive - * MIDI data. The returned receiver must be closed when the application - * has finished using it. + * Obtains the current time-stamp of the device, in microseconds. If a + * device supports time-stamps, it should start counting at 0 when the + * device is opened and continue incrementing its time-stamp in microseconds + * until the device is closed. If it does not support time-stamps, it should + * always return -1. * - *

    Usually the returned receiver implements - * the {@code MidiDeviceReceiver} interface. + * @return the current time-stamp of the device in microseconds, or -1 if + * time-stamping is not supported by the device + */ + long getMicrosecondPosition(); + + /** + * Obtains the maximum number of MIDI IN connections available on this MIDI + * device for receiving MIDI data. * - *

    Obtaining a Receiver with this method does not - * open the device. To be able to use the device, it has to be - * opened explicitly by calling {@link #open}. Also, closing the - * Receiver does not close the device. It has to be - * closed explicitly by calling {@link #close}. + * @return maximum number of MIDI IN connections, or -1 if an unlimited + * number of connections is available + */ + int getMaxReceivers(); + + /** + * Obtains the maximum number of MIDI OUT connections available on this MIDI + * device for transmitting MIDI data. * - * @return a receiver for the device. + * @return maximum number of MIDI OUT connections, or -1 if an unlimited + * number of connections is available + */ + int getMaxTransmitters(); + + /** + * Obtains a MIDI IN receiver through which the MIDI device may receive MIDI + * data. The returned receiver must be closed when the application has + * finished using it. + *

    + * Usually the returned receiver implements the {@code MidiDeviceReceiver} + * interface. + *

    + * Obtaining a {@code Receiver} with this method does not open the device. + * To be able to use the device, it has to be opened explicitly by calling + * {@link #open}. Also, closing the {@code Receiver} does not close the + * device. It has to be closed explicitly by calling {@link #close}. + * + * @return a receiver for the device * @throws MidiUnavailableException thrown if a receiver is not available - * due to resource restrictions + * due to resource restrictions * @see Receiver#close() */ - public Receiver getReceiver() throws MidiUnavailableException; - + Receiver getReceiver() throws MidiUnavailableException; /** - * Returns all currently active, non-closed receivers - * connected with this MidiDevice. - * A receiver can be removed - * from the device by closing it. - * - *

    Usually the returned receivers implement - * the {@code MidiDeviceReceiver} interface. + * Returns all currently active, non-closed receivers connected with this + * MidiDevice. A receiver can be removed from the device by closing it. + *

    + * Usually the returned receivers implement the {@code MidiDeviceReceiver} + * interface. * * @return an unmodifiable list of the open receivers * @since 1.5 */ List getReceivers(); - /** * Obtains a MIDI OUT connection from which the MIDI device will transmit - * MIDI data The returned transmitter must be closed when the application + * MIDI data. The returned transmitter must be closed when the application * has finished using it. + *

    + * Usually the returned transmitter implements the + * {@code MidiDeviceTransmitter} interface. + *

    + * Obtaining a {@code Transmitter} with this method does not open the + * device. To be able to use the device, it has to be opened explicitly by + * calling {@link #open}. Also, closing the {@code Transmitter} does not + * close the device. It has to be closed explicitly by calling + * {@link #close}. * - *

    Usually the returned transmitter implements - * the {@code MidiDeviceTransmitter} interface. - * - *

    Obtaining a Transmitter with this method does not - * open the device. To be able to use the device, it has to be - * opened explicitly by calling {@link #open}. Also, closing the - * Transmitter does not close the device. It has to be - * closed explicitly by calling {@link #close}. - * - * @return a MIDI OUT transmitter for the device. + * @return a MIDI OUT transmitter for the device * @throws MidiUnavailableException thrown if a transmitter is not available - * due to resource restrictions + * due to resource restrictions * @see Transmitter#close() */ - public Transmitter getTransmitter() throws MidiUnavailableException; - + Transmitter getTransmitter() throws MidiUnavailableException; /** - * Returns all currently active, non-closed transmitters - * connected with this MidiDevice. - * A transmitter can be removed - * from the device by closing it. - * - *

    Usually the returned transmitters implement - * the {@code MidiDeviceTransmitter} interface. + * Returns all currently active, non-closed transmitters connected with this + * MidiDevice. A transmitter can be removed from the device by closing it. + *

    + * Usually the returned transmitters implement the + * {@code MidiDeviceTransmitter} interface. * * @return an unmodifiable list of the open transmitters * @since 1.5 */ List getTransmitters(); - - /** - * A MidiDevice.Info object contains assorted - * data about a {@link MidiDevice}, including its - * name, the company who created it, and descriptive text. + * A {@code MidiDevice.Info} object contains assorted data about a + * {@link MidiDevice}, including its name, the company who created it, and + * descriptive text. * * @see MidiDevice#getDeviceInfo */ - public static class Info { + class Info { /** * The device's name. @@ -303,16 +269,16 @@ public interface MidiDevice extends AutoCloseable { */ private String version; - /** * Constructs a device info object. * - * @param name the name of the device - * @param vendor the name of the company who provides the device - * @param description a description of the device - * @param version version information for the device + * @param name the name of the device + * @param vendor the name of the company who provides the device + * @param description a description of the device + * @param version version information for the device */ - protected Info(String name, String vendor, String description, String version) { + protected Info(String name, String vendor, String description, + String version) { this.name = name; this.vendor = vendor; @@ -320,20 +286,18 @@ public interface MidiDevice extends AutoCloseable { this.version = version; } - /** - * Reports whether two objects are equal. - * Returns true if the objects are identical. - * @param obj the reference object with which to compare this - * object - * @return true if this object is the same as the - * obj argument; false otherwise + * Reports whether two objects are equal. Returns {@code true} if the + * objects are identical. + * + * @param obj the reference object with which to compare this object + * @return {@code true} if this object is the same as the {@code obj} + * argument; {@code false} otherwise */ public final boolean equals(Object obj) { return super.equals(obj); } - /** * Finalizes the hashcode method. */ @@ -341,7 +305,6 @@ public interface MidiDevice extends AutoCloseable { return super.hashCode(); } - /** * Obtains the name of the device. * @@ -351,43 +314,40 @@ public interface MidiDevice extends AutoCloseable { return name; } - /** * Obtains the name of the company who supplies the device. + * * @return device the vendor's name */ public final String getVendor() { return vendor; } - /** * Obtains the description of the device. + * * @return a description of the device */ public final String getDescription() { return description; } - /** * Obtains the version of the device. + * * @return textual version information for the device. */ public final String getVersion() { return version; } - /** * Provides a string representation of the device information. - + * * @return a description of the info object */ public final String toString() { return name; } } // class Info - - } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDeviceReceiver.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDeviceReceiver.java index 550c7a4ccb8..569850836e1 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDeviceReceiver.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDeviceReceiver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -26,16 +26,18 @@ package javax.sound.midi; /** - *

    {@code MidiDeviceReceiver} is a {@code Receiver} which represents - * a MIDI input connector of a {@code MidiDevice} - * (see {@link MidiDevice#getReceiver()}). + * {@code MidiDeviceReceiver} is a {@code Receiver} which represents a MIDI + * input connector of a {@code MidiDevice} (see + * {@link MidiDevice#getReceiver()}). * * @since 1.7 */ public interface MidiDeviceReceiver extends Receiver { + /** * Obtains a MidiDevice object which is an owner of this Receiver. + * * @return a MidiDevice object which is an owner of this Receiver */ - public MidiDevice getMidiDevice(); + MidiDevice getMidiDevice(); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDeviceTransmitter.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDeviceTransmitter.java index 730628c5e8d..aaf7aba72d3 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDeviceTransmitter.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiDeviceTransmitter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -25,11 +25,10 @@ package javax.sound.midi; - /** - *

    {@code MidiDeviceTransmitter} is a {@code Transmitter} which represents - * a MIDI input connector of a {@code MidiDevice} - * (see {@link MidiDevice#getTransmitter()}). + * {@code MidiDeviceTransmitter} is a {@code Transmitter} which represents a + * MIDI input connector of a {@code MidiDevice} (see + * {@link MidiDevice#getTransmitter()}). * * @since 1.7 */ @@ -37,7 +36,8 @@ public interface MidiDeviceTransmitter extends Transmitter { /** * Obtains a MidiDevice object which is an owner of this Transmitter. + * * @return a MidiDevice object which is an owner of this Transmitter */ - public MidiDevice getMidiDevice(); + MidiDevice getMidiDevice(); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiEvent.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiEvent.java index b5f4c5ca08d..caf6e7936ad 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiEvent.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2002, 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 @@ -26,41 +26,35 @@ package javax.sound.midi; /** - * MIDI events contain a MIDI message and a corresponding time-stamp - * expressed in ticks, and can represent the MIDI event information - * stored in a MIDI file or a {@link Sequence} object. The - * duration of a tick is specified by the timing information contained - * in the MIDI file or Sequence object. + * MIDI events contain a MIDI message and a corresponding time-stamp expressed + * in ticks, and can represent the MIDI event information stored in a MIDI file + * or a {@link Sequence} object. The duration of a tick is specified by the + * timing information contained in the MIDI file or {@code Sequence} object. *

    - * In Java Sound, MidiEvent objects are typically contained in a - * {@link Track}, and Tracks are likewise - * contained in a Sequence. - * + * In Java Sound, {@code MidiEvent} objects are typically contained in a + * {@link Track}, and {@code Tracks} are likewise contained in a + * {@code Sequence}. * * @author David Rivas * @author Kara Kytle */ public class MidiEvent { - - // Instance variables - /** * The MIDI message for this event. */ private final MidiMessage message; - /** * The tick value for this event. */ private long tick; - /** - * Constructs a new MidiEvent. - * @param message the MIDI message contained in the event - * @param tick the time-stamp for the event, in MIDI ticks + * Constructs a new {@code MidiEvent}. + * + * @param message the MIDI message contained in the event + * @param tick the time-stamp for the event, in MIDI ticks */ public MidiEvent(MidiMessage message, long tick) { @@ -70,24 +64,25 @@ public class MidiEvent { /** * Obtains the MIDI message contained in the event. + * * @return the MIDI message */ public MidiMessage getMessage() { return message; } - /** - * Sets the time-stamp for the event, in MIDI ticks - * @param tick the new time-stamp, in MIDI ticks + * Sets the time-stamp for the event, in MIDI ticks. + * + * @param tick the new time-stamp, in MIDI ticks */ public void setTick(long tick) { this.tick = tick; } - /** - * Obtains the time-stamp for the event, in MIDI ticks + * Obtains the time-stamp for the event, in MIDI ticks. + * * @return the time-stamp for the event, in MIDI ticks */ public long getTick() { diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiFileFormat.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiFileFormat.java index c34bb6d1900..474881571c4 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiFileFormat.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiFileFormat.java @@ -25,29 +25,23 @@ package javax.sound.midi; -import java.io.InputStream; -import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; - /** - * A MidiFileFormat object encapsulates a MIDI file's - * type, as well as its length and timing information. - * - *

    A MidiFileFormat object can - * include a set of properties. A property is a pair of key and value: - * the key is of type String, the associated property - * value is an arbitrary object. - * Properties specify additional informational - * meta data (like a author, or copyright). - * Properties are optional information, and file reader and file - * writer implementations are not required to provide or - * recognize properties. - * - *

    The following table lists some common properties that should - * be used in implementations: + * A {@code MidiFileFormat} object encapsulates a MIDI file's type, as well as + * its length and timing information. + *

    + * A {@code MidiFileFormat} object can include a set of properties. A property + * is a pair of key and value: the key is of type {@code String}, the associated + * property value is an arbitrary object. Properties specify additional + * informational meta data (like a author, or copyright). Properties are + * optional information, and file reader and file writer implementations are not + * required to provide or recognize properties. + *

    + * The following table lists some common properties that should be used in + * implementations: * * @@ -83,24 +77,21 @@ import java.util.Map; * *
    MIDI File Format Properties
    * - * @see MidiSystem#getMidiFileFormat(java.io.File) - * @see Sequencer#setSequence(java.io.InputStream stream) - * * @author Kara Kytle * @author Florian Bomers + * @see MidiSystem#getMidiFileFormat(java.io.File) + * @see Sequencer#setSequence(java.io.InputStream stream) */ - public class MidiFileFormat { - /** * Represents unknown length. + * * @see #getByteLength * @see #getMicrosecondLength */ public static final int UNKNOWN_LENGTH = -1; - /** * The type of MIDI file. */ @@ -132,19 +123,22 @@ public class MidiFileFormat { */ protected long microsecondLength; - - /** The set of properties */ + /** + * The set of properties. + */ private HashMap properties; - /** - * Constructs a MidiFileFormat. + * Constructs a {@code MidiFileFormat}. * - * @param type the MIDI file type (0, 1, or 2) - * @param divisionType the timing division type (PPQ or one of the SMPTE types) - * @param resolution the timing resolution - * @param bytes the length of the MIDI file in bytes, or UNKNOWN_LENGTH if not known - * @param microseconds the duration of the file in microseconds, or UNKNOWN_LENGTH if not known + * @param type the MIDI file type (0, 1, or 2) + * @param divisionType the timing division type (PPQ or one of the SMPTE + * types) + * @param resolution the timing resolution + * @param bytes the length of the MIDI file in bytes, or UNKNOWN_LENGTH if + * not known + * @param microseconds the duration of the file in microseconds, or + * UNKNOWN_LENGTH if not known * @see #UNKNOWN_LENGTH * @see Sequence#PPQ * @see Sequence#SMPTE_24 @@ -162,21 +156,18 @@ public class MidiFileFormat { this.properties = null; } - /** - * Construct a MidiFileFormat with a set of properties. - * - * @param type the MIDI file type (0, 1, or 2) - * @param divisionType the timing division type - * (PPQ or one of the SMPTE types) - * @param resolution the timing resolution - * @param bytes the length of the MIDI file in bytes, - * or UNKNOWN_LENGTH if not known - * @param microseconds the duration of the file in microseconds, - * or UNKNOWN_LENGTH if not known - * @param properties a Map<String,Object> object - * with properties + * Construct a {@code MidiFileFormat} with a set of properties. * + * @param type the MIDI file type (0, 1, or 2) + * @param divisionType the timing division type (PPQ or one of the SMPTE + * types) + * @param resolution the timing resolution + * @param bytes the length of the MIDI file in bytes, or UNKNOWN_LENGTH if + * not known + * @param microseconds the duration of the file in microseconds, or + * UNKNOWN_LENGTH if not known + * @param properties a {@code Map} object with properties * @see #UNKNOWN_LENGTH * @see Sequence#PPQ * @see Sequence#SMPTE_24 @@ -192,10 +183,9 @@ public class MidiFileFormat { this.properties = new HashMap(properties); } - - /** * Obtains the MIDI file type. + * * @return the file's type (0, 1, or 2) */ public int getType() { @@ -206,7 +196,6 @@ public class MidiFileFormat { * Obtains the timing division type for the MIDI file. * * @return the division type (PPQ or one of the SMPTE types) - * * @see Sequence#Sequence(float, int) * @see Sequence#PPQ * @see Sequence#SMPTE_24 @@ -219,11 +208,10 @@ public class MidiFileFormat { return divisionType; } - /** - * Obtains the timing resolution for the MIDI file. - * If the division type is PPQ, the resolution is specified in ticks per beat. - * For SMTPE timing, the resolution is specified in ticks per frame. + * Obtains the timing resolution for the MIDI file. If the division type is + * PPQ, the resolution is specified in ticks per beat. For SMTPE timing, the + * resolution is specified in ticks per frame. * * @return the number of ticks per beat (PPQ) or per frame (SMPTE) * @see #getDivisionType @@ -233,9 +221,9 @@ public class MidiFileFormat { return resolution; } - /** * Obtains the length of the MIDI file, expressed in 8-bit bytes. + * * @return the number of bytes in the file, or UNKNOWN_LENGTH if not known * @see #UNKNOWN_LENGTH */ @@ -245,7 +233,9 @@ public class MidiFileFormat { /** * Obtains the length of the MIDI file, expressed in microseconds. - * @return the file's duration in microseconds, or UNKNOWN_LENGTH if not known + * + * @return the file's duration in microseconds, or UNKNOWN_LENGTH if not + * known * @see Sequence#getMicrosecondLength() * @see #getByteLength * @see #UNKNOWN_LENGTH @@ -255,14 +245,11 @@ public class MidiFileFormat { } /** - * Obtain an unmodifiable map of properties. - * The concept of properties is further explained in - * the {@link MidiFileFormat class description}. - * - * @return a Map<String,Object> object containing - * all properties. If no properties are recognized, an empty map is - * returned. + * Obtain an unmodifiable map of properties. The concept of properties is + * further explained in the {@link MidiFileFormat class description}. * + * @return a {@code Map} object containing all properties. If + * no properties are recognized, an empty map is returned. * @see #getProperty(String) * @since 1.5 */ @@ -277,20 +264,16 @@ public class MidiFileFormat { return Collections.unmodifiableMap(ret); } - /** - * Obtain the property value specified by the key. - * The concept of properties is further explained in - * the {@link MidiFileFormat class description}. - * - *

    If the specified property is not defined for a - * particular file format, this method returns - * null. - * - * @param key the key of the desired property - * @return the value of the property with the specified key, - * or null if the property does not exist. + * Obtain the property value specified by the key. The concept of properties + * is further explained in the {@link MidiFileFormat class description}. + *

    + * If the specified property is not defined for a particular file format, + * this method returns {@code null}. * + * @param key the key of the desired property + * @return the value of the property with the specified key, or {@code null} + * if the property does not exist * @see #properties() * @since 1.5 */ @@ -300,6 +283,4 @@ public class MidiFileFormat { } return properties.get(key); } - - } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiMessage.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiMessage.java index 728d654cea8..0633c32f72b 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiMessage.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -26,83 +26,76 @@ package javax.sound.midi; /** - * MidiMessage is the base class for MIDI messages. They include - * not only the standard MIDI messages that a synthesizer can respond to, but also - * "meta-events" that can be used by sequencer programs. There are meta-events + * {@code MidiMessage} is the base class for MIDI messages. They include not + * only the standard MIDI messages that a synthesizer can respond to, but also + * "meta-events" that can be used by sequencer programs. There are meta-events * for such information as lyrics, copyrights, tempo indications, time and key - * signatures, markers, etc. For more information, see the Standard MIDI Files 1.0 - * specification, which is part of the Complete MIDI 1.0 Detailed Specification - * published by the MIDI Manufacturer's Association + * signatures, markers, etc. For more information, see the Standard MIDI Files + * 1.0 specification, which is part of the Complete MIDI 1.0 Detailed + * Specification published by the MIDI Manufacturer's Association * (http://www.midi.org). *

    - * The base MidiMessage class provides access to three types of + * The base {@code MidiMessage} class provides access to three types of * information about a MIDI message: *

      *
    • The messages's status byte
    • - *
    • The total length of the message in bytes (the status byte plus any data bytes)
    • + *
    • The total length of the message in bytes (the status byte plus any data + * bytes)
    • *
    • A byte array containing the complete message
    • *
    * - * MidiMessage includes methods to get, but not set, these values. + * {@code MidiMessage} includes methods to get, but not set, these values. * Setting them is a subclass responsibility. *

    - * - * The MIDI standard expresses MIDI data in bytes. However, because - * JavaTM uses signed bytes, the Java Sound API uses integers - * instead of bytes when expressing MIDI data. For example, the - * {@link #getStatus()} method of - * MidiMessage returns MIDI status bytes as integers. If you are - * processing MIDI data that originated outside Java Sound and now - * is encoded as signed bytes, the bytes can - * can be converted to integers using this conversion: + * The MIDI standard expresses MIDI data in + * bytes. However, because JavaTM uses signed bytes, the Java Sound + * API uses integers instead of bytes when expressing MIDI data. For example, + * the {@link #getStatus()} method of {@code MidiMessage} returns MIDI status + * bytes as integers. If you are processing MIDI data that originated outside + * Java Sound and now is encoded as signed bytes, the bytes can can be + * converted to integers using this conversion: + * *

    {@code int i = (int)(byte & 0xFF)}
    *

    - * If you simply need to pass a known MIDI byte value as a method parameter, - * it can be expressed directly as an integer, using (for example) decimal or - * hexadecimal notation. For instance, to pass the "active sensing" status byte + * If you simply need to pass a known MIDI byte value as a method parameter, it + * can be expressed directly as an integer, using (for example) decimal or + * hexadecimal notation. For instance, to pass the "active sensing" status byte * as the first argument to ShortMessage's - * {@link ShortMessage#setMessage(int) setMessage(int)} - * method, you can express it as 254 or 0xFE. - * - * @see Track - * @see Sequence - * @see Receiver + * {@link ShortMessage#setMessage(int) setMessage(int)} method, you can express + * it as 254 or 0xFE. * * @author David Rivas * @author Kara Kytle + * @see Track + * @see Sequence + * @see Receiver */ - public abstract class MidiMessage implements Cloneable { - // Instance variables - /** - * The MIDI message data. The first byte is the status - * byte for the message; subsequent bytes up to the length - * of the message are data bytes for this message. + * The MIDI message data. The first byte is the status byte for the message; + * subsequent bytes up to the length of the message are data bytes for this + * message. + * * @see #getLength */ protected byte[] data; - /** - * The number of bytes in the MIDI message, including the - * status byte and any data bytes. + * The number of bytes in the MIDI message, including the status byte and + * any data bytes. + * * @see #getLength */ protected int length = 0; - /** - * Constructs a new MidiMessage. This protected - * constructor is called by concrete subclasses, which should - * ensure that the data array specifies a complete, valid MIDI - * message. - * - * @param data an array of bytes containing the complete message. - * The message data may be changed using the setMessage - * method. + * Constructs a new {@code MidiMessage}. This protected constructor is + * called by concrete subclasses, which should ensure that the data array + * specifies a complete, valid MIDI message. * + * @param data an array of bytes containing the complete message. The + * message data may be changed using the {@code setMessage} method. * @see #setMessage */ protected MidiMessage(byte[] data) { @@ -112,20 +105,21 @@ public abstract class MidiMessage implements Cloneable { } } - /** - * Sets the data for the MIDI message. This protected - * method is called by concrete subclasses, which should - * ensure that the data array specifies a complete, valid MIDI - * message. + * Sets the data for the MIDI message. This protected method is called by + * concrete subclasses, which should ensure that the data array specifies a + * complete, valid MIDI message. * - * @param data the data bytes in the MIDI message - * @param length the number of bytes in the data byte array - * @throws InvalidMidiDataException if the parameter values do not specify a valid MIDI meta message + * @param data the data bytes in the MIDI message + * @param length the number of bytes in the data byte array + * @throws InvalidMidiDataException if the parameter values do not specify a + * valid MIDI meta message */ - protected void setMessage(byte[] data, int length) throws InvalidMidiDataException { + protected void setMessage(byte[] data, int length) + throws InvalidMidiDataException { if (length < 0 || (length > 0 && length > data.length)) { - throw new IndexOutOfBoundsException("length out of bounds: "+length); + throw new IndexOutOfBoundsException( + "length out of bounds: " + length); } this.length = length; @@ -135,16 +129,14 @@ public abstract class MidiMessage implements Cloneable { System.arraycopy(data, 0, this.data, 0, length); } - /** - * Obtains the MIDI message data. The first byte of the returned byte - * array is the status byte of the message. Any subsequent bytes up to - * the length of the message are data bytes. The byte array may have a - * length which is greater than that of the actual message; the total - * length of the message in bytes is reported by the {@link #getLength} - * method. + * Obtains the MIDI message data. The first byte of the returned byte array + * is the status byte of the message. Any subsequent bytes up to the length + * of the message are data bytes. The byte array may have a length which is + * greater than that of the actual message; the total length of the message + * in bytes is reported by the {@link #getLength} method. * - * @return the byte array containing the complete MidiMessage data + * @return the byte array containing the complete {@code MidiMessage} data */ public byte[] getMessage() { byte[] returnedArray = new byte[length]; @@ -152,12 +144,11 @@ public abstract class MidiMessage implements Cloneable { return returnedArray; } - /** - * Obtains the status byte for the MIDI message. The status "byte" is + * Obtains the status byte for the MIDI message. The status "byte" is * represented as an integer; see the - * discussion in the - * MidiMessage class description. + * discussion in the {@code MidiMessage} + * class description. * * @return the integer representation of this event's status byte */ @@ -168,13 +159,11 @@ public abstract class MidiMessage implements Cloneable { return 0; } - /** - * Obtains the total length of the MIDI message in bytes. A - * MIDI message consists of one status byte and zero or more - * data bytes. The return value ranges from 1 for system real-time messages, - * to 2 or 3 for channel messages, to any value for meta and system - * exclusive messages. + * Obtains the total length of the MIDI message in bytes. A MIDI message + * consists of one status byte and zero or more data bytes. The return value + * ranges from 1 for system real-time messages, to 2 or 3 for channel + * messages, to any value for meta and system exclusive messages. * * @return the length of the message in bytes */ @@ -182,11 +171,11 @@ public abstract class MidiMessage implements Cloneable { return length; } - /** - * Creates a new object of the same class and with the same contents - * as this object. - * @return a clone of this instance. + * Creates a new object of the same class and with the same contents as this + * object. + * + * @return a clone of this instance */ public abstract Object clone(); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiSystem.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiSystem.java index 635dc54ce7a..9f790fd0f01 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiSystem.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiSystem.java @@ -25,59 +25,52 @@ package javax.sound.midi; -import java.io.FileInputStream; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.IOException; - +import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Properties; import java.util.Set; -import java.net.URL; - -import javax.sound.midi.spi.MidiFileWriter; -import javax.sound.midi.spi.MidiFileReader; -import javax.sound.midi.spi.SoundbankReader; import javax.sound.midi.spi.MidiDeviceProvider; +import javax.sound.midi.spi.MidiFileReader; +import javax.sound.midi.spi.MidiFileWriter; +import javax.sound.midi.spi.SoundbankReader; -import com.sun.media.sound.JDK13Services; -import com.sun.media.sound.ReferenceCountingDevice; import com.sun.media.sound.AutoConnectSequencer; +import com.sun.media.sound.JDK13Services; import com.sun.media.sound.MidiDeviceReceiverEnvelope; import com.sun.media.sound.MidiDeviceTransmitterEnvelope; - +import com.sun.media.sound.ReferenceCountingDevice; /** - * The MidiSystem class provides access to the installed MIDI - * system resources, including devices such as synthesizers, sequencers, and - * MIDI input and output ports. A typical simple MIDI application might - * begin by invoking one or more MidiSystem methods to learn - * what devices are installed and to obtain the ones needed in that - * application. + * The {@code MidiSystem} class provides access to the installed MIDI system + * resources, including devices such as synthesizers, sequencers, and MIDI input + * and output ports. A typical simple MIDI application might begin by invoking + * one or more {@code MidiSystem} methods to learn what devices are installed + * and to obtain the ones needed in that application. *

    - * The class also has methods for reading files, streams, and URLs that - * contain standard MIDI file data or soundbanks. You can query the - * MidiSystem for the format of a specified MIDI file. + * The class also has methods for reading files, streams, and URLs that contain + * standard MIDI file data or soundbanks. You can query the {@code MidiSystem} + * for the format of a specified MIDI file. *

    - * You cannot instantiate a MidiSystem; all the methods are - * static. - * - *

    Properties can be used to specify default MIDI devices. - * Both system properties and a properties file are considered. - * The sound.properties properties file is read from - * an implementation-specific location (typically it is the lib - * directory in the Java installation directory). - * If a property exists both as a system property and in the - * properties file, the system property takes precedence. If none is - * specified, a suitable default is chosen among the available devices. - * The syntax of the properties file is specified in - * {@link java.util.Properties#load(InputStream) Properties.load}. The - * following table lists the available property keys and which methods - * consider them: + * You cannot instantiate a {@code MidiSystem}; all the methods are static. + *

    + * Properties can be used to specify default MIDI devices. Both system + * properties and a properties file are considered. The "sound.properties" + * properties file is read from an implementation-specific location (typically + * it is the {@code lib} directory in the Java installation directory). If a + * property exists both as a system property and in the properties file, the + * system property takes precedence. If none is specified, a suitable default is + * chosen among the available devices. The syntax of the properties file is + * specified in {@link Properties#load(InputStream) Properties.load}. The + * following table lists the available property keys and which methods consider + * them: * * * @@ -87,80 +80,64 @@ import com.sun.media.sound.MidiDeviceTransmitterEnvelope; * * * - * + * * * * * - * + * * * * * - * + * * * * * - * + * * * * *
    MIDI System Property Keys
    Affected Method
    javax.sound.midi.Receiver{@code javax.sound.midi.Receiver}{@link Receiver}{@link #getReceiver}
    javax.sound.midi.Sequencer{@code javax.sound.midi.Sequencer}{@link Sequencer}{@link #getSequencer}
    javax.sound.midi.Synthesizer{@code javax.sound.midi.Synthesizer}{@link Synthesizer}{@link #getSynthesizer}
    javax.sound.midi.Transmitter{@code javax.sound.midi.Transmitter}{@link Transmitter}{@link #getTransmitter}
    * - * The property value consists of the provider class name - * and the device name, separated by the hash mark ("#"). - * The provider class name is the fully-qualified - * name of a concrete {@link javax.sound.midi.spi.MidiDeviceProvider - * MIDI device provider} class. The device name is matched against - * the String returned by the getName - * method of MidiDevice.Info. - * Either the class name, or the device name may be omitted. - * If only the class name is specified, the trailing hash mark - * is optional. - * - *

    If the provider class is specified, and it can be - * successfully retrieved from the installed providers, - * the list of - * MidiDevice.Info objects is retrieved - * from the provider. Otherwise, or when these devices - * do not provide a subsequent match, the list is retrieved - * from {@link #getMidiDeviceInfo} to contain - * all available MidiDevice.Info objects. - * - *

    If a device name is specified, the resulting list of - * MidiDevice.Info objects is searched: - * the first one with a matching name, and whose - * MidiDevice implements the - * respective interface, will be returned. - * If no matching MidiDevice.Info object - * is found, or the device name is not specified, - * the first suitable device from the resulting - * list will be returned. For Sequencer and Synthesizer, - * a device is suitable if it implements the respective - * interface; whereas for Receiver and Transmitter, a device is - * suitable if it - * implements neither Sequencer nor Synthesizer and provides - * at least one Receiver or Transmitter, respectively. - * - * For example, the property javax.sound.midi.Receiver - * with a value - * "com.sun.media.sound.MidiProvider#SunMIDI1" - * will have the following consequences when - * getReceiver is called: - * if the class com.sun.media.sound.MidiProvider exists - * in the list of installed MIDI device providers, - * the first Receiver device with name - * "SunMIDI1" will be returned. If it cannot - * be found, the first Receiver from that provider - * will be returned, regardless of name. - * If there is none, the first Receiver with name - * "SunMIDI1" in the list of all devices - * (as returned by getMidiDeviceInfo) will be returned, - * or, if not found, the first Receiver that can - * be found in the list of all devices is returned. - * If that fails, too, a MidiUnavailableException - * is thrown. + * The property value consists of the provider class name and the device name, + * separated by the hash mark ("#"). The provider class name is the + * fully-qualified name of a concrete + * {@link MidiDeviceProvider MIDI device provider} class. The device name is + * matched against the {@code String} returned by the {@code getName} method of + * {@code MidiDevice.Info}. Either the class name, or the device name may be + * omitted. If only the class name is specified, the trailing hash mark is + * optional. + *

    + * If the provider class is specified, and it can be successfully retrieved from + * the installed providers, the list of {@code MidiDevice.Info} objects is + * retrieved from the provider. Otherwise, or when these devices do not provide + * a subsequent match, the list is retrieved from {@link #getMidiDeviceInfo} to + * contain all available {@code MidiDevice.Info} objects. + *

    + * If a device name is specified, the resulting list of {@code MidiDevice.Info} + * objects is searched: the first one with a matching name, and whose + * {@code MidiDevice} implements the respective interface, will be returned. If + * no matching {@code MidiDevice.Info} object is found, or the device name is + * not specified, the first suitable device from the resulting list will be + * returned. For Sequencer and Synthesizer, a device is suitable if it + * implements the respective interface; whereas for Receiver and Transmitter, a + * device is suitable if it implements neither Sequencer nor Synthesizer and + * provides at least one Receiver or Transmitter, respectively. + *

    + * For example, the property {@code javax.sound.midi.Receiver} with a value + * {@code "com.sun.media.sound.MidiProvider#SunMIDI1"} will have the following + * consequences when {@code getReceiver} is called: if the class + * {@code com.sun.media.sound.MidiProvider} exists in the list of installed MIDI + * device providers, the first {@code Receiver} device with name + * {@code "SunMIDI1"} will be returned. If it cannot be found, the first + * {@code Receiver} from that provider will be returned, regardless of name. If + * there is none, the first {@code Receiver} with name {@code "SunMIDI1"} in the + * list of all devices (as returned by {@code getMidiDeviceInfo}) will be + * returned, or, if not found, the first {@code Receiver} that can be found in + * the list of all devices is returned. If that fails, too, a + * {@code MidiUnavailableException} is thrown. * * @author Kara Kytle * @author Florian Bomers @@ -174,17 +151,15 @@ public class MidiSystem { private MidiSystem() { } - /** - * Obtains an array of information objects representing - * the set of all MIDI devices available on the system. - * A returned information object can then be used to obtain the - * corresponding device object, by invoking + * Obtains an array of information objects representing the set of all MIDI + * devices available on the system. A returned information object can then + * be used to obtain the corresponding device object, by invoking * {@link #getMidiDevice(MidiDevice.Info) getMidiDevice}. * - * @return an array of MidiDevice.Info objects, one - * for each installed MIDI device. If no such devices are installed, - * an array of length 0 is returned. + * @return an array of {@code MidiDevice.Info} objects, one for each + * installed MIDI device. If no such devices are installed, an array + * of length 0 is returned. */ public static MidiDevice.Info[] getMidiDeviceInfo() { List allInfos = new ArrayList<>(); @@ -201,16 +176,15 @@ public class MidiSystem { return infosArray; } - /** * Obtains the requested MIDI device. * - * @param info a device information object representing the desired device. + * @param info a device information object representing the desired device * @return the requested device * @throws MidiUnavailableException if the requested device is not available - * due to resource restrictions - * @throws IllegalArgumentException if the info object does not represent - * a MIDI device installed on the system + * due to resource restrictions + * @throws IllegalArgumentException if the info object does not represent a + * MIDI device installed on the system * @see #getMidiDeviceInfo */ public static MidiDevice getMidiDevice(MidiDevice.Info info) throws MidiUnavailableException { @@ -226,44 +200,38 @@ public class MidiSystem { throw new IllegalArgumentException("Requested device not installed: " + info); } - /** - * Obtains a MIDI receiver from an external MIDI port - * or other default device. - * The returned receiver always implements - * the {@code MidiDeviceReceiver} interface. - * - *

    If the system property - * javax.sound.midi.Receiver - * is defined or it is defined in the file "sound.properties", - * it is used to identify the device that provides the default receiver. - * For details, refer to the {@link MidiSystem class description}. - * - * If a suitable MIDI port is not available, the Receiver is - * retrieved from an installed synthesizer. - * - *

    If a native receiver provided by the default device does not implement - * the {@code MidiDeviceReceiver} interface, it will be wrapped in a - * wrapper class that implements the {@code MidiDeviceReceiver} interface. - * The corresponding {@code Receiver} method calls will be forwarded - * to the native receiver. - * - *

    If this method returns successfully, the {@link - * javax.sound.midi.MidiDevice MidiDevice} the - * Receiver belongs to is opened implicitly, if it is - * not already open. It is possible to close an implicitly opened - * device by calling {@link javax.sound.midi.Receiver#close close} - * on the returned Receiver. All open Receiver - * instances have to be closed in order to release system resources - * hold by the MidiDevice. For a - * detailed description of open/close behaviour see the class - * description of {@link javax.sound.midi.MidiDevice MidiDevice}. - * + * Obtains a MIDI receiver from an external MIDI port or other default + * device. The returned receiver always implements the + * {@code MidiDeviceReceiver} interface. + *

    + * If the system property {@code javax.sound.midi.Receiver} is defined or it + * is defined in the file "sound.properties", it is used to identify the + * device that provides the default receiver. For details, refer to the + * {@link MidiSystem class description}. + *

    + * If a suitable MIDI port is not available, the Receiver is retrieved from + * an installed synthesizer. + *

    + * If a native receiver provided by the default device does not implement + * the {@code MidiDeviceReceiver} interface, it will be wrapped in a wrapper + * class that implements the {@code MidiDeviceReceiver} interface. The + * corresponding {@code Receiver} method calls will be forwarded to the + * native receiver. + *

    + * If this method returns successfully, the {@link MidiDevice MidiDevice} + * the {@code Receiver} belongs to is opened implicitly, if it is not + * already open. It is possible to close an implicitly opened device by + * calling {@link Receiver#close close} on the returned {@code Receiver}. + * All open {@code Receiver} instances have to be closed in order to release + * system resources hold by the {@code MidiDevice}. For a detailed + * description of open/close behaviour see the class description of + * {@link MidiDevice MidiDevice}. * * @return the default MIDI receiver - * @throws MidiUnavailableException if the default receiver is not - * available due to resource restrictions, - * or no device providing receivers is installed in the system + * @throws MidiUnavailableException if the default receiver is not available + * due to resource restrictions, or no device providing receivers is + * installed in the system */ public static Receiver getReceiver() throws MidiUnavailableException { // may throw MidiUnavailableException @@ -280,41 +248,35 @@ public class MidiSystem { return receiver; } - /** - * Obtains a MIDI transmitter from an external MIDI port - * or other default source. - * The returned transmitter always implements - * the {@code MidiDeviceTransmitter} interface. - * - *

    If the system property - * javax.sound.midi.Transmitter - * is defined or it is defined in the file "sound.properties", - * it is used to identify the device that provides the default transmitter. - * For details, refer to the {@link MidiSystem class description}. - * - *

    If a native transmitter provided by the default device does not implement + * Obtains a MIDI transmitter from an external MIDI port or other default + * source. The returned transmitter always implements the + * {@code MidiDeviceTransmitter} interface. + *

    + * If the system property {@code javax.sound.midi.Transmitter} is defined or + * it is defined in the file "sound.properties", it is used to identify the + * device that provides the default transmitter. For details, refer to the + * {@link MidiSystem class description}. + *

    + * If a native transmitter provided by the default device does not implement * the {@code MidiDeviceTransmitter} interface, it will be wrapped in a - * wrapper class that implements the {@code MidiDeviceTransmitter} interface. - * The corresponding {@code Transmitter} method calls will be forwarded - * to the native transmitter. - * - *

    If this method returns successfully, the {@link - * javax.sound.midi.MidiDevice MidiDevice} the - * Transmitter belongs to is opened implicitly, if it - * is not already open. It is possible to close an implicitly - * opened device by calling {@link - * javax.sound.midi.Transmitter#close close} on the returned - * Transmitter. All open Transmitter - * instances have to be closed in order to release system resources - * hold by the MidiDevice. For a detailed description - * of open/close behaviour see the class description of {@link - * javax.sound.midi.MidiDevice MidiDevice}. + * wrapper class that implements the {@code MidiDeviceTransmitter} + * interface. The corresponding {@code Transmitter} method calls will be + * forwarded to the native transmitter. + *

    + * If this method returns successfully, the {@link MidiDevice MidiDevice} + * the {@code Transmitter} belongs to is opened implicitly, if it is not + * already open. It is possible to close an implicitly opened device by + * calling {@link Transmitter#close close} on the returned + * {@code Transmitter}. All open {@code Transmitter} instances have to be + * closed in order to release system resources hold by the + * {@code MidiDevice}. For a detailed description of open/close behaviour + * see the class description of {@link MidiDevice MidiDevice}. * * @return the default MIDI transmitter * @throws MidiUnavailableException if the default transmitter is not - * available due to resource restrictions, - * or no device providing transmitters is installed in the system + * available due to resource restrictions, or no device providing + * transmitters is installed in the system */ public static Transmitter getTransmitter() throws MidiUnavailableException { // may throw MidiUnavailableException @@ -331,59 +293,48 @@ public class MidiSystem { return transmitter; } - /** * Obtains the default synthesizer. - * - *

    If the system property - * javax.sound.midi.Synthesizer - * is defined or it is defined in the file "sound.properties", - * it is used to identify the default synthesizer. - * For details, refer to the {@link MidiSystem class description}. + *

    + * If the system property {@code javax.sound.midi.Synthesizer} is defined or + * it is defined in the file "sound.properties", it is used to identify the + * default synthesizer. For details, refer to the + * {@link MidiSystem class description}. * * @return the default synthesizer - * @throws MidiUnavailableException if the synthesizer is not - * available due to resource restrictions, - * or no synthesizer is installed in the system + * @throws MidiUnavailableException if the synthesizer is not available due + * to resource restrictions, or no synthesizer is installed in the + * system */ public static Synthesizer getSynthesizer() throws MidiUnavailableException { // may throw MidiUnavailableException return (Synthesizer) getDefaultDeviceWrapper(Synthesizer.class); } - /** - * Obtains the default Sequencer, connected to - * a default device. - * The returned Sequencer instance is - * connected to the default Synthesizer, - * as returned by {@link #getSynthesizer}. - * If there is no Synthesizer - * available, or the default Synthesizer - * cannot be opened, the sequencer is connected - * to the default Receiver, as returned - * by {@link #getReceiver}. - * The connection is made by retrieving a Transmitter - * instance from the Sequencer and setting its - * Receiver. - * Closing and re-opening the sequencer will restore the - * connection to the default device. - * - *

    This method is equivalent to calling - * getSequencer(true). - * - *

    If the system property - * javax.sound.midi.Sequencer - * is defined or it is defined in the file "sound.properties", - * it is used to identify the default sequencer. - * For details, refer to the {@link MidiSystem class description}. + * Obtains the default {@code Sequencer}, connected to a default device. The + * returned {@code Sequencer} instance is connected to the default + * {@code Synthesizer}, as returned by {@link #getSynthesizer}. If there is + * no {@code Synthesizer} available, or the default {@code Synthesizer} + * cannot be opened, the {@code sequencer} is connected to the default + * {@code Receiver}, as returned by {@link #getReceiver}. The connection is + * made by retrieving a {@code Transmitter} instance from the + * {@code Sequencer} and setting its {@code Receiver}. Closing and + * re-opening the sequencer will restore the connection to the default + * device. + *

    + * This method is equivalent to calling {@code getSequencer(true)}. + *

    + * If the system property {@code javax.sound.midi.Sequencer} is defined or + * it is defined in the file "sound.properties", it is used to identify the + * default sequencer. For details, refer to the + * {@link MidiSystem class description}. * * @return the default sequencer, connected to a default Receiver - * @throws MidiUnavailableException if the sequencer is not - * available due to resource restrictions, - * or there is no Receiver available by any - * installed MidiDevice, - * or no sequencer is installed in the system. + * @throws MidiUnavailableException if the sequencer is not available due to + * resource restrictions, or there is no {@code Receiver} available + * by any installed {@code MidiDevice}, or no sequencer is installed + * in the system * @see #getSequencer(boolean) * @see #getSynthesizer * @see #getReceiver @@ -392,49 +343,37 @@ public class MidiSystem { return getSequencer(true); } - - /** - * Obtains the default Sequencer, optionally - * connected to a default device. - * - *

    If connected is true, the returned - * Sequencer instance is - * connected to the default Synthesizer, - * as returned by {@link #getSynthesizer}. - * If there is no Synthesizer - * available, or the default Synthesizer - * cannot be opened, the sequencer is connected - * to the default Receiver, as returned - * by {@link #getReceiver}. - * The connection is made by retrieving a Transmitter - * instance from the Sequencer and setting its - * Receiver. - * Closing and re-opening the sequencer will restore the + * Obtains the default {@code Sequencer}, optionally connected to a default + * device. + *

    + * If {@code connected} is true, the returned {@code Sequencer} instance is + * connected to the default {@code Synthesizer}, as returned by + * {@link #getSynthesizer}. If there is no {@code Synthesizer} available, or + * the default {@code Synthesizer} cannot be opened, the {@code sequencer} + * is connected to the default {@code Receiver}, as returned by + * {@link #getReceiver}. The connection is made by retrieving a + * {@code Transmitter} instance from the {@code Sequencer} and setting its + * {@code Receiver}. Closing and re-opening the sequencer will restore the * connection to the default device. + *

    + * If {@code connected} is false, the returned {@code Sequencer} instance is + * not connected, it has no open {@code Transmitters}. In order to play the + * sequencer on a MIDI device, or a {@code Synthesizer}, it is necessary to + * get a {@code Transmitter} and set its {@code Receiver}. + *

    + * If the system property {@code javax.sound.midi.Sequencer} is defined or + * it is defined in the file "sound.properties", it is used to identify the + * default sequencer. For details, refer to the + * {@link MidiSystem class description}. * - *

    If connected is false, the returned - * Sequencer instance is not connected, it - * has no open Transmitters. In order to - * play the sequencer on a MIDI device, or a Synthesizer, - * it is necessary to get a Transmitter and set its - * Receiver. - * - *

    If the system property - * javax.sound.midi.Sequencer - * is defined or it is defined in the file "sound.properties", - * it is used to identify the default sequencer. - * For details, refer to the {@link MidiSystem class description}. - * - * @param connected whether or not the returned {@code Sequencer} - * is connected to the default {@code Synthesizer} + * @param connected whether or not the returned {@code Sequencer} is + * connected to the default {@code Synthesizer} * @return the default sequencer - * @throws MidiUnavailableException if the sequencer is not - * available due to resource restrictions, - * or no sequencer is installed in the system, - * or if connected is true, and there is - * no Receiver available by any installed - * MidiDevice + * @throws MidiUnavailableException if the sequencer is not available due to + * resource restrictions, or no sequencer is installed in the + * system, or if {@code connected} is true, and there is no + * {@code Receiver} available by any installed {@code MidiDevice} * @see #getSynthesizer * @see #getReceiver * @since 1.5 @@ -501,23 +440,20 @@ public class MidiSystem { return seq; } - - - /** - * Constructs a MIDI sound bank by reading it from the specified stream. - * The stream must point to - * a valid MIDI soundbank file. In general, MIDI soundbank providers may - * need to read some data from the stream before determining whether they - * support it. These parsers must - * be able to mark the stream, read enough data to determine whether they - * support the stream, and, if not, reset the stream's read pointer to - * its original position. If the input stream does not support this, - * this method may fail with an IOException. - * @param stream the source of the sound bank data. + * Constructs a MIDI sound bank by reading it from the specified stream. The + * stream must point to a valid MIDI soundbank file. In general, MIDI + * soundbank providers may need to read some data from the stream before + * determining whether they support it. These parsers must be able to mark + * the stream, read enough data to determine whether they support the + * stream, and, if not, reset the stream's read pointer to its original + * position. If the input stream does not support this, this method may fail + * with an {@code IOException}. + * + * @param stream the source of the sound bank data * @return the sound bank - * @throws InvalidMidiDataException if the stream does not point to - * valid MIDI soundbank data recognized by the system + * @throws InvalidMidiDataException if the stream does not point to valid + * MIDI soundbank data recognized by the system * @throws IOException if an I/O error occurred when loading the soundbank * @see InputStream#markSupported * @see InputStream#mark @@ -542,15 +478,14 @@ public class MidiSystem { } - /** - * Constructs a Soundbank by reading it from the specified URL. - * The URL must point to a valid MIDI soundbank file. + * Constructs a {@code Soundbank} by reading it from the specified URL. The + * URL must point to a valid MIDI soundbank file. * - * @param url the source of the sound bank data + * @param url the source of the sound bank data * @return the sound bank * @throws InvalidMidiDataException if the URL does not point to valid MIDI - * soundbank data recognized by the system + * soundbank data recognized by the system * @throws IOException if an I/O error occurred when loading the soundbank */ public static Soundbank getSoundbank(URL url) @@ -573,16 +508,14 @@ public class MidiSystem { } - /** - * Constructs a Soundbank by reading it from the specified - * File. - * The File must point to a valid MIDI soundbank file. + * Constructs a {@code Soundbank} by reading it from the specified + * {@code File}. The {@code File} must point to a valid MIDI soundbank file. * - * @param file the source of the sound bank data + * @param file the source of the sound bank data * @return the sound bank - * @throws InvalidMidiDataException if the File does not - * point to valid MIDI soundbank data recognized by the system + * @throws InvalidMidiDataException if the {@code File} does not point to + * valid MIDI soundbank data recognized by the system * @throws IOException if an I/O error occurred when loading the soundbank */ public static Soundbank getSoundbank(File file) @@ -604,35 +537,33 @@ public class MidiSystem { throw new InvalidMidiDataException("cannot get soundbank from stream"); } - - /** * Obtains the MIDI file format of the data in the specified input stream. * The stream must point to valid MIDI file data for a file type recognized * by the system. *

    * This method and/or the code it invokes may need to read some data from - * the stream to determine whether its data format is supported. The - * implementation may therefore - * need to mark the stream, read enough data to determine whether it is in - * a supported format, and reset the stream's read pointer to its original - * position. If the input stream does not permit this set of operations, - * this method may fail with an IOException. + * the stream to determine whether its data format is supported. The + * implementation may therefore need to mark the stream, read enough data to + * determine whether it is in a supported format, and reset the stream's + * read pointer to its original position. If the input stream does not + * permit this set of operations, this method may fail with an + * {@code IOException}. *

    * This operation can only succeed for files of a type which can be parsed - * by an installed file reader. It may fail with an InvalidMidiDataException - * even for valid files if no compatible file reader is installed. It - * will also fail with an InvalidMidiDataException if a compatible file reader - * is installed, but encounters errors while determining the file format. + * by an installed file reader. It may fail with an + * {@code InvalidMidiDataException} even for valid files if no compatible + * file reader is installed. It will also fail with an + * {@code InvalidMidiDataException} if a compatible file reader is + * installed, but encounters errors while determining the file format. * - * @param stream the input stream from which file format information - * should be extracted - * @return an MidiFileFormat object describing the MIDI file - * format + * @param stream the input stream from which file format information should + * be extracted + * @return an {@code MidiFileFormat} object describing the MIDI file format * @throws InvalidMidiDataException if the stream does not point to valid - * MIDI file data recognized by the system + * MIDI file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the - * stream + * stream * @see #getMidiFileFormat(URL) * @see #getMidiFileFormat(File) * @see InputStream#markSupported @@ -661,26 +592,24 @@ public class MidiSystem { } } - /** - * Obtains the MIDI file format of the data in the specified URL. The URL - * must point to valid MIDI file data for a file type recognized - * by the system. + * Obtains the MIDI file format of the data in the specified URL. The URL + * must point to valid MIDI file data for a file type recognized by the + * system. *

    * This operation can only succeed for files of a type which can be parsed - * by an installed file reader. It may fail with an InvalidMidiDataException - * even for valid files if no compatible file reader is installed. It - * will also fail with an InvalidMidiDataException if a compatible file reader - * is installed, but encounters errors while determining the file format. + * by an installed file reader. It may fail with an + * {@code InvalidMidiDataException} even for valid files if no compatible + * file reader is installed. It will also fail with an + * {@code InvalidMidiDataException} if a compatible file reader is + * installed, but encounters errors while determining the file format. * - * @param url the URL from which file format information should be - * extracted - * @return a MidiFileFormat object describing the MIDI file - * format + * @param url the URL from which file format information should be + * extracted + * @return a {@code MidiFileFormat} object describing the MIDI file format * @throws InvalidMidiDataException if the URL does not point to valid MIDI - * file data recognized by the system + * file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the URL - * * @see #getMidiFileFormat(InputStream) * @see #getMidiFileFormat(File) */ @@ -707,26 +636,24 @@ public class MidiSystem { } } - /** - * Obtains the MIDI file format of the specified File. The - * File must point to valid MIDI file data for a file type + * Obtains the MIDI file format of the specified {@code File}. The + * {@code File} must point to valid MIDI file data for a file type * recognized by the system. *

    * This operation can only succeed for files of a type which can be parsed - * by an installed file reader. It may fail with an InvalidMidiDataException - * even for valid files if no compatible file reader is installed. It - * will also fail with an InvalidMidiDataException if a compatible file reader - * is installed, but encounters errors while determining the file format. + * by an installed file reader. It may fail with an + * {@code InvalidMidiDataException} even for valid files if no compatible + * file reader is installed. It will also fail with an + * {@code InvalidMidiDataException} if a compatible file reader is + * installed, but encounters errors while determining the file format. * - * @param file the File from which file format information - * should be extracted - * @return a MidiFileFormat object describing the MIDI file - * format - * @throws InvalidMidiDataException if the File does not point - * to valid MIDI file data recognized by the system + * @param file the {@code File} from which file format information should + * be extracted + * @return a {@code MidiFileFormat} object describing the MIDI file format + * @throws InvalidMidiDataException if the {@code File} does not point to + * valid MIDI file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the file - * * @see #getMidiFileFormat(InputStream) * @see #getMidiFileFormat(URL) */ @@ -753,35 +680,33 @@ public class MidiSystem { } } - /** - * Obtains a MIDI sequence from the specified input stream. The stream must - * point to valid MIDI file data for a file type recognized - * by the system. + * Obtains a MIDI sequence from the specified input stream. The stream must + * point to valid MIDI file data for a file type recognized by the system. *

    - * This method and/or the code it invokes may need to read some data - * from the stream to determine whether - * its data format is supported. The implementation may therefore - * need to mark the stream, read enough data to determine whether it is in - * a supported format, and reset the stream's read pointer to its original - * position. If the input stream does not permit this set of operations, - * this method may fail with an IOException. + * This method and/or the code it invokes may need to read some data from + * the stream to determine whether its data format is supported. The + * implementation may therefore need to mark the stream, read enough data to + * determine whether it is in a supported format, and reset the stream's + * read pointer to its original position. If the input stream does not + * permit this set of operations, this method may fail with an + * {@code IOException}. *

    * This operation can only succeed for files of a type which can be parsed - * by an installed file reader. It may fail with an InvalidMidiDataException - * even for valid files if no compatible file reader is installed. It - * will also fail with an InvalidMidiDataException if a compatible file reader - * is installed, but encounters errors while constructing the Sequence + * by an installed file reader. It may fail with an + * {@code InvalidMidiDataException} even for valid files if no compatible + * file reader is installed. It will also fail with an + * {@code InvalidMidiDataException} if a compatible file reader is + * installed, but encounters errors while constructing the {@code Sequence} * object from the file data. * - * @param stream the input stream from which the Sequence - * should be constructed - * @return a Sequence object based on the MIDI file data - * contained in the input stream - * @throws InvalidMidiDataException if the stream does not point to - * valid MIDI file data recognized by the system - * @throws IOException if an I/O exception occurs while accessing the - * stream + * @param stream the input stream from which the {@code Sequence} should be + * constructed + * @return a {@code Sequence} object based on the MIDI file data contained + * in the input stream + * @throws InvalidMidiDataException if the stream does not point to valid + * MIDI file data recognized by the system + * @throws IOException if an I/O exception occurs while accessing the stream * @see InputStream#markSupported * @see InputStream#mark */ @@ -808,25 +733,23 @@ public class MidiSystem { } } - /** - * Obtains a MIDI sequence from the specified URL. The URL must - * point to valid MIDI file data for a file type recognized - * by the system. + * Obtains a MIDI sequence from the specified URL. The URL must point to + * valid MIDI file data for a file type recognized by the system. *

    * This operation can only succeed for files of a type which can be parsed - * by an installed file reader. It may fail with an InvalidMidiDataException - * even for valid files if no compatible file reader is installed. It - * will also fail with an InvalidMidiDataException if a compatible file reader - * is installed, but encounters errors while constructing the Sequence + * by an installed file reader. It may fail with an + * {@code InvalidMidiDataException} even for valid files if no compatible + * file reader is installed. It will also fail with an + * {@code InvalidMidiDataException} if a compatible file reader is + * installed, but encounters errors while constructing the {@code Sequence} * object from the file data. * - * @param url the URL from which the Sequence should be - * constructed - * @return a Sequence object based on the MIDI file data - * pointed to by the URL + * @param url the URL from which the {@code Sequence} should be constructed + * @return a {@code Sequence} object based on the MIDI file data pointed to + * by the URL * @throws InvalidMidiDataException if the URL does not point to valid MIDI - * file data recognized by the system + * file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the URL */ public static Sequence getSequence(URL url) @@ -852,25 +775,25 @@ public class MidiSystem { } } - /** - * Obtains a MIDI sequence from the specified File. - * The File must point to valid MIDI file data - * for a file type recognized by the system. + * Obtains a MIDI sequence from the specified {@code File}. The {@code File} + * must point to valid MIDI file data for a file type recognized by the + * system. *

    * This operation can only succeed for files of a type which can be parsed - * by an installed file reader. It may fail with an InvalidMidiDataException - * even for valid files if no compatible file reader is installed. It - * will also fail with an InvalidMidiDataException if a compatible file reader - * is installed, but encounters errors while constructing the Sequence + * by an installed file reader. It may fail with an + * {@code InvalidMidiDataException} even for valid files if no compatible + * file reader is installed. It will also fail with an + * {@code InvalidMidiDataException} if a compatible file reader is + * installed, but encounters errors while constructing the {@code Sequence} * object from the file data. * - * @param file the File from which the Sequence - * should be constructed - * @return a Sequence object based on the MIDI file data - * pointed to by the File + * @param file the {@code File} from which the {@code Sequence} should be + * constructed + * @return a {@code Sequence} object based on the MIDI file data pointed to + * by the File * @throws InvalidMidiDataException if the File does not point to valid MIDI - * file data recognized by the system + * file data recognized by the system * @throws IOException if an I/O exception occurs */ public static Sequence getSequence(File file) @@ -896,12 +819,12 @@ public class MidiSystem { } } - /** * Obtains the set of MIDI file types for which file writing support is * provided by the system. - * @return array of unique file types. If no file types are supported, - * an array of length 0 is returned. + * + * @return array of unique file types. If no file types are supported, an + * array of length 0 is returned. */ public static int[] getMidiFileTypes() { @@ -927,13 +850,13 @@ public class MidiSystem { return resultTypes; } - /** * Indicates whether file writing support for the specified MIDI file type * is provided by the system. - * @param fileType the file type for which write capabilities are queried - * @return true if the file type is supported, - * otherwise false + * + * @param fileType the file type for which write capabilities are queried + * @return {@code true} if the file type is supported, otherwise + * {@code false} */ public static boolean isFileTypeSupported(int fileType) { @@ -948,14 +871,13 @@ public class MidiSystem { return false; } - /** * Obtains the set of MIDI file types that the system can write from the * sequence specified. - * @param sequence the sequence for which MIDI file type support - * is queried - * @return the set of unique supported file types. If no file types are supported, - * returns an array of length 0. + * + * @param sequence the sequence for which MIDI file type support is queried + * @return the set of unique supported file types. If no file types are + * supported, returns an array of length 0. */ public static int[] getMidiFileTypes(Sequence sequence) { @@ -981,15 +903,14 @@ public class MidiSystem { return resultTypes; } - /** * Indicates whether a MIDI file of the file type specified can be written * from the sequence indicated. - * @param fileType the file type for which write capabilities - * are queried - * @param sequence the sequence for which file writing support is queried - * @return true if the file type is supported for this - * sequence, otherwise false + * + * @param fileType the file type for which write capabilities are queried + * @param sequence the sequence for which file writing support is queried + * @return {@code true} if the file type is supported for this sequence, + * otherwise {@code false} */ public static boolean isFileTypeSupported(int fileType, Sequence sequence) { @@ -1004,19 +925,20 @@ public class MidiSystem { return false; } - /** * Writes a stream of bytes representing a file of the MIDI file type * indicated to the output stream provided. - * @param in sequence containing MIDI data to be written to the file - * @param fileType the file type of the file to be written to the output stream - * @param out stream to which the file data should be written + * + * @param in sequence containing MIDI data to be written to the file + * @param fileType the file type of the file to be written to the output + * stream + * @param out stream to which the file data should be written * @return the number of bytes written to the output stream * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file format is not supported by - * the system + * the system * @see #isFileTypeSupported(int, Sequence) - * @see #getMidiFileTypes(Sequence) + * @see #getMidiFileTypes(Sequence) */ public static int write(Sequence in, int fileType, OutputStream out) throws IOException { @@ -1038,19 +960,19 @@ public class MidiSystem { return bytesWritten; } - /** * Writes a stream of bytes representing a file of the MIDI file type * indicated to the external file provided. - * @param in sequence containing MIDI data to be written to the file - * @param type the file type of the file to be written to the output stream - * @param out external file to which the file data should be written + * + * @param in sequence containing MIDI data to be written to the file + * @param type the file type of the file to be written to the output stream + * @param out external file to which the file data should be written * @return the number of bytes written to the file * @throws IOException if an I/O exception occurs - * @throws IllegalArgumentException if the file type is not supported by - * the system + * @throws IllegalArgumentException if the file type is not supported by the + * system * @see #isFileTypeSupported(int, Sequence) - * @see #getMidiFileTypes(Sequence) + * @see #getMidiFileTypes(Sequence) */ public static int write(Sequence in, int type, File out) throws IOException { @@ -1072,8 +994,6 @@ public class MidiSystem { return bytesWritten; } - - // HELPER METHODS @SuppressWarnings("unchecked") private static List getMidiDeviceProviders() { @@ -1095,19 +1015,16 @@ public class MidiSystem { return (List) getProviders(MidiFileReader.class); } - - /** Attempts to locate and return a default MidiDevice of the specified - * type. - * + /** + * Attempts to locate and return a default MidiDevice of the specified type. * This method wraps {@link #getDefaultDevice}. It catches the - * IllegalArgumentException thrown by - * getDefaultDevice and instead throws a - * MidiUnavailableException, with the catched + * {@code IllegalArgumentException} thrown by {@code getDefaultDevice} and + * instead throws a {@code MidiUnavailableException}, with the catched * exception chained. * - * @param deviceClass The requested device type, one of Synthesizer.class, - * Sequencer.class, Receiver.class or Transmitter.class. - * @throws MidiUnavalableException on failure. + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @throws MidiUnavailableException on failure */ private static MidiDevice getDefaultDeviceWrapper(Class deviceClass) throws MidiUnavailableException{ @@ -1120,13 +1037,12 @@ public class MidiSystem { } } - - /** Attempts to locate and return a default MidiDevice of the specified - * type. + /** + * Attempts to locate and return a default MidiDevice of the specified type. * - * @param deviceClass The requested device type, one of Synthesizer.class, - * Sequencer.class, Receiver.class or Transmitter.class. - * @throws IllegalArgumentException on failure. + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @throws IllegalArgumentException on failure */ private static MidiDevice getDefaultDevice(Class deviceClass) { List providers = getMidiDeviceProviders(); @@ -1169,16 +1085,15 @@ public class MidiSystem { throw new IllegalArgumentException("Requested device not installed"); } - - - /** Return a MidiDeviceProcider of a given class from the list of - MidiDeviceProviders. - - @param providerClassName The class name of the provider to be returned. - @param provider The list of MidiDeviceProviders that is searched. - @return A MidiDeviceProvider of the requested class, or null if none - is found. - */ + /** + * Return a MidiDeviceProvider of a given class from the list of + * MidiDeviceProviders. + * + * @param providerClassName The class name of the provider to be returned + * @param providers The list of MidiDeviceProviders that is searched + * @return A MidiDeviceProvider of the requested class, or null if none is + * found + */ private static MidiDeviceProvider getNamedProvider(String providerClassName, List providers) { for(int i = 0; i < providers.size(); i++) { @@ -1190,15 +1105,15 @@ public class MidiSystem { return null; } - - /** Return a MidiDevice with a given name from a given MidiDeviceProvider. - @param deviceName The name of the MidiDevice to be returned. - @param provider The MidiDeviceProvider to check for MidiDevices. - @param deviceClass The requested device type, one of Synthesizer.class, - Sequencer.class, Receiver.class or Transmitter.class. - - @return A MidiDevice matching the requirements, or null if none is found. - */ + /** + * Return a MidiDevice with a given name from a given MidiDeviceProvider. + * + * @param deviceName The name of the MidiDevice to be returned + * @param provider The MidiDeviceProvider to check for MidiDevices + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @return A MidiDevice matching the requirements, or null if none is found + */ private static MidiDevice getNamedDevice(String deviceName, MidiDeviceProvider provider, Class deviceClass) { @@ -1222,14 +1137,14 @@ public class MidiSystem { return null; } - - /** Return a MidiDevice with a given name from a given MidiDeviceProvider. - @param deviceName The name of the MidiDevice to be returned. - @param provider The MidiDeviceProvider to check for MidiDevices. - @param deviceClass The requested device type, one of Synthesizer.class, - Sequencer.class, Receiver.class or Transmitter.class. - - @return A MidiDevice matching the requirements, or null if none is found. + /** + * Return a MidiDevice with a given name from a given MidiDeviceProvider. + * + * @param deviceName The name of the MidiDevice to be returned + * @param provider The MidiDeviceProvider to check for MidiDevices + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @return A MidiDevice matching the requirements, or null if none is found */ private static MidiDevice getNamedDevice(String deviceName, MidiDeviceProvider provider, @@ -1249,16 +1164,16 @@ public class MidiSystem { return null; } - - /** Return a MidiDevice with a given name from a list of - MidiDeviceProviders. - @param deviceName The name of the MidiDevice to be returned. - @param providers The List of MidiDeviceProviders to check for - MidiDevices. - @param deviceClass The requested device type, one of Synthesizer.class, - Sequencer.class, Receiver.class or Transmitter.class. - @return A Mixer matching the requirements, or null if none is found. - */ + /** + * Return a MidiDevice with a given name from a list of MidiDeviceProviders. + * + * @param deviceName The name of the MidiDevice to be returned + * @param providers The List of MidiDeviceProviders to check for + * MidiDevices + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @return A Mixer matching the requirements, or null if none is found + */ private static MidiDevice getNamedDevice(String deviceName, List providers, Class deviceClass) { @@ -1282,15 +1197,15 @@ public class MidiSystem { return null; } - - /** Return a MidiDevice with a given name from a list of - MidiDeviceProviders. - @param deviceName The name of the MidiDevice to be returned. - @param providers The List of MidiDeviceProviders to check for - MidiDevices. - @param deviceClass The requested device type, one of Synthesizer.class, - Sequencer.class, Receiver.class or Transmitter.class. - @return A Mixer matching the requirements, or null if none is found. + /** + * Return a MidiDevice with a given name from a list of MidiDeviceProviders. + * + * @param deviceName The name of the MidiDevice to be returned + * @param providers The List of MidiDeviceProviders to check for + * MidiDevices + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @return A Mixer matching the requirements, or null if none is found */ private static MidiDevice getNamedDevice(String deviceName, List providers, @@ -1310,14 +1225,15 @@ public class MidiSystem { return null; } - - /** From a given MidiDeviceProvider, return the first appropriate device. - @param provider The MidiDeviceProvider to check for MidiDevices. - @param deviceClass The requested device type, one of Synthesizer.class, - Sequencer.class, Receiver.class or Transmitter.class. - @return A MidiDevice is considered appropriate, or null if no - appropriate device is found. - */ + /** + * From a given MidiDeviceProvider, return the first appropriate device. + * + * @param provider The MidiDeviceProvider to check for MidiDevices + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @return A MidiDevice is considered appropriate, or null if no appropriate + * device is found + */ private static MidiDevice getFirstDevice(MidiDeviceProvider provider, Class deviceClass) { MidiDevice device; @@ -1340,13 +1256,14 @@ public class MidiSystem { return null; } - - /** From a given MidiDeviceProvider, return the first appropriate device. - @param provider The MidiDeviceProvider to check for MidiDevices. - @param deviceClass The requested device type, one of Synthesizer.class, - Sequencer.class, Receiver.class or Transmitter.class. - @return A MidiDevice is considered appropriate, or null if no - appropriate device is found. + /** + * From a given MidiDeviceProvider, return the first appropriate device. + * + * @param provider The MidiDeviceProvider to check for MidiDevices + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @return A MidiDevice is considered appropriate, or null if no appropriate + * device is found */ private static MidiDevice getFirstDevice(MidiDeviceProvider provider, Class deviceClass, @@ -1363,15 +1280,16 @@ public class MidiSystem { return null; } - - /** From a List of MidiDeviceProviders, return the first appropriate - MidiDevice. - @param providers The List of MidiDeviceProviders to search. - @param deviceClass The requested device type, one of Synthesizer.class, - Sequencer.class, Receiver.class or Transmitter.class. - @return A MidiDevice that is considered appropriate, or null - if none is found. - */ + /** + * From a List of MidiDeviceProviders, return the first appropriate + * MidiDevice. + * + * @param providers The List of MidiDeviceProviders to search + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @return A MidiDevice that is considered appropriate, or null if none is + * found + */ private static MidiDevice getFirstDevice(List providers, Class deviceClass) { MidiDevice device; @@ -1394,14 +1312,15 @@ public class MidiSystem { return null; } - - /** From a List of MidiDeviceProviders, return the first appropriate - MidiDevice. - @param providers The List of MidiDeviceProviders to search. - @param deviceClass The requested device type, one of Synthesizer.class, - Sequencer.class, Receiver.class or Transmitter.class. - @return A MidiDevice that is considered appropriate, or null - if none is found. + /** + * From a List of MidiDeviceProviders, return the first appropriate + * MidiDevice. + * + * @param providers The List of MidiDeviceProviders to search + * @param deviceClass The requested device type, one of Synthesizer.class, + * Sequencer.class, Receiver.class or Transmitter.class + * @return A MidiDevice that is considered appropriate, or null if none is + * found */ private static MidiDevice getFirstDevice(List providers, Class deviceClass, @@ -1419,28 +1338,29 @@ public class MidiSystem { return null; } - - /** Checks if a MidiDevice is appropriate. - If deviceClass is Synthesizer or Sequencer, a device implementing - the respective interface is considered appropriate. If deviceClass - is Receiver or Transmitter, a device is considered appropriate if - it implements neither Synthesizer nor Transmitter, and if it can - provide at least one Receiver or Transmitter, respectively. - - @param device the MidiDevice to test - @param allowSynthesizer if true, Synthesizers are considered - appropriate. Otherwise only pure MidiDevices are considered - appropriate (unless allowSequencer is true). This flag only has an - effect for deviceClass Receiver and Transmitter. For other device - classes (Sequencer and Synthesizer), this flag has no effect. - @param allowSequencer if true, Sequencers are considered - appropriate. Otherwise only pure MidiDevices are considered - appropriate (unless allowSynthesizer is true). This flag only has an - effect for deviceClass Receiver and Transmitter. For other device - classes (Sequencer and Synthesizer), this flag has no effect. - @return true if the device is considered appropriate according to the - rules given above, false otherwise. - */ + /** + * Checks if a MidiDevice is appropriate. If deviceClass is Synthesizer or + * Sequencer, a device implementing the respective interface is considered + * appropriate. If deviceClass is Receiver or Transmitter, a device is + * considered appropriate if it implements neither Synthesizer nor + * Transmitter, and if it can provide at least one Receiver or Transmitter, + * respectively. + * + * @param device the MidiDevice to test + * @param allowSynthesizer if true, Synthesizers are considered + * appropriate. Otherwise only pure MidiDevices are considered + * appropriate (unless allowSequencer is true). This flag only has + * an effect for deviceClass Receiver and Transmitter. For other + * device classes (Sequencer and Synthesizer), this flag has no + * effect. + * @param allowSequencer if true, Sequencers are considered appropriate. + * Otherwise only pure MidiDevices are considered appropriate + * (unless allowSynthesizer is true). This flag only has an effect + * for deviceClass Receiver and Transmitter. For other device + * classes (Sequencer and Synthesizer), this flag has no effect. + * @return true if the device is considered appropriate according to the + * rules given above, false otherwise + */ private static boolean isAppropriateDevice(MidiDevice device, Class deviceClass, boolean allowSynthesizer, @@ -1473,12 +1393,12 @@ public class MidiSystem { return false; } - /** - * Obtains the set of services currently installed on the system - * using the SPI mechanism in 1.3. - * @return a List of instances of providers for the requested service. - * If no providers are available, a List of length 0 will be returned. + * Obtains the set of services currently installed on the system using the + * SPI mechanism in 1.3. + * + * @return a List of instances of providers for the requested service. If no + * providers are available, a List of length 0 will be returned. */ private static List getProviders(Class providerClass) { return JDK13Services.getProviders(providerClass); diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiUnavailableException.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiUnavailableException.java index 85ace347d8b..b52fac8d813 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiUnavailableException.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiUnavailableException.java @@ -25,39 +25,37 @@ package javax.sound.midi; - /** - * A MidiUnavailableException is thrown when a requested MIDI - * component cannot be opened or created because it is unavailable. This often - * occurs when a device is in use by another application. More generally, it - * can occur when there is a finite number of a certain kind of resource that can - * be used for some purpose, and all of them are already in use (perhaps all by - * this application). For an example of the latter case, see the + * A {@code MidiUnavailableException} is thrown when a requested MIDI component + * cannot be opened or created because it is unavailable. This often occurs when + * a device is in use by another application. More generally, it can occur when + * there is a finite number of a certain kind of resource that can be used for + * some purpose, and all of them are already in use (perhaps all by this + * application). For an example of the latter case, see the * {@link Transmitter#setReceiver(Receiver) setReceiver} method of - * Transmitter. + * {@code Transmitter}. * * @author Kara Kytle */ public class MidiUnavailableException extends Exception { + private static final long serialVersionUID = 6093809578628944323L; /** - * Constructs a MidiUnavailableException that has - * null as its error detail message. + * Constructs a {@code MidiUnavailableException} that has {@code null} as + * its error detail message. */ public MidiUnavailableException() { - super(); } /** - * Constructs a MidiUnavailableException with the - * specified detail message. + * Constructs a {@code MidiUnavailableException} with the specified detail + * message. * - * @param message the string to display as an error detail message + * @param message the string to display as an error detail message */ - public MidiUnavailableException(String message) { - + public MidiUnavailableException(final String message) { super(message); } } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/Patch.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/Patch.java index d8bc7cf1b4a..f1e438200b9 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/Patch.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/Patch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2002, 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 @@ -25,88 +25,77 @@ package javax.sound.midi; - /** - * A Patch object represents a location, on a MIDI - * synthesizer, into which a single instrument is stored (loaded). - * Every Instrument object has its own Patch - * object that specifies the memory location - * into which that instrument should be loaded. The - * location is specified abstractly by a bank index and a program number (not by - * any scheme that directly refers to a specific address or offset in RAM). - * This is a hierarchical indexing scheme: MIDI provides for up to 16384 banks, - * each of which contains up to 128 program locations. For example, a - * minimal sort of synthesizer might have only one bank of instruments, and - * only 32 instruments (programs) in that bank. + * A {@code Patch} object represents a location, on a MIDI synthesizer, into + * which a single instrument is stored (loaded). Every {@code Instrument} object + * has its own {@code Patch} object that specifies the memory location into + * which that instrument should be loaded. The location is specified abstractly + * by a bank index and a program number (not by any scheme that directly refers + * to a specific address or offset in RAM). This is a hierarchical indexing + * scheme: MIDI provides for up to 16384 banks, each of which contains up to 128 + * program locations. For example, a minimal sort of synthesizer might have only + * one bank of instruments, and only 32 instruments (programs) in that bank. *

    - * To select what instrument should play the notes on a particular MIDI - * channel, two kinds of MIDI message are used that specify a patch location: - * a bank-select command, and a program-change channel command. The Java Sound + * To select what instrument should play the notes on a particular MIDI channel, + * two kinds of MIDI message are used that specify a patch location: a + * bank-select command, and a program-change channel command. The Java Sound * equivalent is the - * {@link MidiChannel#programChange(int, int) programChange(int, int)} - * method of MidiChannel. + * {@link MidiChannel#programChange(int, int) programChange(int, int)} method of + * {@code MidiChannel}. * + * @author Kara Kytle * @see Instrument * @see Instrument#getPatch() * @see MidiChannel#programChange(int, int) * @see Synthesizer#loadInstruments(Soundbank, Patch[]) * @see Soundbank * @see Sequence#getPatchList() - * - * @author Kara Kytle */ - public class Patch { - /** - * Bank index + * Bank index. */ private final int bank; - /** - * Program change number + * Program change number. */ private final int program; - /** * Constructs a new patch object from the specified bank and program * numbers. - * @param bank the bank index (in the range from 0 to 16383) - * @param program the program index (in the range from 0 to 127) + * + * @param bank the bank index (in the range from 0 to 16383) + * @param program the program index (in the range from 0 to 127) */ public Patch(int bank, int program) { - this.bank = bank; this.program = program; } - /** - * Returns the number of the bank that contains the instrument - * whose location this Patch specifies. + * Returns the number of the bank that contains the instrument whose + * location this {@code Patch} specifies. + * * @return the bank number, whose range is from 0 to 16383 * @see MidiChannel#programChange(int, int) */ public int getBank() { - return bank; } - /** - * Returns the index, within - * a bank, of the instrument whose location this Patch specifies. - * @return the instrument's program number, whose range is from 0 to 127 + * Returns the index, within a bank, of the instrument whose location this + * {@code Patch} specifies. * + * @return the instrument's program number, whose range is from 0 to 127 * @see MidiChannel#getProgram * @see MidiChannel#programChange(int) * @see MidiChannel#programChange(int, int) */ public int getProgram() { - return program; } } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/Receiver.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/Receiver.java index 9df0a5d7153..55e038cfa86 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/Receiver.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/Receiver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, 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 @@ -25,50 +25,46 @@ package javax.sound.midi; - /** - * A Receiver receives {@link MidiEvent} objects and - * typically does something useful in response, such as interpreting them to - * generate sound or raw MIDI output. Common MIDI receivers include - * synthesizers and MIDI Out ports. + * A {@code Receiver} receives {@link MidiEvent} objects and typically does + * something useful in response, such as interpreting them to generate sound or + * raw MIDI output. Common MIDI receivers include synthesizers and MIDI Out + * ports. * + * @author Kara Kytle * @see MidiDevice * @see Synthesizer * @see Transmitter - * - * @author Kara Kytle */ public interface Receiver extends AutoCloseable { - //$$fb 2002-04-12: fix for 4662090: Contradiction in Receiver specification + /** - * Sends a MIDI message and time-stamp to this receiver. - * If time-stamping is not supported by this receiver, the time-stamp - * value should be -1. - * @param message the MIDI message to send - * @param timeStamp the time-stamp for the message, in microseconds. + * Sends a MIDI message and time-stamp to this receiver. If time-stamping is + * not supported by this receiver, the time-stamp value should be -1. + * + * @param message the MIDI message to send + * @param timeStamp the time-stamp for the message, in microseconds * @throws IllegalStateException if the receiver is closed */ - public void send(MidiMessage message, long timeStamp); + void send(MidiMessage message, long timeStamp); /** - * Indicates that the application has finished using the receiver, and - * that limited resources it requires may be released or made available. - * - *

    If the creation of this Receiver resulted in - * implicitly opening the underlying device, the device is - * implicitly closed by this method. This is true unless the device is - * kept open by other Receiver or Transmitter - * instances that opened the device implicitly, and unless the device - * has been opened explicitly. If the device this - * Receiver is retrieved from is closed explicitly by - * calling {@link MidiDevice#close MidiDevice.close}, the - * Receiver is closed, too. For a detailed - * description of open/close behaviour see the class description - * of {@link javax.sound.midi.MidiDevice MidiDevice}. + * Indicates that the application has finished using the receiver, and that + * limited resources it requires may be released or made available. + *

    + * If the creation of this {@code Receiver} resulted in implicitly opening + * the underlying device, the device is implicitly closed by this method. + * This is true unless the device is kept open by other {@code Receiver} or + * {@code Transmitter} instances that opened the device implicitly, and + * unless the device has been opened explicitly. If the device this + * {@code Receiver} is retrieved from is closed explicitly by calling + * {@link MidiDevice#close MidiDevice.close}, the {@code Receiver} is + * closed, too. For a detailed description of open/close behaviour see the + * class description of {@link MidiDevice MidiDevice}. * * @see javax.sound.midi.MidiSystem#getReceiver */ - public void close(); + void close(); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/Sequence.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/Sequence.java index 14cb66110ed..3dd0ca5801c 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/Sequence.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/Sequence.java @@ -26,72 +26,77 @@ package javax.sound.midi; import java.util.Vector; -import com.sun.media.sound.MidiUtils; - /** - * A Sequence is a data structure containing musical - * information (often an entire song or composition) that can be played - * back by a {@link Sequencer} object. Specifically, the - * Sequence contains timing - * information and one or more tracks. Each {@link Track track} consists of a - * series of MIDI events (such as note-ons, note-offs, program changes, and meta-events). - * The sequence's timing information specifies the type of unit that is used - * to time-stamp the events in the sequence. + * A {@code Sequence} is a data structure containing musical information (often + * an entire song or composition) that can be played back by a {@link Sequencer} + * object. Specifically, the {@code Sequence} contains timing information and + * one or more tracks. Each {@link Track track} consists of a series of MIDI + * events (such as note-ons, note-offs, program changes, and meta-events). The + * sequence's timing information specifies the type of unit that is used to + * time-stamp the events in the sequence. *

    - * A Sequence can be created from a MIDI file by reading the file - * into an input stream and invoking one of the getSequence methods of - * {@link MidiSystem}. A sequence can also be built from scratch by adding new - * Tracks to an empty Sequence, and adding - * {@link MidiEvent} objects to these Tracks. + * A {@code Sequence} can be created from a MIDI file by reading the file into + * an input stream and invoking one of the {@code getSequence} methods of + * {@link MidiSystem}. A sequence can also be built from scratch by adding new + * {@code Tracks} to an empty {@code Sequence}, and adding {@link MidiEvent} + * objects to these {@code Tracks}. * + * @author Kara Kytle * @see Sequencer#setSequence(java.io.InputStream stream) * @see Sequencer#setSequence(Sequence sequence) * @see Track#add(MidiEvent) * @see MidiFileFormat - * - * @author Kara Kytle */ public class Sequence { - // Timing types /** - * The tempo-based timing type, for which the resolution is expressed in pulses (ticks) per quarter note. + * The tempo-based timing type, for which the resolution is expressed in + * pulses (ticks) per quarter note. + * * @see #Sequence(float, int) */ public static final float PPQ = 0.0f; /** - * The SMPTE-based timing type with 24 frames per second (resolution is expressed in ticks per frame). + * The SMPTE-based timing type with 24 frames per second (resolution is + * expressed in ticks per frame). + * * @see #Sequence(float, int) */ public static final float SMPTE_24 = 24.0f; /** - * The SMPTE-based timing type with 25 frames per second (resolution is expressed in ticks per frame). + * The SMPTE-based timing type with 25 frames per second (resolution is + * expressed in ticks per frame). + * * @see #Sequence(float, int) */ public static final float SMPTE_25 = 25.0f; /** - * The SMPTE-based timing type with 29.97 frames per second (resolution is expressed in ticks per frame). + * The SMPTE-based timing type with 29.97 frames per second (resolution is + * expressed in ticks per frame). + * * @see #Sequence(float, int) */ public static final float SMPTE_30DROP = 29.97f; /** - * The SMPTE-based timing type with 30 frames per second (resolution is expressed in ticks per frame). + * The SMPTE-based timing type with 30 frames per second (resolution is + * expressed in ticks per frame). + * * @see #Sequence(float, int) */ public static final float SMPTE_30 = 30.0f; - // Variables /** * The timing division type of the sequence. + * * @see #PPQ * @see #SMPTE_24 * @see #SMPTE_25 @@ -103,33 +108,33 @@ public class Sequence { /** * The timing resolution of the sequence. + * * @see #getResolution */ protected int resolution; /** * The MIDI tracks in this sequence. + * * @see #getTracks */ protected Vector tracks = new Vector(); - /** - * Constructs a new MIDI sequence with the specified timing division - * type and timing resolution. The division type must be one of the - * recognized MIDI timing types. For tempo-based timing, - * divisionType is PPQ (pulses per quarter note) and - * the resolution is specified in ticks per beat. For SMTPE timing, - * divisionType specifies the number of frames per - * second and the resolution is specified in ticks per frame. - * The sequence will contain no initial tracks. Tracks may be - * added to or removed from the sequence using {@link #createTrack} - * and {@link #deleteTrack}. - * - * @param divisionType the timing division type (PPQ or one of the SMPTE types) - * @param resolution the timing resolution - * @throws InvalidMidiDataException if divisionType is not valid + * Constructs a new MIDI sequence with the specified timing division type + * and timing resolution. The division type must be one of the recognized + * MIDI timing types. For tempo-based timing, {@code divisionType} is PPQ + * (pulses per quarter note) and the resolution is specified in ticks per + * beat. For SMTPE timing, {@code divisionType} specifies the number of + * frames per second and the resolution is specified in ticks per frame. The + * sequence will contain no initial tracks. Tracks may be added to or + * removed from the sequence using {@link #createTrack} and + * {@link #deleteTrack}. * + * @param divisionType the timing division type (PPQ or one of the SMPTE + * types) + * @param resolution the timing resolution + * @throws InvalidMidiDataException if {@code divisionType} is not valid * @see #PPQ * @see #SMPTE_24 * @see #SMPTE_25 @@ -156,27 +161,25 @@ public class Sequence { this.resolution = resolution; } - /** - * Constructs a new MIDI sequence with the specified timing division - * type, timing resolution, and number of tracks. The division type must be one of the - * recognized MIDI timing types. For tempo-based timing, - * divisionType is PPQ (pulses per quarter note) and - * the resolution is specified in ticks per beat. For SMTPE timing, - * divisionType specifies the number of frames per - * second and the resolution is specified in ticks per frame. - * The sequence will be initialized with the number of tracks specified by - * numTracks. These tracks are initially empty (i.e. - * they contain only the meta-event End of Track). - * The tracks may be retrieved for editing using the {@link #getTracks} - * method. Additional tracks may be added, or existing tracks removed, - * using {@link #createTrack} and {@link #deleteTrack}. - * - * @param divisionType the timing division type (PPQ or one of the SMPTE types) - * @param resolution the timing resolution - * @param numTracks the initial number of tracks in the sequence. - * @throws InvalidMidiDataException if divisionType is not valid + * Constructs a new MIDI sequence with the specified timing division type, + * timing resolution, and number of tracks. The division type must be one of + * the recognized MIDI timing types. For tempo-based timing, + * {@code divisionType} is PPQ (pulses per quarter note) and the resolution + * is specified in ticks per beat. For SMTPE timing, {@code divisionType} + * specifies the number of frames per second and the resolution is specified + * in ticks per frame. The sequence will be initialized with the number of + * tracks specified by {@code numTracks}. These tracks are initially empty + * (i.e. they contain only the meta-event End of Track). The tracks may be + * retrieved for editing using the {@link #getTracks} method. Additional + * tracks may be added, or existing tracks removed, using + * {@link #createTrack} and {@link #deleteTrack}. * + * @param divisionType the timing division type (PPQ or one of the SMPTE + * types) + * @param resolution the timing resolution + * @param numTracks the initial number of tracks in the sequence + * @throws InvalidMidiDataException if {@code divisionType} is not valid * @see #PPQ * @see #SMPTE_24 * @see #SMPTE_25 @@ -206,11 +209,10 @@ public class Sequence { } } - /** * Obtains the timing division type for this sequence. - * @return the division type (PPQ or one of the SMPTE types) * + * @return the division type (PPQ or one of the SMPTE types) * @see #PPQ * @see #SMPTE_24 * @see #SMPTE_25 @@ -223,11 +225,10 @@ public class Sequence { return divisionType; } - /** - * Obtains the timing resolution for this sequence. - * If the sequence's division type is PPQ, the resolution is specified in ticks per beat. - * For SMTPE timing, the resolution is specified in ticks per frame. + * Obtains the timing resolution for this sequence. If the sequence's + * division type is PPQ, the resolution is specified in ticks per beat. For + * SMTPE timing, the resolution is specified in ticks per frame. * * @return the number of ticks per beat (PPQ) or per frame (SMPTE) * @see #getDivisionType @@ -238,13 +239,13 @@ public class Sequence { return resolution; } - /** - * Creates a new, initially empty track as part of this sequence. - * The track initially contains the meta-event End of Track. - * The newly created track is returned. All tracks in the sequence - * may be retrieved using {@link #getTracks}. Tracks may be - * removed from the sequence using {@link #deleteTrack}. + * Creates a new, initially empty track as part of this sequence. The track + * initially contains the meta-event End of Track. The newly created track + * is returned. All tracks in the sequence may be retrieved using + * {@link #getTracks}. Tracks may be removed from the sequence using + * {@link #deleteTrack}. + * * @return the newly created track */ public Track createTrack() { @@ -255,13 +256,12 @@ public class Sequence { return track; } - /** * Removes the specified track from the sequence. - * @param track the track to remove - * @return true if the track existed in the track and was removed, - * otherwise false. * + * @param track the track to remove + * @return {@code true} if the track existed in the track and was removed, + * otherwise {@code false} * @see #createTrack * @see #getTracks */ @@ -273,12 +273,11 @@ public class Sequence { } } - /** - * Obtains an array containing all the tracks in this sequence. - * If the sequence contains no tracks, an array of length 0 is returned. - * @return the array of tracks + * Obtains an array containing all the tracks in this sequence. If the + * sequence contains no tracks, an array of length 0 is returned. * + * @return the array of tracks * @see #createTrack * @see #deleteTrack */ @@ -287,22 +286,20 @@ public class Sequence { return tracks.toArray(new Track[tracks.size()]); } - /** * Obtains the duration of this sequence, expressed in microseconds. - * @return this sequence's duration in microseconds. + * + * @return this sequence's duration in microseconds */ public long getMicrosecondLength() { return com.sun.media.sound.MidiUtils.tick2microsecond(this, getTickLength(), null); } - /** * Obtains the duration of this sequence, expressed in MIDI ticks. * * @return this sequence's length in ticks - * * @see #getMicrosecondLength */ public long getTickLength() { @@ -321,15 +318,12 @@ public class Sequence { } } - /** - * Obtains a list of patches referenced in this sequence. - * This patch list may be used to load the required - * {@link Instrument} objects - * into a {@link Synthesizer}. - * - * @return an array of {@link Patch} objects used in this sequence + * Obtains a list of patches referenced in this sequence. This patch list + * may be used to load the required {@link Instrument} objects into a + * {@link Synthesizer}. * + * @return an array of {@link Patch} objects used in this sequence * @see Synthesizer#loadInstruments(Soundbank, Patch[]) */ public Patch[] getPatchList() { diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/Sequencer.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/Sequencer.java index b587d29b544..17d6a9dc197 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/Sequencer.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/Sequencer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2003, 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 @@ -25,19 +25,18 @@ package javax.sound.midi; -import java.io.InputStream; import java.io.IOException; - +import java.io.InputStream; /** * A hardware or software device that plays back a MIDI - * {@link Sequence sequence} is known as a sequencer. - * A MIDI sequence contains lists of time-stamped MIDI data, such as - * might be read from a standard MIDI file. Most - * sequencers also provide functions for creating and editing sequences. + * {@link Sequence sequence} is known as a sequencer. A MIDI sequence + * contains lists of time-stamped MIDI data, such as might be read from a + * standard MIDI file. Most sequencers also provide functions for creating and + * editing sequences. *

    - * The Sequencer interface includes methods for the following - * basic MIDI sequencer operations: + * The {@code Sequencer} interface includes methods for the following basic MIDI + * sequencer operations: *

      *
    • obtaining a sequence from MIDI file data
    • *
    • starting and stopping playback
    • @@ -48,729 +47,635 @@ import java.io.IOException; *
    • controlling the timing of another device
    • *
    * In addition, the following operations are supported, either directly, or - * indirectly through objects that the Sequencer has access to: + * indirectly through objects that the {@code Sequencer} has access to: *
      *
    • editing the data by adding or deleting individual MIDI events or entire * tracks
    • *
    • muting or soloing individual tracks in the sequence
    • - *
    • notifying listener objects about any meta-events or - * control-change events encountered while playing back the sequence.
    • + *
    • notifying listener objects about any meta-events or control-change events + * encountered while playing back the sequence.
    • *
    * - * @see Sequencer.SyncMode + * @author Kara Kytle + * @author Florian Bomers + * @see SyncMode * @see #addMetaEventListener * @see ControllerEventListener * @see Receiver * @see Transmitter * @see MidiDevice - * - * @author Kara Kytle - * @author Florian Bomers */ public interface Sequencer extends MidiDevice { - /** - * A value indicating that looping should continue - * indefinitely rather than complete after a specific - * number of loops. + * A value indicating that looping should continue indefinitely rather than + * complete after a specific number of loops. * * @see #setLoopCount * @since 1.5 */ - public static final int LOOP_CONTINUOUSLY = -1; - - + int LOOP_CONTINUOUSLY = -1; /** * Sets the current sequence on which the sequencer operates. + *

    + * This method can be called even if the {@code Sequencer} is closed. * - *

    This method can be called even if the - * Sequencer is closed. - * - * @param sequence the sequence to be loaded. - * @throws InvalidMidiDataException if the sequence contains invalid - * MIDI data, or is not supported. + * @param sequence the sequence to be loaded + * @throws InvalidMidiDataException if the sequence contains invalid MIDI + * data, or is not supported */ - public void setSequence(Sequence sequence) throws InvalidMidiDataException; - + void setSequence(Sequence sequence) throws InvalidMidiDataException; /** - * Sets the current sequence on which the sequencer operates. - * The stream must point to MIDI file data. + * Sets the current sequence on which the sequencer operates. The stream + * must point to MIDI file data. + *

    + * This method can be called even if the {@code Sequencer} is closed. * - *

    This method can be called even if the - * Sequencer is closed. - * - * @param stream stream containing MIDI file data. - * @throws IOException if an I/O exception occurs during reading of the stream. - * @throws InvalidMidiDataException if invalid data is encountered - * in the stream, or the stream is not supported. + * @param stream stream containing MIDI file data + * @throws IOException if an I/O exception occurs during reading of the + * stream + * @throws InvalidMidiDataException if invalid data is encountered in the + * stream, or the stream is not supported */ - public void setSequence(InputStream stream) throws IOException, InvalidMidiDataException; - + void setSequence(InputStream stream) + throws IOException, InvalidMidiDataException; /** * Obtains the sequence on which the Sequencer is currently operating. + *

    + * This method can be called even if the {@code Sequencer} is closed. * - *

    This method can be called even if the - * Sequencer is closed. - * - * @return the current sequence, or null if no sequence is currently set. + * @return the current sequence, or {@code null} if no sequence is currently + * set */ - public Sequence getSequence(); - + Sequence getSequence(); /** - * Starts playback of the MIDI data in the currently - * loaded sequence. - * Playback will begin from the current position. - * If the playback position reaches the loop end point, - * and the loop count is greater than 0, playback will - * resume at the loop start point for the number of - * repetitions set with setLoopCount. - * After that, or if the loop count is 0, playback will - * continue to play to the end of the sequence. - * - *

    The implementation ensures that the synthesizer - * is brought to a consistent state when jumping - * to the loop start point by sending appropriate - * controllers, pitch bend, and program change events. - * - * @throws IllegalStateException if the Sequencer is - * closed. + * Starts playback of the MIDI data in the currently loaded sequence. + * Playback will begin from the current position. If the playback position + * reaches the loop end point, and the loop count is greater than 0, + * playback will resume at the loop start point for the number of + * repetitions set with {@code setLoopCount}. After that, or if the loop + * count is 0, playback will continue to play to the end of the sequence. + *

    + * The implementation ensures that the synthesizer is brought to a + * consistent state when jumping to the loop start point by sending + * appropriate controllers, pitch bend, and program change events. * + * @throws IllegalStateException if the {@code Sequencer} is closed * @see #setLoopStartPoint * @see #setLoopEndPoint * @see #setLoopCount * @see #stop */ - public void start(); - + void start(); /** - * Stops recording, if active, and playback of the currently loaded sequence, - * if any. - * - * @throws IllegalStateException if the Sequencer is - * closed. + * Stops recording, if active, and playback of the currently loaded + * sequence, if any. * + * @throws IllegalStateException if the {@code Sequencer} is closed * @see #start * @see #isRunning */ - public void stop(); - + void stop(); /** - * Indicates whether the Sequencer is currently running. The default is false. - * The Sequencer starts running when either {@link #start} or {@link #startRecording} - * is called. isRunning then returns true until playback of the - * sequence completes or {@link #stop} is called. - * @return true if the Sequencer is running, otherwise false + * Indicates whether the Sequencer is currently running. The default is + * {@code false}. The Sequencer starts running when either{@link #start} or + * {@link #startRecording} is called. {@code isRunning} then returns + * {@code true} until playback of the sequence completes or {@link #stop} is + * called. + * + * @return {@code true} if the Sequencer is running, otherwise {@code false} */ - public boolean isRunning(); - + boolean isRunning(); /** - * Starts recording and playback of MIDI data. Data is recorded to all enabled tracks, - * on the channel(s) for which they were enabled. Recording begins at the current position - * of the sequencer. Any events already in the track are overwritten for the duration - * of the recording session. Events from the currently loaded sequence, - * if any, are delivered to the sequencer's transmitter(s) along with messages - * received during recording. + * Starts recording and playback of MIDI data. Data is recorded to all + * enabled tracks, on the channel(s) for which they were enabled. Recording + * begins at the current position of the sequencer. Any events already in + * the track are overwritten for the duration of the recording session. + * Events from the currently loaded sequence, if any, are delivered to the + * sequencer's transmitter(s) along with messages received during recording. *

    - * Note that tracks are not by default enabled for recording. In order to record MIDI data, - * at least one track must be specifically enabled for recording. + * Note that tracks are not by default enabled for recording. In order to + * record MIDI data, at least one track must be specifically enabled for + * recording. * - * @throws IllegalStateException if the Sequencer is - * closed. - * - * @see #startRecording + * @throws IllegalStateException if the {@code Sequencer} is closed * @see #recordEnable * @see #recordDisable */ - public void startRecording(); - + void startRecording(); /** - * Stops recording, if active. Playback of the current sequence continues. - * - * @throws IllegalStateException if the Sequencer is - * closed. + * Stops recording, if active. Playback of the current sequence continues. * + * @throws IllegalStateException if the {@code Sequencer} is closed * @see #startRecording * @see #isRecording */ - public void stopRecording(); - + void stopRecording(); /** - * Indicates whether the Sequencer is currently recording. The default is false. - * The Sequencer begins recording when {@link #startRecording} is called, - * and then returns true until {@link #stop} or {@link #stopRecording} - * is called. - * @return true if the Sequencer is recording, otherwise false + * Indicates whether the Sequencer is currently recording. The default is + * {@code false}. The Sequencer begins recording when + * {@link #startRecording} is called, and then returns {@code true} until + * {@link #stop} or {@link #stopRecording} is called. + * + * @return {@code true} if the Sequencer is recording, otherwise + * {@code false} */ - public boolean isRecording(); - + boolean isRecording(); /** - * Prepares the specified track for recording events received on a particular channel. - * Once enabled, a track will receive events when recording is active. - * @param track the track to which events will be recorded - * @param channel the channel on which events will be received. If -1 is specified - * for the channel value, the track will receive data from all channels. - * @throws IllegalArgumentException thrown if the track is not part of the current - * sequence. + * Prepares the specified track for recording events received on a + * particular channel. Once enabled, a track will receive events when + * recording is active. + * + * @param track the track to which events will be recorded + * @param channel the channel on which events will be received. If -1 is + * specified for the channel value, the track will receive data from + * all channels. + * @throws IllegalArgumentException thrown if the track is not part of the + * current sequence */ - public void recordEnable(Track track, int channel); - + void recordEnable(Track track, int channel); /** - * Disables recording to the specified track. Events will no longer be recorded - * into this track. - * @param track the track to disable for recording, or null to disable - * recording for all tracks. + * Disables recording to the specified track. Events will no longer be + * recorded into this track. + * + * @param track the track to disable for recording, or {@code null} to + * disable recording for all tracks */ - public void recordDisable(Track track); - + void recordDisable(Track track); /** - * Obtains the current tempo, expressed in beats per minute. The - * actual tempo of playback is the product of the returned value - * and the tempo factor. + * Obtains the current tempo, expressed in beats per minute. The actual + * tempo of playback is the product of the returned value and the tempo + * factor. * * @return the current tempo in beats per minute - * * @see #getTempoFactor * @see #setTempoInBPM(float) * @see #getTempoInMPQ */ - public float getTempoInBPM(); - + float getTempoInBPM(); /** - * Sets the tempo in beats per minute. The actual tempo of playback - * is the product of the specified value and the tempo factor. + * Sets the tempo in beats per minute. The actual tempo of playback is the + * product of the specified value and the tempo factor. * - * @param bpm desired new tempo in beats per minute + * @param bpm desired new tempo in beats per minute * @see #getTempoFactor * @see #setTempoInMPQ(float) * @see #getTempoInBPM */ - public void setTempoInBPM(float bpm); - + void setTempoInBPM(float bpm); /** - * Obtains the current tempo, expressed in microseconds per quarter - * note. The actual tempo of playback is the product of the returned - * value and the tempo factor. + * Obtains the current tempo, expressed in microseconds per quarter note. + * The actual tempo of playback is the product of the returned value and the + * tempo factor. * * @return the current tempo in microseconds per quarter note * @see #getTempoFactor * @see #setTempoInMPQ(float) * @see #getTempoInBPM */ - public float getTempoInMPQ(); - + float getTempoInMPQ(); /** - * Sets the tempo in microseconds per quarter note. The actual tempo - * of playback is the product of the specified value and the tempo - * factor. + * Sets the tempo in microseconds per quarter note. The actual tempo of + * playback is the product of the specified value and the tempo factor. * - * @param mpq desired new tempo in microseconds per quarter note. + * @param mpq desired new tempo in microseconds per quarter note * @see #getTempoFactor * @see #setTempoInBPM(float) * @see #getTempoInMPQ */ - public void setTempoInMPQ(float mpq); - + void setTempoInMPQ(float mpq); /** - * Scales the sequencer's actual playback tempo by the factor provided. - * The default is 1.0. A value of 1.0 represents the natural rate (the - * tempo specified in the sequence), 2.0 means twice as fast, etc. - * The tempo factor does not affect the values returned by - * {@link #getTempoInMPQ} and {@link #getTempoInBPM}. - * Those values indicate the tempo prior to scaling. + * Scales the sequencer's actual playback tempo by the factor provided. The + * default is 1.0. A value of 1.0 represents the natural rate (the tempo + * specified in the sequence), 2.0 means twice as fast, etc. The tempo + * factor does not affect the values returned by {@link #getTempoInMPQ} and + * {@link #getTempoInBPM}. Those values indicate the tempo prior to scaling. *

    * Note that the tempo factor cannot be adjusted when external - * synchronization is used. In that situation, - * setTempoFactor always sets the tempo factor to 1.0. + * synchronization is used. In that situation, {@code setTempoFactor} always + * sets the tempo factor to 1.0. * - * @param factor the requested tempo scalar + * @param factor the requested tempo scalar * @see #getTempoFactor */ - public void setTempoFactor(float factor); - + void setTempoFactor(float factor); /** - * Returns the current tempo factor for the sequencer. The default is - * 1.0. + * Returns the current tempo factor for the sequencer. The default is 1.0. * - * @return tempo factor. + * @return tempo factor * @see #setTempoFactor(float) */ - public float getTempoFactor(); - + float getTempoFactor(); /** - * Obtains the length of the current sequence, expressed in MIDI ticks, - * or 0 if no sequence is set. + * Obtains the length of the current sequence, expressed in MIDI ticks, or 0 + * if no sequence is set. + * * @return length of the sequence in ticks */ - public long getTickLength(); - + long getTickLength(); /** - * Obtains the current position in the sequence, expressed in MIDI - * ticks. (The duration of a tick in seconds is determined both by - * the tempo and by the timing resolution stored in the - * {@link Sequence}.) + * Obtains the current position in the sequence, expressed in MIDI ticks. + * (The duration of a tick in seconds is determined both by the tempo and by + * the timing resolution stored in the {@link Sequence}.) * * @return current tick * @see #setTickPosition */ - public long getTickPosition(); - + long getTickPosition(); /** - * Sets the current sequencer position in MIDI ticks - * @param tick the desired tick position + * Sets the current sequencer position in MIDI ticks. + * + * @param tick the desired tick position * @see #getTickPosition */ - public void setTickPosition(long tick); - + void setTickPosition(long tick); /** - * Obtains the length of the current sequence, expressed in microseconds, - * or 0 if no sequence is set. - * @return length of the sequence in microseconds. + * Obtains the length of the current sequence, expressed in microseconds, or + * 0 if no sequence is set. + * + * @return length of the sequence in microseconds */ - public long getMicrosecondLength(); - + long getMicrosecondLength(); /** - * Obtains the current position in the sequence, expressed in - * microseconds. + * Obtains the current position in the sequence, expressed in microseconds. + * * @return the current position in microseconds * @see #setMicrosecondPosition */ - public long getMicrosecondPosition(); - + long getMicrosecondPosition(); /** - * Sets the current position in the sequence, expressed in microseconds - * @param microseconds desired position in microseconds + * Sets the current position in the sequence, expressed in microseconds. + * + * @param microseconds desired position in microseconds * @see #getMicrosecondPosition */ - public void setMicrosecondPosition(long microseconds); - + void setMicrosecondPosition(long microseconds); /** - * Sets the source of timing information used by this sequencer. - * The sequencer synchronizes to the master, which is the internal clock, - * MIDI clock, or MIDI time code, depending on the value of - * sync. The sync argument must be one - * of the supported modes, as returned by - * {@link #getMasterSyncModes}. - * - * @param sync the desired master synchronization mode + * Sets the source of timing information used by this sequencer. The + * sequencer synchronizes to the master, which is the internal clock, MIDI + * clock, or MIDI time code, depending on the value of {@code sync}. The + * {@code sync} argument must be one of the supported modes, as returned by + * {@link #getMasterSyncModes}. * + * @param sync the desired master synchronization mode * @see SyncMode#INTERNAL_CLOCK * @see SyncMode#MIDI_SYNC * @see SyncMode#MIDI_TIME_CODE * @see #getMasterSyncMode */ - public void setMasterSyncMode(SyncMode sync); - + void setMasterSyncMode(SyncMode sync); /** * Obtains the current master synchronization mode for this sequencer. * * @return the current master synchronization mode - * - * @see #setMasterSyncMode(Sequencer.SyncMode) + * @see #setMasterSyncMode(SyncMode) * @see #getMasterSyncModes */ - public SyncMode getMasterSyncMode(); - + SyncMode getMasterSyncMode(); /** * Obtains the set of master synchronization modes supported by this * sequencer. * * @return the available master synchronization modes - * * @see SyncMode#INTERNAL_CLOCK * @see SyncMode#MIDI_SYNC * @see SyncMode#MIDI_TIME_CODE * @see #getMasterSyncMode - * @see #setMasterSyncMode(Sequencer.SyncMode) + * @see #setMasterSyncMode(SyncMode) */ - public SyncMode[] getMasterSyncModes(); - + SyncMode[] getMasterSyncModes(); /** - * Sets the slave synchronization mode for the sequencer. - * This indicates the type of timing information sent by the sequencer - * to its receiver. The sync argument must be one - * of the supported modes, as returned by - * {@link #getSlaveSyncModes}. - * - * @param sync the desired slave synchronization mode + * Sets the slave synchronization mode for the sequencer. This indicates the + * type of timing information sent by the sequencer to its receiver. The + * {@code sync} argument must be one of the supported modes, as returned by + * {@link #getSlaveSyncModes}. * + * @param sync the desired slave synchronization mode * @see SyncMode#MIDI_SYNC * @see SyncMode#MIDI_TIME_CODE * @see SyncMode#NO_SYNC * @see #getSlaveSyncModes */ - public void setSlaveSyncMode(SyncMode sync); - + void setSlaveSyncMode(SyncMode sync); /** * Obtains the current slave synchronization mode for this sequencer. * * @return the current slave synchronization mode - * - * @see #setSlaveSyncMode(Sequencer.SyncMode) + * @see #setSlaveSyncMode(SyncMode) * @see #getSlaveSyncModes */ - public SyncMode getSlaveSyncMode(); - + SyncMode getSlaveSyncMode(); /** - * Obtains the set of slave synchronization modes supported by the sequencer. + * Obtains the set of slave synchronization modes supported by the + * sequencer. * * @return the available slave synchronization modes - * * @see SyncMode#MIDI_SYNC * @see SyncMode#MIDI_TIME_CODE * @see SyncMode#NO_SYNC */ - public SyncMode[] getSlaveSyncModes(); - + SyncMode[] getSlaveSyncModes(); /** - * Sets the mute state for a track. This method may fail for a number - * of reasons. For example, the track number specified may not be valid - * for the current sequence, or the sequencer may not support this functionality. - * An application which needs to verify whether this operation succeeded should - * follow this call with a call to {@link #getTrackMute}. + * Sets the mute state for a track. This method may fail for a number of + * reasons. For example, the track number specified may not be valid for the + * current sequence, or the sequencer may not support this functionality. An + * application which needs to verify whether this operation succeeded should + * follow this call with a call to {@link #getTrackMute}. * - * @param track the track number. Tracks in the current sequence are numbered - * from 0 to the number of tracks in the sequence minus 1. - * @param mute the new mute state for the track. true implies the - * track should be muted, false implies the track should be unmuted. + * @param track the track number. Tracks in the current sequence are + * numbered from 0 to the number of tracks in the sequence minus 1. + * @param mute the new mute state for the track. {@code true} implies the + * track should be muted, {@code false} implies the track should be + * unmuted. * @see #getSequence */ - public void setTrackMute(int track, boolean mute); - + void setTrackMute(int track, boolean mute); /** - * Obtains the current mute state for a track. The default mute - * state for all tracks which have not been muted is false. In any - * case where the specified track has not been muted, this method should - * return false. This applies if the sequencer does not support muting - * of tracks, and if the specified track index is not valid. + * Obtains the current mute state for a track. The default mute state for + * all tracks which have not been muted is false. In any case where the + * specified track has not been muted, this method should return false. This + * applies if the sequencer does not support muting of tracks, and if the + * specified track index is not valid. * - * @param track the track number. Tracks in the current sequence are numbered - * from 0 to the number of tracks in the sequence minus 1. - * @return true if muted, false if not. + * @param track the track number. Tracks in the current sequence are + * numbered from 0 to the number of tracks in the sequence minus 1. + * @return {@code true} if muted, {@code false} if not */ - public boolean getTrackMute(int track); + boolean getTrackMute(int track); /** - * Sets the solo state for a track. If solo is true - * only this track and other solo'd tracks will sound. If solo - * is false then only other solo'd tracks will sound, unless no - * tracks are solo'd in which case all un-muted tracks will sound. + * Sets the solo state for a track. If {@code solo} is {@code true} only + * this track and other solo'd tracks will sound. If {@code solo} is + * {@code false} then only other solo'd tracks will sound, unless no tracks + * are solo'd in which case all un-muted tracks will sound. *

    - * This method may fail for a number - * of reasons. For example, the track number specified may not be valid - * for the current sequence, or the sequencer may not support this functionality. - * An application which needs to verify whether this operation succeeded should - * follow this call with a call to {@link #getTrackSolo}. + * This method may fail for a number of reasons. For example, the track + * number specified may not be valid for the current sequence, or the + * sequencer may not support this functionality. An application which needs + * to verify whether this operation succeeded should follow this call with a + * call to {@link #getTrackSolo}. * - * @param track the track number. Tracks in the current sequence are numbered - * from 0 to the number of tracks in the sequence minus 1. - * @param solo the new solo state for the track. true implies the - * track should be solo'd, false implies the track should not be solo'd. + * @param track the track number. Tracks in the current sequence are + * numbered from 0 to the number of tracks in the sequence minus 1. + * @param solo the new solo state for the track. {@code true} implies the + * track should be solo'd, {@code false} implies the track should + * not be solo'd. * @see #getSequence */ - public void setTrackSolo(int track, boolean solo); - + void setTrackSolo(int track, boolean solo); /** - * Obtains the current solo state for a track. The default mute - * state for all tracks which have not been solo'd is false. In any - * case where the specified track has not been solo'd, this method should - * return false. This applies if the sequencer does not support soloing - * of tracks, and if the specified track index is not valid. + * Obtains the current solo state for a track. The default mute state for + * all tracks which have not been solo'd is false. In any case where the + * specified track has not been solo'd, this method should return false. + * This applies if the sequencer does not support soloing of tracks, and if + * the specified track index is not valid. * - * @param track the track number. Tracks in the current sequence are numbered - * from 0 to the number of tracks in the sequence minus 1. - * @return true if solo'd, false if not. + * @param track the track number. Tracks in the current sequence are + * numbered from 0 to the number of tracks in the sequence minus 1. + * @return {@code true} if solo'd, {@code false} if not */ - public boolean getTrackSolo(int track); - + boolean getTrackSolo(int track); /** - * Registers a meta-event listener to receive - * notification whenever a meta-event is encountered in the sequence - * and processed by the sequencer. This method can fail if, for - * instance,this class of sequencer does not support meta-event - * notification. - * - * @param listener listener to add - * @return true if the listener was successfully added, - * otherwise false + * Registers a meta-event listener to receive notification whenever a + * meta-event is encountered in the sequence and processed by the sequencer. + * This method can fail if, for instance,this class of sequencer does not + * support meta-event notification. * + * @param listener listener to add + * @return {@code true} if the listener was successfully added, otherwise + * {@code false} * @see #removeMetaEventListener * @see MetaEventListener * @see MetaMessage */ - public boolean addMetaEventListener(MetaEventListener listener); - + boolean addMetaEventListener(MetaEventListener listener); /** - * Removes the specified meta-event listener from this sequencer's - * list of registered listeners, if in fact the listener is registered. + * Removes the specified meta-event listener from this sequencer's list of + * registered listeners, if in fact the listener is registered. * - * @param listener the meta-event listener to remove + * @param listener the meta-event listener to remove * @see #addMetaEventListener */ - public void removeMetaEventListener(MetaEventListener listener); - + void removeMetaEventListener(MetaEventListener listener); /** - * Registers a controller event listener to receive notification - * whenever the sequencer processes a control-change event of the - * requested type or types. The types are specified by the - * controllers argument, which should contain an array of - * MIDI controller numbers. (Each number should be between 0 and 127, - * inclusive. See the MIDI 1.0 Specification for the numbers that - * correspond to various types of controllers.) + * Registers a controller event listener to receive notification whenever + * the sequencer processes a control-change event of the requested type or + * types. The types are specified by the {@code controllers} argument, which + * should contain an array of MIDI controller numbers. (Each number should + * be between 0 and 127, inclusive. See the MIDI 1.0 Specification for the + * numbers that correspond to various types of controllers.) *

    - * The returned array contains the MIDI controller - * numbers for which the listener will now receive events. - * Some sequencers might not support controller event notification, in - * which case the array has a length of 0. Other sequencers might - * support notification for some controllers but not all. - * This method may be invoked repeatedly. - * Each time, the returned array indicates all the controllers - * that the listener will be notified about, not only the controllers - * requested in that particular invocation. - * - * @param listener the controller event listener to add to the list of - * registered listeners - * @param controllers the MIDI controller numbers for which change - * notification is requested - * @return the numbers of all the MIDI controllers whose changes will - * now be reported to the specified listener + * The returned array contains the MIDI controller numbers for which the + * listener will now receive events. Some sequencers might not support + * controller event notification, in which case the array has a length of 0. + * Other sequencers might support notification for some controllers but not + * all. This method may be invoked repeatedly. Each time, the returned array + * indicates all the controllers that the listener will be notified about, + * not only the controllers requested in that particular invocation. * + * @param listener the controller event listener to add to the list of + * registered listeners + * @param controllers the MIDI controller numbers for which change + * notification is requested + * @return the numbers of all the MIDI controllers whose changes will now be + * reported to the specified listener * @see #removeControllerEventListener * @see ControllerEventListener */ - public int[] addControllerEventListener(ControllerEventListener listener, int[] controllers); - + int[] addControllerEventListener(ControllerEventListener listener, + int[] controllers); /** - * Removes a controller event listener's interest in one or more - * types of controller event. The controllers argument - * is an array of MIDI numbers corresponding to the controllers for - * which the listener should no longer receive change notifications. - * To completely remove this listener from the list of registered - * listeners, pass in null for controllers. - * The returned array contains the MIDI controller - * numbers for which the listener will now receive events. The - * array has a length of 0 if the listener will not receive - * change notifications for any controllers. - * - * @param listener old listener - * @param controllers the MIDI controller numbers for which change - * notification should be cancelled, or null to cancel - * for all controllers - * @return the numbers of all the MIDI controllers whose changes will - * now be reported to the specified listener + * Removes a controller event listener's interest in one or more types of + * controller event. The {@code controllers} argument is an array of MIDI + * numbers corresponding to the controllers for which the listener should no + * longer receive change notifications. To completely remove this listener + * from the list of registered listeners, pass in {@code null} for + * {@code controllers}. The returned array contains the MIDI controller + * numbers for which the listener will now receive events. The array has a + * length of 0 if the listener will not receive change notifications for any + * controllers. * + * @param listener old listener + * @param controllers the MIDI controller numbers for which change + * notification should be cancelled, or {@code null} to cancel for + * all controllers + * @return the numbers of all the MIDI controllers whose changes will now be + * reported to the specified listener * @see #addControllerEventListener */ - public int[] removeControllerEventListener(ControllerEventListener listener, int[] controllers); - + int[] removeControllerEventListener(ControllerEventListener listener, + int[] controllers); /** - * Sets the first MIDI tick that will be - * played in the loop. If the loop count is - * greater than 0, playback will jump to this - * point when reaching the loop end point. - * - *

    A value of 0 for the starting point means the - * beginning of the loaded sequence. The starting - * point must be lower than or equal to the ending - * point, and it must fall within the size of the - * loaded sequence. - * - *

    A sequencer's loop start point defaults to - * start of the sequence. - * - * @param tick the loop's starting position, - * in MIDI ticks (zero-based) - * @throws IllegalArgumentException if the requested - * loop start point cannot be set, usually because - * it falls outside the sequence's - * duration or because the start point is - * after the end point + * Sets the first MIDI tick that will be played in the loop. If the loop + * count is greater than 0, playback will jump to this point when reaching + * the loop end point. + *

    + * A value of 0 for the starting point means the beginning of the loaded + * sequence. The starting point must be lower than or equal to the ending + * point, and it must fall within the size of the loaded sequence. + *

    + * A sequencer's loop start point defaults to start of the sequence. * + * @param tick the loop's starting position, in MIDI ticks (zero-based) + * @throws IllegalArgumentException if the requested loop start point cannot + * be set, usually because it falls outside the sequence's duration + * or because the start point is after the end point * @see #setLoopEndPoint * @see #setLoopCount * @see #getLoopStartPoint * @see #start * @since 1.5 */ - public void setLoopStartPoint(long tick); - + void setLoopStartPoint(long tick); /** - * Obtains the start position of the loop, - * in MIDI ticks. + * Obtains the start position of the loop, in MIDI ticks. * - * @return the start position of the loop, - in MIDI ticks (zero-based) + * @return the start position of the loop, in MIDI ticks (zero-based) * @see #setLoopStartPoint * @since 1.5 */ - public long getLoopStartPoint(); - + long getLoopStartPoint(); /** - * Sets the last MIDI tick that will be played in - * the loop. If the loop count is 0, the loop end - * point has no effect and playback continues to + * Sets the last MIDI tick that will be played in the loop. If the loop + * count is 0, the loop end point has no effect and playback continues to * play when reaching the loop end point. + *

    + * A value of -1 for the ending point indicates the last tick of the + * sequence. Otherwise, the ending point must be greater than or equal to + * the starting point, and it must fall within the size of the loaded + * sequence. + *

    + * A sequencer's loop end point defaults to -1, meaning the end of the + * sequence. * - *

    A value of -1 for the ending point - * indicates the last tick of the sequence. - * Otherwise, the ending point must be greater - * than or equal to the starting point, and it must - * fall within the size of the loaded sequence. - * - *

    A sequencer's loop end point defaults to -1, - * meaning the end of the sequence. - * - * @param tick the loop's ending position, - * in MIDI ticks (zero-based), or - * -1 to indicate the final tick - * @throws IllegalArgumentException if the requested - * loop point cannot be set, usually because - * it falls outside the sequence's - * duration or because the ending point is - * before the starting point - * + * @param tick the loop's ending position, in MIDI ticks (zero-based), or + * -1 to indicate the final tick + * @throws IllegalArgumentException if the requested loop point cannot be + * set, usually because it falls outside the sequence's duration or + * because the ending point is before the starting point * @see #setLoopStartPoint * @see #setLoopCount * @see #getLoopEndPoint * @see #start * @since 1.5 */ - public void setLoopEndPoint(long tick); - + void setLoopEndPoint(long tick); /** - * Obtains the end position of the loop, - * in MIDI ticks. + * Obtains the end position of the loop, in MIDI ticks. * - * @return the end position of the loop, in MIDI - * ticks (zero-based), or -1 to indicate - * the end of the sequence + * @return the end position of the loop, in MIDI ticks (zero-based), or -1 + * to indicate the end of the sequence * @see #setLoopEndPoint * @since 1.5 */ - public long getLoopEndPoint(); - + long getLoopEndPoint(); /** - * Sets the number of repetitions of the loop for - * playback. - * When the playback position reaches the loop end point, - * it will loop back to the loop start point - * count times, after which playback will - * continue to play to the end of the sequence. + * Sets the number of repetitions of the loop for playback. When the + * playback position reaches the loop end point, it will loop back to the + * loop start point {@code count} times, after which playback will continue + * to play to the end of the sequence. *

    - * If the current position when this method is invoked - * is greater than the loop end point, playback - * continues to the end of the sequence without looping, - * unless the loop end point is changed subsequently. + * If the current position when this method is invoked is greater than the + * loop end point, playback continues to the end of the sequence without + * looping, unless the loop end point is changed subsequently. *

    - * A count value of 0 disables looping: - * playback will continue at the loop end point, and it - * will not loop back to the loop start point. + * A {@code count} value of 0 disables looping: playback will continue at + * the loop end point, and it will not loop back to the loop start point. * This is a sequencer's default. + *

    + * If playback is stopped during looping, the current loop status is + * cleared; subsequent start requests are not affected by an interrupted + * loop operation. * - *

    If playback is stopped during looping, the - * current loop status is cleared; subsequent start - * requests are not affected by an interrupted loop - * operation. - * - * @param count the number of times playback should - * loop back from the loop's end position - * to the loop's start position, or - * {@link #LOOP_CONTINUOUSLY} - * to indicate that looping should - * continue until interrupted - * - * @throws IllegalArgumentException if count is - * negative and not equal to {@link #LOOP_CONTINUOUSLY} - * + * @param count the number of times playback should loop back from the + * loop's end position to the loop's start position, or + * {@link #LOOP_CONTINUOUSLY} to indicate that looping should + * continue until interrupted + * @throws IllegalArgumentException if {@code count} is negative and not + * equal to {@link #LOOP_CONTINUOUSLY} * @see #setLoopStartPoint * @see #setLoopEndPoint * @see #getLoopCount * @see #start * @since 1.5 */ - public void setLoopCount(int count); - + void setLoopCount(int count); /** - * Obtains the number of repetitions for - * playback. + * Obtains the number of repetitions for playback. * - * @return the number of loops after which - * playback plays to the end of the + * @return the number of loops after which playback plays to the end of the * sequence * @see #setLoopCount * @see #start * @since 1.5 */ - public int getLoopCount(); + int getLoopCount(); /** - * A SyncMode object represents one of the ways in which - * a MIDI sequencer's notion of time can be synchronized with a master - * or slave device. - * If the sequencer is being synchronized to a master, the - * sequencer revises its current time in response to messages from - * the master. If the sequencer has a slave, the sequencer - * similarly sends messages to control the slave's timing. + * A {@code SyncMode} object represents one of the ways in which a MIDI + * sequencer's notion of time can be synchronized with a master or slave + * device. If the sequencer is being synchronized to a master, the sequencer + * revises its current time in response to messages from the master. If the + * sequencer has a slave, the sequencer similarly sends messages to control + * the slave's timing. *

    - * There are three predefined modes that specify possible masters - * for a sequencer: INTERNAL_CLOCK, - * MIDI_SYNC, and MIDI_TIME_CODE. The - * latter two work if the sequencer receives MIDI messages from - * another device. In these two modes, the sequencer's time gets reset - * based on system real-time timing clock messages or MIDI time code - * (MTC) messages, respectively. These two modes can also be used - * as slave modes, in which case the sequencer sends the corresponding - * types of MIDI messages to its receiver (whether or not the sequencer - * is also receiving them from a master). A fourth mode, - * NO_SYNC, is used to indicate that the sequencer should - * not control its receiver's timing. + * There are three predefined modes that specify possible masters for a + * sequencer: {@code INTERNAL_CLOCK}, {@code MIDI_SYNC}, and + * {@code MIDI_TIME_CODE}. The latter two work if the sequencer receives + * MIDI messages from another device. In these two modes, the sequencer's + * time gets reset based on system real-time timing clock messages or MIDI + * time code (MTC) messages, respectively. These two modes can also be used + * as slave modes, in which case the sequencer sends the corresponding types + * of MIDI messages to its receiver (whether or not the sequencer is also + * receiving them from a master). A fourth mode, {@code NO_SYNC}, is used to + * indicate that the sequencer should not control its receiver's timing. * - * @see Sequencer#setMasterSyncMode(Sequencer.SyncMode) - * @see Sequencer#setSlaveSyncMode(Sequencer.SyncMode) + * @see Sequencer#setMasterSyncMode(SyncMode) + * @see Sequencer#setSlaveSyncMode(SyncMode) */ - public static class SyncMode { + class SyncMode { /** * Synchronization mode name. @@ -779,27 +684,27 @@ public interface Sequencer extends MidiDevice { /** * Constructs a synchronization mode. - * @param name name of the synchronization mode + * + * @param name name of the synchronization mode */ protected SyncMode(String name) { this.name = name; } - /** - * Determines whether two objects are equal. - * Returns true if the objects are identical - * @param obj the reference object with which to compare - * @return true if this object is the same as the - * obj argument, false otherwise + * Determines whether two objects are equal. Returns {@code true} if the + * objects are identical. + * + * @param obj the reference object with which to compare + * @return {@code true} if this object is the same as the {@code obj} + * argument, {@code false} otherwise */ public final boolean equals(Object obj) { return super.equals(obj); } - /** * Finalizes the hashcode method. */ @@ -808,10 +713,10 @@ public interface Sequencer extends MidiDevice { return super.hashCode(); } - /** * Provides this synchronization mode's name as the string * representation of the mode. + * * @return the name of this synchronization mode */ public final String toString() { @@ -819,50 +724,41 @@ public interface Sequencer extends MidiDevice { return name; } - /** - * A master synchronization mode that makes the sequencer get - * its timing information from its internal clock. This is not - * a legal slave sync mode. + * A master synchronization mode that makes the sequencer get its timing + * information from its internal clock. This is not a legal slave sync + * mode. */ public static final SyncMode INTERNAL_CLOCK = new SyncMode("Internal Clock"); - /** - * A master or slave synchronization mode that specifies the - * use of MIDI clock - * messages. If this mode is used as the master sync mode, - * the sequencer gets its timing information from system real-time - * MIDI clock messages. This mode only applies as the master sync - * mode for sequencers that are also MIDI receivers. If this is the - * slave sync mode, the sequencer sends system real-time MIDI clock - * messages to its receiver. MIDI clock messages are sent at a rate - * of 24 per quarter note. + * A master or slave synchronization mode that specifies the use of MIDI + * clock messages. If this mode is used as the master sync mode, the + * sequencer gets its timing information from system real-time MIDI + * clock messages. This mode only applies as the master sync mode for + * sequencers that are also MIDI receivers. If this is the slave sync + * mode, the sequencer sends system real-time MIDI clock messages to its + * receiver. MIDI clock messages are sent at a rate of 24 per quarter + * note. */ public static final SyncMode MIDI_SYNC = new SyncMode("MIDI Sync"); - /** - * A master or slave synchronization mode that specifies the - * use of MIDI Time Code. - * If this mode is used as the master sync mode, - * the sequencer gets its timing information from MIDI Time Code - * messages. This mode only applies as the master sync - * mode to sequencers that are also MIDI receivers. If this - * mode is used as the - * slave sync mode, the sequencer sends MIDI Time Code - * messages to its receiver. (See the MIDI 1.0 Detailed - * Specification for a description of MIDI Time Code.) + * A master or slave synchronization mode that specifies the use of MIDI + * Time Code. If this mode is used as the master sync mode, the + * sequencer gets its timing information from MIDI Time Code messages. + * This mode only applies as the master sync mode to sequencers that are + * also MIDI receivers. If this mode is used as the slave sync mode, the + * sequencer sends MIDI Time Code messages to its receiver. (See the + * MIDI 1.0 Detailed Specification for a description of MIDI Time Code.) */ public static final SyncMode MIDI_TIME_CODE = new SyncMode("MIDI Time Code"); - /** * A slave synchronization mode indicating that no timing information - * should be sent to the receiver. This is not a legal master sync - * mode. + * should be sent to the receiver. This is not a legal master sync mode. */ public static final SyncMode NO_SYNC = new SyncMode("No Timing"); - } // class SyncMode + } } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/ShortMessage.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/ShortMessage.java index 02301ca2a49..8dcf92f9552 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/ShortMessage.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/ShortMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -26,156 +26,158 @@ package javax.sound.midi; /** - * A ShortMessage contains a MIDI message that has at most - * two data bytes following its status byte. The types of MIDI message - * that satisfy this criterion are channel voice, channel mode, system common, - * and system real-time--in other words, everything except system exclusive - * and meta-events. The ShortMessage class provides methods - * for getting and setting the contents of the MIDI message. + * A {@code ShortMessage} contains a MIDI message that has at most two data + * bytes following its status byte. The types of MIDI message that satisfy this + * criterion are channel voice, channel mode, system common, and system + * real-time--in other words, everything except system exclusive and + * meta-events. The {@code ShortMessage} class provides methods for getting and + * setting the contents of the MIDI message. *

    - * A number of ShortMessage methods have integer parameters by which - * you specify a MIDI status or data byte. If you know the numeric value, you - * can express it directly. For system common and system real-time messages, - * you can often use the corresponding fields of ShortMessage, such as - * {@link #SYSTEM_RESET SYSTEM_RESET}. For channel messages, - * the upper four bits of the status byte are specified by a command value and - * the lower four bits are specified by a MIDI channel number. To - * convert incoming MIDI data bytes that are in the form of Java's signed bytes, - * you can use the conversion code - * given in the {@link MidiMessage} class description. - * - * @see SysexMessage - * @see MetaMessage + * A number of {@code ShortMessage} methods have integer parameters by which you + * specify a MIDI status or data byte. If you know the numeric value, you can + * express it directly. For system common and system real-time messages, you can + * often use the corresponding fields of {@code ShortMessage}, such as + * {@link #SYSTEM_RESET SYSTEM_RESET}. For channel messages, the upper four bits + * of the status byte are specified by a command value and the lower four bits + * are specified by a MIDI channel number. To convert incoming MIDI data bytes + * that are in the form of Java's signed bytes, you can use the + * conversion code given in the + * {@link MidiMessage} class description. * * @author David Rivas * @author Kara Kytle * @author Florian Bomers + * @see SysexMessage + * @see MetaMessage */ - public class ShortMessage extends MidiMessage { - // Status byte defines - // System common messages /** * Status byte for MIDI Time Code Quarter Frame message (0xF1, or 241). + * * @see MidiMessage#getStatus */ public static final int MIDI_TIME_CODE = 0xF1; // 241 /** * Status byte for Song Position Pointer message (0xF2, or 242). + * * @see MidiMessage#getStatus */ public static final int SONG_POSITION_POINTER = 0xF2; // 242 /** * Status byte for MIDI Song Select message (0xF3, or 243). + * * @see MidiMessage#getStatus */ public static final int SONG_SELECT = 0xF3; // 243 /** * Status byte for Tune Request message (0xF6, or 246). + * * @see MidiMessage#getStatus */ public static final int TUNE_REQUEST = 0xF6; // 246 /** * Status byte for End of System Exclusive message (0xF7, or 247). + * * @see MidiMessage#getStatus */ public static final int END_OF_EXCLUSIVE = 0xF7; // 247 - // System real-time messages /** * Status byte for Timing Clock message (0xF8, or 248). + * * @see MidiMessage#getStatus */ public static final int TIMING_CLOCK = 0xF8; // 248 /** * Status byte for Start message (0xFA, or 250). + * * @see MidiMessage#getStatus */ public static final int START = 0xFA; // 250 /** * Status byte for Continue message (0xFB, or 251). + * * @see MidiMessage#getStatus */ public static final int CONTINUE = 0xFB; // 251 /** * Status byte for Stop message (0xFC, or 252). + * * @see MidiMessage#getStatus */ public static final int STOP = 0xFC; //252 /** * Status byte for Active Sensing message (0xFE, or 254). + * * @see MidiMessage#getStatus */ public static final int ACTIVE_SENSING = 0xFE; // 254 /** * Status byte for System Reset message (0xFF, or 255). + * * @see MidiMessage#getStatus */ public static final int SYSTEM_RESET = 0xFF; // 255 - // Channel voice message upper nibble defines /** - * Command value for Note Off message (0x80, or 128) + * Command value for Note Off message (0x80, or 128). */ public static final int NOTE_OFF = 0x80; // 128 /** - * Command value for Note On message (0x90, or 144) + * Command value for Note On message (0x90, or 144). */ public static final int NOTE_ON = 0x90; // 144 /** - * Command value for Polyphonic Key Pressure (Aftertouch) message (0xA0, or 160) + * Command value for Polyphonic Key Pressure (Aftertouch) message (0xA0, or + * 160). */ public static final int POLY_PRESSURE = 0xA0; // 160 /** - * Command value for Control Change message (0xB0, or 176) + * Command value for Control Change message (0xB0, or 176). */ public static final int CONTROL_CHANGE = 0xB0; // 176 /** - * Command value for Program Change message (0xC0, or 192) + * Command value for Program Change message (0xC0, or 192). */ public static final int PROGRAM_CHANGE = 0xC0; // 192 /** - * Command value for Channel Pressure (Aftertouch) message (0xD0, or 208) + * Command value for Channel Pressure (Aftertouch) message (0xD0, or 208). */ public static final int CHANNEL_PRESSURE = 0xD0; // 208 /** - * Command value for Pitch Bend message (0xE0, or 224) + * Command value for Pitch Bend message (0xE0, or 224). */ public static final int PITCH_BEND = 0xE0; // 224 - - // Instance variables - /** - * Constructs a new ShortMessage. The - * contents of the new message are guaranteed to specify - * a valid MIDI message. Subsequently, you may set the - * contents of the message using one of the setMessage - * methods. + * Constructs a new {@code ShortMessage}. The contents of the new message + * are guaranteed to specify a valid MIDI message. Subsequently, you may set + * the contents of the message using one of the {@code setMessage} methods. + * * @see #setMessage */ public ShortMessage() { @@ -188,14 +190,13 @@ public class ShortMessage extends MidiMessage { } /** - * Constructs a new {@code ShortMessage} which represents a MIDI - * message that takes no data bytes. - * The contents of the message can be changed by using one of - * the {@code setMessage} methods. + * Constructs a new {@code ShortMessage} which represents a MIDI message + * that takes no data bytes. The contents of the message can be changed by + * using one of the {@code setMessage} methods. * - * @param status the MIDI status byte - * @throws InvalidMidiDataException if {@code status} does not specify - * a valid MIDI status byte for a message that requires no data bytes + * @param status the MIDI status byte + * @throws InvalidMidiDataException if {@code status} does not specify a + * valid MIDI status byte for a message that requires no data bytes * @see #setMessage(int) * @see #setMessage(int, int, int) * @see #setMessage(int, int, int, int) @@ -210,16 +211,15 @@ public class ShortMessage extends MidiMessage { /** * Constructs a new {@code ShortMessage} which represents a MIDI message * that takes up to two data bytes. If the message only takes one data byte, - * the second data byte is ignored. If the message does not take - * any data bytes, both data bytes are ignored. - * The contents of the message can be changed by using one of - * the {@code setMessage} methods. + * the second data byte is ignored. If the message does not take any data + * bytes, both data bytes are ignored. The contents of the message can be + * changed by using one of the {@code setMessage} methods. * - * @param status the MIDI status byte - * @param data1 the first data byte - * @param data2 the second data byte + * @param status the MIDI status byte + * @param data1 the first data byte + * @param data2 the second data byte * @throws InvalidMidiDataException if the status byte or all data bytes - * belonging to the message do not specify a valid MIDI message + * belonging to the message do not specify a valid MIDI message * @see #setMessage(int) * @see #setMessage(int, int, int) * @see #setMessage(int, int, int, int) @@ -235,20 +235,19 @@ public class ShortMessage extends MidiMessage { } /** - * Constructs a new {@code ShortMessage} which represents a channel - * MIDI message that takes up to two data bytes. If the message only takes - * one data byte, the second data byte is ignored. If the message does not - * take any data bytes, both data bytes are ignored. - * The contents of the message can be changed by using one of - * the {@code setMessage} methods. + * Constructs a new {@code ShortMessage} which represents a channel MIDI + * message that takes up to two data bytes. If the message only takes one + * data byte, the second data byte is ignored. If the message does not take + * any data bytes, both data bytes are ignored. The contents of the message + * can be changed by using one of the {@code setMessage} methods. * - * @param command the MIDI command represented by this message - * @param channel the channel associated with the message - * @param data1 the first data byte - * @param data2 the second data byte - * @throws InvalidMidiDataException if the command value, channel value - * or all data bytes belonging to the message do not specify - * a valid MIDI message + * @param command the MIDI command represented by this message + * @param channel the channel associated with the message + * @param data1 the first data byte + * @param data2 the second data byte + * @throws InvalidMidiDataException if the command value, channel value or + * all data bytes belonging to the message do not specify a valid + * MIDI message * @see #setMessage(int) * @see #setMessage(int, int, int) * @see #setMessage(int, int, int, int) @@ -264,12 +263,11 @@ public class ShortMessage extends MidiMessage { setMessage(command, channel, data1, data2); } - /** - * Constructs a new ShortMessage. - * @param data an array of bytes containing the complete message. - * The message data may be changed using the setMessage - * method. + * Constructs a new {@code ShortMessage}. + * + * @param data an array of bytes containing the complete message. The + * message data may be changed using the {@code setMessage} method. * @see #setMessage */ // $$fb this should throw an Exception in case of an illegal message! @@ -279,12 +277,12 @@ public class ShortMessage extends MidiMessage { super(data); } - /** * Sets the parameters for a MIDI message that takes no data bytes. - * @param status the MIDI status byte - * @throws InvalidMidiDataException if status does not - * specify a valid MIDI status byte for a message that requires no data bytes. + * + * @param status the MIDI status byte + * @throws InvalidMidiDataException if {@code status} does not specify a + * valid MIDI status byte for a message that requires no data bytes * @see #setMessage(int, int, int) * @see #setMessage(int, int, int, int) */ @@ -297,19 +295,17 @@ public class ShortMessage extends MidiMessage { setMessage(status, 0, 0); } - /** - * Sets the parameters for a MIDI message that takes one or two data - * bytes. If the message takes only one data byte, the second data - * byte is ignored; if the message does not take any data bytes, both - * data bytes are ignored. + * Sets the parameters for a MIDI message that takes one or two data bytes. + * If the message takes only one data byte, the second data byte is ignored; + * if the message does not take any data bytes, both data bytes are ignored. * - * @param status the MIDI status byte - * @param data1 the first data byte - * @param data2 the second data byte - * @throws InvalidMidiDataException if the - * the status byte, or all data bytes belonging to the message, do - * not specify a valid MIDI message. + * @param status the MIDI status byte + * @param data1 the first data byte + * @param data2 the second data byte + * @throws InvalidMidiDataException if the the status byte, or all data + * bytes belonging to the message, do not specify a valid MIDI + * message * @see #setMessage(int, int, int, int) * @see #setMessage(int) */ @@ -345,22 +341,18 @@ public class ShortMessage extends MidiMessage { } } - /** - * Sets the short message parameters for a channel message - * which takes up to two data bytes. If the message only - * takes one data byte, the second data byte is ignored; if - * the message does not take any data bytes, both data bytes - * are ignored. - * - * @param command the MIDI command represented by this message - * @param channel the channel associated with the message - * @param data1 the first data byte - * @param data2 the second data byte - * @throws InvalidMidiDataException if the - * status byte or all data bytes belonging to the message, do - * not specify a valid MIDI message + * Sets the short message parameters for a channel message which takes up to + * two data bytes. If the message only takes one data byte, the second data + * byte is ignored; if the message does not take any data bytes, both data + * bytes are ignored. * + * @param command the MIDI command represented by this message + * @param channel the channel associated with the message + * @param data1 the first data byte + * @param data2 the second data byte + * @throws InvalidMidiDataException if the status byte or all data bytes + * belonging to the message, do not specify a valid MIDI message * @see #setMessage(int, int, int) * @see #setMessage(int) * @see #getCommand @@ -379,12 +371,12 @@ public class ShortMessage extends MidiMessage { setMessage((command & 0xF0) | (channel & 0x0F), data1, data2); } - /** - * Obtains the MIDI channel associated with this event. This method - * assumes that the event is a MIDI channel message; if not, the return - * value will not be meaningful. - * @return MIDI channel associated with the message. + * Obtains the MIDI channel associated with this event. This method assumes + * that the event is a MIDI channel message; if not, the return value will + * not be meaningful. + * + * @return MIDI channel associated with the message * @see #setMessage(int, int, int, int) */ public int getChannel() { @@ -392,11 +384,11 @@ public class ShortMessage extends MidiMessage { return (getStatus() & 0x0F); } - /** - * Obtains the MIDI command associated with this event. This method - * assumes that the event is a MIDI channel message; if not, the return - * value will not be meaningful. + * Obtains the MIDI command associated with this event. This method assumes + * that the event is a MIDI channel message; if not, the return value will + * not be meaningful. + * * @return the MIDI command associated with this event * @see #setMessage(int, int, int, int) */ @@ -405,10 +397,10 @@ public class ShortMessage extends MidiMessage { return (getStatus() & 0xF0); } - /** * Obtains the first data byte in the message. - * @return the value of the data1 field + * + * @return the value of the {@code data1} field * @see #setMessage(int, int, int) */ public int getData1() { @@ -418,10 +410,10 @@ public class ShortMessage extends MidiMessage { return 0; } - /** * Obtains the second data byte in the message. - * @return the value of the data2 field + * + * @return the value of the {@code data2} field * @see #setMessage(int, int, int) */ public int getData2() { @@ -431,11 +423,11 @@ public class ShortMessage extends MidiMessage { return 0; } - /** - * Creates a new object of the same class and with the same contents - * as this object. - * @return a clone of this instance. + * Creates a new object of the same class and with the same contents as this + * object. + * + * @return a clone of this instance */ public Object clone() { byte[] newData = new byte[length]; @@ -445,15 +437,15 @@ public class ShortMessage extends MidiMessage { return msg; } - /** - * Retrieves the number of data bytes associated with a particular - * status byte value. - * @param status status byte value, which must represent a short MIDI message + * Retrieves the number of data bytes associated with a particular status + * byte value. + * + * @param status status byte value, which must represent a short MIDI + * message * @return data length in bytes (0, 1, or 2) - * @throws InvalidMidiDataException if the - * status argument does not represent the status byte for any - * short message + * @throws InvalidMidiDataException if the {@code status} argument does not + * represent the status byte for any short message */ protected final int getDataLength(int status) throws InvalidMidiDataException { // system common and system real-time messages diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/Soundbank.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/Soundbank.java index 7aba05711c9..727365ea442 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/Soundbank.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/Soundbank.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -25,109 +25,101 @@ package javax.sound.midi; -import java.net.URL; - - /** - * A Soundbank contains a set of Instruments - * that can be loaded into a Synthesizer. - * Note that a Java Sound Soundbank is different from a MIDI bank. - * MIDI permits up to 16383 banks, each containing up to 128 instruments - * (also sometimes called programs, patches, or timbres). - * However, a Soundbank can contain 16383 times 128 instruments, - * because the instruments within a Soundbank are indexed by both - * a MIDI program number and a MIDI bank number (via a Patch - * object). Thus, a Soundbank can be thought of as a collection - * of MIDI banks. + * A {@code Soundbank} contains a set of {@code Instruments} that can be loaded + * into a {@code Synthesizer}. Note that a Java Sound {@code Soundbank} is + * different from a MIDI bank. MIDI permits up to 16383 banks, each containing + * up to 128 instruments (also sometimes called programs, patches, or timbres). + * However, a {@code Soundbank} can contain 16383 times 128 instruments, because + * the instruments within a {@code Soundbank} are indexed by both a MIDI program + * number and a MIDI bank number (via a {@code Patch} object). Thus, a + * {@code Soundbank} can be thought of as a collection of MIDI banks. *

    - * Soundbank includes methods that return String - * objects containing the sound bank's name, manufacturer, version number, and - * description. The precise content and format of these strings is left - * to the implementor. + * {@code Soundbank} includes methods that return {@code String} objects + * containing the sound bank's name, manufacturer, version number, and + * description. The precise content and format of these strings is left to the + * implementor. *

    - * Different synthesizers use a variety of synthesis techniques. A common - * one is wavetable synthesis, in which a segment of recorded sound is - * played back, often with looping and pitch change. The Downloadable Sound - * (DLS) format uses segments of recorded sound, as does the Headspace Engine. - * Soundbanks and Instruments that are based on - * wavetable synthesis (or other uses of stored sound recordings) should - * typically implement the getResources() - * method to provide access to these recorded segments. This is optional, - * however; the method can return an zero-length array if the synthesis technique - * doesn't use sampled sound (FM synthesis and physical modeling are examples - * of such techniques), or if it does but the implementor chooses not to make the - * samples accessible. + * Different synthesizers use a variety of synthesis techniques. A common one is + * wavetable synthesis, in which a segment of recorded sound is played back, + * often with looping and pitch change. The Downloadable Sound (DLS) format uses + * segments of recorded sound, as does the Headspace Engine. {@code Soundbanks} + * and {@code Instruments} that are based on wavetable synthesis (or other uses + * of stored sound recordings) should typically implement the + * {@code getResources()} method to provide access to these recorded segments. + * This is optional, however; the method can return an zero-length array if the + * synthesis technique doesn't use sampled sound (FM synthesis and physical + * modeling are examples of such techniques), or if it does but the implementor + * chooses not to make the samples accessible. * + * @author David Rivas + * @author Kara Kytle * @see Synthesizer#getDefaultSoundbank * @see Synthesizer#isSoundbankSupported * @see Synthesizer#loadInstruments(Soundbank, Patch[]) * @see Patch * @see Instrument * @see SoundbankResource - * - * @author David Rivas - * @author Kara Kytle */ - public interface Soundbank { - /** * Obtains the name of the sound bank. - * @return a String naming the sound bank + * + * @return a {@code String} naming the sound bank */ - public String getName(); + String getName(); /** * Obtains the version string for the sound bank. - * @return a String that indicates the sound bank's version + * + * @return a {@code String} that indicates the sound bank's version */ - public String getVersion(); + String getVersion(); /** - * Obtains a string naming the company that provides the - * sound bank + * Obtains a {@code string} naming the company that provides the sound bank. + * * @return the vendor string */ - public String getVendor(); + String getVendor(); /** * Obtains a textual description of the sound bank, suitable for display. - * @return a String that describes the sound bank + * + * @return a {@code String} that describes the sound bank */ - public String getDescription(); - + String getDescription(); /** * Extracts a list of non-Instrument resources contained in the sound bank. - * @return an array of resources, excluding instruments. If the sound bank contains - * no resources (other than instruments), returns an array of length 0. + * + * @return an array of resources, excluding instruments. If the sound bank + * contains no resources (other than instruments), returns an array + * of length 0. */ - public SoundbankResource[] getResources(); - + SoundbankResource[] getResources(); /** * Obtains a list of instruments contained in this sound bank. - * @return an array of the Instruments in this - * SoundBank - * If the sound bank contains no instruments, returns an array of length 0. * + * @return an array of the {@code Instruments} in this {@code SoundBank}. If + * the sound bank contains no instruments, returns an array of + * length 0. * @see Synthesizer#getLoadedInstruments * @see #getInstrument(Patch) */ - public Instrument[] getInstruments(); + Instrument[] getInstruments(); /** - * Obtains an Instrument from the given Patch. - * @param patch a Patch object specifying the bank index - * and program change number - * @return the requested instrument, or null if the - * sound bank doesn't contain that instrument + * Obtains an {@code Instrument} from the given {@code Patch}. * + * @param patch a {@code Patch} object specifying the bank index and + * program change number + * @return the requested instrument, or {@code null} if the sound bank + * doesn't contain that instrument * @see #getInstruments * @see Synthesizer#loadInstruments(Soundbank, Patch[]) */ - public Instrument getInstrument(Patch patch); - - + Instrument getInstrument(Patch patch); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/SoundbankResource.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/SoundbankResource.java index 52ba8f78feb..8ac530105eb 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/SoundbankResource.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/SoundbankResource.java @@ -25,81 +25,72 @@ package javax.sound.midi; +import javax.sound.sampled.AudioInputStream; + /** - * A SoundbankResource represents any audio resource stored - * in a {@link Soundbank}. Common soundbank resources include: + * A {@code SoundbankResource} represents any audio resource stored in a + * {@link Soundbank}. Common soundbank resources include: *

      - *
    • Instruments. An instrument may be specified in a variety of - * ways. However, all soundbanks have some mechanism for defining - * instruments. In doing so, they may reference other resources - * stored in the soundbank. Each instrument has a Patch - * which specifies the MIDI program and bank by which it may be - * referenced in MIDI messages. Instrument information may be - * stored in {@link Instrument} objects. - *
    • Audio samples. A sample typically is a sampled audio waveform - * which contains a short sound recording whose duration is a fraction of - * a second, or at most a few seconds. These audio samples may be - * used by a {@link Synthesizer} to synthesize sound in response to MIDI - * commands, or extracted for use by an application. - * (The terminology reflects musicians' use of the word "sample" to refer - * collectively to a series of contiguous audio samples or frames, rather than - * to a single, instantaneous sample.) - * The data class for an audio sample will be an object - * that encapsulates the audio sample data itself and information - * about how to interpret it (the format of the audio data), such - * as an {@link javax.sound.sampled.AudioInputStream}.
    • - *
    • Embedded sequences. A sound bank may contain built-in - * song data stored in a data object such as a {@link Sequence}. + *
    • Instruments. An instrument may be specified in a variety of ways. + * However, all soundbanks have some mechanism for defining instruments. In + * doing so, they may reference other resources stored in the soundbank. Each + * instrument has a {@code Patch} which specifies the MIDI program and bank by + * which it may be referenced in MIDI messages. Instrument information may be + * stored in {@link Instrument} objects.
    • + *
    • Audio samples. A sample typically is a sampled audio waveform which + * contains a short sound recording whose duration is a fraction of a second, or + * at most a few seconds. These audio samples may be used by a + * {@link Synthesizer} to synthesize sound in response to MIDI commands, or + * extracted for use by an application. (The terminology reflects musicians' use + * of the word "sample" to refer collectively to a series of contiguous audio + * samples or frames, rather than to a single, instantaneous sample.) The data + * class for an audio sample will be an object that encapsulates the audio + * sample data itself and information about how to interpret it (the format of + * the audio data), such as an {@link AudioInputStream}.
    • + *
    • Embedded sequences. A sound bank may contain built-in song data stored in + * a data object such as a {@link Sequence}.
    • *
    - *

    - * Synthesizers that use wavetable synthesis or related - * techniques play back the audio in a sample when - * synthesizing notes, often when emulating the real-world instrument that - * was originally recorded. However, there is not necessarily a one-to-one - * correspondence between the Instruments and samples - * in a Soundbank. A single Instrument can use - * multiple SoundbankResources (typically for notes of dissimilar pitch or - * brightness). Also, more than one Instrument can use the same - * sample. + * Synthesizers that use wavetable synthesis or related techniques play back the + * audio in a sample when synthesizing notes, often when emulating the + * real-world instrument that was originally recorded. However, there is not + * necessarily a one-to-one correspondence between the {@code Instruments} and + * samples in a {@code Soundbank}. A single {@code Instrument} can use multiple + * SoundbankResources (typically for notes of dissimilar pitch or brightness). + * Also, more than one {@code Instrument} can use the same sample. * * @author Kara Kytle */ - public abstract class SoundbankResource { - /** - * The sound bank that contains the SoundbankResources + * The sound bank that contains the {@code SoundbankResources}. */ private final Soundbank soundBank; - /** - * The name of the SoundbankResource + * The name of the {@code SoundbankResource}. */ private final String name; - /** * The class used to represent the sample's data. */ private final Class dataClass; - /** * The wavetable index. */ //private final int index; - /** - * Constructs a new SoundbankResource from the given sound bank - * and wavetable index. (Setting the SoundbankResource's name, - * sampled audio data, and instruments is a subclass responsibility.) - * @param soundBank the sound bank containing this SoundbankResource - * @param name the name of the sample - * @param dataClass the class used to represent the sample's data + * Constructs a new {@code SoundbankResource} from the given sound bank and + * wavetable index. (Setting the {@code SoundbankResource's} name, sampled + * audio data, and instruments is a subclass responsibility.) * + * @param soundBank the sound bank containing this + * {@code SoundbankResource} + * @param name the name of the sample + * @param dataClass the class used to represent the sample's data * @see #getSoundbank * @see #getName * @see #getDataClass @@ -112,65 +103,65 @@ public abstract class SoundbankResource { this.dataClass = dataClass; } - /** - * Obtains the sound bank that contains this SoundbankResource. - * @return the sound bank in which this SoundbankResource is stored + * Obtains the sound bank that contains this {@code SoundbankResource}. + * + * @return the sound bank in which this {@code SoundbankResource} is stored */ public Soundbank getSoundbank() { return soundBank; } - /** - * Obtains the name of the resource. This should generally be a string + * Obtains the name of the resource. This should generally be a string * descriptive of the resource. + * * @return the instrument's name */ public String getName() { return name; } - /** - * Obtains the class used by this sample to represent its data. - * The object returned by getData will be of this - * class. If this SoundbankResource object does not support - * direct access to its data, returns null. - * @return the class used to represent the sample's data, or - * null if the data is not accessible + * Obtains the class used by this sample to represent its data. The object + * returned by {@code getData} will be of this class. If this + * {@code SoundbankResource} object does not support direct access to its + * data, returns {@code null}. + * + * @return the class used to represent the sample's data, or null if the + * data is not accessible */ public Class getDataClass() { return dataClass; } - /** - * Obtains the sampled audio that is stored in this SoundbankResource. - * The type of object returned depends on the implementation of the - * concrete class, and may be queried using getDataClass. + * Obtains the sampled audio that is stored in this + * {@code SoundbankResource}. The type of object returned depends on the + * implementation of the concrete class, and may be queried using + * {@code getDataClass}. + * * @return an object containing the sampled audio data * @see #getDataClass */ public abstract Object getData(); - /** - * Obtains the index of this SoundbankResource into the - * Soundbank's set of SoundbankResources. + * Obtains the index of this {@code SoundbankResource} into the + * {@code Soundbank's} set of {@code SoundbankResources}. + * * @return the wavetable index */ //public int getIndex() { // return index; //} - /** * Obtains a list of the instruments in the sound bank that use the - * SoundbankResource for sound synthesis. - * @return an array of Instruments that reference this - * SoundbankResource + * {@code SoundbankResource} for sound synthesis. * + * @return an array of {@code Instruments} that reference this + * {@code SoundbankResource} * @see Instrument#getSamples */ //public abstract Instrument[] getInstruments(); diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/Synthesizer.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/Synthesizer.java index 6763a969504..3d8c7a64d23 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/Synthesizer.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/Synthesizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, 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 @@ -25,46 +25,43 @@ package javax.sound.midi; -import javax.sound.sampled.Control; - - /** - * A Synthesizer generates sound. This usually happens when one of - * the Synthesizer's {@link MidiChannel} objects receives a - * {@link MidiChannel#noteOn(int, int) noteOn} message, either - * directly or via the Synthesizer object. - * Many Synthesizers support Receivers, through which - * MIDI events can be delivered to the Synthesizer. - * In such cases, the Synthesizer typically responds by sending - * a corresponding message to the appropriate MidiChannel, or by - * processing the event itself if the event isn't one of the MIDI channel - * messages. + * A {@code Synthesizer} generates sound. This usually happens when one of the + * {@code Synthesizer}'s {@link MidiChannel} objects receives a + * {@link MidiChannel#noteOn(int, int) noteOn} message, either directly or via + * the {@code Synthesizer} object. Many {@code Synthesizer}s support + * {@code Receivers}, through which MIDI events can be delivered to the + * {@code Synthesizer}. In such cases, the {@code Synthesizer} typically + * responds by sending a corresponding message to the appropriate + * {@code MidiChannel}, or by processing the event itself if the event isn't one + * of the MIDI channel messages. *

    - * The Synthesizer interface includes methods for loading and - * unloading instruments from soundbanks. An instrument is a specification for synthesizing a - * certain type of sound, whether that sound emulates a traditional instrument or is - * some kind of sound effect or other imaginary sound. A soundbank is a collection of instruments, organized - * by bank and program number (via the instrument's Patch object). - * Different Synthesizer classes might implement different sound-synthesis - * techniques, meaning that some instruments and not others might be compatible with a - * given synthesizer. - * Also, synthesizers may have a limited amount of memory for instruments, meaning - * that not every soundbank and instrument can be used by every synthesizer, even if - * the synthesis technique is compatible. - * To see whether the instruments from - * a certain soundbank can be played by a given synthesizer, invoke the - * {@link #isSoundbankSupported(Soundbank) isSoundbankSupported} method of - * Synthesizer. + * The {@code Synthesizer} interface includes methods for loading and unloading + * instruments from soundbanks. An instrument is a specification for + * synthesizing a certain type of sound, whether that sound emulates a + * traditional instrument or is some kind of sound effect or other imaginary + * sound. A soundbank is a collection of instruments, organized by bank and + * program number (via the instrument's {@code Patch} object). Different + * {@code Synthesizer} classes might implement different sound-synthesis + * techniques, meaning that some instruments and not others might be compatible + * with a given synthesizer. Also, synthesizers may have a limited amount of + * memory for instruments, meaning that not every soundbank and instrument can + * be used by every synthesizer, even if the synthesis technique is compatible. + * To see whether the instruments from a certain soundbank can be played by a + * given synthesizer, invoke the + * {@link #isSoundbankSupported(Soundbank) isSoundbankSupported} + * method of {@code Synthesizer}. *

    * "Loading" an instrument means that that instrument becomes available for - * synthesizing notes. The instrument is loaded into the bank and - * program location specified by its Patch object. Loading does - * not necessarily mean that subsequently played notes will immediately have - * the sound of this newly loaded instrument. For the instrument to play notes, - * one of the synthesizer's MidiChannel objects must receive (or have received) - * a program-change message that causes that particular instrument's - * bank and program number to be selected. + * synthesizing notes. The instrument is loaded into the bank and program + * location specified by its {@code Patch} object. Loading does not necessarily + * mean that subsequently played notes will immediately have the sound of this + * newly loaded instrument. For the instrument to play notes, one of the + * synthesizer's {@code MidiChannel} objects must receive (or have received) a + * program-change message that causes that particular instrument's bank and + * program number to be selected. * + * @author Kara Kytle * @see MidiSystem#getSynthesizer * @see Soundbank * @see Instrument @@ -72,107 +69,103 @@ import javax.sound.sampled.Control; * @see Receiver * @see Transmitter * @see MidiDevice - * - * @author Kara Kytle */ public interface Synthesizer extends MidiDevice { - // SYNTHESIZER METHODS - /** - * Obtains the maximum number of notes that this synthesizer can sound simultaneously. + * Obtains the maximum number of notes that this synthesizer can sound + * simultaneously. + * * @return the maximum number of simultaneous notes * @see #getVoiceStatus */ - public int getMaxPolyphony(); - + int getMaxPolyphony(); /** * Obtains the processing latency incurred by this synthesizer, expressed in - * microseconds. This latency measures the worst-case delay between the - * time a MIDI message is delivered to the synthesizer and the time that the + * microseconds. This latency measures the worst-case delay between the time + * a MIDI message is delivered to the synthesizer and the time that the * synthesizer actually produces the corresponding result. *

    - * Although the latency is expressed in microseconds, a synthesizer's actual measured - * delay may vary over a wider range than this resolution suggests. For example, - * a synthesizer might have a worst-case delay of a few milliseconds or more. + * Although the latency is expressed in microseconds, a synthesizer's actual + * measured delay may vary over a wider range than this resolution suggests. + * For example, a synthesizer might have a worst-case delay of a few + * milliseconds or more. * * @return the worst-case delay, in microseconds */ - public long getLatency(); - + long getLatency(); /** - * Obtains the set of MIDI channels controlled by this synthesizer. Each - * non-null element in the returned array is a MidiChannel that + * Obtains the set of MIDI channels controlled by this synthesizer. Each + * non-null element in the returned array is a {@code MidiChannel} that * receives the MIDI messages sent on that channel number. *

    - * The MIDI 1.0 specification provides for 16 channels, so this - * method returns an array of at least 16 elements. However, if this synthesizer + * The MIDI 1.0 specification provides for 16 channels, so this method + * returns an array of at least 16 elements. However, if this synthesizer * doesn't make use of all 16 channels, some of the elements of the array - * might be null, so you should check each element - * before using it. - * @return an array of the MidiChannel objects managed by this - * Synthesizer. Some of the array elements may be null. + * might be {@code null}, so you should check each element before using it. + * + * @return an array of the {@code MidiChannel} objects managed by this + * {@code Synthesizer}. Some of the array elements may be + * {@code null}. */ - public MidiChannel[] getChannels(); - + MidiChannel[] getChannels(); /** - * Obtains the current status of the voices produced by this synthesizer. - * If this class of Synthesizer does not provide voice - * information, the returned array will always be of length 0. Otherwise, - * its length is always equal to the total number of voices, as returned by - * getMaxPolyphony(). (See the VoiceStatus class - * description for an explanation of synthesizer voices.) + * Obtains the current status of the voices produced by this synthesizer. If + * this class of {@code Synthesizer} does not provide voice information, the + * returned array will always be of length 0. Otherwise, its length is + * always equal to the total number of voices, as returned by + * {@code getMaxPolyphony()}. (See the {@code VoiceStatus} class description + * for an explanation of synthesizer voices.) * - * @return an array of VoiceStatus objects that supply - * information about the corresponding synthesizer voices + * @return an array of {@code VoiceStatus} objects that supply information + * about the corresponding synthesizer voices * @see #getMaxPolyphony * @see VoiceStatus */ - public VoiceStatus[] getVoiceStatus(); - + VoiceStatus[] getVoiceStatus(); /** * Informs the caller whether this synthesizer is capable of loading - * instruments from the specified soundbank. - * If the soundbank is unsupported, any attempts to load instruments from - * it will result in an IllegalArgumentException. - * @param soundbank soundbank for which support is queried - * @return true if the soundbank is supported, otherwise false + * instruments from the specified soundbank. If the soundbank is + * unsupported, any attempts to load instruments from it will result in an + * {@code IllegalArgumentException}. + * + * @param soundbank soundbank for which support is queried + * @return {@code true} if the soundbank is supported, otherwise + * {@code false} * @see #loadInstruments * @see #loadAllInstruments * @see #unloadInstruments * @see #unloadAllInstruments * @see #getDefaultSoundbank */ - public boolean isSoundbankSupported(Soundbank soundbank); - + boolean isSoundbankSupported(Soundbank soundbank); /** - * Makes a particular instrument available for synthesis. This instrument - * is loaded into the patch location specified by its Patch - * object, so that if a program-change message is - * received (or has been received) that causes that patch to be selected, - * subsequent notes will be played using the sound of - * instrument. If the specified instrument is already loaded, - * this method does nothing and returns true. + * Makes a particular instrument available for synthesis. This instrument is + * loaded into the patch location specified by its {@code Patch} object, so + * that if a program-change message is received (or has been received) that + * causes that patch to be selected, subsequent notes will be played using + * the sound of {@code instrument}. If the specified instrument is already + * loaded, this method does nothing and returns {@code true}. *

    - * The instrument must be part of a soundbank - * that this Synthesizer supports. (To make sure, you can use - * the getSoundbank method of Instrument and the - * isSoundbankSupported method of Synthesizer.) - * @param instrument instrument to load - * @return true if the instrument is successfully loaded (or - * already had been), false if the instrument could not be - * loaded (for example, if the synthesizer has insufficient - * memory to load it) - * @throws IllegalArgumentException if this - * Synthesizer doesn't support the specified instrument's - * soundbank + * The instrument must be part of a soundbank that this {@code Synthesizer} + * supports. (To make sure, you can use the {@code getSoundbank} method of + * {@code Instrument} and the {@code isSoundbankSupported} method of + * {@code Synthesizer}.) + * + * @param instrument instrument to load + * @return {@code true} if the instrument is successfully loaded (or already + * had been), {@code false} if the instrument could not be loaded + * (for example, if the synthesizer has insufficient memory to load + * it) + * @throws IllegalArgumentException if this {@code Synthesizer} doesn't + * support the specified instrument's soundbank * @see #unloadInstrument * @see #loadInstruments * @see #loadAllInstruments @@ -180,138 +173,139 @@ public interface Synthesizer extends MidiDevice { * @see SoundbankResource#getSoundbank * @see MidiChannel#programChange(int, int) */ - public boolean loadInstrument(Instrument instrument); - + boolean loadInstrument(Instrument instrument); /** * Unloads a particular instrument. - * @param instrument instrument to unload - * @throws IllegalArgumentException if this - * Synthesizer doesn't support the specified instrument's - * soundbank + * + * @param instrument instrument to unload + * @throws IllegalArgumentException if this {@code Synthesizer} doesn't + * support the specified instrument's soundbank * @see #loadInstrument * @see #unloadInstruments * @see #unloadAllInstruments * @see #getLoadedInstruments * @see #remapInstrument */ - public void unloadInstrument(Instrument instrument); - + void unloadInstrument(Instrument instrument); /** - * Remaps an instrument. Instrument to takes the - * place of instrument from.
    - * For example, if from was located at bank number 2, - * program number 11, remapping causes that bank and program location - * to be occupied instead by to.
    - * If the function succeeds, instrument from is unloaded. - *

    To cancel the remapping reload instrument from by - * invoking one of {@link #loadInstrument}, {@link #loadInstruments} - * or {@link #loadAllInstruments}. + * Remaps an instrument. Instrument {@code to} takes the place of instrument + * {@code from}. + *
    + * For example, if {@code from} was located at bank number 2, program number + * 11, remapping causes that bank and program location to be occupied + * instead by {@code to}. + *
    + * If the function succeeds, instrument {@code from} is unloaded. + *

    + * To cancel the remapping reload instrument {@code from} by invoking one of + * {@link #loadInstrument}, {@link #loadInstruments} or + * {@link #loadAllInstruments}. * - * @param from the Instrument object to be replaced - * @param to the Instrument object to be used in place - * of the old instrument, it should be loaded into the synthesizer - * @return true if the instrument successfully remapped, - * false if feature is not implemented by synthesizer - * @throws IllegalArgumentException if instrument - * from or instrument to aren't supported by - * synthesizer or if instrument to is not loaded - * @throws NullPointerException if from or - * to parameters have null value + * @param from the {@code Instrument} object to be replaced + * @param to the {@code Instrument} object to be used in place of the old + * instrument, it should be loaded into the synthesizer + * @return {@code true} if the instrument successfully remapped, + * {@code false} if feature is not implemented by synthesizer + * @throws IllegalArgumentException if instrument {@code from} or instrument + * {@code to} aren't supported by synthesizer or if instrument + * {@code to} is not loaded + * @throws NullPointerException if {@code from} or {@code to} parameters + * have null value * @see #loadInstrument * @see #loadInstruments * @see #loadAllInstruments */ - public boolean remapInstrument(Instrument from, Instrument to); - + boolean remapInstrument(Instrument from, Instrument to); /** - * Obtains the default soundbank for the synthesizer, if one exists. - * (Some synthesizers provide a default or built-in soundbank.) - * If a synthesizer doesn't have a default soundbank, instruments must - * be loaded explicitly from an external soundbank. - * @return default soundbank, or null if one does not exist. + * Obtains the default soundbank for the synthesizer, if one exists. (Some + * synthesizers provide a default or built-in soundbank.) If a synthesizer + * doesn't have a default soundbank, instruments must be loaded explicitly + * from an external soundbank. + * + * @return default soundbank, or {@code null} if one does not exist * @see #isSoundbankSupported */ - public Soundbank getDefaultSoundbank(); - + Soundbank getDefaultSoundbank(); /** - * Obtains a list of instruments that come with the synthesizer. These - * instruments might be built into the synthesizer, or they might be - * part of a default soundbank provided with the synthesizer, etc. + * Obtains a list of instruments that come with the synthesizer. These + * instruments might be built into the synthesizer, or they might be part of + * a default soundbank provided with the synthesizer, etc. *

    - * Note that you don't use this method to find out which instruments are + * Note that you don't use this method to find out which instruments are * currently loaded onto the synthesizer; for that purpose, you use - * getLoadedInstruments(). - * Nor does the method indicate all the instruments that can be loaded onto - * the synthesizer; it only indicates the subset that come with the synthesizer. - * To learn whether another instrument can be loaded, you can invoke - * isSoundbankSupported(), and if the instrument's - * Soundbank is supported, you can try loading the instrument. + * {@code getLoadedInstruments()}. Nor does the method indicate all the + * instruments that can be loaded onto the synthesizer; it only indicates + * the subset that come with the synthesizer. To learn whether another + * instrument can be loaded, you can invoke {@code isSoundbankSupported()}, + * and if the instrument's {@code Soundbank} is supported, you can try + * loading the instrument. * - * @return list of available instruments. If the synthesizer - * has no instruments coming with it, an array of length 0 is returned. + * @return list of available instruments. If the synthesizer has no + * instruments coming with it, an array of length 0 is returned. * @see #getLoadedInstruments * @see #isSoundbankSupported(Soundbank) * @see #loadInstrument */ - public Instrument[] getAvailableInstruments(); - + Instrument[] getAvailableInstruments(); /** * Obtains a list of the instruments that are currently loaded onto this - * Synthesizer. + * {@code Synthesizer}. + * * @return a list of currently loaded instruments * @see #loadInstrument * @see #getAvailableInstruments * @see Soundbank#getInstruments */ - public Instrument[] getLoadedInstruments(); - + Instrument[] getLoadedInstruments(); /** - * Loads onto the Synthesizer all instruments contained - * in the specified Soundbank. - * @param soundbank the Soundbank whose are instruments are - * to be loaded - * @return true if the instruments are all successfully loaded (or - * already had been), false if any instrument could not be - * loaded (for example, if the Synthesizer had insufficient memory) + * Loads onto the {@code Synthesizer} all instruments contained in the + * specified {@code Soundbank}. + * + * @param soundbank the {@code Soundbank} whose are instruments are to be + * loaded + * @return {@code true} if the instruments are all successfully loaded (or + * already had been), {@code false} if any instrument could not be + * loaded (for example, if the {@code Synthesizer} had insufficient + * memory) * @throws IllegalArgumentException if the requested soundbank is - * incompatible with this synthesizer. + * incompatible with this synthesizer * @see #isSoundbankSupported * @see #loadInstrument * @see #loadInstruments */ - public boolean loadAllInstruments(Soundbank soundbank); - - + boolean loadAllInstruments(Soundbank soundbank); /** - * Unloads all instruments contained in the specified Soundbank. - * @param soundbank soundbank containing instruments to unload - * @throws IllegalArgumentException thrown if the soundbank is not supported. + * Unloads all instruments contained in the specified {@code Soundbank}. + * + * @param soundbank soundbank containing instruments to unload + * @throws IllegalArgumentException thrown if the soundbank is not supported * @see #isSoundbankSupported * @see #unloadInstrument * @see #unloadInstruments */ - public void unloadAllInstruments(Soundbank soundbank); - + void unloadAllInstruments(Soundbank soundbank); /** * Loads the instruments referenced by the specified patches, from the - * specified Soundbank. Each of the Patch objects - * indicates a bank and program number; the Instrument that - * has the matching Patch is loaded into that bank and program - * location. - * @param soundbank the Soundbank containing the instruments to load - * @param patchList list of patches for which instruments should be loaded - * @return true if the instruments are all successfully loaded (or - * already had been), false if any instrument could not be - * loaded (for example, if the Synthesizer had insufficient memory) - * @throws IllegalArgumentException thrown if the soundbank is not supported. + * specified {@code Soundbank}. Each of the {@code Patch} objects indicates + * a bank and program number; the {@code Instrument} that has the matching + * {@code Patch} is loaded into that bank and program location. + * + * @param soundbank the {@code Soundbank} containing the instruments to + * load + * @param patchList list of patches for which instruments should be loaded + * @return {@code true} if the instruments are all successfully loaded (or + * already had been), {@code false} if any instrument could not be + * loaded (for example, if the {@code Synthesizer} had insufficient + * memory) + * @throws IllegalArgumentException thrown if the soundbank is not supported * @see #isSoundbankSupported * @see Instrument#getPatch * @see #loadAllInstruments @@ -319,76 +313,76 @@ public interface Synthesizer extends MidiDevice { * @see Soundbank#getInstrument(Patch) * @see Sequence#getPatchList() */ - public boolean loadInstruments(Soundbank soundbank, Patch[] patchList); + boolean loadInstruments(Soundbank soundbank, Patch[] patchList); /** - * Unloads the instruments referenced by the specified patches, from the MIDI sound bank specified. - * @param soundbank soundbank containing instruments to unload - * @param patchList list of patches for which instruments should be unloaded - * @throws IllegalArgumentException thrown if the soundbank is not supported. + * Unloads the instruments referenced by the specified patches, from the + * MIDI sound bank specified. * + * @param soundbank soundbank containing instruments to unload + * @param patchList list of patches for which instruments should be + * unloaded + * @throws IllegalArgumentException thrown if the soundbank is not supported * @see #unloadInstrument * @see #unloadAllInstruments * @see #isSoundbankSupported * @see Instrument#getPatch * @see #loadInstruments */ - public void unloadInstruments(Soundbank soundbank, Patch[] patchList); - + void unloadInstruments(Soundbank soundbank, Patch[] patchList); // RECEIVER METHODS /** * Obtains the name of the receiver. + * * @return receiver name */ - // public abstract String getName(); - + // abstract String getName(); /** * Opens the receiver. + * * @throws MidiUnavailableException if the receiver is cannot be opened, - * usually because the MIDI device is in use by another application. - * @throws SecurityException if the receiver cannot be opened due to security - * restrictions. + * usually because the MIDI device is in use by another application. + * @throws SecurityException if the receiver cannot be opened due to + * security restrictions */ - // public abstract void open() throws MidiUnavailableException, SecurityException; - + // abstract void open() throws MidiUnavailableException, SecurityException; /** * Closes the receiver. */ - // public abstract void close(); - + // abstract void close(); /** * Sends a MIDI event to the receiver. - * @param event event to send. - * @throws IllegalStateException if the receiver is not open. + * + * @param event event to send + * @throws IllegalStateException if the receiver is not open */ - // public void send(MidiEvent event) throws IllegalStateException { + // void send(MidiEvent event) throws IllegalStateException { // // } - /** - * Obtains the set of controls supported by the - * element. If no controls are supported, returns an - * array of length 0. + * Obtains the set of controls supported by the element. If no controls are + * supported, returns an array of length 0. + * * @return set of controls */ // $$kk: 03.04.99: josh bloch recommends getting rid of this: // what can you really do with a set of untyped controls?? - // $$kk: 03.05.99: i am putting this back in. for one thing, + // $$kk: 03.05.99: i am putting this back in. for one thing, // you can check the length and know whether you should keep // looking.... - // public Control[] getControls(); + // Control[] getControls(); /** * Obtains the specified control. - * @param controlClass class of the requested control - * @return requested control object, or null if the - * control is not supported. + * + * @param controlClass class of the requested control + * @return requested control object, or null if the control is not supported */ - // public Control getControl(Class controlClass); + // Control getControl(Class controlClass); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/SysexMessage.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/SysexMessage.java index ae4e418e8e6..8bcd00a9030 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/SysexMessage.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/SysexMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -26,47 +26,47 @@ package javax.sound.midi; /** - * A SysexMessage object represents a MIDI system exclusive message. + * A {@code SysexMessage} object represents a MIDI system exclusive message. *

    - * When a system exclusive message is read from a MIDI file, it always has - * a defined length. Data from a system exclusive message from a MIDI file - * should be stored in the data array of a SysexMessage as - * follows: the system exclusive message status byte (0xF0 or 0xF7), all - * message data bytes, and finally the end-of-exclusive flag (0xF7). - * The length reported by the SysexMessage object is therefore - * the length of the system exclusive data plus two: one byte for the status - * byte and one for the end-of-exclusive flag. + * When a system exclusive message is read from a MIDI file, it always has a + * defined length. Data from a system exclusive message from a MIDI file should + * be stored in the data array of a {@code SysexMessage} as follows: the system + * exclusive message status byte (0xF0 or 0xF7), all message data bytes, and + * finally the end-of-exclusive flag (0xF7). The length reported by the + * {@code SysexMessage} object is therefore the length of the system exclusive + * data plus two: one byte for the status byte and one for the end-of-exclusive + * flag. *

    - * As dictated by the Standard MIDI Files specification, two status byte values are legal - * for a SysexMessage read from a MIDI file: + * As dictated by the Standard MIDI Files specification, two status byte values + * are legal for a {@code SysexMessage} read from a MIDI file: *

      *
    • 0xF0: System Exclusive message (same as in MIDI wire protocol)
    • *
    • 0xF7: Special System Exclusive message
    • *
    - *

    - * When Java Sound is used to handle system exclusive data that is being received - * using MIDI wire protocol, it should place the data in one or more - * SysexMessages. In this case, the length of the system exclusive data + * When Java Sound is used to handle system exclusive data that is being + * received using MIDI wire protocol, it should place the data in one or more + * {@code SysexMessages}. In this case, the length of the system exclusive data * is not known in advance; the end of the system exclusive data is marked by an * end-of-exclusive flag (0xF7) in the MIDI wire byte stream. *

      *
    • 0xF0: System Exclusive message (same as in MIDI wire protocol)
    • *
    • 0xF7: End of Exclusive (EOX)
    • *
    - * The first SysexMessage object containing data for a particular system - * exclusive message should have the status value 0xF0. If this message contains all - * the system exclusive data - * for the message, it should end with the status byte 0xF7 (EOX). - * Otherwise, additional system exclusive data should be sent in one or more - * SysexMessages with a status value of 0xF7. The SysexMessage - * containing the last of the data for the system exclusive message should end with the - * value 0xF7 (EOX) to mark the end of the system exclusive message. + * The first {@code SysexMessage} object containing data for a particular system + * exclusive message should have the status value 0xF0. If this message contains + * all the system exclusive data for the message, it should end with the status + * byte 0xF7 (EOX). Otherwise, additional system exclusive data should be sent + * in one or more {@code SysexMessages} with a status value of 0xF7. The + * {@code SysexMessage} containing the last of the data for the system exclusive + * message should end with the value 0xF7 (EOX) to mark the end of the system + * exclusive message. *

    - * If system exclusive data from SysexMessages objects is being transmitted - * using MIDI wire protocol, only the initial 0xF0 status byte, the system exclusive - * data itself, and the final 0xF7 (EOX) byte should be propagated; any 0xF7 status - * bytes used to indicate that a SysexMessage contains continuing system - * exclusive data should not be propagated via MIDI wire protocol. + * If system exclusive data from {@code SysexMessages} objects is being + * transmitted using MIDI wire protocol, only the initial 0xF0 status byte, the + * system exclusive data itself, and the final 0xF7 (EOX) byte should be + * propagated; any 0xF7 status bytes used to indicate that a + * {@code SysexMessage} contains continuing system exclusive data should not be + * propagated via MIDI wire protocol. * * @author David Rivas * @author Kara Kytle @@ -74,43 +74,36 @@ package javax.sound.midi; */ public class SysexMessage extends MidiMessage { - // Status byte defines - /** * Status byte for System Exclusive message (0xF0, or 240). + * * @see MidiMessage#getStatus */ public static final int SYSTEM_EXCLUSIVE = 0xF0; // 240 - /** - * Status byte for Special System Exclusive message (0xF7, or 247), which is used - * in MIDI files. It has the same value as END_OF_EXCLUSIVE, which - * is used in the real-time "MIDI wire" protocol. + * Status byte for Special System Exclusive message (0xF7, or 247), which is + * used in MIDI files. It has the same value as END_OF_EXCLUSIVE, which is + * used in the real-time "MIDI wire" protocol. + * * @see MidiMessage#getStatus */ public static final int SPECIAL_SYSTEM_EXCLUSIVE = 0xF7; // 247 - - // Instance variables - - - /* - * The data bytes for this system exclusive message. These are - * initialized to null and are set explicitly - * by {@link #setMessage(int, byte[], int, long) setMessage}. + /** + * The data bytes for this system exclusive message. These are initialized + * to {@code null} and are set explicitly by + * {@link #setMessage(int, byte[], int, long) setMessage}. */ //protected byte[] data = null; - /** - * Constructs a new SysexMessage. The - * contents of the new message are guaranteed to specify - * a valid MIDI message. Subsequently, you may set the - * contents of the message using one of the setMessage - * methods. + * Constructs a new {@code SysexMessage}. The contents of the new message + * are guaranteed to specify a valid MIDI message. Subsequently, you may set + * the contents of the message using one of the {@code setMessage} methods. + * * @see #setMessage */ public SysexMessage() { @@ -121,18 +114,17 @@ public class SysexMessage extends MidiMessage { } /** - * Constructs a new {@code SysexMessage} and sets the data for - * the message. The first byte of the data array must be a valid system - * exclusive status byte (0xF0 or 0xF7). - * The contents of the message can be changed by using one of - * the {@code setMessage} methods. + * Constructs a new {@code SysexMessage} and sets the data for the message. + * The first byte of the data array must be a valid system exclusive status + * byte (0xF0 or 0xF7). The contents of the message can be changed by using + * one of the {@code setMessage} methods. * - * @param data the system exclusive message data including the status byte - * @param length the length of the valid message data in the array, - * including the status byte; it should be non-negative and less than - * or equal to {@code data.length} - * @throws InvalidMidiDataException if the parameter values - * do not specify a valid MIDI meta message. + * @param data the system exclusive message data including the status byte + * @param length the length of the valid message data in the array, + * including the status byte; it should be non-negative and less + * than or equal to {@code data.length} + * @throws InvalidMidiDataException if the parameter values do not specify a + * valid MIDI meta message. * @see #setMessage(byte[], int) * @see #setMessage(int, byte[], int) * @see #getData() @@ -146,17 +138,17 @@ public class SysexMessage extends MidiMessage { /** * Constructs a new {@code SysexMessage} and sets the data for the message. - * The contents of the message can be changed by using one of - * the {@code setMessage} methods. + * The contents of the message can be changed by using one of the + * {@code setMessage} methods. * - * @param status the status byte for the message; it must be a valid system - * exclusive status byte (0xF0 or 0xF7) - * @param data the system exclusive message data (without the status byte) - * @param length the length of the valid message data in the array; - * it should be non-negative and less than or equal to - * {@code data.length} - * @throws InvalidMidiDataException if the parameter values - * do not specify a valid MIDI meta message. + * @param status the status byte for the message; it must be a valid system + * exclusive status byte (0xF0 or 0xF7) + * @param data the system exclusive message data (without the status byte) + * @param length the length of the valid message data in the array; it + * should be non-negative and less than or equal to + * {@code data.length} + * @throws InvalidMidiDataException if the parameter values do not specify a + * valid MIDI meta message * @see #setMessage(byte[], int) * @see #setMessage(int, byte[], int) * @see #getData() @@ -168,26 +160,24 @@ public class SysexMessage extends MidiMessage { setMessage(status, data, length); } - /** - * Constructs a new SysexMessage. - * @param data an array of bytes containing the complete message. - * The message data may be changed using the setMessage - * method. + * Constructs a new {@code SysexMessage}. + * + * @param data an array of bytes containing the complete message. The + * message data may be changed using the {@code setMessage} method. * @see #setMessage */ protected SysexMessage(byte[] data) { super(data); } - /** - * Sets the data for the system exclusive message. The - * first byte of the data array must be a valid system - * exclusive status byte (0xF0 or 0xF7). - * @param data the system exclusive message data - * @param length the length of the valid message data in - * the array, including the status byte. + * Sets the data for the system exclusive message. The first byte of the + * data array must be a valid system exclusive status byte (0xF0 or 0xF7). + * + * @param data the system exclusive message data + * @param length the length of the valid message data in the array, + * including the status byte */ public void setMessage(byte[] data, int length) throws InvalidMidiDataException { int status = (data[0] & 0xFF); @@ -197,14 +187,14 @@ public class SysexMessage extends MidiMessage { super.setMessage(data, length); } - /** * Sets the data for the system exclusive message. - * @param status the status byte for the message (0xF0 or 0xF7) - * @param data the system exclusive message data - * @param length the length of the valid message data in - * the array - * @throws InvalidMidiDataException if the status byte is invalid for a sysex message + * + * @param status the status byte for the message (0xF0 or 0xF7) + * @param data the system exclusive message data + * @param length the length of the valid message data in the array + * @throws InvalidMidiDataException if the status byte is invalid for a + * sysex message */ public void setMessage(int status, byte[] data, int length) throws InvalidMidiDataException { if ( (status != 0xF0) && (status != 0xF7) ) { @@ -225,11 +215,11 @@ public class SysexMessage extends MidiMessage { } } - /** - * Obtains a copy of the data for the system exclusive message. - * The returned array of bytes does not include the status byte. - * @return array containing the system exclusive message data. + * Obtains a copy of the data for the system exclusive message. The returned + * array of bytes does not include the status byte. + * + * @return array containing the system exclusive message data */ public byte[] getData() { byte[] returnedArray = new byte[length - 1]; @@ -237,10 +227,10 @@ public class SysexMessage extends MidiMessage { return returnedArray; } - /** - * Creates a new object of the same class and with the same contents - * as this object. + * Creates a new object of the same class and with the same contents as this + * object. + * * @return a clone of this instance */ public Object clone() { diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/Track.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/Track.java index d9e0f438b6c..95a42c7f703 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/Track.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/Track.java @@ -25,41 +25,40 @@ package javax.sound.midi; -import java.util.Vector; import java.util.ArrayList; import java.util.HashSet; + import com.sun.media.sound.MidiUtils; /** - * A MIDI track is an independent stream of MIDI events (time-stamped MIDI - * data) that can be stored along with other tracks in a standard MIDI file. - * The MIDI specification allows only 16 channels of MIDI data, but tracks - * are a way to get around this limitation. A MIDI file can contain any number - * of tracks, each containing its own stream of up to 16 channels of MIDI data. + * A MIDI track is an independent stream of MIDI events (time-stamped MIDI data) + * that can be stored along with other tracks in a standard MIDI file. The MIDI + * specification allows only 16 channels of MIDI data, but tracks are a way to + * get around this limitation. A MIDI file can contain any number of tracks, + * each containing its own stream of up to 16 channels of MIDI data. *

    - * A Track occupies a middle level in the hierarchy of data played - * by a {@link Sequencer}: sequencers play sequences, which contain tracks, - * which contain MIDI events. A sequencer may provide controls that mute - * or solo individual tracks. + * A {@code Track} occupies a middle level in the hierarchy of data played by a + * {@link Sequencer}: sequencers play sequences, which contain tracks, which + * contain MIDI events. A sequencer may provide controls that mute or solo + * individual tracks. *

    * The timing information and resolution for a track is controlled by and stored - * in the sequence containing the track. A given Track - * is considered to belong to the particular {@link Sequence} that - * maintains its timing. For this reason, a new (empty) track is created by calling the - * {@link Sequence#createTrack} method, rather than by directly invoking a - * Track constructor. + * in the sequence containing the track. A given {@code Track} is considered to + * belong to the particular {@link Sequence} that maintains its timing. For this + * reason, a new (empty) track is created by calling the + * {@link Sequence#createTrack} method, rather than by directly invoking a + * {@code Track} constructor. *

    - * The Track class provides methods to edit the track by adding - * or removing MidiEvent objects from it. These operations keep - * the event list in the correct time order. Methods are also - * included to obtain the track's size, in terms of either the number of events - * it contains or its duration in ticks. - * - * @see Sequencer#setTrackMute - * @see Sequencer#setTrackSolo + * The {@code Track} class provides methods to edit the track by adding or + * removing {@code MidiEvent} objects from it. These operations keep the event + * list in the correct time order. Methods are also included to obtain the + * track's size, in terms of either the number of events it contains or its + * duration in ticks. * * @author Kara Kytle * @author Florian Bomers + * @see Sequencer#setTrackMute + * @see Sequencer#setTrackSolo */ public class Track { @@ -73,10 +72,9 @@ public class Track { private MidiEvent eotEvent; - /** - * Package-private constructor. Constructs a new, empty Track object, - * which initially contains one event, the meta-event End of Track. + * Package-private constructor. Constructs a new, empty Track object, which + * initially contains one event, the meta-event End of Track. */ Track() { // start with the end of track event @@ -87,14 +85,14 @@ public class Track { } /** - * Adds a new event to the track. However, if the event is already - * contained in the track, it is not added again. The list of events - * is kept in time order, meaning that this event inserted at the - * appropriate place in the list, not necessarily at the end. + * Adds a new event to the track. However, if the event is already contained + * in the track, it is not added again. The list of events is kept in time + * order, meaning that this event inserted at the appropriate place in the + * list, not necessarily at the end. * - * @param event the event to add - * @return true if the event did not already exist in the - * track and was added, otherwise false + * @param event the event to add + * @return {@code true} if the event did not already exist in the track and + * was added, otherwise {@code false} */ public boolean add(MidiEvent event) { if (event == null) { @@ -176,12 +174,12 @@ public class Track { return false; } - /** * Removes the specified event from the track. - * @param event the event to remove - * @return true if the event existed in the track and was removed, - * otherwise false + * + * @param event the event to remove + * @return {@code true} if the event existed in the track and was removed, + * otherwise {@code false} */ public boolean remove(MidiEvent event) { @@ -207,15 +205,14 @@ public class Track { return false; } - /** * Obtains the event at the specified index. - * @param index the location of the desired event in the event vector - * @throws ArrayIndexOutOfBoundsException if the - * specified index is negative or not less than the current size of - * this track. - * @see #size + * + * @param index the location of the desired event in the event vector * @return the event at the specified index + * @throws ArrayIndexOutOfBoundsException if the specified index is negative + * or not less than the current size of this track + * @see #size */ public MidiEvent get(int index) throws ArrayIndexOutOfBoundsException { try { @@ -227,9 +224,9 @@ public class Track { } } - /** * Obtains the number of events in this track. + * * @return the size of the track's event vector */ public int size() { @@ -238,12 +235,12 @@ public class Track { } } - /** - * Obtains the length of the track, expressed in MIDI ticks. (The - * duration of a tick in seconds is determined by the timing resolution - * of the Sequence containing this track, and also by - * the tempo of the music as set by the sequencer.) + * Obtains the length of the track, expressed in MIDI ticks. (The duration + * of a tick in seconds is determined by the timing resolution of the + * {@code Sequence} containing this track, and also by the tempo of the + * music as set by the sequencer.) + * * @return the duration, in ticks * @see Sequence#Sequence(float, int) * @see Sequencer#setTempoInBPM(float) @@ -271,5 +268,4 @@ public class Track { throw new InvalidMidiDataException("cannot modify end of track message"); } } - } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/Transmitter.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/Transmitter.java index e78b800c728..639aa2c750d 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/Transmitter.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/Transmitter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, 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 @@ -25,52 +25,49 @@ package javax.sound.midi; - /** - * A Transmitter sends {@link MidiEvent} objects to one or more - * {@link Receiver Receivers}. Common MIDI transmitters include sequencers - * and MIDI input ports. - * - * @see Receiver + * A {@code Transmitter} sends {@link MidiEvent} objects to one or more + * {@link Receiver Receivers}. Common MIDI transmitters include sequencers and + * MIDI input ports. * * @author Kara Kytle + * @see Receiver */ public interface Transmitter extends AutoCloseable { - /** * Sets the receiver to which this transmitter will deliver MIDI messages. * If a receiver is currently set, it is replaced with this one. - * @param receiver the desired receiver. + * + * @param receiver the desired receiver */ - public void setReceiver(Receiver receiver); - + void setReceiver(Receiver receiver); /** - * Obtains the current receiver to which this transmitter will deliver MIDI messages. - * @return the current receiver. If no receiver is currently set, - * returns null + * Obtains the current receiver to which this transmitter will deliver MIDI + * messages. + * + * @return the current receiver. If no receiver is currently set, returns + * {@code null}. */ - public Receiver getReceiver(); - + Receiver getReceiver(); /** * Indicates that the application has finished using the transmitter, and * that limited resources it requires may be released or made available. - * - *

    If the creation of this Transmitter resulted in - * implicitly opening the underlying device, the device is - * implicitly closed by this method. This is true unless the device is - * kept open by other Receiver or Transmitter - * instances that opened the device implicitly, and unless the device - * has been opened explicitly. If the device this - * Transmitter is retrieved from is closed explicitly - * by calling {@link MidiDevice#close MidiDevice.close}, the - * Transmitter is closed, too. For a detailed - * description of open/close behaviour see the class description - * of {@link javax.sound.midi.MidiDevice MidiDevice}. + *

    + * If the creation of this {@code Transmitter} resulted in implicitly + * opening the underlying device, the device is implicitly closed by this + * method. This is true unless the device is kept open by other + * {@code Receiver} or {@code Transmitter} instances that opened the device + * implicitly, and unless the device has been opened explicitly. If the + * device this {@code Transmitter} is retrieved from is closed explicitly by + * calling {@link MidiDevice#close MidiDevice.close}, the + * {@code Transmitter} is closed, too. For a detailed description of + * open/close behaviour see the class description of + * {@link MidiDevice MidiDevice}. * * @see javax.sound.midi.MidiSystem#getTransmitter */ - public void close(); + void close(); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/VoiceStatus.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/VoiceStatus.java index 45f2e4d964c..2d679613e01 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/VoiceStatus.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/VoiceStatus.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -25,93 +25,83 @@ package javax.sound.midi; - /** - * A VoiceStatus object contains information about the current - * status of one of the voices produced by a {@link Synthesizer}. + * A {@code VoiceStatus} object contains information about the current status of + * one of the voices produced by a {@link Synthesizer}. *

    * MIDI synthesizers are generally capable of producing some maximum number of - * simultaneous notes, also referred to as voices. A voice is a stream - * of successive single notes, and the process of assigning incoming MIDI notes to - * specific voices is known as voice allocation. - * However, the voice-allocation algorithm and the contents of each voice are - * normally internal to a MIDI synthesizer and hidden from outside view. One can, of - * course, learn from MIDI messages which notes the synthesizer is playing, and - * one might be able deduce something about the assignment of notes to voices. - * But MIDI itself does not provide a means to report which notes a - * synthesizer has assigned to which voice, nor even to report how many voices - * the synthesizer is capable of synthesizing. + * simultaneous notes, also referred to as voices. A voice is a stream of + * successive single notes, and the process of assigning incoming MIDI notes to + * specific voices is known as voice allocation. However, the voice-allocation + * algorithm and the contents of each voice are normally internal to a MIDI + * synthesizer and hidden from outside view. One can, of course, learn from MIDI + * messages which notes the synthesizer is playing, and one might be able deduce + * something about the assignment of notes to voices. But MIDI itself does not + * provide a means to report which notes a synthesizer has assigned to which + * voice, nor even to report how many voices the synthesizer is capable of + * synthesizing. *

    - * In Java Sound, however, a - * Synthesizer class can expose the contents of its voices through its - * {@link Synthesizer#getVoiceStatus() getVoiceStatus()} method. - * This behavior is recommended but optional; - * synthesizers that don't expose their voice allocation simply return a - * zero-length array. A Synthesizer that does report its voice status - * should maintain this information at - * all times for all of its voices, whether they are currently sounding or - * not. In other words, a given type of Synthesizer always has a fixed - * number of voices, equal to the maximum number of simultaneous notes it is - * capable of sounding. + * In Java Sound, however, a {@code Synthesizer} class can expose the contents + * of its voices through its + * {@link Synthesizer#getVoiceStatus() getVoiceStatus()} method. This behavior + * is recommended but optional; synthesizers that don't expose their voice + * allocation simply return a zero-length array. A {@code Synthesizer} that does + * report its voice status should maintain this information at all times for all + * of its voices, whether they are currently sounding or not. In other words, a + * given type of {@code Synthesizer} always has a fixed number of voices, equal + * to the maximum number of simultaneous notes it is capable of sounding. *

    - * - * If the voice is not currently processing a MIDI note, it - * is considered inactive. A voice is inactive when it has - * been given no note-on commands, or when every note-on command received has - * been terminated by a corresponding note-off (or by an "all notes off" - * message). For example, this happens when a synthesizer capable of playing 16 - * simultaneous notes is told to play a four-note chord; only - * four voices are active in this case (assuming no earlier notes are still playing). - * Usually, a voice whose status is reported as active is producing audible sound, but this - * is not always true; it depends on the details of the instrument (that - * is, the synthesis algorithm) and how long the note has been going on. - * For example, a voice may be synthesizing the sound of a single hand-clap. Because - * this sound dies away so quickly, it may become inaudible before a note-off - * message is received. In such a situation, the voice is still considered active - * even though no sound is currently being produced. + * If the voice is not currently processing + * a MIDI note, it is considered inactive. A voice is inactive when it has been + * given no note-on commands, or when every note-on command received has been + * terminated by a corresponding note-off (or by an "all notes off" message). + * For example, this happens when a synthesizer capable of playing 16 + * simultaneous notes is told to play a four-note chord; only four voices are + * active in this case (assuming no earlier notes are still playing). Usually, a + * voice whose status is reported as active is producing audible sound, but this + * is not always true; it depends on the details of the instrument (that is, the + * synthesis algorithm) and how long the note has been going on. For example, a + * voice may be synthesizing the sound of a single hand-clap. Because this sound + * dies away so quickly, it may become inaudible before a note-off message is + * received. In such a situation, the voice is still considered active even + * though no sound is currently being produced. *

    - * Besides its active or inactive status, the VoiceStatus class - * provides fields that reveal the voice's current MIDI channel, bank and - * program number, MIDI note number, and MIDI volume. All of these can - * change during the course of a voice. While the voice is inactive, each - * of these fields has an unspecified value, so you should check the active - * field first. - * - * @see Synthesizer#getMaxPolyphony - * @see Synthesizer#getVoiceStatus + * Besides its active or inactive status, the {@code VoiceStatus} class provides + * fields that reveal the voice's current MIDI channel, bank and program number, + * MIDI note number, and MIDI volume. All of these can change during the course + * of a voice. While the voice is inactive, each of these fields has an + * unspecified value, so you should check the active field first. * * @author David Rivas * @author Kara Kytle + * @see Synthesizer#getMaxPolyphony + * @see Synthesizer#getVoiceStatus */ - public class VoiceStatus { - /** - * Indicates whether the voice is currently processing a MIDI note. - * See the explanation of - * active and inactive voices. + * Indicates whether the voice is currently processing a MIDI note. See the + * explanation of + * active and inactive voices. */ public boolean active = false; - /** - * The MIDI channel on which this voice is playing. The value is a - * zero-based channel number if the voice is active, or - * unspecified if the voice is inactive. + * The MIDI channel on which this voice is playing. The value is a + * zero-based channel number if the voice is active, or unspecified if the + * voice is inactive. * * @see MidiChannel * @see #active */ public int channel = 0; - /** * The bank number of the instrument that this voice is currently using. * This is a number dictated by the MIDI bank-select message; it does not - * refer to a SoundBank object. - * The value ranges from 0 to 16383 if the voice is active, and is - * unspecified if the voice is inactive. + * refer to a {@code SoundBank} object. The value ranges from 0 to 16383 if + * the voice is active, and is unspecified if the voice is inactive. + * * @see Patch * @see Soundbank * @see #active @@ -119,11 +109,10 @@ public class VoiceStatus { */ public int bank = 0; - /** * The program number of the instrument that this voice is currently using. - * The value ranges from 0 to 127 if the voice is active, and is - * unspecified if the voice is inactive. + * The value ranges from 0 to 127 if the voice is active, and is unspecified + * if the voice is inactive. * * @see MidiChannel#getProgram * @see Patch @@ -131,28 +120,24 @@ public class VoiceStatus { */ public int program = 0; - /** - * The MIDI note that this voice is playing. The range for an active voice - * is from 0 to 127 in semitones, with 60 referring to Middle C. - * The value is unspecified if the voice is inactive. + * The MIDI note that this voice is playing. The range for an active voice + * is from 0 to 127 in semitones, with 60 referring to Middle C. The value + * is unspecified if the voice is inactive. * * @see MidiChannel#noteOn * @see #active */ public int note = 0; - /** - * The current MIDI volume level for the voice. - * The value ranges from 0 to 127 if the voice is active, and is - * unspecified if the voice is inactive. + * The current MIDI volume level for the voice. The value ranges from 0 to + * 127 if the voice is active, and is unspecified if the voice is inactive. *

    - * Note that this value does not necessarily reflect - * the instantaneous level of the sound produced by this - * voice; that level is the result of many contributing - * factors, including the current instrument and the - * shape of the amplitude envelope it produces. + * Note that this value does not necessarily reflect the instantaneous level + * of the sound produced by this voice; that level is the result of many + * contributing factors, including the current instrument and the shape of + * the amplitude envelope it produces. * * @see #active */ diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java index ecb72b32dd2..bbdca9e97bb 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java @@ -26,13 +26,13 @@ package javax.sound.midi.spi; import java.io.File; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.net.URL; +import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MidiFileFormat; import javax.sound.midi.Sequence; -import javax.sound.midi.InvalidMidiDataException; /** * A {@code MidiFileReader} supplies MIDI file-reading services. Classes @@ -106,7 +106,7 @@ public abstract class MidiFileReader { * @param stream the input stream from which the {@code Sequence} should * be constructed * @return a {@code Sequence} object based on the MIDI file data contained - * in the input stream. + * in the input stream * @throws InvalidMidiDataException if the stream does not point to valid * MIDI file data recognized by the system * @throws IOException if an I/O exception occurs diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java index c7e82d9960f..501c18b6ad5 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java @@ -32,12 +32,12 @@ import java.net.URL; import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.Soundbank; +import javax.sound.midi.Synthesizer; /** * A {@code SoundbankReader} supplies soundbank file-reading services. Concrete * subclasses of {@code SoundbankReader} parse a given soundbank file, producing - * a {@link javax.sound.midi.Soundbank} object that can be loaded into a - * {@link javax.sound.midi.Synthesizer}. + * a {@link Soundbank} object that can be loaded into a {@link Synthesizer}. * * @since 1.3 * @author Kara Kytle @@ -47,7 +47,7 @@ public abstract class SoundbankReader { /** * Obtains a soundbank object from the URL provided. * - * @param url URL representing the soundbank. + * @param url URL representing the soundbank * @return soundbank object * @throws InvalidMidiDataException if the URL does not point to valid MIDI * soundbank data recognized by this soundbank reader diff --git a/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java b/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java index 459ef997855..db528aebb83 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java @@ -26,19 +26,19 @@ package javax.sound.sampled; import java.io.File; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.net.URL; - +import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Properties; import java.util.Set; import java.util.Vector; -import java.util.ArrayList; -import javax.sound.sampled.spi.AudioFileWriter; import javax.sound.sampled.spi.AudioFileReader; +import javax.sound.sampled.spi.AudioFileWriter; import javax.sound.sampled.spi.FormatConversionProvider; import javax.sound.sampled.spi.MixerProvider; @@ -60,14 +60,14 @@ import com.sun.media.sound.JDK13Services; *

    * Properties can be used to specify the default mixer for specific line types. * Both system properties and a properties file are considered. The - * {@code sound.properties} properties file is read from an - * implementation-specific location (typically it is the {@code lib} directory - * in the Java installation directory). If a property exists both as a system - * property and in the properties file, the system property takes precedence. - * If none is specified, a suitable default is chosen among the available - * devices. The syntax of the properties file is specified in - * {@link java.util.Properties#load(InputStream) Properties.load}. The following - * table lists the available property keys and which methods consider them: + * "sound.properties" properties file is read from an implementation-specific + * location (typically it is the {@code lib} directory in the Java installation + * directory). If a property exists both as a system property and in the + * properties file, the system property takes precedence. If none is specified, + * a suitable default is chosen among the available devices. The syntax of the + * properties file is specified in + * {@link Properties#load(InputStream) Properties.load}. The following table + * lists the available property keys and which methods consider them: * * * @@ -100,12 +100,11 @@ import com.sun.media.sound.JDK13Services; * * The property value consists of the provider class name and the mixer name, * separated by the hash mark ("#"). The provider class name is the - * fully-qualified name of a concrete - * {@link javax.sound.sampled.spi.MixerProvider mixer provider} class. The mixer - * name is matched against the {@code String} returned by the {@code getName} - * method of {@code Mixer.Info}. Either the class name, or the mixer name may be - * omitted. If only the class name is specified, the trailing hash mark is - * optional. + * fully-qualified name of a concrete {@link MixerProvider mixer provider} + * class. The mixer name is matched against the {@code String} returned by the + * {@code getName} method of {@code Mixer.Info}. Either the class name, or the + * mixer name may be omitted. If only the class name is specified, the trailing + * hash mark is optional. *

    * If the provider class is specified, and it can be successfully retrieved from * the installed providers, the list of {@code Mixer.Info} objects is retrieved @@ -1324,10 +1323,9 @@ public class AudioSystem { * Obtains the set of format converters (codecs, transcoders, etc.) that are * currently installed on the system. * - * @return an array of {@link javax.sound.sampled.spi.FormatConversionProvider - * FormatConversionProvider} objects representing the available - * format converters. If no format converters readers are available - * on the system, an array of length 0 is returned. + * @return an array of {@link FormatConversionProvider} objects representing + * the available format converters. If no format converters readers + * are available on the system, an array of length 0 is returned. */ @SuppressWarnings("unchecked") private static List getFormatConversionProviders() { @@ -1338,10 +1336,9 @@ public class AudioSystem { * Obtains the set of audio file readers that are currently installed on the * system. * - * @return a List of {@link javax.sound.sampled.spi.AudioFileReader - * AudioFileReader} objects representing the installed audio file - * readers. If no audio file readers are available on the system, an - * empty List is returned. + * @return a List of {@link AudioFileReader} objects representing the + * installed audio file readers. If no audio file readers are + * available on the system, an empty List is returned. */ @SuppressWarnings("unchecked") private static List getAudioFileReaders() { @@ -1352,10 +1349,9 @@ public class AudioSystem { * Obtains the set of audio file writers that are currently installed on the * system. * - * @return a List of {@link javax.sound.sampled.spi.AudioFileWriter - * AudioFileWriter} objects representing the available audio file - * writers. If no audio file writers are available on the system, an - * empty List is returned. + * @return a List of {@link AudioFileWriter} objects representing the + * available audio file writers. If no audio file writers are + * available on the system, an empty List is returned. */ @SuppressWarnings("unchecked") private static List getAudioFileWriters() { diff --git a/jdk/src/java.desktop/share/classes/javax/sound/sampled/DataLine.java b/jdk/src/java.desktop/share/classes/javax/sound/sampled/DataLine.java index 9a81a76c5b6..6246a40d64f 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/DataLine.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/DataLine.java @@ -355,11 +355,11 @@ public interface DataLine extends Line { * {@code true} for all formats returned by {@code getFormats()}. *

    * Some fields in the AudioFormat instances can be set to - * {@link javax.sound.sampled.AudioSystem#NOT_SPECIFIED NOT_SPECIFIED} - * if that field does not apply to the format, or if the format supports - * a wide range of values for that field. For example, a multi-channel - * device supporting up to 64 channels, could set the channel field in - * the {@code AudioFormat} instances returned by this method to + * {@link AudioSystem#NOT_SPECIFIED NOT_SPECIFIED} if that field does + * not apply to the format, or if the format supports a wide range of + * values for that field. For example, a multi-channel device supporting + * up to 64 channels, could set the channel field in the + * {@code AudioFormat} instances returned by this method to * {@code NOT_SPECIFIED}. * * @return a set of supported audio formats diff --git a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileReader.java b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileReader.java index daa75556785..818df436f49 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileReader.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileReader.java @@ -26,8 +26,8 @@ package javax.sound.sampled.spi; import java.io.File; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import javax.sound.sampled.AudioFileFormat; diff --git a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java index a4cc31bdf18..0cb6dc6acae 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.io.OutputStream; import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; import static javax.sound.sampled.AudioFileFormat.Type; @@ -110,8 +111,7 @@ public abstract class AudioFileWriter { * the length be written into the file header, and cannot be written from * start to finish unless the length is known in advance. An attempt to * write such a file type will fail with an IOException if the length in the - * audio file format is {@link javax.sound.sampled.AudioSystem#NOT_SPECIFIED - * AudioSystem.NOT_SPECIFIED}. + * audio file format is {@link AudioSystem#NOT_SPECIFIED}. * * @param stream the audio input stream containing audio data to be written * to the output stream diff --git a/jdk/src/java.desktop/share/classes/javax/swing/CellEditor.java b/jdk/src/java.desktop/share/classes/javax/swing/CellEditor.java index f1b625b7969..bf9a23d2f77 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/CellEditor.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/CellEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2005, 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 @@ -47,7 +47,7 @@ import javax.swing.event.*; * new component implement the interface. Or the developer can * choose a wrapper based approach and provide a companion object which * implements the CellEditor interface (See - * JCellEditor for example). The wrapper approach + * DefaultCellEditor for example). The wrapper approach * is particularly useful if the user want to use a 3rd party ISV * editor with JTable, but the ISV didn't implement the * CellEditor interface. The user can simply create an object diff --git a/jdk/src/java.desktop/share/classes/javax/swing/ImageIcon.java b/jdk/src/java.desktop/share/classes/javax/swing/ImageIcon.java index 8f7812e5919..564e173c5c8 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/ImageIcon.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/ImageIcon.java @@ -490,12 +490,33 @@ public class ImageIcon implements Icon, Serializable, Accessible { private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { - s.defaultReadObject(); + ObjectInputStream.GetField f = s.readFields(); + + imageObserver = (ImageObserver) f.get("imageObserver", null); + description = (String) f.get("description", null); + width = f.get("width", -1); + height = f.get("height", -1); + accessibleContext = (AccessibleImageIcon) f.get("accessibleContext", null); int w = s.readInt(); int h = s.readInt(); int[] pixels = (int[])(s.readObject()); + if (pixels == null && (w != -1 || h != -1)) { + throw new IllegalStateException("Inconsistent width and height" + + " for null image [" + w + ", " + h + "]"); + } + + if (pixels != null && (w < 0 || h < 0)) { + throw new IllegalStateException("Inconsistent width and height" + + " for image [" + w + ", " + h + "]"); + } + + if (w != getIconWidth() || h != getIconHeight()) { + throw new IllegalStateException("Inconsistent width and height" + + " for image [" + w + ", " + h + "]"); + } + if (pixels != null) { Toolkit tk = Toolkit.getDefaultToolkit(); ColorModel cm = ColorModel.getRGBdefault(); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java index 765610ebbad..17cbf60100b 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java @@ -1888,7 +1888,7 @@ public abstract class JComponent extends Container implements Serializable, * description: The preferred vertical alignment of the component. */ public void setAlignmentY(float alignmentY) { - this.alignmentY = alignmentY > 1.0f ? 1.0f : alignmentY < 0.0f ? 0.0f : alignmentY; + this.alignmentY = validateAlignment(alignmentY); isAlignmentYSet = true; } @@ -1917,10 +1917,14 @@ public abstract class JComponent extends Container implements Serializable, * description: The preferred horizontal alignment of the component. */ public void setAlignmentX(float alignmentX) { - this.alignmentX = alignmentX > 1.0f ? 1.0f : alignmentX < 0.0f ? 0.0f : alignmentX; + this.alignmentX = validateAlignment(alignmentX); isAlignmentXSet = true; } + private float validateAlignment(float alignment) { + return alignment > 1.0f ? 1.0f : alignment < 0.0f ? 0.0f : alignment; + } + /** * Sets the input verifier for this component. * @@ -5514,7 +5518,24 @@ public abstract class JComponent extends Container implements Serializable, private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - s.defaultReadObject(); + ObjectInputStream.GetField f = s.readFields(); + + isAlignmentXSet = f.get("isAlignmentXSet", false); + alignmentX = validateAlignment(f.get("alignmentX", 0f)); + isAlignmentYSet = f.get("isAlignmentYSet", false); + alignmentY = validateAlignment(f.get("alignmentY", 0f)); + listenerList = (EventListenerList) f.get("listenerList", null); + vetoableChangeSupport = (VetoableChangeSupport) f.get("vetoableChangeSupport", null); + autoscrolls = f.get("autoscrolls", false); + border = (Border) f.get("border", null); + flags = f.get("flags", 0); + inputVerifier = (InputVerifier) f.get("inputVerifier", null); + verifyInputWhenFocusTarget = f.get("verifyInputWhenFocusTarget", false); + popupMenu = (JPopupMenu) f.get("popupMenu", null); + focusInputMap = (InputMap) f.get("focusInputMap", null); + ancestorInputMap = (InputMap) f.get("ancestorInputMap", null); + windowInputMap = (ComponentInputMap) f.get("windowInputMap", null); + actionMap = (ActionMap) f.get("actionMap", null); /* If there's no ReadObjectCallback for this stream yet, that is, if * this is the first call to JComponent.readObject() for this diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java b/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java index bf690ddbb5b..1edf4943357 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JFileChooser.java @@ -50,6 +50,8 @@ import java.awt.Toolkit; import java.awt.event.*; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.lang.ref.WeakReference; /** @@ -460,10 +462,14 @@ public class JFileChooser extends JComponent implements Accessible { * bound: false */ public void setDragEnabled(boolean b) { + checkDragEnabled(b); + dragEnabled = b; + } + + private static void checkDragEnabled(boolean b) { if (b && GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } - dragEnabled = b; } /** @@ -949,9 +955,7 @@ public class JFileChooser extends JComponent implements Accessible { if(this.dialogType == dialogType) { return; } - if(!(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG || dialogType == CUSTOM_DIALOG)) { - throw new IllegalArgumentException("Incorrect Dialog Type: " + dialogType); - } + checkDialogType(dialogType); int oldValue = this.dialogType; this.dialogType = dialogType; if(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG) { @@ -960,6 +964,14 @@ public class JFileChooser extends JComponent implements Accessible { firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, oldValue, dialogType); } + private static void checkDialogType(int dialogType) { + if (!(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG + || dialogType == CUSTOM_DIALOG)) { + throw new IllegalArgumentException( + "Incorrect Dialog Type: " + dialogType); + } + } + /** * Sets the string that goes in the JFileChooser window's * title bar. @@ -1349,12 +1361,17 @@ public class JFileChooser extends JComponent implements Accessible { return; } - if ((mode == FILES_ONLY) || (mode == DIRECTORIES_ONLY) || (mode == FILES_AND_DIRECTORIES)) { + checkFileSelectionMode(mode); int oldValue = fileSelectionMode; fileSelectionMode = mode; firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, oldValue, fileSelectionMode); - } else { - throw new IllegalArgumentException("Incorrect Mode for file selection: " + mode); + } + + private static void checkFileSelectionMode(int mode) { + if ((mode != FILES_ONLY) && (mode != DIRECTORIES_ONLY) + && (mode != FILES_AND_DIRECTORIES)) { + throw new IllegalArgumentException( + "Incorrect Mode for file selection: " + mode); } } @@ -1901,7 +1918,43 @@ public class JFileChooser extends JComponent implements Accessible { */ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); + ObjectInputStream.GetField f = in.readFields(); + + dialogTitle = (String) f.get("dialogTitle", null); + approveButtonText = (String) f.get("approveButtonText", null); + approveButtonToolTipText = + (String) f.get("approveButtonToolTipText", null); + approveButtonMnemonic = f.get("approveButtonMnemonic", 0); + @SuppressWarnings("unchecked") + Vector newFilters = (Vector) f.get("filters", null); + if (newFilters == null) { + throw new InvalidObjectException("Null filters"); + } + filters = newFilters; + dialog = (JDialog) f.get("dialog", null); + int newDialogType = f.get("dialogType", OPEN_DIALOG); + checkDialogType(newDialogType); + dialogType = newDialogType; + returnValue = f.get("returnValue", 0); + accessory = (JComponent) f.get("accessory", null); + fileView = (FileView) f.get("fileView", null); + controlsShown = f.get("controlsShown", false); + useFileHiding = f.get("useFileHiding", false); + int newFileSelectionMode = f.get("fileSelectionMode", FILES_ONLY); + checkFileSelectionMode(newFileSelectionMode); + fileSelectionMode = newFileSelectionMode; + multiSelectionEnabled = f.get("multiSelectionEnabled", false); + useAcceptAllFileFilter = f.get("useAcceptAllFileFilter", false); + boolean newDragEnabled = f.get("dragEnabled", false); + checkDragEnabled(newDragEnabled); + dragEnabled = newDragEnabled; + fileFilter = (FileFilter) f.get("fileFilter", null); + fileSystemView = (FileSystemView) f.get("fileSystemView", null); + currentDirectory = (File) f.get("currentDirectory", null); + selectedFile = (File) f.get("selectedFile", null); + selectedFiles = (File[]) f.get("selectedFiles", null); + accessibleContext = (AccessibleContext) f.get("accessibleContext", null); + installShowFilesListener(); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JFrame.java b/jdk/src/java.desktop/share/classes/javax/swing/JFrame.java index cc3b0807f96..9de3edef45a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JFrame.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JFrame.java @@ -24,14 +24,22 @@ */ package javax.swing; -import java.awt.*; -import java.awt.event.*; -import java.beans.PropertyChangeListener; -import java.util.Locale; -import java.util.Vector; -import java.io.Serializable; +import java.awt.AWTEvent; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.LayoutManager; +import java.awt.event.WindowEvent; -import javax.accessibility.*; +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; /** @@ -297,33 +305,28 @@ public class JFrame extends Frame implements WindowConstants, * @see #setDefaultCloseOperation * @see java.awt.Window#processWindowEvent */ - protected void processWindowEvent(WindowEvent e) { + protected void processWindowEvent(final WindowEvent e) { super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { - switch(defaultCloseOperation) { - case HIDE_ON_CLOSE: - setVisible(false); - break; - case DISPOSE_ON_CLOSE: - dispose(); - break; - case DO_NOTHING_ON_CLOSE: - default: - break; - case EXIT_ON_CLOSE: - // This needs to match the checkExit call in - // setDefaultCloseOperation - System.exit(0); - break; + switch (defaultCloseOperation) { + case HIDE_ON_CLOSE: + setVisible(false); + break; + case DISPOSE_ON_CLOSE: + dispose(); + break; + case EXIT_ON_CLOSE: + // This needs to match the checkExit call in + // setDefaultCloseOperation + System.exit(0); + break; + case DO_NOTHING_ON_CLOSE: + default: } } } -// public void setMenuBar(MenuBar menu) { -// throw new IllegalComponentStateException("Please use setJMenuBar() with JFrame."); -// } - /** * Sets the operation that will happen by default when * the user initiates a "close" on this frame. diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JLayer.java b/jdk/src/java.desktop/share/classes/javax/swing/JLayer.java index 57bccae7ec6..8c58c916a4e 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JLayer.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JLayer.java @@ -158,8 +158,9 @@ public final class JLayer private LayerUI layerUI; private JPanel glassPane; private long eventMask; - private transient boolean isPainting; - private transient boolean isPaintingImmediately; + private transient boolean isPaintCalling; + private transient boolean isPaintImmediatelyCalling; + private transient boolean isImageUpdateCalling; private static final LayerEventController eventController = new LayerEventController(); @@ -405,30 +406,57 @@ public final class JLayer * @param h the height of the region to be painted */ public void paintImmediately(int x, int y, int w, int h) { - if (!isPaintingImmediately && getUI() != null) { - isPaintingImmediately = true; + if (!isPaintImmediatelyCalling && getUI() != null) { + isPaintImmediatelyCalling = true; try { getUI().paintImmediately(x, y, w, h, this); } finally { - isPaintingImmediately = false; + isPaintImmediatelyCalling = false; } } else { super.paintImmediately(x, y, w, h); } } + /** + * Delegates its functionality to the + * {@link javax.swing.plaf.LayerUI#imageUpdate(java.awt.Image, int, int, int, int, int, JLayer)} method, + * if the {@code LayerUI} is set. + * + * @param img the image being observed + * @param infoflags see {@code imageUpdate} for more information + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @return {@code false} if the infoflags indicate that the + * image is completely loaded; {@code true} otherwise. + */ + public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { + if (!isImageUpdateCalling && getUI() != null) { + isImageUpdateCalling = true; + try { + return getUI().imageUpdate(img, infoflags, x, y, w, h, this); + } finally { + isImageUpdateCalling = false; + } + } else { + return super.imageUpdate(img, infoflags, x, y, w, h); + } + } + /** * Delegates all painting to the {@link javax.swing.plaf.LayerUI} object. * * @param g the {@code Graphics} to render to */ public void paint(Graphics g) { - if (!isPainting) { - isPainting = true; + if (!isPaintCalling) { + isPaintCalling = true; try { super.paintComponent(g); } finally { - isPainting = false; + isPaintCalling = false; } } else { super.paint(g); @@ -646,15 +674,21 @@ public final class JLayer return 1; } + @SuppressWarnings("unchecked") private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - s.defaultReadObject(); - if (layerUI != null) { - setUI(layerUI); - } + ObjectInputStream.GetField f = s.readFields(); + + view = (V) f.get("view", null); + glassPane = (JPanel) f.get("glassPane", null); + eventMask = f.get("eventMask", 0l); if (eventMask != 0) { eventController.updateAWTEventListener(0, eventMask); } + LayerUI newLayerUI = (LayerUI) f.get("layerUI", null); + if (newLayerUI != null) { + setUI(newLayerUI); + } } /** diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JOptionPane.java b/jdk/src/java.desktop/share/classes/javax/swing/JOptionPane.java index b3d52fc5274..413b3cfab73 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JOptionPane.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JOptionPane.java @@ -43,13 +43,10 @@ import java.awt.event.WindowEvent; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.io.IOException; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.Vector; import javax.swing.plaf.OptionPaneUI; import javax.swing.event.InternalFrameEvent; @@ -2055,15 +2052,22 @@ public class JOptionPane extends JComponent implements Accessible * description: The option pane's message type. */ public void setMessageType(int newType) { + checkMessageType(newType); + int oldType = messageType; + messageType = newType; + firePropertyChange(MESSAGE_TYPE_PROPERTY, oldType, messageType); + } + + private static void checkMessageType(int newType){ if(newType != ERROR_MESSAGE && newType != INFORMATION_MESSAGE && newType != WARNING_MESSAGE && newType != QUESTION_MESSAGE && newType != PLAIN_MESSAGE) - throw new RuntimeException("JOptionPane: type must be one of JOptionPane.ERROR_MESSAGE, JOptionPane.INFORMATION_MESSAGE, JOptionPane.WARNING_MESSAGE, JOptionPane.QUESTION_MESSAGE or JOptionPane.PLAIN_MESSAGE"); - - int oldType = messageType; - - messageType = newType; - firePropertyChange(MESSAGE_TYPE_PROPERTY, oldType, messageType); + throw new RuntimeException("JOptionPane: type must be one of" + + " JOptionPane.ERROR_MESSAGE," + + " JOptionPane.INFORMATION_MESSAGE," + + " JOptionPane.WARNING_MESSAGE," + + " JOptionPane.QUESTION_MESSAGE" + + " or JOptionPane.PLAIN_MESSAGE"); } /** @@ -2097,16 +2101,23 @@ public class JOptionPane extends JComponent implements Accessible * description: The option pane's option type. */ public void setOptionType(int newType) { - if(newType != DEFAULT_OPTION && newType != YES_NO_OPTION && - newType != YES_NO_CANCEL_OPTION && newType != OK_CANCEL_OPTION) - throw new RuntimeException("JOptionPane: option type must be one of JOptionPane.DEFAULT_OPTION, JOptionPane.YES_NO_OPTION, JOptionPane.YES_NO_CANCEL_OPTION or JOptionPane.OK_CANCEL_OPTION"); - + checkOptionType(newType); int oldType = optionType; - optionType = newType; firePropertyChange(OPTION_TYPE_PROPERTY, oldType, optionType); } + private static void checkOptionType(int newType) { + if (newType != DEFAULT_OPTION && newType != YES_NO_OPTION + && newType != YES_NO_CANCEL_OPTION + && newType != OK_CANCEL_OPTION) { + throw new RuntimeException("JOptionPane: option type must be one of" + + " JOptionPane.DEFAULT_OPTION, JOptionPane.YES_NO_OPTION," + + " JOptionPane.YES_NO_CANCEL_OPTION" + + " or JOptionPane.OK_CANCEL_OPTION"); + } + } + /** * Returns the type of options that are displayed. * @@ -2385,7 +2396,15 @@ public class JOptionPane extends JComponent implements Accessible private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - s.defaultReadObject(); + ObjectInputStream.GetField f = s.readFields(); + + int newMessageType = f.get("messageType", 0); + checkMessageType(newMessageType); + messageType = newMessageType; + int newOptionType = f.get("optionType", 0); + checkOptionType(newOptionType); + optionType = newOptionType; + wantsInput = f.get("wantsInput", false); Vector values = (Vector)s.readObject(); int indexCounter = 0; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JPopupMenu.java b/jdk/src/java.desktop/share/classes/javax/swing/JPopupMenu.java index ca00144b774..89311ba1228 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JPopupMenu.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JPopupMenu.java @@ -1345,7 +1345,20 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { // implements javax.swing.MenuElement private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - s.defaultReadObject(); + ObjectInputStream.GetField f = s.readFields(); + + int newDesiredLocationX = f.get("desiredLocationX", 0); + int newDesiredLocationY = f.get("desiredLocationY", 0); + Point p = adjustPopupLocationToFitScreen( + newDesiredLocationX, newDesiredLocationY); + desiredLocationX = p.x; + desiredLocationY = p.y; + + label = (String) f.get("label", null); + paintBorder = f.get("paintBorder", false); + margin = (Insets) f.get("margin", null); + lightWeightPopup = f.get("lightWeightPopup", false); + selectionModel = (SingleSelectionModel) f.get("selectionModel", null); Vector values = (Vector)s.readObject(); int indexCounter = 0; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java b/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java index 96c050529fe..ffde325f8d8 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java @@ -495,10 +495,7 @@ public class JTabbedPane extends JComponent * */ public void setTabPlacement(int tabPlacement) { - if (tabPlacement != TOP && tabPlacement != LEFT && - tabPlacement != BOTTOM && tabPlacement != RIGHT) { - throw new IllegalArgumentException("illegal tab placement: must be TOP, BOTTOM, LEFT, or RIGHT"); - } + checkTabPlacement(tabPlacement); if (this.tabPlacement != tabPlacement) { int oldValue = this.tabPlacement; this.tabPlacement = tabPlacement; @@ -508,6 +505,14 @@ public class JTabbedPane extends JComponent } } + private static void checkTabPlacement(int tabPlacement) { + if (tabPlacement != TOP && tabPlacement != LEFT && + tabPlacement != BOTTOM && tabPlacement != RIGHT) { + throw new IllegalArgumentException("illegal tab placement:" + + " must be TOP, BOTTOM, LEFT, or RIGHT"); + } + } + /** * Returns the policy used by the tabbedpane to layout the tabs when all the * tabs will not fit within a single run. @@ -551,9 +556,7 @@ public class JTabbedPane extends JComponent * */ public void setTabLayoutPolicy(int tabLayoutPolicy) { - if (tabLayoutPolicy != WRAP_TAB_LAYOUT && tabLayoutPolicy != SCROLL_TAB_LAYOUT) { - throw new IllegalArgumentException("illegal tab layout policy: must be WRAP_TAB_LAYOUT or SCROLL_TAB_LAYOUT"); - } + checkTabLayoutPolicy(tabLayoutPolicy); if (this.tabLayoutPolicy != tabLayoutPolicy) { int oldValue = this.tabLayoutPolicy; this.tabLayoutPolicy = tabLayoutPolicy; @@ -563,6 +566,14 @@ public class JTabbedPane extends JComponent } } + private static void checkTabLayoutPolicy(int tabLayoutPolicy) { + if (tabLayoutPolicy != WRAP_TAB_LAYOUT + && tabLayoutPolicy != SCROLL_TAB_LAYOUT) { + throw new IllegalArgumentException("illegal tab layout policy:" + + " must be WRAP_TAB_LAYOUT or SCROLL_TAB_LAYOUT"); + } + } + /** * Returns the currently selected index for this tabbedpane. * Returns -1 if there is no currently selected tab. @@ -1816,7 +1827,19 @@ public class JTabbedPane extends JComponent private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - s.defaultReadObject(); + ObjectInputStream.GetField f = s.readFields(); + + int newTabPlacement = f.get("tabPlacement", TOP); + checkTabPlacement(newTabPlacement); + tabPlacement = newTabPlacement; + int newTabLayoutPolicy = f.get("tabLayoutPolicy", 0); + checkTabLayoutPolicy(newTabLayoutPolicy); + tabLayoutPolicy = newTabLayoutPolicy; + model = (SingleSelectionModel) f.get("model", null); + haveRegistered = f.get("haveRegistered", false); + changeListener = (ChangeListener) f.get("changeListener", null); + visComp = (Component) f.get("visComp", null); + if ((ui != null) && (getUIClassID().equals(uiClassID))) { ui.installUI(this); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java index a4f30ac33a5..d88dbed9985 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java @@ -37,6 +37,7 @@ import java.beans.*; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; +import java.io.InvalidObjectException; import javax.accessibility.*; @@ -1203,11 +1204,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * AUTO_RESIZE_ALL_COLUMNS JTable.AUTO_RESIZE_ALL_COLUMNS */ public void setAutoResizeMode(int mode) { - if ((mode == AUTO_RESIZE_OFF) || - (mode == AUTO_RESIZE_NEXT_COLUMN) || - (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) || - (mode == AUTO_RESIZE_LAST_COLUMN) || - (mode == AUTO_RESIZE_ALL_COLUMNS)) { + if (isValidAutoResizeMode(mode)) { int old = autoResizeMode; autoResizeMode = mode; resizeAndRepaint(); @@ -1218,6 +1215,14 @@ public class JTable extends JComponent implements TableModelListener, Scrollable } } + private static boolean isValidAutoResizeMode(int mode) { + return (mode == AUTO_RESIZE_OFF) + || (mode == AUTO_RESIZE_NEXT_COLUMN) + || (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) + || (mode == AUTO_RESIZE_LAST_COLUMN) + || (mode == AUTO_RESIZE_ALL_COLUMNS); + } + /** * Returns the auto resize mode of the table. The default mode * is AUTO_RESIZE_SUBSEQUENT_COLUMNS. @@ -1439,10 +1444,14 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * bound: false */ public void setDragEnabled(boolean b) { + checkDragEnabled(b); + dragEnabled = b; + } + + private void checkDragEnabled(boolean b) { if (b && GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } - dragEnabled = b; } /** @@ -1489,6 +1498,11 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @since 1.6 */ public final void setDropMode(DropMode dropMode) { + checkDropMode(dropMode); + this.dropMode = dropMode; + } + + private static void checkDropMode(DropMode dropMode) { if (dropMode != null) { switch (dropMode) { case USE_SELECTION: @@ -1499,14 +1513,12 @@ public class JTable extends JComponent implements TableModelListener, Scrollable case ON_OR_INSERT: case ON_OR_INSERT_ROWS: case ON_OR_INSERT_COLS: - this.dropMode = dropMode; return; } } - - throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for table"); + throw new IllegalArgumentException(dropMode + + ": Unsupported drop mode for table"); } - /** * Returns the drop mode for this component. * @@ -5865,7 +5877,75 @@ public class JTable extends JComponent implements TableModelListener, Scrollable private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - s.defaultReadObject(); + ObjectInputStream.GetField f = s.readFields(); + + TableModel newDataModel = (TableModel) f.get("dataModel", null); + if (newDataModel == null) { + throw new InvalidObjectException("Null dataModel"); + } + dataModel = newDataModel; + + TableColumnModel newColumnModel = (TableColumnModel) f.get("columnModel", null); + if (newColumnModel == null) { + throw new InvalidObjectException("Null columnModel"); + } + columnModel = newColumnModel; + + ListSelectionModel newSelectionModel = (ListSelectionModel) f.get("selectionModel", null); + if (newSelectionModel == null) { + throw new InvalidObjectException("Null selectionModel"); + } + selectionModel = newSelectionModel; + + tableHeader = (JTableHeader) f.get("tableHeader", null); + int newRowHeight = f.get("rowHeight", 0); + if (newRowHeight <= 0) { + throw new InvalidObjectException("Row height less than 1"); + } + rowHeight = newRowHeight; + + rowMargin = f.get("rowMargin", 0); + Color newGridColor = (Color) f.get("gridColor", null); + if (newGridColor == null) { + throw new InvalidObjectException("Null gridColor"); + } + gridColor = newGridColor; + + showHorizontalLines = f.get("showHorizontalLines", false); + showVerticalLines = f.get("showVerticalLines", false); + int newAutoResizeMode = f.get("autoResizeMode", 0); + if (!isValidAutoResizeMode(newAutoResizeMode)) { + throw new InvalidObjectException("autoResizeMode is not valid"); + } + autoResizeMode = newAutoResizeMode; + autoCreateColumnsFromModel = f.get("autoCreateColumnsFromModel", false); + preferredViewportSize = (Dimension) f.get("preferredViewportSize", null); + rowSelectionAllowed = f.get("rowSelectionAllowed", false); + cellSelectionEnabled = f.get("cellSelectionEnabled", false); + selectionForeground = (Color) f.get("selectionForeground", null); + selectionBackground = (Color) f.get("selectionBackground", null); + rowModel = (SizeSequence) f.get("rowModel", null); + + boolean newDragEnabled = f.get("dragEnabled", false); + checkDragEnabled(newDragEnabled); + dragEnabled = newDragEnabled; + + surrendersFocusOnKeystroke = f.get("surrendersFocusOnKeystroke", false); + editorRemover = (PropertyChangeListener) f.get("editorRemover", null); + columnSelectionAdjusting = f.get("columnSelectionAdjusting", false); + rowSelectionAdjusting = f.get("rowSelectionAdjusting", false); + printError = (Throwable) f.get("printError", null); + isRowHeightSet = f.get("isRowHeightSet", false); + updateSelectionOnSort = f.get("updateSelectionOnSort", false); + ignoreSortChange = f.get("ignoreSortChange", false); + sorterChanged = f.get("sorterChanged", false); + autoCreateRowSorter = f.get("autoCreateRowSorter", false); + fillsViewportHeight = f.get("fillsViewportHeight", false); + DropMode newDropMode = (DropMode) f.get("dropMode", + DropMode.USE_SELECTION); + checkDropMode(newDropMode); + dropMode = newDropMode; + if ((ui != null) && (getUIClassID().equals(uiClassID))) { ui.installUI(this); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JTree.java b/jdk/src/java.desktop/share/classes/javax/swing/JTree.java index 3188156e347..6d50f6f653a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JTree.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JTree.java @@ -1216,10 +1216,14 @@ public class JTree extends JComponent implements Scrollable, Accessible * bound: false */ public void setDragEnabled(boolean b) { + checkDragEnabled(b); + dragEnabled = b; + } + + private static void checkDragEnabled(boolean b) { if (b && GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } - dragEnabled = b; } /** @@ -1262,18 +1266,23 @@ public class JTree extends JComponent implements Scrollable, Accessible * @since 1.6 */ public final void setDropMode(DropMode dropMode) { + checkDropMode(dropMode); + this.dropMode = dropMode; + } + + private static void checkDropMode(DropMode dropMode) { if (dropMode != null) { switch (dropMode) { case USE_SELECTION: case ON: case INSERT: case ON_OR_INSERT: - this.dropMode = dropMode; return; } } - throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for tree"); + throw new IllegalArgumentException(dropMode + + ": Unsupported drop mode for tree"); } /** @@ -3089,7 +3098,34 @@ public class JTree extends JComponent implements Scrollable, Accessible private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - s.defaultReadObject(); + ObjectInputStream.GetField f = s.readFields(); + + rootVisible = f.get("rootVisible", false); + rowHeight = f.get("rowHeight", 0); + rowHeightSet = f.get("rowHeightSet", false); + showsRootHandles = f.get("showsRootHandles", false); + showsRootHandlesSet = f.get("showsRootHandlesSet", false); + editable = f.get("editable", false); + largeModel = f.get("largeModel", false); + visibleRowCount = f.get("visibleRowCount", 0); + invokesStopCellEditing = f.get("invokesStopCellEditing", false); + scrollsOnExpand = f.get("scrollsOnExpand", false); + scrollsOnExpandSet = f.get("scrollsOnExpandSet", false); + toggleClickCount = f.get("toggleClickCount", 0); + leadPath = (TreePath) f.get("leadPath", null); + anchorPath = (TreePath) f.get("anchorPath", null); + expandsSelectedPaths = f.get("expandsSelectedPaths", false); + settingUI = f.get("settingUI", false); + boolean newDragEnabled = f.get("dragEnabled", false); + checkDragEnabled(newDragEnabled); + dragEnabled = newDragEnabled; + DropMode newDropMode = (DropMode) f.get("dropMode", + DropMode.USE_SELECTION); + checkDropMode(newDropMode); + dropMode = newDropMode; + + expandRow = f.get("expandRow", -1); + dropTimer = (TreeTimer) f.get("dropTimer", null); // Create an instance of expanded state. diff --git a/jdk/src/java.desktop/share/classes/javax/swing/LegacyGlueFocusTraversalPolicy.java b/jdk/src/java.desktop/share/classes/javax/swing/LegacyGlueFocusTraversalPolicy.java index de33d4c4dae..ac366ca8df6 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/LegacyGlueFocusTraversalPolicy.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/LegacyGlueFocusTraversalPolicy.java @@ -194,7 +194,23 @@ final class LegacyGlueFocusTraversalPolicy extends FocusTraversalPolicy private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); + ObjectInputStream.GetField f = in.readFields(); + + @SuppressWarnings("unchecked") + HashMap newForwardMap = + (HashMap ) f.get("forwardMap", null); + if (newForwardMap == null) { + throw new InvalidObjectException("Null forwardMap"); + } + forwardMap = newForwardMap; + @SuppressWarnings("unchecked") + HashMap newBackwardMap = + (HashMap) f.get("backwardMap", null); + if (newBackwardMap == null) { + throw new InvalidObjectException("Null backwardMap"); + } + backwardMap = newBackwardMap; + delegatePolicy = (FocusTraversalPolicy)in.readObject(); delegateManager = (DefaultFocusManager)in.readObject(); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/SwingUtilities.java b/jdk/src/java.desktop/share/classes/javax/swing/SwingUtilities.java index fb7b2820fd2..07705f4a812 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/SwingUtilities.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/SwingUtilities.java @@ -374,7 +374,8 @@ public class SwingUtilities implements SwingConstants sourceWheelEvent.isPopupTrigger(), sourceWheelEvent.getScrollType(), sourceWheelEvent.getScrollAmount(), - sourceWheelEvent.getWheelRotation()); + sourceWheelEvent.getWheelRotation(), + sourceWheelEvent.getPreciseWheelRotation()); } else if (sourceEvent instanceof MenuDragMouseEvent) { MenuDragMouseEvent sourceMenuDragEvent = (MenuDragMouseEvent)sourceEvent; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/Timer.java b/jdk/src/java.desktop/share/classes/javax/swing/Timer.java index 6caced7dd8d..ffaa9d53b3c 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/Timer.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/Timer.java @@ -401,14 +401,15 @@ public class Timer implements Serializable * @see #setInitialDelay */ public void setDelay(int delay) { - if (delay < 0) { - throw new IllegalArgumentException("Invalid delay: " + delay); - } - else { + checkDelay(delay, "Invalid delay: "); this.delay = delay; } - } + private static void checkDelay(int delay, String message) { + if (delay < 0) { + throw new IllegalArgumentException(message + delay); + } + } /** * Returns the delay, in milliseconds, @@ -435,14 +436,9 @@ public class Timer implements Serializable * @see #setDelay */ public void setInitialDelay(int initialDelay) { - if (initialDelay < 0) { - throw new IllegalArgumentException("Invalid initial delay: " + - initialDelay); - } - else { + checkDelay(initialDelay, "Invalid initial delay: "); this.initialDelay = initialDelay; } - } /** @@ -638,7 +634,26 @@ public class Timer implements Serializable throws ClassNotFoundException, IOException { this.acc = AccessController.getContext(); - in.defaultReadObject(); + ObjectInputStream.GetField f = in.readFields(); + + EventListenerList newListenerList = (EventListenerList) + f.get("listenerList", null); + if (newListenerList == null) { + throw new InvalidObjectException("Null listenerList"); + } + listenerList = newListenerList; + + int newInitialDelay = f.get("initialDelay", 0); + checkDelay(newInitialDelay, "Invalid initial delay: "); + initialDelay = newInitialDelay; + + int newDelay = f.get("delay", 0); + checkDelay(newDelay, "Invalid delay: "); + delay = newDelay; + + repeats = f.get("repeats", false); + coalesce = f.get("coalesce", false); + actionCommand = (String) f.get("actionCommand", null); } /* diff --git a/jdk/src/java.desktop/share/classes/javax/swing/event/SwingPropertyChangeSupport.java b/jdk/src/java.desktop/share/classes/javax/swing/event/SwingPropertyChangeSupport.java index 817a2f79bb8..3543e1c3720 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/event/SwingPropertyChangeSupport.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/event/SwingPropertyChangeSupport.java @@ -107,7 +107,7 @@ public final class SwingPropertyChangeSupport extends PropertyChangeSupport { * @see #SwingPropertyChangeSupport(Object sourceBean, boolean notifyOnEDT) * @since 1.6 */ - public final boolean isNotifyOnEDT() { + public boolean isNotifyOnEDT() { return notifyOnEDT; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/ComboBoxUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/ComboBoxUI.java index e0d9f1fb7f9..2ba9741c770 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/ComboBoxUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/ComboBoxUI.java @@ -37,16 +37,25 @@ public abstract class ComboBoxUI extends ComponentUI { /** * Set the visibility of the popup + * + * @param c a {@code JComboBox} + * @param v a {@code boolean} determining the visibilty of the popup */ public abstract void setPopupVisible( JComboBox c, boolean v ); /** * Determine the visibility of the popup + * + * @param c a {@code JComboBox} + * @return true if popup of the {@code JComboBox} is visible */ public abstract boolean isPopupVisible( JComboBox c ); /** * Determine whether or not the combo box itself is traversable + * + * @param c a {@code JComboBox} + * @return true if the given {@code JComboBox} is traversable */ public abstract boolean isFocusTraversable( JComboBox c ); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/ComponentUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/ComponentUI.java index 190d450e09a..15a05cdd6b0 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/ComponentUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/ComponentUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, 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 @@ -173,7 +173,8 @@ public abstract class ComponentUI { * this argument is often ignored, * but might be used if the UI object is stateless * and shared by multiple components - * + * @return a {@code Dimension} object containing given component's preferred + * size appropriate for the look and feel * @see javax.swing.JComponent#getPreferredSize * @see java.awt.LayoutManager#preferredLayoutSize */ @@ -240,7 +241,8 @@ public abstract class ComponentUI { * and shared by multiple components * @param x the x coordinate of the point * @param y the y coordinate of the point - * + * @return {@code true} if the specified {@code x,y} location is contained + * within the look and feel's defined shape for the given component * @see javax.swing.JComponent#contains * @see java.awt.Component#contains */ @@ -258,6 +260,9 @@ public abstract class ComponentUI { * stateful, then it should return a new instance per component. * The default implementation of this method throws an error, as it * should never be invoked. + * + * @param c a {@code JComponent} for which to create a UI delegate + * @return a {@code ComponentUI} object for {@code c} */ public static ComponentUI createUI(JComponent c) { throw new Error("ComponentUI.createUI not implemented."); @@ -332,8 +337,9 @@ public abstract class ComponentUI { * Component.AccessibleAWTComponent.getAccessibleChildrenCount() instead * of this method. * - * @see #getAccessibleChild + * @param c {@code JComponent} for which to get count of accessible children * @return the number of accessible children in the object + * @see #getAccessibleChild */ public int getAccessibleChildrenCount(JComponent c) { return SwingUtilities.getAccessibleChildrenCount(c); @@ -351,9 +357,10 @@ public abstract class ComponentUI { * Component.AccessibleAWTComponent.getAccessibleChild() instead of * this method. * - * @see #getAccessibleChildrenCount + * @param c a {@code JComponent} for which to get a child object * @param i zero-based index of child * @return the ith Accessible child of the object + * @see #getAccessibleChildrenCount */ public Accessible getAccessibleChild(JComponent c, int i) { return SwingUtilities.getAccessibleChild(c, i); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/FileChooserUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/FileChooserUI.java index d9b4361ae47..e3f2373b4cd 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/FileChooserUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/FileChooserUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, 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 @@ -52,6 +52,8 @@ public abstract class FileChooserUI extends ComponentUI * JFileChooser will use this button as default button * for dialog windows. * + * @param fc the {@code JFileChooser} whose default button is requested + * @return the default JButton for current look and feel * @since 1.7 */ public JButton getDefaultButton(JFileChooser fc) { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/LayerUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/LayerUI.java index a8584fd0fdc..a60da23517a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/LayerUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/LayerUI.java @@ -716,10 +716,22 @@ public class LayerUI * @param y the y value of the region to be painted * @param width the width of the region to be painted * @param height the height of the region to be painted - * + * @param l a {@code JLayer} component * @see JComponent#paintImmediately(int, int, int, int) */ public void paintImmediately(int x, int y, int width, int height, JLayer l) { l.paintImmediately(x, y, width, height); } + + /** + * Delegates its functionality to the default implementation of the {@code JLayer.imageUpdate} method + * which is inherited from {@code JLayer}'s base classes. + *

    + * This method is to be overridden instead of {@code JLayer.imageUpdate}. + *

    + * Note: This method is usually called not on the Event Dispatching Thread. + */ + public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h, JLayer l) { + return l.imageUpdate(img, infoflags, x, y, w, h); + } } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/OptionPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/OptionPaneUI.java index 49137e7a0db..fc967b84315 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/OptionPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/OptionPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, 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 @@ -38,12 +38,18 @@ public abstract class OptionPaneUI extends ComponentUI /** * Requests the component representing the default value to have * focus. + * + * @param op a {@code JOptionPane} */ public abstract void selectInitialValue(JOptionPane op); /** * Returns true if the user has supplied instances of Component for * either the options or message. + * + * @param op a {@code JOptionPane} + * @return {@code true} if the given {@code JOptionPane} contains user + * created {@code Component}s */ public abstract boolean containsCustomComponents(JOptionPane op); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/PopupMenuUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/PopupMenuUI.java index 5f57c659258..ab485a2c4ad 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/PopupMenuUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/PopupMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2000, 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 @@ -39,6 +39,11 @@ import javax.swing.JPopupMenu; public abstract class PopupMenuUI extends ComponentUI { /** + * Returns whether or not the given {@code MouseEvent} is the popup menu + * trigger event for the platform + * + * @param e a {@code MouseEvent} + * @return true if the {@code MouseEvent e} is the popup menu trigger * @since 1.3 */ public boolean isPopupTrigger(MouseEvent e) { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/SplitPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/SplitPaneUI.java index ed62e39a4d7..15afcee9a0d 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/SplitPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/SplitPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, 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 @@ -38,32 +38,49 @@ public abstract class SplitPaneUI extends ComponentUI /** * Messaged to relayout the JSplitPane based on the preferred size * of the children components. + * + * @param jc a {@code JSplitPane} */ public abstract void resetToPreferredSizes(JSplitPane jc); /** * Sets the location of the divider to location. + * + * @param jc a {@code JSplitPane} + * @param location an integer specifying the location of the divider */ public abstract void setDividerLocation(JSplitPane jc, int location); /** * Returns the location of the divider. + * + * @param jc a {@code JSplitPane} + * @return an integer specifying the location of the divider */ public abstract int getDividerLocation(JSplitPane jc); /** * Returns the minimum possible location of the divider. + * + * @param jc a {@code JSplitPane} + * @return and integer specifying the minimum location of the divider */ public abstract int getMinimumDividerLocation(JSplitPane jc); /** * Returns the maximum possible location of the divider. + * + * @param jc a {@code JSplitPane} + * @return an integer specifying the maximum location of the divider */ public abstract int getMaximumDividerLocation(JSplitPane jc); /** * Messaged after the JSplitPane the receiver is providing the look * and feel for paints its children. + * + * @param jc a {@code JSplitPane} + * @param g the {@code Graphics} context */ public abstract void finishedPaintingChildren(JSplitPane jc, Graphics g); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java index 0ce25c19071..6332d1ddc23 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -42,8 +42,9 @@ public abstract class TextUI extends ComponentUI * Converts the given location in the model to a place in * the view coordinate system. * + * @param t the text component for which this UI is installed * @param pos the local location in the model to translate >= 0 - * @return the coordinates as a rectangle + * @return the coordinates as a {@code Rectangle} * @exception BadLocationException if the given position does not * represent a valid location in the associated document */ @@ -53,8 +54,10 @@ public abstract class TextUI extends ComponentUI * Converts the given location in the model to a place in * the view coordinate system. * + * @param t the text component for which this UI is installed * @param pos the local location in the model to translate >= 0 - * @return the coordinates as a rectangle + * @param bias the bias for the position + * @return the coordinates as a {@code Rectangle} * @exception BadLocationException if the given position does not * represent a valid location in the associated document */ @@ -64,6 +67,7 @@ public abstract class TextUI extends ComponentUI * Converts the given place in the view coordinate system * to the nearest representative location in the model. * + * @param t the text component for which this UI is installed * @param pt the location in the view to translate. This * should be in the same coordinate system as the mouse * events. @@ -75,6 +79,7 @@ public abstract class TextUI extends ComponentUI * Provides a mapping from the view coordinate space to the logical * coordinate space of the model. * + * @param t the text component for which this UI is installed * @param pt the location in the view to translate. * This should be in the same coordinate system * as the mouse events. @@ -117,6 +122,7 @@ public abstract class TextUI extends ComponentUI * Causes the portion of the view responsible for the * given part of the model to be repainted. * + * @param t the text component for which this UI is installed * @param p0 the beginning of the range >= 0 * @param p1 the end of the range >= p0 */ @@ -126,8 +132,13 @@ public abstract class TextUI extends ComponentUI * Causes the portion of the view responsible for the * given part of the model to be repainted. * + * @param t the text component for which this UI is installed * @param p0 the beginning of the range >= 0 * @param p1 the end of the range >= p0 + * @param firstBias the bias of the first character position, toward the + * previous character or the next character + * @param secondBias the bias of the second character position, toward the + * previous character or the next character */ public abstract void damageRange(JTextComponent t, int p0, int p1, Position.Bias firstBias, @@ -139,6 +150,7 @@ public abstract class TextUI extends ComponentUI * things like the commands available, stream readers and * writers, etc. * + * @param t the text component for which this UI is installed * @return the editor kit binding */ public abstract EditorKit getEditorKit(JTextComponent t); @@ -149,13 +161,18 @@ public abstract class TextUI extends ComponentUI * can be traversed to determine how the model is being * represented spatially. * - * @return the view + * @param t the text component for which this UI is installed + * @return a {@code View} with the allocation of the associated + * text component */ public abstract View getRootView(JTextComponent t); /** * Returns the string to be used as the tooltip at the passed in location. * + * @param t the text component for which this UI is installed + * @param pt a {@code Point} specifying location for which to get a tooltip + * @return a {@code String} containing the tooltip * @see javax.swing.text.JTextComponent#getToolTipText * @since 1.4 */ diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/TreeUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/TreeUI.java index d1ded67b15b..5968b335402 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/TreeUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/TreeUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, 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 @@ -38,68 +38,109 @@ import javax.swing.tree.TreePath; public abstract class TreeUI extends ComponentUI { /** - * Returns the Rectangle enclosing the label portion that the - * last item in path will be drawn into. Will return null if - * any component in path is currently valid. - */ + * Returns the Rectangle enclosing the label portion that the + * last item in path will be drawn into. Will return null if + * any component in path is currently valid. + * + * @param tree the {@code JTree} for {@code path} + * @param path the {@code TreePath} identifying the node + * @return the {@code Rectangle} enclosing the label portion that the + * last item in path will be drawn into, {@code null} if any + * component in path is currently valid. + */ public abstract Rectangle getPathBounds(JTree tree, TreePath path); /** - * Returns the path for passed in row. If row is not visible - * null is returned. - */ + * Returns the path for passed in row. If row is not visible + * null is returned. + * + * @param tree a {@code JTree} object + * @param row an integer specifying a row + * @return the {@code path} for {@code row} or {@code null} if {@code row} + * is not visible + */ public abstract TreePath getPathForRow(JTree tree, int row); /** - * Returns the row that the last item identified in path is visible - * at. Will return -1 if any of the elements in path are not - * currently visible. - */ + * Returns the row that the last item identified in path is visible + * at. Will return -1 if any of the elements in path are not + * currently visible. + * + * @param tree the {@code JTree} for {@code path} + * @param path the {@code TreePath} object to look in + * @return an integer specifying the row at which the last item + * identified is visible, -1 if any of the elements in + * {@code path} are not currently visible + */ public abstract int getRowForPath(JTree tree, TreePath path); /** - * Returns the number of rows that are being displayed. - */ + * Returns the number of rows that are being displayed. + * + * @param tree the {@code JTree} for which to count rows + * @return an integer specifying the number of row being displayed + */ public abstract int getRowCount(JTree tree); /** - * Returns the path to the node that is closest to x,y. If - * there is nothing currently visible this will return null, otherwise - * it'll always return a valid path. If you need to test if the - * returned object is exactly at x, y you should get the bounds for - * the returned path and test x, y against that. - */ + * Returns the path to the node that is closest to x,y. If + * there is nothing currently visible this will return null, otherwise + * it'll always return a valid path. If you need to test if the + * returned object is exactly at x, y you should get the bounds for + * the returned path and test x, y against that. + * + * @param tree a {@code JTree} object + * @param x an integer giving the number of pixels horizontally from the + * left edge of the display area + * @param y an integer giving the number of pixels vertically from the top + * of the display area, minus any top margin + * @return the {@code TreePath} node closest to {@code x,y} or {@code null} + * if there is nothing currently visible + */ public abstract TreePath getClosestPathForLocation(JTree tree, int x, int y); /** - * Returns true if the tree is being edited. The item that is being - * edited can be returned by getEditingPath(). - */ + * Returns true if the tree is being edited. The item that is being + * edited can be returned by getEditingPath(). + * + * @param tree a {@code JTree} object + * @return true if {@code tree} is being edited + */ public abstract boolean isEditing(JTree tree); /** - * Stops the current editing session. This has no effect if the - * tree isn't being edited. Returns true if the editor allows the - * editing session to stop. - */ + * Stops the current editing session. This has no effect if the + * tree isn't being edited. Returns true if the editor allows the + * editing session to stop. + * + * @param tree a {@code JTree} object + * @return true if the editor allows the editing session to stop + */ public abstract boolean stopEditing(JTree tree); /** - * Cancels the current editing session. This has no effect if the - * tree isn't being edited. Returns true if the editor allows the - * editing session to stop. - */ + * Cancels the current editing session. This has no effect if the + * tree isn't being edited. + * + * @param tree a {@code JTree} object + */ public abstract void cancelEditing(JTree tree); /** - * Selects the last item in path and tries to edit it. Editing will - * fail if the CellEditor won't allow it for the selected item. - */ + * Selects the last item in path and tries to edit it. Editing will + * fail if the CellEditor won't allow it for the selected item. + * + * @param tree the {@code JTree} being edited + * @param path the {@code TreePath} to be edited + */ public abstract void startEditingAtPath(JTree tree, TreePath path); /** * Returns the path to the element that is being edited. + * + * @param tree the {@code JTree} for which to return a path + * @return a {@code TreePath} containing the path to {@code tree} */ public abstract TreePath getEditingPath(JTree tree); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicInternalFrameUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicInternalFrameUI.java index ffbd5ea628b..c7c5ad05a9d 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -351,10 +351,15 @@ public class BasicInternalFrameUI extends InternalFrameUI /** - * Installs necessary mouse handlers on newPane - * and adds it to the frame. - * Reverse process for the currentPane. - */ + * Installs necessary mouse handlers on newPane + * and adds it to the frame. + * Reverse process for the currentPane. + * + * @param currentPane this {@code Jcomponent} is the current pane being + * viewed that has mouse handlers installed + * @param newPane this {@code Jcomponent} is the pane which will be added + * and have mouse handlers installed + */ protected void replacePane(JComponent currentPane, JComponent newPane) { if(currentPane != null) { deinstallMouseHandlers(currentPane); @@ -517,11 +522,12 @@ public class BasicInternalFrameUI extends InternalFrameUI } /// DesktopManager methods - /** Returns the proper DesktopManager. Calls getDesktopPane() to - * find the JDesktop component and returns the desktopManager from - * it. If this fails, it will return a default DesktopManager that - * should work in arbitrary parents. - */ + /** + * Returns the proper DesktopManager. Calls getDesktopPane() to + * find the JDesktop component and returns the desktopManager from + * it. If this fails, it will return a default DesktopManager that + * should work in arbitrary parents. + */ protected DesktopManager getDesktopManager() { if(frame.getDesktopPane() != null && frame.getDesktopPane().getDesktopManager() != null) @@ -539,6 +545,8 @@ public class BasicInternalFrameUI extends InternalFrameUI * This method is called when the user wants to close the frame. * The playCloseSound Action is fired. * This action is delegated to the desktopManager. + * + * @param f the {@code JInternalFrame} being viewed */ protected void closeFrame(JInternalFrame f) { // Internal Frame Auditory Cue Activation @@ -551,6 +559,8 @@ public class BasicInternalFrameUI extends InternalFrameUI * This method is called when the user wants to maximize the frame. * The playMaximizeSound Action is fired. * This action is delegated to the desktopManager. + * + * @param f the {@code JInternalFrame} being viewed */ protected void maximizeFrame(JInternalFrame f) { // Internal Frame Auditory Cue Activation @@ -563,6 +573,8 @@ public class BasicInternalFrameUI extends InternalFrameUI * This method is called when the user wants to minimize the frame. * The playRestoreDownSound Action is fired. * This action is delegated to the desktopManager. + * + * @param f the {@code JInternalFrame} being viewed */ protected void minimizeFrame(JInternalFrame f) { // Internal Frame Auditory Cue Activation @@ -579,6 +591,8 @@ public class BasicInternalFrameUI extends InternalFrameUI * This method is called when the user wants to iconify the frame. * The playMinimizeSound Action is fired. * This action is delegated to the desktopManager. + * + * @param f the {@code JInternalFrame} being viewed */ protected void iconifyFrame(JInternalFrame f) { // Internal Frame Auditory Cue Activation @@ -591,6 +605,8 @@ public class BasicInternalFrameUI extends InternalFrameUI * This method is called when the user wants to deiconify the frame. * The playRestoreUpSound Action is fired. * This action is delegated to the desktopManager. + * + * @param f the {@code JInternalFrame} being viewed */ protected void deiconifyFrame(JInternalFrame f) { // Internal Frame Auditory Cue Activation @@ -603,15 +619,21 @@ public class BasicInternalFrameUI extends InternalFrameUI getDesktopManager().deiconifyFrame(f); } - /** This method is called when the frame becomes selected. + /** + * This method is called when the frame becomes selected. * This action is delegated to the desktopManager. + * + * @param f the {@code JInternalFrame} being viewed */ protected void activateFrame(JInternalFrame f) { getDesktopManager().activateFrame(f); } - /** This method is called when the frame is no longer selected. - * This action is delegated to the desktopManager. - */ + /** + * This method is called when the frame is no longer selected. + * This action is delegated to the desktopManager. + * + * @param f the {@code JInternalFrame} being viewed + */ protected void deactivateFrame(JInternalFrame f) { getDesktopManager().deactivateFrame(f); } @@ -769,7 +791,7 @@ public class BasicInternalFrameUI extends InternalFrameUI resizeDir = SOUTH; } } else { - /* the mouse press happened inside the frame, not in the + /* the mouse press happened inside the frame, not in the border */ discardRelease = true; return; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java index c7642f4e4c4..ebb0862587a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java @@ -93,8 +93,10 @@ public class BasicScrollBarUI private final static int scrollSpeedThrottle = 60; // delay in milli seconds - /** True indicates a middle click will absolutely position the - * scrollbar. */ + /** + * True indicates a middle click will absolutely position the + * scrollbar. + */ private boolean supportsAbsolutePositioning; /** @@ -877,6 +879,10 @@ public class BasicScrollBarUI * Set the bounds of the thumb and force a repaint that includes * the old thumbBounds and the new one. * + * @param x set the x location of the thumb + * @param y set the y location of the thumb + * @param width set the width of the thumb + * @param height set the height of the thumb * @see #getThumbBounds */ protected void setThumbBounds(int x, int y, int width, int height) diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java index b6ca67de67e..bfd4e768ab1 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java @@ -656,10 +656,15 @@ public class BasicSliderUI extends SliderUI{ } /** - * Gets the height of the tick area for horizontal sliders and the width of the - * tick area for vertical sliders. BasicSliderUI uses the returned value to - * determine the tick area rectangle. If you want to give your ticks some room, - * make this larger than you need and paint your ticks away from the sides in paintTicks(). + * Gets the height of the tick area for horizontal sliders and the width of + * the tick area for vertical sliders. BasicSliderUI uses the returned value + * to determine the tick area rectangle. If you want to give your ticks some + * room, make this larger than you need and paint your ticks away from the + * sides in paintTicks(). + * + * @return an integer representing the height of the tick area for + * horizontal sliders, and the width of the tick area for the vertical + * sliders */ protected int getTickLength() { return 8; @@ -867,7 +872,7 @@ public class BasicSliderUI extends SliderUI{ * Returns the smallest value that has an entry in the label table. * * @return smallest value that has an entry in the label table, or - * null. + * null. * @since 1.6 */ protected Integer getLowestValue() { @@ -894,7 +899,11 @@ public class BasicSliderUI extends SliderUI{ /** - * Returns the label that corresponds to the highest slider value in the label table. + * Returns the label that corresponds to the highest slider value in the + * label table. + * + * @return the label that corresponds to the highest slider value in the + * label table * @see JSlider#setLabelTable */ protected Component getLowestValueLabel() { @@ -906,7 +915,11 @@ public class BasicSliderUI extends SliderUI{ } /** - * Returns the label that corresponds to the lowest slider value in the label table. + * Returns the label that corresponds to the lowest slider value in the + * label table. + * + * @return the label that corresponds to the lowest slider value in the + * label table * @see JSlider#setLabelTable */ protected Component getHighestValueLabel() { @@ -1166,8 +1179,14 @@ public class BasicSliderUI extends SliderUI{ } /** - * Called for every label in the label table. Used to draw the labels for horizontal sliders. - * The graphics have been translated to labelRect.y already. + * Called for every label in the label table. Used to draw the labels for + * horizontal sliders. The graphics have been translated to labelRect.y + * already. + * + * @param g the graphics context in which to paint + * @param value the value of the slider + * @param label the component label in the label table that needs to be + * painted * @see JSlider#setLabelTable */ protected void paintHorizontalLabel( Graphics g, int value, Component label ) { @@ -1179,8 +1198,14 @@ public class BasicSliderUI extends SliderUI{ } /** - * Called for every label in the label table. Used to draw the labels for vertical sliders. - * The graphics have been translated to labelRect.x already. + * Called for every label in the label table. Used to draw the labels for + * vertical sliders. The graphics have been translated to labelRect.x + * already. + * + * @param g the graphics context in which to paint + * @param value the value of the slider + * @param label the component label in the label table that needs to be + * painted * @see JSlider#setLabelTable */ protected void paintVerticalLabel( Graphics g, int value, Component label ) { @@ -1342,9 +1367,12 @@ public class BasicSliderUI extends SliderUI{ } /** - * This function is called when a mousePressed was detected in the track, not - * in the thumb. The default behavior is to scroll by block. You can - * override this method to stop it from scrolling or to add additional behavior. + * This function is called when a mousePressed was detected in the track, + * not in the thumb. The default behavior is to scroll by block. You can + * override this method to stop it from scrolling or to add additional + * behavior. + * + * @param dir the direction and number of blocks to scroll */ protected void scrollDueToClickInTrack( int dir ) { scrollByBlock( dir ); @@ -1387,6 +1415,7 @@ public class BasicSliderUI extends SliderUI{ * @param value the slider value to get the location for * @param trackY y-origin of the track * @param trackHeight the height of the track + * @return the y location for the specified value of the slider * @since 1.6 */ protected int yPositionForValue(int value, int trackY, int trackHeight) { @@ -1417,6 +1446,9 @@ public class BasicSliderUI extends SliderUI{ * track at the the bottom or the top, this method sets the value to either * the minimum or maximum value of the slider, depending on if the slider * is inverted or not. + * + * @param yPos the location of the slider along the y axis + * @return the value at the y position */ public int valueForYPosition( int yPos ) { int value; @@ -1449,6 +1481,9 @@ public class BasicSliderUI extends SliderUI{ * track at the left or the right, this method sets the value to either the * minimum or maximum value of the slider, depending on if the slider is * inverted or not. + * + * @param xPos the location of the slider along the x axis + * @return the value of the x position */ public int valueForXPosition( int xPos ) { int value; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java index bf27557ac99..7490b8ea458 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -1174,6 +1174,16 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { * this function draws the border around each tab * note that this function does now draw the background of the tab. * that is done elsewhere + * + * @param g the graphics context in which to paint + * @param tabPlacement the placement (left, right, bottom, top) of the tab + * @param tabIndex the index of the tab with respect to other tabs + * @param x the x coordinate of tab + * @param y the y coordinate of tab + * @param w the width of the tab + * @param h the height of the tab + * @param isSelected a {@code boolean} which determines whether or not + * the tab is selected */ protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, @@ -3530,12 +3540,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { else if (name =="indexForTitle") { calculatedBaseline = false; Integer index = (Integer) e.getNewValue(); - // remove the current index - // to let updateHtmlViews() insert the correct one - if (htmlViews != null) { - htmlViews.removeElementAt(index); - } - updateHtmlViews(index); + updateHtmlViews(index, false); } else if (name == "tabLayoutPolicy") { BasicTabbedPaneUI.this.uninstallUI(pane); BasicTabbedPaneUI.this.installUI(pane); @@ -3574,13 +3579,13 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { calculatedBaseline = false; } else if (name == "indexForNullComponent") { isRunsDirty = true; - updateHtmlViews((Integer)e.getNewValue()); + updateHtmlViews((Integer)e.getNewValue(), true); } else if (name == "font") { calculatedBaseline = false; } } - private void updateHtmlViews(int index) { + private void updateHtmlViews(int index, boolean inserted) { String title = tabPane.getTitleAt(index); boolean isHTML = BasicHTML.isHTMLString(title); if (isHTML) { @@ -3588,16 +3593,24 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { htmlViews = createHTMLVector(); } else { // Vector already exists View v = BasicHTML.createHTMLView(tabPane, title); - htmlViews.insertElementAt(v, index); + setHtmlView(v, inserted, index); } } else { // Not HTML if (htmlViews!=null) { // Add placeholder - htmlViews.insertElementAt(null, index); + setHtmlView(null, inserted, index); } // else nada! } updateMnemonics(); } + private void setHtmlView(View v, boolean inserted, int index) { + if (inserted || index >= htmlViews.size()) { + htmlViews.insertElementAt(v, index); + } else { + htmlViews.setElementAt(v, index); + } + } + // // ChangeListener // @@ -3716,7 +3729,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { return; } isRunsDirty = true; - updateHtmlViews(tp.indexOfComponent(child)); + updateHtmlViews(tp.indexOfComponent(child), true); } public void componentRemoved(ContainerEvent e) { JTabbedPane tp = (JTabbedPane)e.getContainer(); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java b/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java index 111ab923a85..6b1bf61bb00 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java @@ -1426,11 +1426,18 @@ public abstract class AbstractDocument implements Document, Serializable { // --- serialization --------------------------------------------- + @SuppressWarnings("unchecked") private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { - s.defaultReadObject(); + ObjectInputStream.GetField f = s.readFields(); + + documentProperties = + (Dictionary) f.get("documentProperties", null); listenerList = new EventListenerList(); + data = (Content) f.get("data", null); + context = (AttributeContext) f.get("context", null); + documentFilter = (DocumentFilter) f.get("documentFilter", null); // Restore bidi structure //REMIND(bcb) This creates an initial bidi element to account for diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java b/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java index 5eb0b2b10fe..cd17fed60bd 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java @@ -1516,7 +1516,30 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { - s.defaultReadObject(); + ObjectInputStream.GetField f = s.readFields(); + + EventListenerList newListenerList = (EventListenerList) f.get("listenerList", null); + if (newListenerList == null) { + throw new InvalidObjectException("Null listenerList"); + } + listenerList = newListenerList; + component = (JTextComponent) f.get("component", null); + updatePolicy = f.get("updatePolicy", 0); + visible = f.get("visible", false); + active = f.get("active", false); + dot = f.get("dot", 0); + mark = f.get("mark", 0); + selectionTag = f.get("selectionTag", null); + selectionVisible = f.get("selectionVisible", false); + flasher = (Timer) f.get("flasher", null); + magicCaretPosition = (Point) f.get("magicCaretPosition", null); + dotLTR = f.get("dotLTR", false); + markLTR = f.get("markLTR", false); + ownsSelection = f.get("ownsSelection", false); + forceCaretPositionChange = f.get("forceCaretPositionChange", false); + caretWidth = f.get("caretWidth", 0); + aspectRatio = f.get("aspectRatio", 0.0f); + handler = new Handler(); if (!s.readBoolean()) { dotBias = Position.Bias.Forward; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java b/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java index 78788cbfad1..09faa5671cb 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java @@ -1082,8 +1082,9 @@ public class DefaultStyledDocument extends AbstractDocument implements StyledDoc private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { - listeningStyles = new Vector

    Audio System Property Keys