diff --git a/.hgtags b/.hgtags index 99b55cd1110..31681df35e7 100644 --- a/.hgtags +++ b/.hgtags @@ -249,3 +249,4 @@ b32e2219736e42baaf45daf0ad67ed34f6033799 jdk9-b02 099891b1d86f3719e116ac717ffdafc90d037fb7 jdk9-b04 dd311791ad6895a3989020dd6c6c46db87972ab8 jdk9-b05 85dbdc227c5e11429b4fc4a8ba763f50107edd6e jdk9-b06 +c826d05f1fb0773f6a28caa763307dd30d90d36e jdk9-b07 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index eccf997b9eb..b35a11c862e 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -249,3 +249,4 @@ fd8d51bdf9aadf7ae83e65e8655c53581017c363 jdk9-b03 cb4c3440bc2748101923e2488506e61009ab1bf5 jdk9-b04 8c63f0b6ada282f27e3a80125e53c3be603f9af7 jdk9-b05 d0b525cd31b87abeb6d5b7e3516953eeb13b323c jdk9-b06 +0ea015c298b201c07fa33990f2445b6d0ef3566d jdk9-b07 diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index 17ed7906f67..649f8ddfc29 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -46,10 +46,24 @@ AC_DEFUN([ADD_JVM_ARG_IF_OK], # Appends a string to a path variable, only adding the : when needed. AC_DEFUN([BASIC_APPEND_TO_PATH], [ - if test "x[$]$1" = x; then - $1="$2" - else - $1="[$]$1:$2" + if test "x$2" != x; then + if test "x[$]$1" = x; then + $1="$2" + else + $1="[$]$1:$2" + fi + fi +]) + +# Prepends a string to a path variable, only adding the : when needed. +AC_DEFUN([BASIC_PREPEND_TO_PATH], +[ + if test "x$2" != x; then + if test "x[$]$1" = x; then + $1="$2" + else + $1="$2:[$]$1" + fi fi ]) @@ -442,43 +456,95 @@ AC_DEFUN_ONCE([BASIC_SETUP_PATHS], # Locate the directory of this script. AUTOCONF_DIR=$TOPDIR/common/autoconf +]) + +AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], +[ + AC_ARG_WITH([devkit], [AS_HELP_STRING([--with-devkit], + [use this devkit for compilers, tools and resources])], + [ + BASIC_FIXUP_PATH([with_devkit]) + DEVKIT_ROOT="$with_devkit" + # Check for a meta data info file in the root of the devkit + if test -f "$DEVKIT_ROOT/devkit.info"; then + # This potentially sets the following: + # DEVKIT_NAME: A descriptive name of the devkit + # DEVKIT_TOOLCHAIN_PATH: Corresponds to --with-toolchain-path + # DEVKIT_EXTRA_PATH: Corresponds to --with-extra-path + # DEVKIT_SYSROOT: Corresponds to --with-sysroot + . $DEVKIT_ROOT/devkit.info + fi + + AC_MSG_CHECKING([for devkit]) + if test "x$DEVKIT_NAME" != x; then + AC_MSG_RESULT([$DEVKIT_NAME in $DEVKIT_ROOT]) + else + AC_MSG_RESULT([$DEVKIT_ROOT]) + fi + + if test "x$DEVKIT_EXTRA_PATH" != x; then + BASIC_PREPEND_TO_PATH([EXTRA_PATH],$DEVKIT_EXTRA_PATH) + fi + + # Fallback default of just /bin if DEVKIT_PATH is not defined + if test "x$DEVKIT_TOOLCHAIN_PATH" = x; then + DEVKIT_TOOLCHAIN_PATH="$DEVKIT_ROOT/bin" + fi + BASIC_PREPEND_TO_PATH([TOOLCHAIN_PATH],$DEVKIT_TOOLCHAIN_PATH) + + # If DEVKIT_SYSROOT is set, use that, otherwise try a couple of known + # places for backwards compatiblity. + if test "x$DEVKIT_SYSROOT" != x; then + SYSROOT="$DEVKIT_SYSROOT" + elif test -d "$DEVKIT_ROOT/$host_alias/libc"; then + SYSROOT="$DEVKIT_ROOT/$host_alias/libc" + elif test -d "$DEVKIT_ROOT/$host/sys-root"; then + SYSROOT="$DEVKIT_ROOT/$host/sys-root" + fi + ] + ) + + # You can force the sysroot if the sysroot encoded into the compiler tools + # is not correct. + AC_ARG_WITH(sys-root, [AS_HELP_STRING([--with-sys-root], + [alias for --with-sysroot for backwards compatability])], + [SYSROOT=$with_sys_root] + ) + + AC_ARG_WITH(sysroot, [AS_HELP_STRING([--with-sysroot], + [use this directory as sysroot)])], + [SYSROOT=$with_sysroot] + ) + + AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir], + [alias for --with-toolchain-path for backwards compatibility])], + [BASIC_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_tools_dir)] + ) + + AC_ARG_WITH([toolchain-path], [AS_HELP_STRING([--with-toolchain-path], + [prepend these directories when searching for toolchain binaries (compilers etc)])], + [BASIC_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_toolchain_path)] + ) + + AC_ARG_WITH([extra-path], [AS_HELP_STRING([--with-extra-path], + [prepend these directories to the default path])], + [BASIC_PREPEND_TO_PATH([EXTRA_PATH],$with_extra_path)] + ) + + # Prepend the extra path to the global path + BASIC_PREPEND_TO_PATH([PATH],$EXTRA_PATH) if test "x$OPENJDK_BUILD_OS" = "xsolaris"; then # Add extra search paths on solaris for utilities like ar and as etc... PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin" fi - # You can force the sys-root if the sys-root encoded into the cross compiler tools - # is not correct. - AC_ARG_WITH(sys-root, [AS_HELP_STRING([--with-sys-root], - [pass this sys-root to the compilers and tools (for cross-compiling)])]) - - if test "x$with_sys_root" != x; then - SYS_ROOT=$with_sys_root - else - SYS_ROOT=/ - fi - AC_SUBST(SYS_ROOT) - - AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir], - [search this directory for compilers and tools (for cross-compiling)])], - [TOOLS_DIR=$with_tools_dir] - ) - - AC_ARG_WITH([devkit], [AS_HELP_STRING([--with-devkit], - [use this directory as base for tools-dir and sys-root (for cross-compiling)])], - [ - if test "x$with_sys_root" != x; then - AC_MSG_ERROR([Cannot specify both --with-devkit and --with-sys-root at the same time]) - fi - BASIC_FIXUP_PATH([with_devkit]) - BASIC_APPEND_TO_PATH([TOOLS_DIR],$with_devkit/bin) - if test -d "$with_devkit/$host_alias/libc"; then - SYS_ROOT=$with_devkit/$host_alias/libc - elif test -d "$with_devkit/$host/sys-root"; then - SYS_ROOT=$with_devkit/$host/sys-root - fi - ]) + AC_MSG_CHECKING([for sysroot]) + AC_MSG_RESULT([$SYSROOT]) + AC_MSG_CHECKING([for toolchain path]) + AC_MSG_RESULT([$TOOLCHAIN_PATH]) + AC_MSG_CHECKING([for extra path]) + AC_MSG_RESULT([$EXTRA_PATH]) ]) AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR], @@ -648,10 +714,10 @@ AC_DEFUN([BASIC_CHECK_GNU_MAKE], fi if test "x$FOUND_MAKE" = x; then - if test "x$TOOLS_DIR" != x; then - # We have a tools-dir, check that as well before giving up. + if test "x$TOOLCHAIN_PATH" != x; then + # We have a toolchain path, check that as well before giving up. OLD_PATH=$PATH - PATH=$TOOLS_DIR:$PATH + PATH=$TOOLCHAIN_PATH:$PATH AC_PATH_PROGS(CHECK_TOOLSDIR_GMAKE, gmake) BASIC_CHECK_MAKE_VERSION("$CHECK_TOOLSDIR_GMAKE", [gmake in tools-dir]) if test "x$FOUND_MAKE" = x; then diff --git a/common/autoconf/build-aux/config.guess b/common/autoconf/build-aux/config.guess index b0c03a79629..355c91e4ebb 100644 --- a/common/autoconf/build-aux/config.guess +++ b/common/autoconf/build-aux/config.guess @@ -76,4 +76,14 @@ if test $? = 0; then OUT=powerpc$KERNEL_BITMODE`echo $OUT | sed -e 's/[^-]*//'` fi +# Test and fix little endian PowerPC64. +# TODO: should be handled by autoconf-config.guess. +if [ "x$OUT" = x ]; then + if [ `uname -m` = ppc64le ]; then + if [ `uname -s` = Linux ]; then + OUT=powerpc64le-unknown-linux-gnu + fi + fi +fi + echo $OUT diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4 index 500c3adb702..22a62748a13 100644 --- a/common/autoconf/build-performance.m4 +++ b/common/autoconf/build-performance.m4 @@ -169,8 +169,8 @@ AC_DEFUN([BPERF_SETUP_CCACHE], if test "x$enable_ccache" = xyes; then AC_MSG_RESULT([yes]) OLD_PATH="$PATH" - if test "x$TOOLS_DIR" != x; then - PATH=$TOOLS_DIR:$PATH + if test "x$TOOLCHAIN_PATH" != x; then + PATH=$TOOLCHAIN_PATH:$PATH fi BASIC_REQUIRE_PROGS(CCACHE, ccache) CCACHE_STATUS="enabled" diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index a96a1d2bf0b..ec0d7490d59 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -100,6 +100,9 @@ JDKOPT_SETUP_DEBUG_LEVEL # With basic setup done, call the custom early hook. CUSTOM_EARLY_HOOK +# Check if we have devkits, extra paths or sysroot set. +BASIC_SETUP_DEVKIT + # To properly create a configuration name, we need to have the OpenJDK target # and options (variants and debug level) parsed. BASIC_SETUP_OUTPUT_DIR diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index bcfa1777bcf..a3f0803b0fe 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -119,6 +119,32 @@ AC_DEFUN_ONCE([FLAGS_SETUP_INIT_FLAGS], # FIXME: likely bug, should be CCXXFLAGS_JDK? or one for C or CXX. CCXXFLAGS="$CCXXFLAGS -nologo" fi + + if test "x$SYSROOT" != "x"; then + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + # Solaris Studio does not have a concept of sysroot. Instead we must + # make sure the default include and lib dirs are appended to each + # compile and link command line. + SYSROOT_CFLAGS="-I$SYSROOT/usr/include" + SYSROOT_LDFLAGS="-L$SYSROOT/usr/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT/usr/ccs/lib$OPENJDK_TARGET_CPU_ISADIR" + fi + elif test "x$TOOLCHAIN_TYPE" = xgcc; then + SYSROOT_CFLAGS="--sysroot=\"$SYSROOT\"" + SYSROOT_LDFLAGS="--sysroot=\"$SYSROOT\"" + elif test "x$TOOLCHAIN_TYPE" = xclang; then + SYSROOT_CFLAGS="-isysroot \"$SYSROOT\"" + SYSROOT_LDFLAGS="-isysroot \"$SYSROOT\"" + fi + # Propagate the sysroot args to hotspot + LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $SYSROOT_CFLAGS" + LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $SYSROOT_CFLAGS" + LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $SYSROOT_LDFLAGS" + fi + AC_SUBST(SYSROOT_CFLAGS) + AC_SUBST(SYSROOT_LDFLAGS) ]) AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], @@ -421,9 +447,9 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], LDFLAGS_JDK="${LDFLAGS_JDK} $with_extra_ldflags" # Hotspot needs these set in their legacy form - LEGACY_EXTRA_CFLAGS=$with_extra_cflags - LEGACY_EXTRA_CXXFLAGS=$with_extra_cxxflags - LEGACY_EXTRA_LDFLAGS=$with_extra_ldflags + LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $with_extra_cflags" + LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $with_extra_cxxflags" + LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $with_extra_ldflags" AC_SUBST(LEGACY_EXTRA_CFLAGS) AC_SUBST(LEGACY_EXTRA_CXXFLAGS) @@ -521,7 +547,13 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_LITTLE_ENDIAN" fi else - CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN" + # Same goes for _BIG_ENDIAN. Do we really need to set *ENDIAN on Solaris if they + # are defined in the system? + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN=" + else + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN" + fi fi # Setup target OS define. Use OS target name but in upper case. @@ -735,4 +767,20 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], [COMPILER_SUPPORTS_TARGET_BITS_FLAG=true], [COMPILER_SUPPORTS_TARGET_BITS_FLAG=false]) AC_SUBST(COMPILER_SUPPORTS_TARGET_BITS_FLAG) + + case "${TOOLCHAIN_TYPE}" in + microsoft) + CFLAGS_WARNINGS_ARE_ERRORS="/WX" + ;; + solstudio) + CFLAGS_WARNINGS_ARE_ERRORS="-errtags -errwarn=%all" + ;; + gcc) + CFLAGS_WARNINGS_ARE_ERRORS="-Werror" + ;; + clang) + CFLAGS_WARNINGS_ARE_ERRORS="-Werror" + ;; + esac + AC_SUBST(CFLAGS_WARNINGS_ARE_ERRORS) ]) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index b3d823b29ed..fdf1c6dc829 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -664,7 +664,6 @@ FREETYPE_BUNDLE_LIB_PATH FREETYPE_LIBS FREETYPE_CFLAGS CUPS_CFLAGS -OPENWIN_HOME X_EXTRA_LIBS X_LIBS X_PRE_LIBS @@ -673,6 +672,7 @@ XMKMF FIXPATH ZIP_DEBUGINFO_FILES ENABLE_DEBUG_SYMBOLS +CFLAGS_WARNINGS_ARE_ERRORS COMPILER_SUPPORTS_TARGET_BITS_FLAG ZERO_ARCHFLAG LDFLAGS_CXX_JDK @@ -707,6 +707,8 @@ SET_EXECUTABLE_ORIGIN SHARED_LIBRARY_FLAGS CXX_FLAG_REORDER C_FLAG_REORDER +SYSROOT_LDFLAGS +SYSROOT_CFLAGS RC_FLAGS AR_OUT_OPTION LD_OUT_OPTION @@ -759,7 +761,7 @@ CXXFLAGS CXX ac_ct_PROPER_COMPILER_CXX PROPER_COMPILER_CXX -TOOLS_DIR_CXX +TOOLCHAIN_PATH_CXX POTENTIAL_CXX OBJEXT EXEEXT @@ -770,11 +772,11 @@ CFLAGS CC ac_ct_PROPER_COMPILER_CC PROPER_COMPILER_CC -TOOLS_DIR_CC +TOOLCHAIN_PATH_CC POTENTIAL_CC -VS_PATH VS_LIB VS_INCLUDE +VS_PATH CYGWIN_LINK EXE_SUFFIX OBJ_SUFFIX @@ -886,7 +888,6 @@ SET_OPENJDK BUILD_LOG_WRAPPER BUILD_LOG_PREVIOUS BUILD_LOG -SYS_ROOT TOPDIR PATH_SEP ZERO_ARCHDEF @@ -1019,9 +1020,6 @@ ac_subst_files='' ac_user_opts=' enable_option_checking with_target_bits -with_sys_root -with_tools_dir -with_devkit enable_openjdk_only with_custom_make_dir with_jdk_variant @@ -1029,6 +1027,12 @@ with_jvm_interpreter with_jvm_variants enable_debug with_debug_level +with_devkit +with_sys_root +with_sysroot +with_tools_dir +with_toolchain_path +with_extra_path with_conf_name with_builddeps_conf with_builddeps_server @@ -1847,12 +1851,6 @@ Optional Packages: --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-target-bits build 32-bit or 64-bit binaries (for platforms that support it), e.g. --with-target-bits=32 [guessed] - --with-sys-root pass this sys-root to the compilers and tools (for - cross-compiling) - --with-tools-dir search this directory for compilers and tools (for - cross-compiling) - --with-devkit use this directory as base for tools-dir and - sys-root (for cross-compiling) --with-custom-make-dir Deprecated. Option is kept for backwards compatibility and is ignored --with-jdk-variant JDK variant to build (normal) [normal] @@ -1860,8 +1858,16 @@ Optional Packages: --with-jvm-variants JVM variants (separated by commas) to build (server, client, minimal1, kernel, zero, zeroshark, core) [server] - --with-debug-level set the debug level (release, fastdebug, slowdebug) - [release] + --with-debug-level set the debug level (release, fastdebug, slowdebug, + optimized (HotSpot build only)) [release] + --with-devkit use this devkit for compilers, tools and resources + --with-sys-root alias for --with-sysroot for backwards compatability + --with-sysroot use this directory as sysroot) + --with-tools-dir alias for --with-toolchain-path for backwards + compatibility + --with-toolchain-path prepend these directories when searching for + toolchain binaries (compilers etc) + --with-extra-path prepend these directories to the default path --with-conf-name use this as the name of the configuration [generated from important configuration options] --with-builddeps-conf use this configuration file for the builddeps @@ -3324,6 +3330,9 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Appends a string to a path variable, only adding the : when needed. +# Prepends a string to a path variable, only adding the : when needed. + + # This will make sure the given variable points to a full and proper # path. This means: # 1) There will be no spaces in the path. On posix platforms, @@ -3406,6 +3415,8 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + #%%% Simple tools %%% # Check if we have found a usable version of make @@ -4232,7 +4243,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=1394794899 +DATE_WHEN_GENERATED=1396624161 ############################################################################### # @@ -13507,6 +13518,12 @@ test -n "$target_alias" && VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; + powerpc64le) + VAR_CPU=ppc64 + VAR_CPU_ARCH=ppc + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; s390) VAR_CPU=s390 VAR_CPU_ARCH=s390 @@ -13632,6 +13649,12 @@ $as_echo "$OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU" >&6; } VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; + powerpc64le) + VAR_CPU=ppc64 + VAR_CPU_ARCH=ppc + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; s390) VAR_CPU=s390 VAR_CPU_ARCH=s390 @@ -14239,180 +14262,6 @@ $as_echo "$as_me: The path of TOPDIR, which resolves as \"$path\", is invalid." # Locate the directory of this script. AUTOCONF_DIR=$TOPDIR/common/autoconf - if test "x$OPENJDK_BUILD_OS" = "xsolaris"; then - # Add extra search paths on solaris for utilities like ar and as etc... - PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin" - fi - - # You can force the sys-root if the sys-root encoded into the cross compiler tools - # is not correct. - -# Check whether --with-sys-root was given. -if test "${with_sys_root+set}" = set; then : - withval=$with_sys_root; -fi - - - if test "x$with_sys_root" != x; then - SYS_ROOT=$with_sys_root - else - SYS_ROOT=/ - fi - - - -# Check whether --with-tools-dir was given. -if test "${with_tools_dir+set}" = set; then : - withval=$with_tools_dir; TOOLS_DIR=$with_tools_dir - -fi - - - -# Check whether --with-devkit was given. -if test "${with_devkit+set}" = set; then : - withval=$with_devkit; - if test "x$with_sys_root" != x; then - as_fn_error $? "Cannot specify both --with-devkit and --with-sys-root at the same time" "$LINENO" 5 - fi - - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - - # Input might be given as Windows format, start by converting to - # unix format. - path="$with_devkit" - new_path=`$CYGPATH -u "$path"` - - # Cygwin tries to hide some aspects of the Windows file system, such that binaries are - # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered - # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then - # "foo.exe" is OK but "foo" is an error. - # - # This test is therefore slightly more accurate than "test -f" to check for file precense. - # It is also a way to make sure we got the proper file name for the real test later on. - test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` - if test "x$test_shortpath" = x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of with_devkit, which resolves as \"$path\", is invalid." >&5 -$as_echo "$as_me: The path of with_devkit, which resolves as \"$path\", is invalid." >&6;} - as_fn_error $? "Cannot locate the the path of with_devkit" "$LINENO" 5 - fi - - # Call helper function which possibly converts this using DOS-style short mode. - # If so, the updated path is stored in $new_path. - - input_path="$new_path" - # Check if we need to convert this using DOS-style short mode. If the path - # contains just simple characters, use it. Otherwise (spaces, weird characters), - # take no chances and rewrite it. - # Note: m4 eats our [], so we need to use [ and ] instead. - has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` - if test "x$has_forbidden_chars" != x; then - # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) - shortmode_path=`$CYGPATH -s -m -a "$input_path"` - path_after_shortmode=`$CYGPATH -u "$shortmode_path"` - if test "x$path_after_shortmode" != "x$input_to_shortpath"; then - # Going to short mode and back again did indeed matter. Since short mode is - # case insensitive, let's make it lowercase to improve readability. - shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - # Now convert it back to Unix-stile (cygpath) - input_path=`$CYGPATH -u "$shortmode_path"` - new_path="$input_path" - fi - fi - - test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` - if test "x$test_cygdrive_prefix" = x; then - # As a simple fix, exclude /usr/bin since it's not a real path. - if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then - # The path is in a Cygwin special directory (e.g. /home). We need this converted to - # a path prefixed by /cygdrive for fixpath to work. - new_path="$CYGWIN_ROOT_PATH$input_path" - fi - fi - - - if test "x$path" != "x$new_path"; then - with_devkit="$new_path" - { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting with_devkit to \"$new_path\"" >&5 -$as_echo "$as_me: Rewriting with_devkit to \"$new_path\"" >&6;} - fi - - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - - path="$with_devkit" - has_colon=`$ECHO $path | $GREP ^.:` - new_path="$path" - if test "x$has_colon" = x; then - # Not in mixed or Windows style, start by that. - new_path=`cmd //c echo $path` - fi - - - input_path="$new_path" - # Check if we need to convert this using DOS-style short mode. If the path - # contains just simple characters, use it. Otherwise (spaces, weird characters), - # take no chances and rewrite it. - # Note: m4 eats our [], so we need to use [ and ] instead. - has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` - if test "x$has_forbidden_chars" != x; then - # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) - new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - fi - - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - if test "x$path" != "x$new_path"; then - with_devkit="$new_path" - { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting with_devkit to \"$new_path\"" >&5 -$as_echo "$as_me: Rewriting with_devkit to \"$new_path\"" >&6;} - fi - - # Save the first 10 bytes of this path to the storage, so fixpath can work. - all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") - - else - # We're on a posix platform. Hooray! :) - path="$with_devkit" - has_space=`$ECHO "$path" | $GREP " "` - if test "x$has_space" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of with_devkit, which resolves as \"$path\", is invalid." >&5 -$as_echo "$as_me: The path of with_devkit, which resolves as \"$path\", is invalid." >&6;} - as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 - fi - - # Use eval to expand a potential ~ - eval path="$path" - if test ! -f "$path" && test ! -d "$path"; then - as_fn_error $? "The path of with_devkit, which resolves as \"$path\", is not found." "$LINENO" 5 - fi - - with_devkit="`cd "$path"; $THEPWDCMD -L`" - fi - - - if test "x$TOOLS_DIR" = x; then - TOOLS_DIR="$with_devkit/bin" - else - TOOLS_DIR="$TOOLS_DIR:$with_devkit/bin" - fi - - if test -d "$with_devkit/$host_alias/libc"; then - SYS_ROOT=$with_devkit/$host_alias/libc - elif test -d "$with_devkit/$host/sys-root"; then - SYS_ROOT=$with_devkit/$host/sys-root - fi - -fi - - # Setup default logging of stdout and stderr to build.log in the output root. BUILD_LOG='$(OUTPUT_ROOT)/build.log' @@ -14647,6 +14496,7 @@ $as_echo "$with_jvm_variants" >&6; } # # Set the debug level # release: no debug information, all optimizations, no asserts. + # optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'. # fastdebug: debug information (-g), all optimizations, all asserts # slowdebug: debug information (-g), no optimizations, all asserts # @@ -14679,6 +14529,7 @@ fi $as_echo "$DEBUG_LEVEL" >&6; } if test "x$DEBUG_LEVEL" != xrelease && \ + test "x$DEBUG_LEVEL" != xoptimized && \ test "x$DEBUG_LEVEL" != xfastdebug && \ test "x$DEBUG_LEVEL" != xslowdebug; then as_fn_error $? "Allowed debug levels are: release, fastdebug and slowdebug" "$LINENO" 5 @@ -14715,8 +14566,30 @@ $as_echo "$DEBUG_LEVEL" >&6; } HOTSPOT_DEBUG_LEVEL="jvmg" HOTSPOT_EXPORT="debug" ;; + optimized ) + VARIANT="OPT" + FASTDEBUG="false" + DEBUG_CLASSFILES="false" + BUILD_VARIANT_RELEASE="-optimized" + HOTSPOT_DEBUG_LEVEL="optimized" + HOTSPOT_EXPORT="optimized" + ;; esac + # The debug level 'optimized' is a little special because it is currently only + # applicable to the HotSpot build where it means to build a completely + # optimized version of the VM without any debugging code (like for the + # 'release' debug level which is called 'product' in the HotSpot build) but + # with the exception that it can contain additional code which is otherwise + # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to + # test new and/or experimental features which are not intended for customer + # shipment. Because these new features need to be tested and benchmarked in + # real world scenarios, we want to build the containing JDK at the 'release' + # debug level. + if test "x$DEBUG_LEVEL" = xoptimized; then + DEBUG_LEVEL="release" + fi + ##### # Generate the legacy makefile targets for hotspot. # The hotspot api for selecting the build artifacts, really, needs to be improved. @@ -14775,6 +14648,291 @@ $as_echo "$DEBUG_LEVEL" >&6; } # With basic setup done, call the custom early hook. +# Check if we have devkits, extra paths or sysroot set. + + +# Check whether --with-devkit was given. +if test "${with_devkit+set}" = set; then : + withval=$with_devkit; + + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$with_devkit" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of with_devkit, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of with_devkit, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of with_devkit" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-stile (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + with_devkit="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting with_devkit to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting with_devkit to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$with_devkit" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + with_devkit="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting with_devkit to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting with_devkit to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a posix platform. Hooray! :) + path="$with_devkit" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of with_devkit, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of with_devkit, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of with_devkit, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + with_devkit="`cd "$path"; $THEPWDCMD -L`" + fi + + DEVKIT_ROOT="$with_devkit" + # Check for a meta data info file in the root of the devkit + if test -f "$DEVKIT_ROOT/devkit.info"; then + # This potentially sets the following: + # DEVKIT_NAME: A descriptive name of the devkit + # DEVKIT_TOOLCHAIN_PATH: Corresponds to --with-toolchain-path + # DEVKIT_EXTRA_PATH: Corresponds to --with-extra-path + # DEVKIT_SYSROOT: Corresponds to --with-sysroot + . $DEVKIT_ROOT/devkit.info + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for devkit" >&5 +$as_echo_n "checking for devkit... " >&6; } + if test "x$DEVKIT_NAME" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVKIT_NAME in $DEVKIT_ROOT" >&5 +$as_echo "$DEVKIT_NAME in $DEVKIT_ROOT" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVKIT_ROOT" >&5 +$as_echo "$DEVKIT_ROOT" >&6; } + fi + + if test "x$DEVKIT_EXTRA_PATH" != x; then + + if test "x$DEVKIT_EXTRA_PATH" != x; then + if test "x$EXTRA_PATH" = x; then + EXTRA_PATH="$DEVKIT_EXTRA_PATH" + else + EXTRA_PATH="$DEVKIT_EXTRA_PATH:$EXTRA_PATH" + fi + fi + + fi + + # Fallback default of just /bin if DEVKIT_PATH is not defined + if test "x$DEVKIT_TOOLCHAIN_PATH" = x; then + DEVKIT_TOOLCHAIN_PATH="$DEVKIT_ROOT/bin" + fi + + if test "x$DEVKIT_TOOLCHAIN_PATH" != x; then + if test "x$TOOLCHAIN_PATH" = x; then + TOOLCHAIN_PATH="$DEVKIT_TOOLCHAIN_PATH" + else + TOOLCHAIN_PATH="$DEVKIT_TOOLCHAIN_PATH:$TOOLCHAIN_PATH" + fi + fi + + + # If DEVKIT_SYSROOT is set, use that, otherwise try a couple of known + # places for backwards compatiblity. + if test "x$DEVKIT_SYSROOT" != x; then + SYSROOT="$DEVKIT_SYSROOT" + elif test -d "$DEVKIT_ROOT/$host_alias/libc"; then + SYSROOT="$DEVKIT_ROOT/$host_alias/libc" + elif test -d "$DEVKIT_ROOT/$host/sys-root"; then + SYSROOT="$DEVKIT_ROOT/$host/sys-root" + fi + + +fi + + + # You can force the sysroot if the sysroot encoded into the compiler tools + # is not correct. + +# Check whether --with-sys-root was given. +if test "${with_sys_root+set}" = set; then : + withval=$with_sys_root; SYSROOT=$with_sys_root + +fi + + + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; SYSROOT=$with_sysroot + +fi + + + +# Check whether --with-tools-dir was given. +if test "${with_tools_dir+set}" = set; then : + withval=$with_tools_dir; + if test "x$with_tools_dir" != x; then + if test "x$TOOLCHAIN_PATH" = x; then + TOOLCHAIN_PATH="$with_tools_dir" + else + TOOLCHAIN_PATH="$with_tools_dir:$TOOLCHAIN_PATH" + fi + fi + + +fi + + + +# Check whether --with-toolchain-path was given. +if test "${with_toolchain_path+set}" = set; then : + withval=$with_toolchain_path; + if test "x$with_toolchain_path" != x; then + if test "x$TOOLCHAIN_PATH" = x; then + TOOLCHAIN_PATH="$with_toolchain_path" + else + TOOLCHAIN_PATH="$with_toolchain_path:$TOOLCHAIN_PATH" + fi + fi + + +fi + + + +# Check whether --with-extra-path was given. +if test "${with_extra_path+set}" = set; then : + withval=$with_extra_path; + if test "x$with_extra_path" != x; then + if test "x$EXTRA_PATH" = x; then + EXTRA_PATH="$with_extra_path" + else + EXTRA_PATH="$with_extra_path:$EXTRA_PATH" + fi + fi + + +fi + + + # Prepend the extra path to the global path + + if test "x$EXTRA_PATH" != x; then + if test "x$PATH" = x; then + PATH="$EXTRA_PATH" + else + PATH="$EXTRA_PATH:$PATH" + fi + fi + + + if test "x$OPENJDK_BUILD_OS" = "xsolaris"; then + # Add extra search paths on solaris for utilities like ar and as etc... + PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SYSROOT" >&5 +$as_echo "$SYSROOT" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for toolchain path" >&5 +$as_echo_n "checking for toolchain path... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLCHAIN_PATH" >&5 +$as_echo "$TOOLCHAIN_PATH" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for extra path" >&5 +$as_echo_n "checking for extra path... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXTRA_PATH" >&5 +$as_echo "$EXTRA_PATH" >&6; } + + # To properly create a configuration name, we need to have the OpenJDK target # and options (variants and debug level) parsed. @@ -16082,10 +16240,10 @@ $as_echo "$as_me: Rewriting FOUND_MAKE to \"$new_complete\"" >&6;} fi if test "x$FOUND_MAKE" = x; then - if test "x$TOOLS_DIR" != x; then - # We have a tools-dir, check that as well before giving up. + if test "x$TOOLCHAIN_PATH" != x; then + # We have a toolchain path, check that as well before giving up. OLD_PATH=$PATH - PATH=$TOOLS_DIR:$PATH + PATH=$TOOLCHAIN_PATH:$PATH for ac_prog in gmake do # Extract the first word of "$ac_prog", so it can be a program name with args. @@ -27207,47 +27365,62 @@ $as_echo "$as_me: Rewriting VS_ENV_CMD to \"$new_complete\"" >&6;} # Lets extract the variables that are set by vcvarsall.bat/vsvars32.bat/vsvars64.bat { $as_echo "$as_me:${as_lineno-$LINENO}: Trying to extract Visual Studio environment variables" >&5 $as_echo "$as_me: Trying to extract Visual Studio environment variables" >&6;} - cd $OUTPUT_ROOT - # FIXME: The code betweeen ---- was inlined from a separate script and is not properly adapted - # to autoconf standards. - #---- + # We need to create a couple of temporary files. + VS_ENV_TMP_DIR="$OUTPUT_ROOT/vs-env" + $MKDIR -p $VS_ENV_TMP_DIR - # Cannot use the VS10 setup script directly (since it only updates the DOS subshell environment) - # but calculate the difference in Cygwin environment before/after running it and then - # apply the diff. + # Cannot use the VS10 setup script directly (since it only updates the DOS subshell environment). + # Instead create a shell script which will set the relevant variables when run. + WINPATH_VS_ENV_CMD="$VS_ENV_CMD" - if test "x$OPENJDK_BUILD_OS_ENV" = xwindows.cygwin; then - _vs10varsall=`cygpath -a -m -s "$VS_ENV_CMD"` - _dosvs10varsall=`cygpath -a -w -s $_vs10varsall` - _dosbash=`cygpath -a -w -s \`which bash\`.*` - else - _dosvs10varsall=`cmd //c echo $VS_ENV_CMD` - _dosbash=`cmd //c echo \`which bash\`` - fi + unix_path="$WINPATH_VS_ENV_CMD" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + windows_path=`$CYGPATH -m "$unix_path"` + WINPATH_VS_ENV_CMD="$windows_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + windows_path=`cmd //c echo $unix_path` + WINPATH_VS_ENV_CMD="$windows_path" + fi - # generate the set of exported vars before/after the vs10 setup - $ECHO "@echo off" > localdevenvtmp.bat - $ECHO "$_dosbash -c \"export -p\" > localdevenvtmp.export0" >> localdevenvtmp.bat - $ECHO "call $_dosvs10varsall $VS_ENV_ARGS" >> localdevenvtmp.bat - $ECHO "$_dosbash -c \"export -p\" > localdevenvtmp.export1" >> localdevenvtmp.bat + WINPATH_BASH="$BASH" + + unix_path="$WINPATH_BASH" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + windows_path=`$CYGPATH -m "$unix_path"` + WINPATH_BASH="$windows_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + windows_path=`cmd //c echo $unix_path` + WINPATH_BASH="$windows_path" + fi + + + # Generate a DOS batch file which runs $VS_ENV_CMD, and then creates a shell + # script (executable by bash) that will setup the important variables. + EXTRACT_VC_ENV_BAT_FILE="$VS_ENV_TMP_DIR/extract-vs-env.bat" + $ECHO "@echo off" > $EXTRACT_VC_ENV_BAT_FILE + # This will end up something like: + # call C:/progra~2/micros~2.0/vc/bin/amd64/vcvars64.bat + $ECHO "call $WINPATH_VS_ENV_CMD $VS_ENV_ARGS" >> $EXTRACT_VC_ENV_BAT_FILE + # These will end up something like: + # C:/CygWin/bin/bash -c 'echo VS_PATH=\"$PATH\" > localdevenv.sh + # The trailing space for everyone except PATH is no typo, but is needed due + # to trailing \ in the Windows paths. These will be stripped later. + $ECHO "$WINPATH_BASH -c 'echo VS_PATH="'\"$PATH\" > set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VCINSTALLDIR="'\"$VCINSTALLDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo WindowsSdkDir="'\"$WindowsSdkDir \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo WINDOWSSDKDIR="'\"$WINDOWSSDKDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE # Now execute the newly created bat file. - # The | cat is to stop SetEnv.Cmd to mess with system colors on msys - cmd /c localdevenvtmp.bat | cat - - # apply the diff (less some non-vs10 vars named by "!") - $SORT localdevenvtmp.export0 | $GREP -v "!" > localdevenvtmp.export0.sort - $SORT localdevenvtmp.export1 | $GREP -v "!" > localdevenvtmp.export1.sort - $COMM -1 -3 localdevenvtmp.export0.sort localdevenvtmp.export1.sort > localdevenv.sh - - # cleanup - $RM localdevenvtmp* - #---- + # The | cat is to stop SetEnv.Cmd to mess with system colors on msys. + # Change directory so we don't need to mess with Windows paths in redirects. + cd $VS_ENV_TMP_DIR + cmd /c extract-vs-env.bat | $CAT cd $CURDIR - if test ! -s $OUTPUT_ROOT/localdevenv.sh; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + + if test ! -s $VS_ENV_TMP_DIR/set-vs-env.sh; then { $as_echo "$as_me:${as_lineno-$LINENO}: Could not succesfully extract the envionment variables needed for the VS setup." >&5 $as_echo "$as_me: Could not succesfully extract the envionment variables needed for the VS setup." >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Try setting --with-tools-dir to the VC/bin directory within the VS installation" >&5 @@ -27261,31 +27434,37 @@ $as_echo "$as_me: or run \"bash.exe -l\" from a VS command prompt and then run c # the configure script to find and run the compiler in the proper way. { $as_echo "$as_me:${as_lineno-$LINENO}: Setting extracted environment variables" >&5 $as_echo "$as_me: Setting extracted environment variables" >&6;} - . $OUTPUT_ROOT/localdevenv.sh + . $VS_ENV_TMP_DIR/set-vs-env.sh + # Now we have VS_PATH, VS_INCLUDE, VS_LIB. For further checking, we + # also define VCINSTALLDIR, WindowsSdkDir and WINDOWSSDKDIR. else # We did not find a vsvars bat file, let's hope we are run from a VS command prompt. { $as_echo "$as_me:${as_lineno-$LINENO}: Cannot locate a valid Visual Studio installation, checking current environment" >&5 $as_echo "$as_me: Cannot locate a valid Visual Studio installation, checking current environment" >&6;} fi - # At this point, we should have corrent variables in the environment, or we can't continue. + # At this point, we should have correct variables in the environment, or we can't continue. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Visual Studio variables" >&5 $as_echo_n "checking for Visual Studio variables... " >&6; } if test "x$VCINSTALLDIR" != x || test "x$WindowsSDKDir" != x || test "x$WINDOWSSDKDIR" != x; then - if test "x$INCLUDE" = x || test "x$LIB" = x; then + if test "x$VS_INCLUDE" = x || test "x$VS_LIB" = x; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: present but broken" >&5 $as_echo "present but broken" >&6; } as_fn_error $? "Your VC command prompt seems broken, INCLUDE and/or LIB is missing." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } - # Remove any trailing \ from INCLUDE and LIB to avoid trouble in spec.gmk. - VS_INCLUDE=`$ECHO "$INCLUDE" | $SED 's/\\\\$//'` - VS_LIB=`$ECHO "$LIB" | $SED 's/\\\\$//'` - # Remove any paths containing # (typically F#) as that messes up make - PATH=`$ECHO "$PATH" | $SED 's/[^:#]*#[^:]*://g'` - VS_PATH="$PATH" + # Remove any trailing "\" and " " from the variables. + VS_INCLUDE=`$ECHO "$VS_INCLUDE" | $SED 's/\\\\* *$//'` + VS_LIB=`$ECHO "$VS_LIB" | $SED 's/\\\\* *$//'` + VCINSTALLDIR=`$ECHO "$VCINSTALLDIR" | $SED 's/\\\\* *$//'` + WindowsSDKDir=`$ECHO "$WindowsSDKDir" | $SED 's/\\\\* *$//'` + WINDOWSSDKDIR=`$ECHO "$WINDOWSSDKDIR" | $SED 's/\\\\* *$//'` + # Remove any paths containing # (typically F#) as that messes up make. This + # is needed if visual studio was installed with F# support. + VS_PATH=`$ECHO "$VS_PATH" | $SED 's/[^:#]*#[^:]*://g'` + @@ -27310,6 +27489,12 @@ $as_echo "$as_me: or run \"bash.exe -l\" from a VS command prompt and then run c as_fn_error $? "Cannot continue" "$LINENO" 5 fi + # Reset path to VS_PATH. It will include everything that was on PATH at the time we + # ran TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV. + PATH="$VS_PATH" + # The microsoft toolchain also requires INCLUDE and LIB to be set. + export INCLUDE="$VS_INCLUDE" + export LIB="$VS_LIB" fi # autoconf magic only relies on PATH, so update it if tools dir is specified @@ -27323,170 +27508,12 @@ $as_echo "$as_me: or run \"bash.exe -l\" from a VS command prompt and then run c PATH="/usr/ccs/bin:$PATH" fi - # Finally add TOOLS_DIR at the beginning, to allow --with-tools-dir to + # Finally add TOOLCHAIN_PATH at the beginning, to allow --with-tools-dir to # override all other locations. - if test "x$TOOLS_DIR" != x; then - PATH=$TOOLS_DIR:$PATH + if test "x$TOOLCHAIN_PATH" != x; then + PATH=$TOOLCHAIN_PATH:$PATH fi - # If a devkit is found on the builddeps server, then prepend its path to the - # PATH variable. If there are cross compilers available in the devkit, these - # will be found by AC_PROG_CC et al. - DEVKIT= - - - if test "x$with_builddeps_server" != x || test "x$with_builddeps_conf" != x; then - # Source the builddeps file again, to make sure it uses the latest variables! - . $builddepsfile - # Look for a target and build machine specific resource! - eval resource=\${builddep_devkit_BUILD_${rewritten_build_var}_TARGET_${rewritten_target_var}} - if test "x$resource" = x; then - # Ok, lets instead look for a target specific resource - eval resource=\${builddep_devkit_TARGET_${rewritten_target_var}} - fi - if test "x$resource" = x; then - # Ok, lets instead look for a build specific resource - eval resource=\${builddep_devkit_BUILD_${rewritten_build_var}} - fi - if test "x$resource" = x; then - # Ok, lets instead look for a generic resource - # (The devkit comes from M4 and not the shell, thus no need for eval here.) - resource=${builddep_devkit} - fi - if test "x$resource" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Using builddeps $resource for devkit" >&5 -$as_echo "$as_me: Using builddeps $resource for devkit" >&6;} - # If the resource in the builddeps.conf file is an existing directory, - # for example /java/linux/cups - if test -d ${resource}; then - depdir=${resource} - else - - # devkit is for example mymodule - # $resource is for example libs/general/libmymod_1_2_3.zip - # $with_builddeps_server is for example ftp://mybuilddeps.myserver.com/builddeps - # $with_builddeps_dir is for example /localhome/builddeps - # depdir is the name of the variable into which we store the depdir, eg MYMOD - # Will download ftp://mybuilddeps.myserver.com/builddeps/libs/general/libmymod_1_2_3.zip and - # unzip into the directory: /localhome/builddeps/libmymod_1_2_3 - filename=`basename $resource` - filebase=`echo $filename | sed 's/\.[^\.]*$//'` - filebase=${filename%%.*} - extension=${filename#*.} - installdir=$with_builddeps_dir/$filebase - if test ! -f $installdir/$filename.unpacked; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Downloading build dependency devkit from $with_builddeps_server/$resource and installing into $installdir" >&5 -$as_echo "$as_me: Downloading build dependency devkit from $with_builddeps_server/$resource and installing into $installdir" >&6;} - if test ! -d $installdir; then - mkdir -p $installdir - fi - if test ! -d $installdir; then - as_fn_error $? "Could not create directory $installdir" "$LINENO" 5 - fi - tmpfile=`mktemp $installdir/devkit.XXXXXXXXX` - touch $tmpfile - if test ! -f $tmpfile; then - as_fn_error $? "Could not create files in directory $installdir" "$LINENO" 5 - fi - - # $with_builddeps_server/$resource is the ftp://abuilddeps.server.com/libs/cups.zip - # $tmpfile is the local file name for the downloaded file. - VALID_TOOL=no - if test "x$BDEPS_FTP" = xwget; then - VALID_TOOL=yes - wget -O $tmpfile $with_builddeps_server/$resource - fi - if test "x$BDEPS_FTP" = xlftp; then - VALID_TOOL=yes - lftp -c "get $with_builddeps_server/$resource -o $tmpfile" - fi - if test "x$BDEPS_FTP" = xftp; then - VALID_TOOL=yes - FTPSERVER=`echo $with_builddeps_server/$resource | cut -f 3 -d '/'` - FTPPATH=`echo $with_builddeps_server/$resource | cut -f 4- -d '/'` - FTPUSERPWD=${FTPSERVER%%@*} - if test "x$FTPSERVER" != "x$FTPUSERPWD"; then - FTPUSER=${userpwd%%:*} - FTPPWD=${userpwd#*@} - FTPSERVER=${FTPSERVER#*@} - else - FTPUSER=ftp - FTPPWD=ftp - fi - # the "pass" command does not work on some - # ftp clients (read ftp.exe) but if it works, - # passive mode is better! - ( \ - echo "user $FTPUSER $FTPPWD" ; \ - echo "pass" ; \ - echo "bin" ; \ - echo "get $FTPPATH $tmpfile" ; \ - ) | ftp -in $FTPSERVER - fi - if test "x$VALID_TOOL" != xyes; then - as_fn_error $? "I do not know how to use the tool: $BDEPS_FTP" "$LINENO" 5 - fi - - mv $tmpfile $installdir/$filename - if test ! -s $installdir/$filename; then - as_fn_error $? "Could not download $with_builddeps_server/$resource" "$LINENO" 5 - fi - case "$extension" in - zip) echo "Unzipping $installdir/$filename..." - (cd $installdir ; rm -f $installdir/$filename.unpacked ; $BDEPS_UNZIP $installdir/$filename > /dev/null && touch $installdir/$filename.unpacked) - ;; - tar.gz) echo "Untaring $installdir/$filename..." - (cd $installdir ; rm -f $installdir/$filename.unpacked ; tar xzf $installdir/$filename && touch $installdir/$filename.unpacked) - ;; - tgz) echo "Untaring $installdir/$filename..." - (cd $installdir ; rm -f $installdir/$filename.unpacked ; tar xzf $installdir/$filename && touch $installdir/$filename.unpacked) - ;; - *) as_fn_error $? "Cannot handle build depency archive with extension $extension" "$LINENO" 5 - ;; - esac - fi - if test -f $installdir/$filename.unpacked; then - depdir=$installdir - fi - - fi - # Source the builddeps file again, because in the previous command, the depdir - # was updated to point at the current build dependency install directory. - . $builddepsfile - # Now extract variables from the builddeps.conf files. - theroot=${builddep_devkit_ROOT} - thecflags=${builddep_devkit_CFLAGS} - thelibs=${builddep_devkit_LIBS} - if test "x$depdir" = x; then - as_fn_error $? "Could not download build dependency devkit" "$LINENO" 5 - fi - DEVKIT=$depdir - if test "x$theroot" != x; then - DEVKIT="$theroot" - fi - if test "x$thecflags" != x; then - DEVKIT_CFLAGS="$thecflags" - fi - if test "x$thelibs" != x; then - DEVKIT_LIBS="$thelibs" - fi - - # Found devkit - PATH="$DEVKIT/bin:$PATH" - SYS_ROOT="$DEVKIT/${rewritten_target}/sys-root" - if test "x$x_includes" = "xNONE"; then - x_includes="$SYS_ROOT/usr/include/X11" - fi - if test "x$x_libraries" = "xNONE"; then - x_libraries="$SYS_ROOT/usr/lib" - fi - - - fi - - fi - - # # Setup the compilers (CC and CXX) @@ -27569,25 +27596,25 @@ done # used. CC= - # If TOOLS_DIR is set, check for all compiler names in there first + # If TOOLCHAIN_PATH is set, check for all compiler names in there first # before checking the rest of the PATH. # FIXME: Now that we prefix the TOOLS_DIR to the PATH in the PRE_DETECTION # step, this should not be necessary. - if test -n "$TOOLS_DIR"; then + if test -n "$TOOLCHAIN_PATH"; then PATH_save="$PATH" - PATH="$TOOLS_DIR" + PATH="$TOOLCHAIN_PATH" for ac_prog in $SEARCH_LIST 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_TOOLS_DIR_CC+:} false; then : +if ${ac_cv_path_TOOLCHAIN_PATH_CC+:} false; then : $as_echo_n "(cached) " >&6 else - case $TOOLS_DIR_CC in + case $TOOLCHAIN_PATH_CC in [\\/]* | ?:[\\/]*) - ac_cv_path_TOOLS_DIR_CC="$TOOLS_DIR_CC" # Let the user override the test with a path. + ac_cv_path_TOOLCHAIN_PATH_CC="$TOOLCHAIN_PATH_CC" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -27597,7 +27624,7 @@ do 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_TOOLS_DIR_CC="$as_dir/$ac_word$ac_exec_ext" + ac_cv_path_TOOLCHAIN_PATH_CC="$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 @@ -27608,20 +27635,20 @@ IFS=$as_save_IFS ;; esac fi -TOOLS_DIR_CC=$ac_cv_path_TOOLS_DIR_CC -if test -n "$TOOLS_DIR_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLS_DIR_CC" >&5 -$as_echo "$TOOLS_DIR_CC" >&6; } +TOOLCHAIN_PATH_CC=$ac_cv_path_TOOLCHAIN_PATH_CC +if test -n "$TOOLCHAIN_PATH_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLCHAIN_PATH_CC" >&5 +$as_echo "$TOOLCHAIN_PATH_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - test -n "$TOOLS_DIR_CC" && break + test -n "$TOOLCHAIN_PATH_CC" && break done - CC=$TOOLS_DIR_CC + CC=$TOOLCHAIN_PATH_CC PATH="$PATH_save" fi @@ -29275,25 +29302,25 @@ done # used. CXX= - # If TOOLS_DIR is set, check for all compiler names in there first + # If TOOLCHAIN_PATH is set, check for all compiler names in there first # before checking the rest of the PATH. # FIXME: Now that we prefix the TOOLS_DIR to the PATH in the PRE_DETECTION # step, this should not be necessary. - if test -n "$TOOLS_DIR"; then + if test -n "$TOOLCHAIN_PATH"; then PATH_save="$PATH" - PATH="$TOOLS_DIR" + PATH="$TOOLCHAIN_PATH" for ac_prog in $SEARCH_LIST 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_TOOLS_DIR_CXX+:} false; then : +if ${ac_cv_path_TOOLCHAIN_PATH_CXX+:} false; then : $as_echo_n "(cached) " >&6 else - case $TOOLS_DIR_CXX in + case $TOOLCHAIN_PATH_CXX in [\\/]* | ?:[\\/]*) - ac_cv_path_TOOLS_DIR_CXX="$TOOLS_DIR_CXX" # Let the user override the test with a path. + ac_cv_path_TOOLCHAIN_PATH_CXX="$TOOLCHAIN_PATH_CXX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -29303,7 +29330,7 @@ do 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_TOOLS_DIR_CXX="$as_dir/$ac_word$ac_exec_ext" + ac_cv_path_TOOLCHAIN_PATH_CXX="$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 @@ -29314,20 +29341,20 @@ IFS=$as_save_IFS ;; esac fi -TOOLS_DIR_CXX=$ac_cv_path_TOOLS_DIR_CXX -if test -n "$TOOLS_DIR_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLS_DIR_CXX" >&5 -$as_echo "$TOOLS_DIR_CXX" >&6; } +TOOLCHAIN_PATH_CXX=$ac_cv_path_TOOLCHAIN_PATH_CXX +if test -n "$TOOLCHAIN_PATH_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLCHAIN_PATH_CXX" >&5 +$as_echo "$TOOLCHAIN_PATH_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - test -n "$TOOLS_DIR_CXX" && break + test -n "$TOOLCHAIN_PATH_CXX" && break done - CXX=$TOOLS_DIR_CXX + CXX=$TOOLCHAIN_PATH_CXX PATH="$PATH_save" fi @@ -40735,6 +40762,32 @@ $as_echo "$tool_specified" >&6; } CCXXFLAGS="$CCXXFLAGS -nologo" fi + if test "x$SYSROOT" != "x"; then + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + # Solaris Studio does not have a concept of sysroot. Instead we must + # make sure the default include and lib dirs are appended to each + # compile and link command line. + SYSROOT_CFLAGS="-I$SYSROOT/usr/include" + SYSROOT_LDFLAGS="-L$SYSROOT/usr/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT/usr/ccs/lib$OPENJDK_TARGET_CPU_ISADIR" + fi + elif test "x$TOOLCHAIN_TYPE" = xgcc; then + SYSROOT_CFLAGS="--sysroot=\"$SYSROOT\"" + SYSROOT_LDFLAGS="--sysroot=\"$SYSROOT\"" + elif test "x$TOOLCHAIN_TYPE" = xclang; then + SYSROOT_CFLAGS="-isysroot \"$SYSROOT\"" + SYSROOT_LDFLAGS="-isysroot \"$SYSROOT\"" + fi + # Propagate the sysroot args to hotspot + LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $SYSROOT_CFLAGS" + LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $SYSROOT_CFLAGS" + LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $SYSROOT_LDFLAGS" + fi + + + # FIXME: Currently we must test this after toolchain but before flags. Fix! @@ -41583,9 +41636,9 @@ fi LDFLAGS_JDK="${LDFLAGS_JDK} $with_extra_ldflags" # Hotspot needs these set in their legacy form - LEGACY_EXTRA_CFLAGS=$with_extra_cflags - LEGACY_EXTRA_CXXFLAGS=$with_extra_cxxflags - LEGACY_EXTRA_LDFLAGS=$with_extra_ldflags + LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $with_extra_cflags" + LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $with_extra_cxxflags" + LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $with_extra_ldflags" @@ -41683,7 +41736,13 @@ fi CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_LITTLE_ENDIAN" fi else - CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN" + # Same goes for _BIG_ENDIAN. Do we really need to set *ENDIAN on Solaris if they + # are defined in the system? + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN=" + else + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN" + fi fi # Setup target OS define. Use OS target name but in upper case. @@ -41989,6 +42048,22 @@ $as_echo "$supports" >&6; } + case "${TOOLCHAIN_TYPE}" in + microsoft) + CFLAGS_WARNINGS_ARE_ERRORS="/WX" + ;; + solstudio) + CFLAGS_WARNINGS_ARE_ERRORS="-errtags -errwarn=%all" + ;; + gcc) + CFLAGS_WARNINGS_ARE_ERRORS="-Werror" + ;; + clang) + CFLAGS_WARNINGS_ARE_ERRORS="-Werror" + ;; + esac + + # Setup debug symbols (need objcopy from the toolchain for that) @@ -42230,21 +42305,23 @@ $as_echo "no" >&6; } # Check if the user has specified sysroot, but not --x-includes or --x-libraries. # Make a simple check for the libraries at the sysroot, and setup --x-includes and # --x-libraries for the sysroot, if that seems to be correct. - if test "x$SYS_ROOT" != "x/"; then - if test "x$x_includes" = xNONE; then - if test -f "$SYS_ROOT/usr/X11R6/include/X11/Xlib.h"; then - x_includes="$SYS_ROOT/usr/X11R6/include" - elif test -f "$SYS_ROOT/usr/include/X11/Xlib.h"; then - x_includes="$SYS_ROOT/usr/include" + if test "x$OPENJDK_TARGET_OS" = "xlinux"; then + if test "x$SYSROOT" != "x"; then + if test "x$x_includes" = xNONE; then + if test -f "$SYSROOT/usr/X11R6/include/X11/Xlib.h"; then + x_includes="$SYSROOT/usr/X11R6/include" + elif test -f "$SYSROOT/usr/include/X11/Xlib.h"; then + x_includes="$SYSROOT/usr/include" + fi fi - fi - if test "x$x_libraries" = xNONE; then - if test -f "$SYS_ROOT/usr/X11R6/lib/libX11.so"; then - x_libraries="$SYS_ROOT/usr/X11R6/lib" - elif test "$SYS_ROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then - x_libraries="$SYS_ROOT/usr/lib64" - elif test -f "$SYS_ROOT/usr/lib/libX11.so"; then - x_libraries="$SYS_ROOT/usr/lib" + if test "x$x_libraries" = xNONE; then + if test -f "$SYSROOT/usr/X11R6/lib/libX11.so"; then + x_libraries="$SYSROOT/usr/X11R6/lib" + elif test "$SYSROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + x_libraries="$SYSROOT/usr/lib64" + elif test -f "$SYSROOT/usr/lib/libX11.so"; then + x_libraries="$SYSROOT/usr/lib" + fi fi fi fi @@ -42976,10 +43053,13 @@ fi if test "x$OPENJDK_TARGET_OS" = xsolaris; then OPENWIN_HOME="/usr/openwin" + X_CFLAGS="-I$SYSROOT$OPENWIN_HOME/include -I$SYSROOT$OPENWIN_HOME/include/X11/extensions" + X_LIBS="-L$SYSROOT$OPENWIN_HOME/sfw/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR \ + -R$OPENWIN_HOME/sfw/lib$OPENJDK_TARGET_CPU_ISADIR \ + -R$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR" fi - - # # Weird Sol10 something check...TODO change to try compile # @@ -43278,14 +43358,14 @@ done # package installation locations. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cups headers" >&5 $as_echo_n "checking for cups headers... " >&6; } - if test -s /opt/sfw/cups/include/cups/cups.h; then + if test -s $SYSROOT/opt/sfw/cups/include/cups/cups.h; then # An SFW package seems to be installed! CUPS_FOUND=yes - CUPS_CFLAGS="-I/opt/sfw/cups/include" - elif test -s /opt/csw/include/cups/cups.h; then + CUPS_CFLAGS="-I$SYSROOT/opt/sfw/cups/include" + elif test -s $SYSROOT/opt/csw/include/cups/cups.h; then # A CSW package seems to be installed! CUPS_FOUND=yes - CUPS_CFLAGS="-I/opt/csw/include" + CUPS_CFLAGS="-I$SYSROOT/opt/csw/include" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CUPS_FOUND" >&5 $as_echo "$CUPS_FOUND" >&6; } @@ -43878,9 +43958,11 @@ $as_echo "yes (using builddeps)" >&6; } fi fi - if test "x$FOUND_FREETYPE" != xyes; then - # Check modules using pkg-config, but only if we have it (ugly output results otherwise) - if test "x$PKG_CONFIG" != x; then + # If we have a sysroot, assume that's where we are supposed to look and skip pkg-config. + if test "x$SYSROOT" = x; then + if test "x$FOUND_FREETYPE" != xyes; then + # Check modules using pkg-config, but only if we have it (ugly output results otherwise) + if test "x$PKG_CONFIG" != x; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FREETYPE" >&5 @@ -43948,23 +44030,24 @@ else $as_echo "yes" >&6; } FOUND_FREETYPE=yes fi - if test "x$FOUND_FREETYPE" = xyes; then - # On solaris, pkg_check adds -lz to freetype libs, which isn't necessary for us. - FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'` - # 64-bit libs for Solaris x86 are installed in the amd64 subdirectory, change lib to lib/amd64 - if test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64; then - FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'` - fi - # BDEPS_CHECK_MODULE will set FREETYPE_CFLAGS and _LIBS, but we don't get a lib path for bundling. - if test "x$BUNDLE_FREETYPE" = xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype using pkg-config, but ignoring since we can not bundle that" >&5 + if test "x$FOUND_FREETYPE" = xyes; then + # On solaris, pkg_check adds -lz to freetype libs, which isn't necessary for us. + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'` + # 64-bit libs for Solaris x86 are installed in the amd64 subdirectory, change lib to lib/amd64 + if test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64; then + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'` + fi + # BDEPS_CHECK_MODULE will set FREETYPE_CFLAGS and _LIBS, but we don't get a lib path for bundling. + if test "x$BUNDLE_FREETYPE" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype using pkg-config, but ignoring since we can not bundle that" >&5 $as_echo "$as_me: Found freetype using pkg-config, but ignoring since we can not bundle that" >&6;} - FOUND_FREETYPE=no - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype" >&5 + FOUND_FREETYPE=no + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype" >&5 $as_echo_n "checking for freetype... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (using pkg-config)" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (using pkg-config)" >&5 $as_echo "yes (using pkg-config)" >&6; } + fi fi fi fi @@ -44578,12 +44661,7 @@ $as_echo "$FREETYPE_LIB_PATH" >&6; } fi else - if test "x$SYS_ROOT" = "x/"; then - FREETYPE_ROOT= - else - FREETYPE_ROOT="$SYS_ROOT" - fi - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr" + FREETYPE_BASE_DIR="$SYSROOT/usr" POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include" POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib" @@ -44876,7 +44954,7 @@ $as_echo "$FREETYPE_LIB_PATH" >&6; } if test "x$FOUND_FREETYPE" != xyes; then - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr/X11" + FREETYPE_BASE_DIR="$SYSROOT/usr/X11" POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include" POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib" @@ -45170,7 +45248,301 @@ $as_echo "$FREETYPE_LIB_PATH" >&6; } fi if test "x$FOUND_FREETYPE" != xyes; then - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr" + FREETYPE_BASE_DIR="$SYSROOT/usr/sfw" + + POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include" + POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib" + METHOD="well-known location" + + # First check if the files exists. + if test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then + # We found an arbitrary include file. That's a good sign. + { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&5 +$as_echo "$as_me: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&6;} + FOUND_FREETYPE=yes + + FREETYPE_LIB_NAME="${LIBRARY_PREFIX}freetype${SHARED_LIBRARY_SUFFIX}" + if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&5 +$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&6;} + FOUND_FREETYPE=no + else + if test "x$OPENJDK_TARGET_OS" = xwindows; then + # On Windows, we will need both .lib and .dll file. + if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/freetype.lib"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/freetype.lib. Ignoring location." >&5 +$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/freetype.lib. Ignoring location." >&6;} + FOUND_FREETYPE=no + fi + elif test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64 && test -s "$POTENTIAL_FREETYPE_LIB_PATH/amd64/$FREETYPE_LIB_NAME"; then + # On solaris-x86_86, default is (normally) PATH/lib/amd64. Update our guess! + POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH/amd64" + fi + fi + fi + + if test "x$FOUND_FREETYPE" = xyes; then + + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_INCLUDE_PATH" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-stile (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a posix platform. Hooray! :) + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`" + fi + + + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$POTENTIAL_FREETYPE_LIB_PATH" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_LIB_PATH" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-stile (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_LIB_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$POTENTIAL_FREETYPE_LIB_PATH" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_LIB_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a posix platform. Hooray! :) + path="$POTENTIAL_FREETYPE_LIB_PATH" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + POTENTIAL_FREETYPE_LIB_PATH="`cd "$path"; $THEPWDCMD -L`" + fi + + + FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype includes" >&5 +$as_echo_n "checking for freetype includes... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_INCLUDE_PATH" >&5 +$as_echo "$FREETYPE_INCLUDE_PATH" >&6; } + FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype libraries" >&5 +$as_echo_n "checking for freetype libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_LIB_PATH" >&5 +$as_echo "$FREETYPE_LIB_PATH" >&6; } + fi + + fi + + if test "x$FOUND_FREETYPE" != xyes; then + FREETYPE_BASE_DIR="$SYSROOT/usr" if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include" @@ -46646,7 +47018,9 @@ $as_echo "$as_me: Downloading build dependency alsa from $with_builddeps_server/ fi fi - if test "x$ALSA_FOUND" = xno; then + # Do not try pkg-config if we have a sysroot set. + if test "x$SYSROOT" = x; then + if test "x$ALSA_FOUND" = xno; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ALSA" >&5 @@ -46714,6 +47088,7 @@ else $as_echo "yes" >&6; } ALSA_FOUND=yes fi + fi fi if test "x$ALSA_FOUND" = xno; then for ac_header in alsa/asoundlib.h @@ -47593,7 +47968,7 @@ fi # libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so) if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then - LIBCXX="/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" + LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" fi # TODO better (platform agnostic) test @@ -48518,8 +48893,8 @@ $as_echo_n "checking is ccache enabled... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } OLD_PATH="$PATH" - if test "x$TOOLS_DIR" != x; then - PATH=$TOOLS_DIR:$PATH + if test "x$TOOLCHAIN_PATH" != x; then + PATH=$TOOLCHAIN_PATH:$PATH fi @@ -50203,6 +50578,7 @@ $CHMOD +x $OUTPUT_ROOT/compare.sh printf "\n" printf "Configuration summary:\n" printf "* Debug level: $DEBUG_LEVEL\n" + printf "* HS debug level: $HOTSPOT_DEBUG_LEVEL\n" printf "* JDK variant: $JDK_VARIANT\n" printf "* JVM variants: $with_jvm_variants\n" printf "* OpenJDK target: OS: $OPENJDK_TARGET_OS, CPU architecture: $OPENJDK_TARGET_CPU_ARCH, address length: $OPENJDK_TARGET_CPU_BITS\n" diff --git a/common/autoconf/help.m4 b/common/autoconf/help.m4 index 2cad8d6fb39..9ae7874fd6b 100644 --- a/common/autoconf/help.m4 +++ b/common/autoconf/help.m4 @@ -200,6 +200,7 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS], printf "\n" printf "Configuration summary:\n" printf "* Debug level: $DEBUG_LEVEL\n" + printf "* HS debug level: $HOTSPOT_DEBUG_LEVEL\n" printf "* JDK variant: $JDK_VARIANT\n" printf "* JVM variants: $with_jvm_variants\n" printf "* OpenJDK target: OS: $OPENJDK_TARGET_OS, CPU architecture: $OPENJDK_TARGET_CPU_ARCH, address length: $OPENJDK_TARGET_CPU_BITS\n" diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index 58d148fe421..b012aa756b4 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -176,6 +176,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], # # Set the debug level # release: no debug information, all optimizations, no asserts. + # optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'. # fastdebug: debug information (-g), all optimizations, all asserts # slowdebug: debug information (-g), no optimizations, all asserts # @@ -189,7 +190,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], ], [ENABLE_DEBUG="no"]) AC_ARG_WITH([debug-level], [AS_HELP_STRING([--with-debug-level], - [set the debug level (release, fastdebug, slowdebug) @<:@release@:>@])], + [set the debug level (release, fastdebug, slowdebug, optimized (HotSpot build only)) @<:@release@:>@])], [ DEBUG_LEVEL="${withval}" if test "x$ENABLE_DEBUG" = xyes; then @@ -199,6 +200,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], AC_MSG_RESULT([$DEBUG_LEVEL]) if test "x$DEBUG_LEVEL" != xrelease && \ + test "x$DEBUG_LEVEL" != xoptimized && \ test "x$DEBUG_LEVEL" != xfastdebug && \ test "x$DEBUG_LEVEL" != xslowdebug; then AC_MSG_ERROR([Allowed debug levels are: release, fastdebug and slowdebug]) @@ -235,8 +237,30 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], HOTSPOT_DEBUG_LEVEL="jvmg" HOTSPOT_EXPORT="debug" ;; + optimized ) + VARIANT="OPT" + FASTDEBUG="false" + DEBUG_CLASSFILES="false" + BUILD_VARIANT_RELEASE="-optimized" + HOTSPOT_DEBUG_LEVEL="optimized" + HOTSPOT_EXPORT="optimized" + ;; esac + # The debug level 'optimized' is a little special because it is currently only + # applicable to the HotSpot build where it means to build a completely + # optimized version of the VM without any debugging code (like for the + # 'release' debug level which is called 'product' in the HotSpot build) but + # with the exception that it can contain additional code which is otherwise + # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to + # test new and/or experimental features which are not intended for customer + # shipment. Because these new features need to be tested and benchmarked in + # real world scenarios, we want to build the containing JDK at the 'release' + # debug level. + if test "x$DEBUG_LEVEL" = xoptimized; then + DEBUG_LEVEL="release" + fi + ##### # Generate the legacy makefile targets for hotspot. # The hotspot api for selecting the build artifacts, really, needs to be improved. diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4 index 6dca4aad3c6..1546529ce80 100644 --- a/common/autoconf/libraries.m4 +++ b/common/autoconf/libraries.m4 @@ -110,21 +110,23 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], # Check if the user has specified sysroot, but not --x-includes or --x-libraries. # Make a simple check for the libraries at the sysroot, and setup --x-includes and # --x-libraries for the sysroot, if that seems to be correct. - if test "x$SYS_ROOT" != "x/"; then - if test "x$x_includes" = xNONE; then - if test -f "$SYS_ROOT/usr/X11R6/include/X11/Xlib.h"; then - x_includes="$SYS_ROOT/usr/X11R6/include" - elif test -f "$SYS_ROOT/usr/include/X11/Xlib.h"; then - x_includes="$SYS_ROOT/usr/include" + if test "x$OPENJDK_TARGET_OS" = "xlinux"; then + if test "x$SYSROOT" != "x"; then + if test "x$x_includes" = xNONE; then + if test -f "$SYSROOT/usr/X11R6/include/X11/Xlib.h"; then + x_includes="$SYSROOT/usr/X11R6/include" + elif test -f "$SYSROOT/usr/include/X11/Xlib.h"; then + x_includes="$SYSROOT/usr/include" + fi fi - fi - if test "x$x_libraries" = xNONE; then - if test -f "$SYS_ROOT/usr/X11R6/lib/libX11.so"; then - x_libraries="$SYS_ROOT/usr/X11R6/lib" - elif test "$SYS_ROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then - x_libraries="$SYS_ROOT/usr/lib64" - elif test -f "$SYS_ROOT/usr/lib/libX11.so"; then - x_libraries="$SYS_ROOT/usr/lib" + if test "x$x_libraries" = xNONE; then + if test -f "$SYSROOT/usr/X11R6/lib/libX11.so"; then + x_libraries="$SYSROOT/usr/X11R6/lib" + elif test "$SYSROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + x_libraries="$SYSROOT/usr/lib64" + elif test -f "$SYSROOT/usr/lib/libX11.so"; then + x_libraries="$SYSROOT/usr/lib" + fi fi fi fi @@ -146,9 +148,12 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], if test "x$OPENJDK_TARGET_OS" = xsolaris; then OPENWIN_HOME="/usr/openwin" + X_CFLAGS="-I$SYSROOT$OPENWIN_HOME/include -I$SYSROOT$OPENWIN_HOME/include/X11/extensions" + X_LIBS="-L$SYSROOT$OPENWIN_HOME/sfw/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR \ + -R$OPENWIN_HOME/sfw/lib$OPENJDK_TARGET_CPU_ISADIR \ + -R$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR" fi - AC_SUBST(OPENWIN_HOME) - # # Weird Sol10 something check...TODO change to try compile @@ -237,14 +242,14 @@ AC_DEFUN_ONCE([LIB_SETUP_CUPS], # Getting nervous now? Lets poke around for standard Solaris third-party # package installation locations. AC_MSG_CHECKING([for cups headers]) - if test -s /opt/sfw/cups/include/cups/cups.h; then + if test -s $SYSROOT/opt/sfw/cups/include/cups/cups.h; then # An SFW package seems to be installed! CUPS_FOUND=yes - CUPS_CFLAGS="-I/opt/sfw/cups/include" - elif test -s /opt/csw/include/cups/cups.h; then + CUPS_CFLAGS="-I$SYSROOT/opt/sfw/cups/include" + elif test -s $SYSROOT/opt/csw/include/cups/cups.h; then # A CSW package seems to be installed! CUPS_FOUND=yes - CUPS_CFLAGS="-I/opt/csw/include" + CUPS_CFLAGS="-I$SYSROOT/opt/csw/include" fi AC_MSG_RESULT([$CUPS_FOUND]) fi @@ -398,24 +403,27 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], fi fi - if test "x$FOUND_FREETYPE" != xyes; then - # Check modules using pkg-config, but only if we have it (ugly output results otherwise) - if test "x$PKG_CONFIG" != x; then - PKG_CHECK_MODULES(FREETYPE, freetype2, [FOUND_FREETYPE=yes], [FOUND_FREETYPE=no]) - if test "x$FOUND_FREETYPE" = xyes; then - # On solaris, pkg_check adds -lz to freetype libs, which isn't necessary for us. - FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'` - # 64-bit libs for Solaris x86 are installed in the amd64 subdirectory, change lib to lib/amd64 - if test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64; then - FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'` - fi - # BDEPS_CHECK_MODULE will set FREETYPE_CFLAGS and _LIBS, but we don't get a lib path for bundling. - if test "x$BUNDLE_FREETYPE" = xyes; then - AC_MSG_NOTICE([Found freetype using pkg-config, but ignoring since we can not bundle that]) - FOUND_FREETYPE=no - else - AC_MSG_CHECKING([for freetype]) - AC_MSG_RESULT([yes (using pkg-config)]) + # If we have a sysroot, assume that's where we are supposed to look and skip pkg-config. + if test "x$SYSROOT" = x; then + if test "x$FOUND_FREETYPE" != xyes; then + # Check modules using pkg-config, but only if we have it (ugly output results otherwise) + if test "x$PKG_CONFIG" != x; then + PKG_CHECK_MODULES(FREETYPE, freetype2, [FOUND_FREETYPE=yes], [FOUND_FREETYPE=no]) + if test "x$FOUND_FREETYPE" = xyes; then + # On solaris, pkg_check adds -lz to freetype libs, which isn't necessary for us. + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'` + # 64-bit libs for Solaris x86 are installed in the amd64 subdirectory, change lib to lib/amd64 + if test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64; then + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'` + fi + # BDEPS_CHECK_MODULE will set FREETYPE_CFLAGS and _LIBS, but we don't get a lib path for bundling. + if test "x$BUNDLE_FREETYPE" = xyes; then + AC_MSG_NOTICE([Found freetype using pkg-config, but ignoring since we can not bundle that]) + FOUND_FREETYPE=no + else + AC_MSG_CHECKING([for freetype]) + AC_MSG_RESULT([yes (using pkg-config)]) + fi fi fi fi @@ -433,21 +441,21 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) fi else - if test "x$SYS_ROOT" = "x/"; then - FREETYPE_ROOT= - else - FREETYPE_ROOT="$SYS_ROOT" - fi - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr" + FREETYPE_BASE_DIR="$SYSROOT/usr" LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) if test "x$FOUND_FREETYPE" != xyes; then - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr/X11" + FREETYPE_BASE_DIR="$SYSROOT/usr/X11" LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) fi if test "x$FOUND_FREETYPE" != xyes; then - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr" + FREETYPE_BASE_DIR="$SYSROOT/usr/sfw" + LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) + fi + + if test "x$FOUND_FREETYPE" != xyes; then + FREETYPE_BASE_DIR="$SYSROOT/usr" if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib/x86_64-linux-gnu], [well-known location]) else @@ -577,8 +585,11 @@ AC_DEFUN_ONCE([LIB_SETUP_ALSA], if test "x$ALSA_FOUND" = xno; then BDEPS_CHECK_MODULE(ALSA, alsa, xxx, [ALSA_FOUND=yes], [ALSA_FOUND=no]) fi - if test "x$ALSA_FOUND" = xno; then - PKG_CHECK_MODULES(ALSA, alsa, [ALSA_FOUND=yes], [ALSA_FOUND=no]) + # Do not try pkg-config if we have a sysroot set. + if test "x$SYSROOT" = x; then + if test "x$ALSA_FOUND" = xno; then + PKG_CHECK_MODULES(ALSA, alsa, [ALSA_FOUND=yes], [ALSA_FOUND=no]) + fi fi if test "x$ALSA_FOUND" = xno; then AC_CHECK_HEADERS([alsa/asoundlib.h], @@ -917,7 +928,7 @@ AC_DEFUN_ONCE([LIB_SETUP_STATIC_LINK_LIBSTDCPP], # libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so) if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then - LIBCXX="/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" + LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" fi # TODO better (platform agnostic) test diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index d1b1573b101..1f06f0ce7d5 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -60,6 +60,12 @@ AC_DEFUN([PLATFORM_EXTRACT_VARS_FROM_CPU], VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; + powerpc64le) + VAR_CPU=ppc64 + VAR_CPU_ARCH=ppc + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; s390) VAR_CPU=s390 VAR_CPU_ARCH=s390 diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index fe5fb1be8d8..c793d0e5c63 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -130,10 +130,8 @@ ifeq ($(OPENJDK_TARGET_OS), windows) export LIB:=@VS_LIB@ endif -# The sys root where standard headers and libraries are found. -# Usually not needed since the configure script should have -# taken it into account already when setting CFLAGS et al. -SYS_ROOT:=@SYS_ROOT@ +SYSROOT_CFLAGS := @SYSROOT_CFLAGS@ +SYSROOT_LDFLAGS := @SYSROOT_LDFLAGS@ # Paths to the source code ADD_SRC_ROOT:=@ADD_SRC_ROOT@ @@ -294,7 +292,6 @@ RMICONNECTOR_IIOP=@RMICONNECTOR_IIOP@ # Necessary additional compiler flags to compile X11 X_CFLAGS:=@X_CFLAGS@ X_LIBS:=@X_LIBS@ -OPENWIN_HOME:=@OPENWIN_HOME@ # The lowest required version of macosx to enforce compatiblity for MACOSX_VERSION_MIN=@MACOSX_VERSION_MIN@ @@ -324,6 +321,8 @@ CXX_O_FLAG_NONE:=@CXX_O_FLAG_NONE@ C_FLAG_DEPS:=@C_FLAG_DEPS@ CXX_FLAG_DEPS:=@CXX_FLAG_DEPS@ +CFLAGS_WARNINGS_ARE_ERRORS:=@CFLAGS_WARNINGS_ARE_ERRORS@ + # Tools that potentially need to be cross compilation aware. CC:=@FIXPATH@ @CCACHE@ @CC@ diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index ba57a850219..b7c00d4f495 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -189,6 +189,12 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], # it for DLL resolution in runtime. if test "x$OPENJDK_BUILD_OS" = "xwindows" && test "x$TOOLCHAIN_TYPE" = "xmicrosoft"; then TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV + # Reset path to VS_PATH. It will include everything that was on PATH at the time we + # ran TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV. + PATH="$VS_PATH" + # The microsoft toolchain also requires INCLUDE and LIB to be set. + export INCLUDE="$VS_INCLUDE" + export LIB="$VS_LIB" fi # autoconf magic only relies on PATH, so update it if tools dir is specified @@ -202,29 +208,11 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], PATH="/usr/ccs/bin:$PATH" fi - # Finally add TOOLS_DIR at the beginning, to allow --with-tools-dir to + # Finally add TOOLCHAIN_PATH at the beginning, to allow --with-tools-dir to # override all other locations. - if test "x$TOOLS_DIR" != x; then - PATH=$TOOLS_DIR:$PATH + if test "x$TOOLCHAIN_PATH" != x; then + PATH=$TOOLCHAIN_PATH:$PATH fi - - # If a devkit is found on the builddeps server, then prepend its path to the - # PATH variable. If there are cross compilers available in the devkit, these - # will be found by AC_PROG_CC et al. - DEVKIT= - BDEPS_CHECK_MODULE(DEVKIT, devkit, xxx, - [ - # Found devkit - PATH="$DEVKIT/bin:$PATH" - SYS_ROOT="$DEVKIT/${rewritten_target}/sys-root" - if test "x$x_includes" = "xNONE"; then - x_includes="$SYS_ROOT/usr/include/X11" - fi - if test "x$x_libraries" = "xNONE"; then - x_libraries="$SYS_ROOT/usr/lib" - fi - ], - []) ]) # Restore path, etc @@ -396,15 +384,15 @@ AC_DEFUN([TOOLCHAIN_FIND_COMPILER], # used. $1= - # If TOOLS_DIR is set, check for all compiler names in there first + # If TOOLCHAIN_PATH is set, check for all compiler names in there first # before checking the rest of the PATH. # FIXME: Now that we prefix the TOOLS_DIR to the PATH in the PRE_DETECTION # step, this should not be necessary. - if test -n "$TOOLS_DIR"; then + if test -n "$TOOLCHAIN_PATH"; then PATH_save="$PATH" - PATH="$TOOLS_DIR" - AC_PATH_PROGS(TOOLS_DIR_$1, $SEARCH_LIST) - $1=$TOOLS_DIR_$1 + PATH="$TOOLCHAIN_PATH" + AC_PATH_PROGS(TOOLCHAIN_PATH_$1, $SEARCH_LIST) + $1=$TOOLCHAIN_PATH_$1 PATH="$PATH_save" fi diff --git a/common/autoconf/toolchain_windows.m4 b/common/autoconf/toolchain_windows.m4 index 37da5554066..b4888a46ac5 100644 --- a/common/autoconf/toolchain_windows.m4 +++ b/common/autoconf/toolchain_windows.m4 @@ -141,46 +141,44 @@ AC_DEFUN([TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV], # Lets extract the variables that are set by vcvarsall.bat/vsvars32.bat/vsvars64.bat AC_MSG_NOTICE([Trying to extract Visual Studio environment variables]) - cd $OUTPUT_ROOT - # FIXME: The code betweeen ---- was inlined from a separate script and is not properly adapted - # to autoconf standards. - #---- + # We need to create a couple of temporary files. + VS_ENV_TMP_DIR="$OUTPUT_ROOT/vs-env" + $MKDIR -p $VS_ENV_TMP_DIR - # Cannot use the VS10 setup script directly (since it only updates the DOS subshell environment) - # but calculate the difference in Cygwin environment before/after running it and then - # apply the diff. + # Cannot use the VS10 setup script directly (since it only updates the DOS subshell environment). + # Instead create a shell script which will set the relevant variables when run. + WINPATH_VS_ENV_CMD="$VS_ENV_CMD" + BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH([WINPATH_VS_ENV_CMD]) + WINPATH_BASH="$BASH" + BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH([WINPATH_BASH]) - if test "x$OPENJDK_BUILD_OS_ENV" = xwindows.cygwin; then - _vs10varsall=`cygpath -a -m -s "$VS_ENV_CMD"` - _dosvs10varsall=`cygpath -a -w -s $_vs10varsall` - _dosbash=`cygpath -a -w -s \`which bash\`.*` - else - _dosvs10varsall=`cmd //c echo $VS_ENV_CMD` - _dosbash=`cmd //c echo \`which bash\`` - fi - - # generate the set of exported vars before/after the vs10 setup - $ECHO "@echo off" > localdevenvtmp.bat - $ECHO "$_dosbash -c \"export -p\" > localdevenvtmp.export0" >> localdevenvtmp.bat - $ECHO "call $_dosvs10varsall $VS_ENV_ARGS" >> localdevenvtmp.bat - $ECHO "$_dosbash -c \"export -p\" > localdevenvtmp.export1" >> localdevenvtmp.bat + # Generate a DOS batch file which runs $VS_ENV_CMD, and then creates a shell + # script (executable by bash) that will setup the important variables. + EXTRACT_VC_ENV_BAT_FILE="$VS_ENV_TMP_DIR/extract-vs-env.bat" + $ECHO "@echo off" > $EXTRACT_VC_ENV_BAT_FILE + # This will end up something like: + # call C:/progra~2/micros~2.0/vc/bin/amd64/vcvars64.bat + $ECHO "call $WINPATH_VS_ENV_CMD $VS_ENV_ARGS" >> $EXTRACT_VC_ENV_BAT_FILE + # These will end up something like: + # C:/CygWin/bin/bash -c 'echo VS_PATH=\"$PATH\" > localdevenv.sh + # The trailing space for everyone except PATH is no typo, but is needed due + # to trailing \ in the Windows paths. These will be stripped later. + $ECHO "$WINPATH_BASH -c 'echo VS_PATH="'\"$PATH\" > set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VCINSTALLDIR="'\"$VCINSTALLDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo WindowsSdkDir="'\"$WindowsSdkDir \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo WINDOWSSDKDIR="'\"$WINDOWSSDKDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE # Now execute the newly created bat file. - # The | cat is to stop SetEnv.Cmd to mess with system colors on msys - cmd /c localdevenvtmp.bat | cat - - # apply the diff (less some non-vs10 vars named by "!") - $SORT localdevenvtmp.export0 | $GREP -v "!" > localdevenvtmp.export0.sort - $SORT localdevenvtmp.export1 | $GREP -v "!" > localdevenvtmp.export1.sort - $COMM -1 -3 localdevenvtmp.export0.sort localdevenvtmp.export1.sort > localdevenv.sh - - # cleanup - $RM localdevenvtmp* - #---- + # The | cat is to stop SetEnv.Cmd to mess with system colors on msys. + # Change directory so we don't need to mess with Windows paths in redirects. + cd $VS_ENV_TMP_DIR + cmd /c extract-vs-env.bat | $CAT cd $CURDIR - if test ! -s $OUTPUT_ROOT/localdevenv.sh; then - AC_MSG_RESULT([no]) + + if test ! -s $VS_ENV_TMP_DIR/set-vs-env.sh; then AC_MSG_NOTICE([Could not succesfully extract the envionment variables needed for the VS setup.]) AC_MSG_NOTICE([Try setting --with-tools-dir to the VC/bin directory within the VS installation]) AC_MSG_NOTICE([or run "bash.exe -l" from a VS command prompt and then run configure from there.]) @@ -190,30 +188,36 @@ AC_DEFUN([TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV], # Now set all paths and other env variables. This will allow the rest of # the configure script to find and run the compiler in the proper way. AC_MSG_NOTICE([Setting extracted environment variables]) - . $OUTPUT_ROOT/localdevenv.sh + . $VS_ENV_TMP_DIR/set-vs-env.sh + # Now we have VS_PATH, VS_INCLUDE, VS_LIB. For further checking, we + # also define VCINSTALLDIR, WindowsSdkDir and WINDOWSSDKDIR. else # We did not find a vsvars bat file, let's hope we are run from a VS command prompt. AC_MSG_NOTICE([Cannot locate a valid Visual Studio installation, checking current environment]) fi - # At this point, we should have corrent variables in the environment, or we can't continue. + # At this point, we should have correct variables in the environment, or we can't continue. AC_MSG_CHECKING([for Visual Studio variables]) if test "x$VCINSTALLDIR" != x || test "x$WindowsSDKDir" != x || test "x$WINDOWSSDKDIR" != x; then - if test "x$INCLUDE" = x || test "x$LIB" = x; then + if test "x$VS_INCLUDE" = x || test "x$VS_LIB" = x; then AC_MSG_RESULT([present but broken]) AC_MSG_ERROR([Your VC command prompt seems broken, INCLUDE and/or LIB is missing.]) else AC_MSG_RESULT([ok]) - # Remove any trailing \ from INCLUDE and LIB to avoid trouble in spec.gmk. - VS_INCLUDE=`$ECHO "$INCLUDE" | $SED 's/\\\\$//'` - VS_LIB=`$ECHO "$LIB" | $SED 's/\\\\$//'` - # Remove any paths containing # (typically F#) as that messes up make - PATH=`$ECHO "$PATH" | $SED 's/[[^:#]]*#[^:]*://g'` - VS_PATH="$PATH" + # Remove any trailing "\" and " " from the variables. + VS_INCLUDE=`$ECHO "$VS_INCLUDE" | $SED 's/\\\\* *$//'` + VS_LIB=`$ECHO "$VS_LIB" | $SED 's/\\\\* *$//'` + VCINSTALLDIR=`$ECHO "$VCINSTALLDIR" | $SED 's/\\\\* *$//'` + WindowsSDKDir=`$ECHO "$WindowsSDKDir" | $SED 's/\\\\* *$//'` + WINDOWSSDKDIR=`$ECHO "$WINDOWSSDKDIR" | $SED 's/\\\\* *$//'` + # Remove any paths containing # (typically F#) as that messes up make. This + # is needed if visual studio was installed with F# support. + VS_PATH=`$ECHO "$VS_PATH" | $SED 's/[[^:#]]*#[^:]*://g'` + + AC_SUBST(VS_PATH) AC_SUBST(VS_INCLUDE) AC_SUBST(VS_LIB) - AC_SUBST(VS_PATH) fi else AC_MSG_RESULT([not found]) diff --git a/common/bin/compare.sh b/common/bin/compare.sh index 08c0d6bb229..ff88bb1fbb9 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -114,7 +114,7 @@ diff_text() { fi if test "x$SUFFIX" = "xproperties"; then # Run through nawk to add possibly missing newline at end of file. - $CAT $OTHER_FILE | $NAWK '{ print }' > $OTHER_FILE.cleaned + $CAT $OTHER_FILE | $NAWK '{ print }' | LC_ALL=C $SORT > $OTHER_FILE.cleaned # Disable this exception since we aren't changing the properties cleaning method yet. # $CAT $OTHER_FILE | $SED -e 's/\([^\\]\):/\1\\:/g' -e 's/\([^\\]\)=/\1\\=/g' -e 's/#.*/#/g' \ # | $SED -f "$SRC_ROOT/common/makefiles/support/unicode2x.sed" \ diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh index d8164d60316..3ada41ee0cd 100644 --- a/common/bin/hgforest.sh +++ b/common/bin/hgforest.sh @@ -24,12 +24,58 @@ # # Shell script for a fast parallel forest command -command="$1" -pull_extra_base="$2" -if [ "" = "$command" ] ; then - echo No command to hg supplied! - exit 1 +global_opts="" +status_output="/dev/stdout" +qflag="false" +vflag="false" +sflag="false" +while [ $# -gt 0 ] +do + case $1 in + -q | --quiet ) + qflag="true" + global_opts="${global_opts} -q" + status_output="/dev/null" + ;; + + -v | --verbose ) + vflag="true" + global_opts="${global_opts} -v" + ;; + + -s | --sequential ) + sflag="true" + ;; + + '--' ) # no more options + shift; break + ;; + + -*) # bad option + usage + ;; + + * ) # non option + break + ;; + esac + shift +done + + +command="$1"; shift +command_args="$@" + +usage() { + echo "usage: $0 [-q|--quiet] [-v|--verbose] [-s|--sequential] [--] [commands...]" > ${status_output} + exit 1 +} + + +if [ "x" = "x$command" ] ; then + echo "ERROR: No command to hg supplied!" + usage fi # Clean out the temporary directory that stores the pid files. @@ -40,17 +86,17 @@ mkdir -p ${tmp} safe_interrupt () { if [ -d ${tmp} ]; then if [ "`ls ${tmp}/*.pid`" != "" ]; then - echo "Waiting for processes ( `cat ${tmp}/*.pid | tr '\n' ' '`) to terminate nicely!" + echo "Waiting for processes ( `cat ${tmp}/*.pid | tr '\n' ' '`) to terminate nicely!" > ${status_output} sleep 1 # Pipe stderr to dev/null to silence kill, that complains when trying to kill # a subprocess that has already exited. kill -TERM `cat ${tmp}/*.pid | tr '\n' ' '` 2> /dev/null wait - echo Interrupt complete! + echo "Interrupt complete!" > ${status_output} fi + rm -f -r ${tmp} fi - rm -f -r ${tmp} - exit 1 + exit 130 } nice_exit () { @@ -58,39 +104,44 @@ nice_exit () { if [ "`ls ${tmp}`" != "" ]; then wait fi + rm -f -r ${tmp} fi - rm -f -r ${tmp} } trap 'safe_interrupt' INT QUIT trap 'nice_exit' EXIT +subrepos="corba jaxp jaxws langtools jdk hotspot nashorn" +subrepos_extra="closed jdk/src/closed jdk/make/closed jdk/test/closed hotspot/make/closed hotspot/src/closed hotspot/test/closed deploy install sponsors pubs" + # Only look in specific locations for possible forests (avoids long searches) pull_default="" repos="" repos_extra="" -if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then - subrepos="corba jaxp jaxws langtools jdk hotspot nashorn" - if [ -f .hg/hgrc ] ; then - pull_default=`hg paths default` - if [ "${pull_default}" = "" ] ; then - echo "ERROR: Need initial clone with 'hg paths default' defined" - exit 1 - fi - fi - if [ "${pull_default}" = "" ] ; then - echo "ERROR: Need initial repository to use this script" +if [ "${command}" = "clone" -o "${command}" = "fclone" -o "${command}" = "tclone" ] ; then + if [ ! -f .hg/hgrc ] ; then + echo "ERROR: Need initial repository to use this script" > ${status_output} exit 1 fi + + pull_default=`hg paths default` + if [ "${pull_default}" = "" ] ; then + echo "ERROR: Need initial clone with 'hg paths default' defined" > ${status_output} + exit 1 + fi + for i in ${subrepos} ; do if [ ! -f ${i}/.hg/hgrc ] ; then repos="${repos} ${i}" fi done - if [ "${pull_extra_base}" != "" ] ; then - subrepos_extra="closed jdk/src/closed jdk/make/closed jdk/test/closed hotspot/make/closed hotspot/src/closed hotspot/test/closed deploy install sponsors pubs" + if [ "${command_args}" != "" ] ; then pull_default_tail=`echo ${pull_default} | sed -e 's@^.*://[^/]*/\(.*\)@\1@'` - pull_extra="${pull_extra_base}/${pull_default_tail}" + if [ "x${pull_default}" = "x${pull_default_tail}" ] ; then + echo "ERROR: Need initial clone from non-local source" > ${status_output} + exit 1 + fi + pull_extra="${command_args}/${pull_default_tail}" for i in ${subrepos_extra} ; do if [ ! -f ${i}/.hg/hgrc ] ; then repos_extra="${repos_extra} ${i}" @@ -100,78 +151,115 @@ if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then at_a_time=2 # Any repos to deal with? if [ "${repos}" = "" -a "${repos_extra}" = "" ] ; then + echo "No repositories to process." > ${status_output} exit fi else - hgdirs=`ls -d ./.hg ./*/.hg ./*/*/.hg ./*/*/*/.hg ./*/*/*/*/.hg 2>/dev/null` - # Derive repository names from the .hg directory locations - for i in ${hgdirs} ; do - repos="${repos} `echo ${i} | sed -e 's@/.hg$@@'`" + for i in . ${subrepos} ${subrepos_extra} ; do + if [ -d ${i}/.hg ] ; then + repos="${repos} ${i}" + fi done + + # Any repos to deal with? + if [ "${repos}" = "" ] ; then + echo "No repositories to process." > ${status_output} + exit + fi + + # any of the repos locked? for i in ${repos} ; do if [ -h ${i}/.hg/store/lock -o -f ${i}/.hg/store/lock ] ; then locked="${i} ${locked}" fi done - at_a_time=8 - # Any repos to deal with? - if [ "${repos}" = "" ] ; then - echo "No repositories to process." - exit - fi if [ "${locked}" != "" ] ; then - echo "These repositories are locked: ${locked}" - exit + echo "ERROR: These repositories are locked: ${locked}" > ${status_output} + exit 1 fi + at_a_time=8 fi # Echo out what repositories we do a command on. -echo "# Repositories: ${repos} ${repos_extra}" -echo +echo "# Repositories: ${repos} ${repos_extra}" > ${status_output} -# Run the supplied command on all repos in parallel. -n=0 -for i in ${repos} ${repos_extra} ; do - n=`expr ${n} '+' 1` - repopidfile=`echo ${i} | sed -e 's@./@@' -e 's@/@_@g'` - reponame=`echo ${i} | sed -e :a -e 's/^.\{1,20\}$/ &/;ta'` - pull_base="${pull_default}" - for j in $repos_extra ; do +if [ "${command}" = "serve" ] ; then + # "serve" is run for all the repos. + ( + ( + ( + echo "[web]" + echo "description = $(basename $(pwd))" + echo "allow_push = *" + echo "push_ssl = False" + + echo "[paths]" + for i in ${repos} ${repos_extra} ; do + if [ "${i}" != "." ] ; then + echo "/$(basename $(pwd))/${i} = ${i}" + else + echo "/$(basename $(pwd)) = $(pwd)" + fi + done + ) > ${tmp}/serve.web-conf + + echo "serving root repo $(basename $(pwd))" + + (PYTHONUNBUFFERED=true hg${global_opts} serve -A ${status_output} -E ${status_output} --pid-file ${tmp}/serve.pid --web-conf ${tmp}/serve.web-conf; echo "$?" > ${tmp}/serve.pid.rc ) 2>&1 & + ) 2>&1 | sed -e "s@^@serve: @" > ${status_output} + ) & +else + # Run the supplied command on all repos in parallel. + n=0 + for i in ${repos} ${repos_extra} ; do + n=`expr ${n} '+' 1` + repopidfile=`echo ${i} | sed -e 's@./@@' -e 's@/@_@g'` + reponame=`echo ${i} | sed -e :a -e 's/^.\{1,20\}$/ &/;ta'` + pull_base="${pull_default}" + for j in $repos_extra ; do if [ "$i" = "$j" ] ; then pull_base="${pull_extra}" fi - done - ( + done ( - if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then - pull_newrepo="`echo ${pull_base}/${i} | sed -e 's@\([^:]/\)//*@\1@g'`" - echo hg clone ${pull_newrepo} ${i} - path="`dirname ${i}`" - if [ "${path}" != "." ] ; then - times=0 - while [ ! -d "${path}" ] ## nested repo, ensure containing dir exists - do - times=`expr ${times} '+' 1` - if [ `expr ${times} '%' 10` -eq 0 ] ; then - echo ${path} still not created, waiting... - fi - sleep 5 - done + ( + if [ "${command}" = "clone" -o "${command}" = "fclone" -o "${command}" = "tclone" ] ; then + pull_newrepo="`echo ${pull_base}/${i} | sed -e 's@\([^:]/\)//*@\1@g'`" + path="`dirname ${i}`" + if [ "${path}" != "." ] ; then + times=0 + while [ ! -d "${path}" ] ## nested repo, ensure containing dir exists + do + times=`expr ${times} '+' 1` + if [ `expr ${times} '%' 10` -eq 0 ] ; then + echo "${path} still not created, waiting..." > ${status_output} + fi + sleep 5 + done + fi + echo "hg clone ${pull_newrepo} ${i}" > ${status_output} + (PYTHONUNBUFFERED=true hg${global_opts} clone ${pull_newrepo} ${i}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & + else + echo "cd ${i} && hg${global_opts} ${command} ${command_args}" > ${status_output} + cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} ${command_args}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & fi - (PYTHONUNBUFFERED=true hg clone ${pull_newrepo} ${i}; echo "$?" > ${tmp}/${repopidfile}.pid.rc )& - else - echo "cd ${i} && hg $*" - cd ${i} && (PYTHONUNBUFFERED=true hg "$@"; echo "$?" > ${tmp}/${repopidfile}.pid.rc )& - fi - echo $! > ${tmp}/${repopidfile}.pid - ) 2>&1 | sed -e "s@^@${reponame}: @") & - if [ `expr ${n} '%' ${at_a_time}` -eq 0 ] ; then - sleep 2 - echo Waiting 5 secs before spawning next background command. - sleep 3 - fi -done + echo $! > ${tmp}/${repopidfile}.pid + ) 2>&1 | sed -e "s@^@${reponame}: @" > ${status_output} + ) & + + if [ `expr ${n} '%' ${at_a_time}` -eq 0 -a "${sflag}" = "false" ] ; then + sleep 2 + echo "Waiting 5 secs before spawning next background command." > ${status_output} + sleep 3 + fi + + if [ "${sflag}" = "true" ] ; then + wait + fi + done +fi + # Wait for all hg commands to complete wait @@ -181,7 +269,8 @@ if [ -d ${tmp} ]; then for rc in ${tmp}/*.pid.rc ; do exit_code=`cat ${rc} | tr -d ' \n\r'` if [ "${exit_code}" != "0" ] ; then - echo "WARNING: ${rc} exited abnormally." + repo="`echo ${rc} | sed -e s@^${tmp}@@ -e 's@/*\([^/]*\)\.pid\.rc$@\1@' -e 's@_@/@g'`" + echo "WARNING: ${repo} exited abnormally." > ${status_output} ec=1 fi done diff --git a/common/src/fixpath.c b/common/src/fixpath.c index a85bf4cc68e..b30f58d6b51 100644 --- a/common/src/fixpath.c +++ b/common/src/fixpath.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 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 @@ -29,7 +29,7 @@ #include #include -void report_error() +void report_error(char const * msg) { LPVOID lpMsgBuf; DWORD dw = GetLastError(); @@ -46,8 +46,8 @@ void report_error() NULL); fprintf(stderr, - "Could not start process! Failed with error %d: %s\n", - dw, lpMsgBuf); + "%s Failed with error %d: %s\n", + msg, dw, lpMsgBuf); LocalFree(lpMsgBuf); } @@ -56,7 +56,7 @@ void report_error() * Test if pos points to /cygdrive/_/ where _ can * be any character. */ -int is_cygdrive_here(int pos, char *in, int len) +int is_cygdrive_here(int pos, char const *in, int len) { // Length of /cygdrive/c/ is 12 if (pos+12 > len) return 0; @@ -81,16 +81,17 @@ int is_cygdrive_here(int pos, char *in, int len) * Works in place since drive letter is always * shorter than /cygdrive/ */ -char *replace_cygdrive_cygwin(char *in) +char *replace_cygdrive_cygwin(char const *in) { - int len = strlen(in); - char *out = malloc(len+1); + size_t len = strlen(in); + char *out = (char*) malloc(len+1); int i,j; if (len < 12) { - strcpy(out, in); + memmove(out, in, len + 1); return out; } + for (i = 0, j = 0; i *bl) { *bl *= 2; - *b = realloc(*b, *bl); + *b = (char*) realloc(*b, *bl); } memcpy(*b+*u, add, addlen); *u += addlen; @@ -125,7 +126,7 @@ char *replace_substring(char *in, char *sub, char *rep) int in_len = strlen(in); int sub_len = strlen(sub); int rep_len = strlen(rep); - char *out = malloc(in_len - sub_len + rep_len + 1); + char *out = (char *) malloc(in_len - sub_len + rep_len + 1); char *p; if (!(p = strstr(in, sub))) { @@ -145,7 +146,7 @@ char *replace_substring(char *in, char *sub, char *rep) char* msys_path_list; // @-separated list of paths prefix to look for char* msys_path_list_end; // Points to last \0 in msys_path_list. -void setup_msys_path_list(char* argument) +void setup_msys_path_list(char const * argument) { char* p; char* drive_letter_pos; @@ -173,7 +174,7 @@ void setup_msys_path_list(char* argument) } while (p != NULL); } -char *replace_cygdrive_msys(char *in) +char *replace_cygdrive_msys(char const *in) { char* str; char* prefix; @@ -195,12 +196,12 @@ char *replace_cygdrive_msys(char *in) return str; } -char*(*replace_cygdrive)(char *in) = NULL; +char*(*replace_cygdrive)(char const *in) = NULL; char *files_to_delete[1024]; int num_files_to_delete = 0; -char *fix_at_file(char *in) +char *fix_at_file(char const *in) { char *tmpdir; char name[2048]; @@ -222,9 +223,13 @@ char *fix_at_file(char *in) exit(-1); } - tmpdir = getenv("TMP"); + tmpdir = getenv("TEMP"); if (tmpdir == NULL) { +#if _WIN64 + tmpdir = "c:/cygwin64/tmp"; +#else tmpdir = "c:/cygwin/tmp"; +#endif } _snprintf(name, sizeof(name), "%s\\atfile_XXXXXX", tmpdir); @@ -240,7 +245,7 @@ char *fix_at_file(char *in) exit(-1); } - buffer = malloc(buflen); + buffer = (char*) malloc(buflen); while((blocklen = fread(block,1,sizeof(block),atin)) > 0) { append(&buffer, &buflen, &used, block, blocklen); } @@ -257,84 +262,229 @@ char *fix_at_file(char *in) fclose(atout); free(fixed); free(buffer); - files_to_delete[num_files_to_delete] = malloc(strlen(name)+1); + files_to_delete[num_files_to_delete] = (char*) malloc(strlen(name)+1); strcpy(files_to_delete[num_files_to_delete], name); num_files_to_delete++; - atname = malloc(strlen(name)+2); + atname = (char*) malloc(strlen(name)+2); atname[0] = '@'; strcpy(atname+1, name); return atname; } -int main(int argc, char **argv) +// given an argument, convert it to the windows command line safe quoted version +// using rules from: +// http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx +// caller is responsible for freeing both input and output. +char * quote_arg(char const * in_arg) { + char *quoted = NULL; + char *current = quoted; + int pass; + + if(strpbrk(in_arg, " \t\n\v\r\\\"") == NULL) { + return _strdup(in_arg); + } + + // process the arg twice. Once to calculate the size and then to copy it. + for(pass=1; pass<=2; pass++) { + char const *arg = in_arg; + + // initial " + if(pass == 2) { + *current = '\"'; + } + current++; + + // process string to be quoted until NUL + do { + int escapes = 0; + + while (*arg == '\\') { + // count escapes. + escapes++; + arg++; + } + + if (*arg == '\0') { + // escape the escapes before final " + escapes *= 2; + } else if (*arg == '"') { + // escape the escapes and the " + escapes = escapes * 2 + 1; + } else { + // escapes aren't special, just echo them. + } + + // emit some escapes + while (escapes > 0) { + if (pass == 2) { + *current = '\\'; + } + current++; + escapes--; + } + + // and the current char + if (pass == 2) { + *current = *arg; + } + current++; + } while( *arg++ != '\0'); + + // allocate the buffer + if (pass == 1) { + size_t alloc = (size_t) (current - quoted + (ptrdiff_t) 2); + current = quoted = (char*) calloc(alloc, sizeof(char)); + } + } + + // final " and \0 + *(current - 1) = '"'; + *current = '\0'; + + return quoted; +} + +int main(int argc, char const ** argv) { STARTUPINFO si; PROCESS_INFORMATION pi; unsigned short rc; - char *new_at_file; - char *old_at_file; char *line; - int i; + char *current; + int i, cmd; DWORD exitCode; - if (argc<3 || argv[1][0] != '-' || (argv[1][1] != 'c' && argv[1][1] != 'm')) { - fprintf(stderr, "Usage: fixpath -c|m /cygdrive/c/WINDOWS/notepad.exe /cygdrive/c/x/test.txt\n"); + if (argc<2 || argv[1][0] != '-' || (argv[1][1] != 'c' && argv[1][1] != 'm')) { + fprintf(stderr, "Usage: fixpath -c|m /cygdrive/c/WINDOWS/notepad.exe [/cygdrive/c/x/test.txt|@/cygdrive/c/x/atfile]\n"); exit(0); } if (getenv("DEBUG_FIXPATH") != NULL) { - fprintf(stderr, "fixpath input line >%s<\n", strstr(GetCommandLine(), argv[1])); + char const * cmdline = GetCommandLine(); + fprintf(stderr, "fixpath input line >%s<\n", strstr( cmdline , argv[1])); } if (argv[1][1] == 'c' && argv[1][2] == '\0') { if (getenv("DEBUG_FIXPATH") != NULL) { - fprintf(stderr, "using cygwin mode\n"); + fprintf(stderr, "fixpath using cygwin mode\n"); } replace_cygdrive = replace_cygdrive_cygwin; } else if (argv[1][1] == 'm') { if (getenv("DEBUG_FIXPATH") != NULL) { - fprintf(stderr, "using msys mode, with path list: %s\n", &argv[1][2]); + fprintf(stderr, "fixpath using msys mode, with path list: %s\n", &argv[1][2]); } setup_msys_path_list(argv[1]); replace_cygdrive = replace_cygdrive_msys; } else { - fprintf(stderr, "Unknown mode: %s\n", argv[1]); + fprintf(stderr, "fixpath Unknown mode: %s\n", argv[1]); exit(-1); } - line = replace_cygdrive(strstr(GetCommandLine(), argv[2])); - for (i=1; i%s< to >%s<\n", var, val); + } + + rc = SetEnvironmentVariable(var, val); + if(!rc) { + // Could not set var for some reason. Try to report why. + const int msg_len = 80 + var_len + strlen(val); + char * msg = (char *) alloca(msg_len); + _snprintf_s(msg, msg_len, _TRUNCATE, "Could not set environment variable [%s=%s]", var, val); + report_error(msg); + exit(1); + } + free(var); + free(val); + } else { + // no more assignments; + break; + } + i++; } + // remember index of the command + cmd = i; + + // handle command and it's args. + while (i < argc) { + char const *replaced = replace_cygdrive(argv[i]); + if(replaced[0] == '@') { + // Found at-file! Fix it! + replaced = fix_at_file(replaced); + } + argv[i] = quote_arg(replaced); + i++; + } + + // determine the length of the line + line = NULL; + // args + for(i = cmd; i < argc; i++) { + line += (ptrdiff_t) strlen(argv[i]); + } + // spaces and null + line += (ptrdiff_t) (argc - cmd + 1); + // allocate + line = (char*) calloc(line - (char*) NULL, sizeof(char)); + + // copy in args. + current = line; + for(i = cmd; i < argc; i++) { + ptrdiff_t len = strlen(argv[i]); + if (i != cmd) { + *current++ = ' '; + } + memmove(current, argv[i], len); + current += len; + } + *current = '\0'; + if (getenv("DEBUG_FIXPATH") != NULL) { fprintf(stderr, "fixpath converted line >%s<\n", line); } + if(cmd == argc) { + if (getenv("DEBUG_FIXPATH") != NULL) { + fprintf(stderr, "fixpath no command provided!\n"); + } + exit(0); + } + ZeroMemory(&si,sizeof(si)); si.cb=sizeof(si); ZeroMemory(&pi,sizeof(pi)); + fflush(stderr); + fflush(stdout); + rc = CreateProcess(NULL, line, 0, 0, TRUE, 0, - 0, - 0, + NULL, + NULL, &si, &pi); if(!rc) { // Could not start process for some reason. Try to report why: - report_error(); - exit(rc); + report_error("Could not start process!"); + exit(126); } WaitForSingleObject(pi.hProcess,INFINITE); @@ -342,15 +492,21 @@ int main(int argc, char **argv) if (getenv("DEBUG_FIXPATH") != NULL) { for (i=0; i pmContexts = new HashMap<>(); + private static Map staticWrapperMap = new ConcurrentHashMap(); protected MonitoringManager monitoringManager; @@ -201,8 +209,9 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB try { // First try the configured class name, if any - Class cls = SharedSecrets.getJavaCorbaAccess().loadClass( className ) ; - sff = (PresentationManager.StubFactoryFactory)cls.newInstance() ; + Class cls = + sun.corba.SharedSecrets.getJavaCorbaAccess().loadClass(className); + sff = (PresentationManager.StubFactoryFactory)cls.newInstance(); } catch (Exception exc) { // Use the default. Log the error as a warning. staticWrapper.errorInSettingDynamicStubFactoryFactory( @@ -235,13 +244,34 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB */ public static PresentationManager getPresentationManager() { - AppContext ac = AppContext.getAppContext(); - PresentationManager pm = (PresentationManager) ac.get(PresentationManager.class); - if (pm == null) { - pm = setupPresentationManager(); - ac.put(PresentationManager.class, pm); + SecurityManager sm = System.getSecurityManager(); + JavaAWTAccess javaAwtAccess = sun.misc.SharedSecrets.getJavaAWTAccess(); + if (sm != null && javaAwtAccess != null) { + Object appletContext; + try { + Class clazz = JavaAWTAccess.class; + Method method = clazz.getMethod("getAppletContext"); + appletContext = method.invoke(javaAwtAccess); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + InternalError err = new InternalError(); + err.initCause(e); + throw err; + } + + if (appletContext != null) { + synchronized (pmContexts) { + PresentationManager pm = pmContexts.get(appletContext); + if (pm == null) { + pm = setupPresentationManager(); + pmContexts.put(appletContext, pm); + } + return pm; + } + } } - return pm; + + // No security manager or AppletAppContext + return Holder.defaultPresentationManager; } /** Get the appropriate StubFactoryFactory. This diff --git a/corba/src/share/classes/org/omg/CORBA/AnySeqHelper.java b/corba/src/share/classes/org/omg/CORBA/AnySeqHelper.java index 03164504ed9..e01c8110ef4 100644 --- a/corba/src/share/classes/org/omg/CORBA/AnySeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/AnySeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/BooleanSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/BooleanSeqHelper.java index 2ebf7327b64..661de0a1255 100644 --- a/corba/src/share/classes/org/omg/CORBA/BooleanSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/BooleanSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/CharSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/CharSeqHelper.java index b3bd4ae0869..15bdec03432 100644 --- a/corba/src/share/classes/org/omg/CORBA/CharSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/CharSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/DoubleSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/DoubleSeqHelper.java index 7a967349ec5..307f1254b5c 100644 --- a/corba/src/share/classes/org/omg/CORBA/DoubleSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/DoubleSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/LongLongSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/LongLongSeqHelper.java index f30c37f2d9f..cad08837d5c 100644 --- a/corba/src/share/classes/org/omg/CORBA/LongLongSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/LongLongSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/LongSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/LongSeqHelper.java index 5f7e678bac2..eae18b59c1a 100644 --- a/corba/src/share/classes/org/omg/CORBA/LongSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/LongSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/OctetSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/OctetSeqHelper.java index b056758a5d5..a937e471615 100644 --- a/corba/src/share/classes/org/omg/CORBA/OctetSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/OctetSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/ShortSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/ShortSeqHelper.java index 2055428deec..bc63630caff 100644 --- a/corba/src/share/classes/org/omg/CORBA/ShortSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/ShortSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/StringValueHelper.java b/corba/src/share/classes/org/omg/CORBA/StringValueHelper.java index 1e88c7f1f34..013c16a1290 100644 --- a/corba/src/share/classes/org/omg/CORBA/StringValueHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/StringValueHelper.java @@ -44,11 +44,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/ULongLongSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/ULongLongSeqHelper.java index fb945bf817f..4267d13108c 100644 --- a/corba/src/share/classes/org/omg/CORBA/ULongLongSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/ULongLongSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/ULongSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/ULongSeqHelper.java index 8681802119b..001fd4a3157 100644 --- a/corba/src/share/classes/org/omg/CORBA/ULongSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/ULongSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/UShortSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/UShortSeqHelper.java index 70b3c793f54..0c09a1fdb73 100644 --- a/corba/src/share/classes/org/omg/CORBA/UShortSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/UShortSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/WCharSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/WCharSeqHelper.java index 7a055d08e20..ef26bf66373 100644 --- a/corba/src/share/classes/org/omg/CORBA/WCharSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/WCharSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/WStringValueHelper.java b/corba/src/share/classes/org/omg/CORBA/WStringValueHelper.java index 94b7e94f412..a535caed09b 100644 --- a/corba/src/share/classes/org/omg/CORBA/WStringValueHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/WStringValueHelper.java @@ -48,11 +48,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/doc-files/compliance.html b/corba/src/share/classes/org/omg/CORBA/doc-files/compliance.html index 5201175d4d7..ff57fbd24be 100644 --- a/corba/src/share/classes/org/omg/CORBA/doc-files/compliance.html +++ b/corba/src/share/classes/org/omg/CORBA/doc-files/compliance.html @@ -18,26 +18,26 @@ href="http://www.omg.org/">www.omg.org to search for the correct specificati
  • CORBA 2.3.1 (formal/99-10-07)
  • +href="http://www.omg.org/cgi-bin/doc?formal/99-10-07">formal/99-10-07)
  • IDL to Java language mapping (ptc/00-01-08)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/00-01-08">ptc/00-01-08)
  • Revised IDL to Java language mapping (ptc/00-11-03)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/00-11-03">ptc/00-11-03)
  • Java to IDL language mapping (ptc/00-01-06)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/00-01-06">ptc/00-01-06)
  • Interoperable Naming Service (ptc/00-08-07)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/00-08-07">ptc/00-08-07)
  • Portable Interceptors (ptc/2001-03-04)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/2001-03-04">ptc/2001-03-04)
These are the only specifications referenced by this document. diff --git a/corba/src/share/classes/org/omg/CORBA/doc-files/generatedfiles.html b/corba/src/share/classes/org/omg/CORBA/doc-files/generatedfiles.html index 53f28a1737f..d63460d0871 100644 --- a/corba/src/share/classes/org/omg/CORBA/doc-files/generatedfiles.html +++ b/corba/src/share/classes/org/omg/CORBA/doc-files/generatedfiles.html @@ -8,7 +8,7 @@

IDL-to-Java Generated Files

-

The files that are generated by the IDL-to-Java compiler, in accordance with the IDL-to-Java Language Mapping Specification, which is implemented in JavaTM SE 6 according the compliance document. +

The files that are generated by the IDL-to-Java compiler, in accordance with the IDL-to-Java Language Mapping Specification, which is implemented in JavaTM SE 6 according the compliance document.

In general IDL names and identifiers are mapped to Java names and identifiers with no change. Because of the nature of the Java language, a single IDL construct may be mapped to several (differently named) Java constructs. The additional names are constructed by appending a descriptive suffix. For example, the IDL interface foo is mapped to the Java interfaces foo and fooOperations, and additional Java classes fooHelper, fooHolder, fooPOA, and optionally fooPOATie. diff --git a/corba/src/share/classes/org/omg/CORBA/package.html b/corba/src/share/classes/org/omg/CORBA/package.html index 02c6d0b1876..437b84870a4 100644 --- a/corba/src/share/classes/org/omg/CORBA/package.html +++ b/corba/src/share/classes/org/omg/CORBA/package.html @@ -344,7 +344,7 @@ public final class AccountHolder implements

For more information on Holder classes, see Chapter 1.4, Mapping for -Basic Types in the +Basic Types in the OMG IDL to Java Language Mapping. The Holder classes defined in the package org.omg.CORBA are:

diff --git a/corba/src/share/classes/org/omg/CosNaming/package.html b/corba/src/share/classes/org/omg/CosNaming/package.html
index e64de1740d6..a7fca8f22aa 100644
--- a/corba/src/share/classes/org/omg/CosNaming/package.html
+++ b/corba/src/share/classes/org/omg/CosNaming/package.html
@@ -331,7 +331,7 @@ Context.
 
 
  • Interoperable Naming Service (ptc/00-08-07) +href="http://www.omg.org/cgi-bin/doc?ptc/00-08-07">ptc/00-08-07)

Related Documentation

diff --git a/corba/src/share/classes/org/omg/Dynamic/package.html b/corba/src/share/classes/org/omg/Dynamic/package.html index f7b27322eb3..0a9895fc871 100644 --- a/corba/src/share/classes/org/omg/Dynamic/package.html +++ b/corba/src/share/classes/org/omg/Dynamic/package.html @@ -33,8 +33,8 @@

This package contains the Dynamic module specified in the OMG Portable Interceptor specification, - -http://cgi.omg.org/cgi-bin/doc?ptc/2000-08-06, section 21.9. Please + +ptc/2000-08-06, section 21.9. Please refer to that OMG specification for further details. diff --git a/corba/src/share/classes/org/omg/DynamicAny/DynAnyFactoryPackage/package.html b/corba/src/share/classes/org/omg/DynamicAny/DynAnyFactoryPackage/package.html index 0cf2fe073f9..9f9e72f12ce 100644 --- a/corba/src/share/classes/org/omg/DynamicAny/DynAnyFactoryPackage/package.html +++ b/corba/src/share/classes/org/omg/DynamicAny/DynAnyFactoryPackage/package.html @@ -38,8 +38,8 @@ interface of the DynamicAny module specified in the OMG The Common Object Request Broker: Architecture and Specification, - -http://cgi.omg.org/cgi-bin/doc?formal/99-10-07, section 9.2.2. Please + +formal/99-10-07, section 9.2.2. Please refer to that OMG specification for further details.

Package Specification

diff --git a/corba/src/share/classes/org/omg/DynamicAny/DynAnyPackage/package.html b/corba/src/share/classes/org/omg/DynamicAny/DynAnyPackage/package.html index d0c2dc30829..480ed552c05 100644 --- a/corba/src/share/classes/org/omg/DynamicAny/DynAnyPackage/package.html +++ b/corba/src/share/classes/org/omg/DynamicAny/DynAnyPackage/package.html @@ -34,8 +34,8 @@ interface of the DynamicAny module specified in the OMG The Common Object Request Broker: Architecture and Specification, - -http://cgi.omg.org/cgi-bin/doc?formal/99-10-07, section 9.2. Please + +formal/99-10-07, section 9.2. Please refer to that OMG specification for further details. diff --git a/corba/src/share/classes/org/omg/IOP/package.html b/corba/src/share/classes/org/omg/IOP/package.html index 34f2aa2060e..f0016bfc271 100644 --- a/corba/src/share/classes/org/omg/IOP/package.html +++ b/corba/src/share/classes/org/omg/IOP/package.html @@ -33,8 +33,8 @@ questions.

This package contains the IOP module specified in the OMG document The Common Object Request Broker: Architecture and Specification, - -http://cgi.omg.org/cgi-bin/doc?formal/99-10-07, section 13.6. Please + +formal/99-10-07, section 13.6. Please refer to that OMG specification for further details.

Please note that we do not provide all parts of the IOP module from diff --git a/corba/src/share/classes/org/omg/Messaging/package.html b/corba/src/share/classes/org/omg/Messaging/package.html index f2fa37bdb4a..61e73d5b685 100644 --- a/corba/src/share/classes/org/omg/Messaging/package.html +++ b/corba/src/share/classes/org/omg/Messaging/package.html @@ -32,8 +32,8 @@ questions.

This package contains the Messaging module specified in the OMG CORBA Messaging specification, - -http://cgi.omg.org/cgi-bin/doc?formal/99-10-07. Please refer to that OMG + +formal/99-10-07. Please refer to that OMG specification for further details.

Please note that we do not provide all parts of the Messaging module from diff --git a/corba/src/share/classes/org/omg/PortableInterceptor/ORBInitInfoPackage/package.html b/corba/src/share/classes/org/omg/PortableInterceptor/ORBInitInfoPackage/package.html index 422069e6b71..d648d5af9e5 100644 --- a/corba/src/share/classes/org/omg/PortableInterceptor/ORBInitInfoPackage/package.html +++ b/corba/src/share/classes/org/omg/PortableInterceptor/ORBInitInfoPackage/package.html @@ -33,8 +33,8 @@ questions.

This package contains the exceptions and typedefs from the ORBInitInfo local interface of the PortableInterceptor module specified in the OMG Portable Interceptor specification, - -http://cgi.omg.org/cgi-bin/doc?ptc/2000-08-06, section 21.7.2. Please + +ptc/2000-08-06, section 21.7.2. Please refer to that OMG specification for further details. diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 3e5fb22b551..856ce390fa1 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -409,3 +409,4 @@ b2fee789d23f3cdabb3db4e51af43038e5692d3a jdk9-b03 3812c088b9456ee22c933e88aee1ece71f4e783a jdk9-b04 bdc5311e1db7598589b77015119b821bf8c828bd jdk9-b05 52377a30a3f87b62d6135706997b8c7a47366e37 jdk9-b06 +52f7edf2589d9f9d35db3008bc5377f279de9c18 jdk9-b07 diff --git a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m b/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m index 1234645c257..0f0ff4e5da4 100644 --- a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m +++ b/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m @@ -95,7 +95,9 @@ static task_t getTask(JNIEnv *env, jobject this_obj) { #define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; } static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { - (*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg); + jclass exceptionClass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"); + CHECK_EXCEPTION; + (*env)->ThrowNew(env, exceptionClass, errMsg); } static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { @@ -129,6 +131,7 @@ static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) { symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J"); + CHECK_EXCEPTION; taskID = (*env)->GetFieldID(env, cls, "task", "J"); CHECK_EXCEPTION; @@ -236,13 +239,16 @@ JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_loo (JNIEnv *env, jobject this_obj, jlong addr) { uintptr_t offset; const char* sym = NULL; + jstring sym_string; struct ps_prochandle* ph = get_proc_handle(env, this_obj); if (ph != NULL && ph->core != NULL) { sym = symbol_for_pc(ph, (uintptr_t) addr, &offset); if (sym == NULL) return 0; + sym_string = (*env)->NewStringUTF(env, sym); + CHECK_EXCEPTION_(0); return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, - (*env)->NewStringUTF(env, sym), (jlong)offset); + sym_string, (jlong)offset); } return 0; } @@ -749,11 +755,14 @@ static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* const char* name; jobject loadObject; jobject loadObjectList; + jstring nameString; base = get_lib_base(ph, i); name = get_lib_name(ph, i); + nameString = (*env)->NewStringUTF(env, name); + CHECK_EXCEPTION; loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, - (*env)->NewStringUTF(env, name), (jlong)0, (jlong)base); + nameString, (jlong)0, (jlong)base); CHECK_EXCEPTION; loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID); CHECK_EXCEPTION; diff --git a/hotspot/agent/src/os/linux/symtab.c b/hotspot/agent/src/os/linux/symtab.c index 7aae801ce20..077532a06f3 100644 --- a/hotspot/agent/src/os/linux/symtab.c +++ b/hotspot/agent/src/os/linux/symtab.c @@ -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 @@ -162,28 +162,27 @@ open_debug_file (const char *pathname, unsigned int crc) static struct elf_section *find_section_by_name(char *name, int fd, ELF_EHDR *ehdr, - ELF_SHDR *shbuf, struct elf_section *scn_cache) { - ELF_SHDR* cursct = NULL; char *strtab; int cnt; + int strtab_size; + // Section cache have to already contain data for e_shstrndx section. + // If it's not true - elf file is broken, so just bail out if (scn_cache[ehdr->e_shstrndx].c_data == NULL) { - if ((scn_cache[ehdr->e_shstrndx].c_data - = read_section_data(fd, ehdr, cursct)) == NULL) { - return NULL; - } + return NULL; } strtab = scn_cache[ehdr->e_shstrndx].c_data; + strtab_size = scn_cache[ehdr->e_shstrndx].c_shdr->sh_size; - for (cursct = shbuf, cnt = 0; - cnt < ehdr->e_shnum; - cnt++, cursct++) { - if (strcmp(cursct->sh_name + strtab, name) == 0) { - scn_cache[cnt].c_data = read_section_data(fd, ehdr, cursct); - return &scn_cache[cnt]; + for (cnt = 0; cnt < ehdr->e_shnum; ++cnt) { + if (scn_cache[cnt].c_shdr->sh_name < strtab_size) { + if (strcmp(scn_cache[cnt].c_shdr->sh_name + strtab, name) == 0) { + scn_cache[cnt].c_data = read_section_data(fd, ehdr, scn_cache[cnt].c_shdr); + return &scn_cache[cnt]; + } } } @@ -195,12 +194,11 @@ static struct elf_section *find_section_by_name(char *name, static int open_file_from_debug_link(const char *name, int fd, ELF_EHDR *ehdr, - ELF_SHDR *shbuf, struct elf_section *scn_cache) { int debug_fd; struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr, - shbuf, scn_cache); + scn_cache); if (debug_link == NULL) return -1; char *debug_filename = debug_link->c_data; @@ -221,7 +219,6 @@ static int open_file_from_debug_link(const char *name, /* Look in the same directory as the object. */ strcpy(last_slash+1, debug_filename); - debug_fd = open_debug_file(debug_pathname, crc); if (debug_fd >= 0) { free(debug_pathname); @@ -261,10 +258,9 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t static struct symtab *build_symtab_from_debug_link(const char *name, int fd, ELF_EHDR *ehdr, - ELF_SHDR *shbuf, struct elf_section *scn_cache) { - fd = open_file_from_debug_link(name, fd, ehdr, shbuf, scn_cache); + fd = open_file_from_debug_link(name, fd, ehdr, scn_cache); if (fd >= 0) { struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); @@ -463,7 +459,7 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t // Then, if that doesn't work, the debug link if (symtab == NULL) { - symtab = build_symtab_from_debug_link(filename, fd, &ehdr, shbuf, + symtab = build_symtab_from_debug_link(filename, fd, &ehdr, scn_cache); } 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 b75669ed026..eea5e4b7271 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 @@ -51,9 +51,9 @@ public class G1CollectedHeap extends SharedHeap { static private CIntegerField summaryBytesUsedField; // G1MonitoringSupport* _g1mm; static private AddressField g1mmField; - // MasterOldRegionSet _old_set; + // HeapRegionSet _old_set; static private long oldSetFieldOffset; - // MasterHumongousRegionSet _humongous_set; + // HeapRegionSet _humongous_set; static private long humongousSetFieldOffset; static { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetBase.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetBase.java index 4ac8f72c25f..94c3e239990 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetBase.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetBase.java @@ -40,12 +40,8 @@ import sun.jvm.hotspot.types.TypeDataBase; // Mirror class for HeapRegionSetBase. Represents a group of regions. public class HeapRegionSetBase extends VMObject { - // uint _length; - static private CIntegerField lengthField; - // uint _region_num; - static private CIntegerField regionNumField; - // size_t _total_used_bytes; - static private CIntegerField totalUsedBytesField; + + static private long countField; static { VM.registerVMInitializedObserver(new Observer() { @@ -58,21 +54,13 @@ public class HeapRegionSetBase extends VMObject { static private synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("HeapRegionSetBase"); - lengthField = type.getCIntegerField("_length"); - regionNumField = type.getCIntegerField("_region_num"); - totalUsedBytesField = type.getCIntegerField("_total_used_bytes"); + countField = type.getField("_count").getOffset(); } - public long length() { - return lengthField.getValue(addr); - } - public long regionNum() { - return regionNumField.getValue(addr); - } - - public long totalUsedBytes() { - return totalUsedBytesField.getValue(addr); + public HeapRegionSetCount count() { + Address countFieldAddr = addr.addOffsetTo(countField); + return (HeapRegionSetCount) VMObjectFactory.newObject(HeapRegionSetCount.class, countFieldAddr); } public HeapRegionSetBase(Address addr) { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetCount.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetCount.java new file mode 100644 index 00000000000..2a4483a54c8 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetCount.java @@ -0,0 +1,73 @@ +/* + * 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 sun.jvm.hotspot.gc_implementation.g1; + +import java.util.Iterator; +import java.util.Observable; +import java.util.Observer; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.runtime.VMObject; +import sun.jvm.hotspot.runtime.VMObjectFactory; +import sun.jvm.hotspot.types.AddressField; +import sun.jvm.hotspot.types.CIntegerField; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; + +// Mirror class for HeapRegionSetCount. Represents a group of regions. + +public class HeapRegionSetCount extends VMObject { + + static private CIntegerField lengthField; + static private CIntegerField capacityField; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + static private synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("HeapRegionSetCount"); + + lengthField = type.getCIntegerField("_length"); + capacityField = type.getCIntegerField("_capacity"); + } + + public long length() { + return lengthField.getValue(addr); + } + + public long capacity() { + return capacityField.getValue(addr); + } + + public HeapRegionSetCount(Address addr) { + super(addr); + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java index 32c1358cbe2..afe4d2a50b5 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java @@ -114,7 +114,8 @@ public class HeapSummary extends Tool { long survivorRegionNum = g1mm.survivorRegionNum(); HeapRegionSetBase oldSet = g1h.oldSet(); HeapRegionSetBase humongousSet = g1h.humongousSet(); - long oldRegionNum = oldSet.regionNum() + humongousSet.regionNum(); + long oldRegionNum = oldSet.count().length() + + humongousSet.count().capacity() / HeapRegion.grainBytes(); printG1Space("G1 Heap:", g1h.n_regions(), g1h.used(), g1h.capacity()); System.out.println("G1 Young Generation:"); diff --git a/hotspot/make/Makefile b/hotspot/make/Makefile index 75893a6a1f9..bde309fc467 100644 --- a/hotspot/make/Makefile +++ b/hotspot/make/Makefile @@ -287,8 +287,43 @@ else @$(ECHO) "Error: trying to build a minimal target but JVM_VARIANT_MINIMAL1 is not true." endif +remove_old_debuginfo: +ifeq ($(JVM_VARIANT_CLIENT), true) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + ifeq ($(OSNAME), windows) + $(RM) -f $(EXPORT_CLIENT_DIR)/jvm.map $(EXPORT_CLIENT_DIR)/jvm.pdb + else + $(RM) -f $(EXPORT_CLIENT_DIR)/libjvm.debuginfo + endif + else + $(RM) -f $(EXPORT_CLIENT_DIR)/libjvm.diz + endif +endif +ifeq ($(findstring true, $(JVM_VARIANT_SERVER) $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + ifeq ($(OSNAME), windows) + $(RM) -f $(EXPORT_SERVER_DIR)/jvm.map $(EXPORT_SERVER_DIR)/jvm.pdb + else + ifeq ($(OS_VENDOR), Darwin) + $(RM) -rf $(EXPORT_SERVER_DIR)/libjvm.dylib.dSYM + else + $(RM) -f $(EXPORT_SERVER_DIR)/libjvm.debuginfo + endif + endif + else + $(RM) -f $(EXPORT_SERVER_DIR)/libjvm.diz + endif +endif +ifeq ($(JVM_VARIANT_MINIMAL1),true) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(RM) -f $(EXPORT_MINIMAL_DIR)/libjvm.debuginfo + else + $(RM) -f $(EXPORT_MINIMAL_DIR)/libjvm.diz + endif +endif + # Export file rule -generic_export: $(EXPORT_LIST) +generic_export: $(EXPORT_LIST) remove_old_debuginfo export_product: $(MAKE) BUILD_FLAVOR=$(@:export_%=%) generic_export @@ -841,4 +876,4 @@ include $(GAMMADIR)/make/jprt.gmk export_jdk_product export_jdk_fastdebug export_jdk_debug \ create_jdk copy_jdk update_jdk test_jdk \ copy_product_jdk copy_fastdebug_jdk copy_debug_jdk \ - $(HS_ALT_MAKE)/Makefile.make + $(HS_ALT_MAKE)/Makefile.make remove_old_debuginfo diff --git a/hotspot/make/aix/makefiles/vm.make b/hotspot/make/aix/makefiles/vm.make index 21818dcdc1a..ab994a3c2ae 100644 --- a/hotspot/make/aix/makefiles/vm.make +++ b/hotspot/make/aix/makefiles/vm.make @@ -101,7 +101,7 @@ CXXFLAGS = \ # This is VERY important! The version define must only be supplied to vm_version.o # If not, ccache will not re-use the cache at all, since the version string might contain # a time and date. -vm_version.o: CXXFLAGS += ${JRE_VERSION} +CXXFLAGS/vm_version.o += ${JRE_VERSION} CXXFLAGS/BYFILE = $(CXXFLAGS/$@) diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index 24f1fa20ec3..dcaa3a11a0c 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 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 @@ -87,9 +87,10 @@ ifeq ($(INCLUDE_ALL_GCS), false) g1BlockOffsetTable.cpp g1CardCounts.cpp g1CollectedHeap.cpp g1CollectorPolicy.cpp \ g1ErgoVerbose.cpp g1GCPhaseTimes.cpp g1HRPrinter.cpp g1HotCardCache.cpp g1Log.cpp \ g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp g1OopClosures.cpp \ - g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \ + g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1StringDedup.cpp g1StringDedupStat.cpp \ + g1StringDedupTable.cpp g1StringDedupThread.cpp g1StringDedupQueue.cpp g1_globals.cpp heapRegion.cpp \ g1BiasedArray.cpp heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \ - ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp \ + ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp g1CodeCacheRemSet.cpp \ adjoiningGenerations.cpp adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp \ cardTableExtension.cpp gcTaskManager.cpp gcTaskThread.cpp objectStartArray.cpp \ parallelScavengeHeap.cpp parMarkBitMap.cpp pcTasks.cpp psAdaptiveSizePolicy.cpp \ diff --git a/hotspot/make/jprt.properties b/hotspot/make/jprt.properties index 9109ded6f98..25b13107dcb 100644 --- a/hotspot/make/jprt.properties +++ b/hotspot/make/jprt.properties @@ -33,7 +33,7 @@ jprt.need.sibling.build=false # This tells jprt what default release we want to build -jprt.hotspot.default.release=jdk8 +jprt.hotspot.default.release=jdk9 jprt.tools.default.release=${jprt.submit.option.release?${jprt.submit.option.release}:${jprt.hotspot.default.release}} @@ -47,72 +47,50 @@ jprt.sync.push=false # sparc etc. # Define the Solaris platforms we want for the various releases -jprt.my.solaris.sparcv9.jdk8=solaris_sparcv9_5.10 -jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10 -jprt.my.solaris.sparcv9.jdk7u8=${jprt.my.solaris.sparcv9.jdk7} +jprt.my.solaris.sparcv9.jdk9=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}} -jprt.my.solaris.x64.jdk8=solaris_x64_5.10 -jprt.my.solaris.x64.jdk7=solaris_x64_5.10 -jprt.my.solaris.x64.jdk7u8=${jprt.my.solaris.x64.jdk7} +jprt.my.solaris.x64.jdk9=solaris_x64_5.10 jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}} -jprt.my.linux.i586.jdk8=linux_i586_2.6 -jprt.my.linux.i586.jdk7=linux_i586_2.6 -jprt.my.linux.i586.jdk7u8=${jprt.my.linux.i586.jdk7} +jprt.my.linux.i586.jdk9=linux_i586_2.6 jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}} -jprt.my.linux.x64.jdk8=linux_x64_2.6 -jprt.my.linux.x64.jdk7=linux_x64_2.6 -jprt.my.linux.x64.jdk7u8=${jprt.my.linux.x64.jdk7} +jprt.my.linux.x64.jdk9=linux_x64_2.6 jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}} -jprt.my.linux.ppc.jdk8=linux_ppc_2.6 -jprt.my.linux.ppc.jdk7=linux_ppc_2.6 -jprt.my.linux.ppc.jdk7u8=${jprt.my.linux.ppc.jdk7} +jprt.my.linux.ppc.jdk9=linux_ppc_2.6 jprt.my.linux.ppc=${jprt.my.linux.ppc.${jprt.tools.default.release}} -jprt.my.linux.ppcv2.jdk8=linux_ppcv2_2.6 -jprt.my.linux.ppcv2.jdk7=linux_ppcv2_2.6 -jprt.my.linux.ppcv2.jdk7u8=${jprt.my.linux.ppcv2.jdk7} +jprt.my.linux.ppcv2.jdk9=linux_ppcv2_2.6 jprt.my.linux.ppcv2=${jprt.my.linux.ppcv2.${jprt.tools.default.release}} -jprt.my.linux.ppcsflt.jdk8=linux_ppcsflt_2.6 -jprt.my.linux.ppcsflt.jdk7=linux_ppcsflt_2.6 -jprt.my.linux.ppcsflt.jdk7u8=${jprt.my.linux.ppcsflt.jdk7} +jprt.my.linux.ppcsflt.jdk9=linux_ppcsflt_2.6 jprt.my.linux.ppcsflt=${jprt.my.linux.ppcsflt.${jprt.tools.default.release}} -jprt.my.linux.armvfpsflt.jdk8=linux_armvfpsflt_2.6 +jprt.my.linux.armvfpsflt.jdk9=linux_armvfpsflt_2.6 jprt.my.linux.armvfpsflt=${jprt.my.linux.armvfpsflt.${jprt.tools.default.release}} -jprt.my.linux.armvfphflt.jdk8=linux_armvfphflt_2.6 +jprt.my.linux.armvfphflt.jdk9=linux_armvfphflt_2.6 jprt.my.linux.armvfphflt=${jprt.my.linux.armvfphflt.${jprt.tools.default.release}} # The ARM GP vfp-sflt build is not currently supported -#jprt.my.linux.armvs.jdk8=linux_armvs_2.6 +#jprt.my.linux.armvs.jdk9=linux_armvs_2.6 #jprt.my.linux.armvs=${jprt.my.linux.armvs.${jprt.tools.default.release}} -jprt.my.linux.armvh.jdk8=linux_armvh_2.6 +jprt.my.linux.armvh.jdk9=linux_armvh_2.6 jprt.my.linux.armvh=${jprt.my.linux.armvh.${jprt.tools.default.release}} -jprt.my.linux.armsflt.jdk8=linux_armsflt_2.6 -jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6 -jprt.my.linux.armsflt.jdk7u8=${jprt.my.linux.armsflt.jdk7} +jprt.my.linux.armsflt.jdk9=linux_armsflt_2.6 jprt.my.linux.armsflt=${jprt.my.linux.armsflt.${jprt.tools.default.release}} -jprt.my.macosx.x64.jdk8=macosx_x64_10.7 -jprt.my.macosx.x64.jdk7=macosx_x64_10.7 -jprt.my.macosx.x64.jdk7u8=${jprt.my.macosx.x64.jdk7} +jprt.my.macosx.x64.jdk9=macosx_x64_10.7 jprt.my.macosx.x64=${jprt.my.macosx.x64.${jprt.tools.default.release}} -jprt.my.windows.i586.jdk8=windows_i586_6.1 -jprt.my.windows.i586.jdk7=windows_i586_6.1 -jprt.my.windows.i586.jdk7u8=${jprt.my.windows.i586.jdk7} +jprt.my.windows.i586.jdk9=windows_i586_6.1 jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}} -jprt.my.windows.x64.jdk8=windows_x64_6.1 -jprt.my.windows.x64.jdk7=windows_x64_6.1 -jprt.my.windows.x64.jdk7u8=${jprt.my.windows.x64.jdk7} +jprt.my.windows.x64.jdk9=windows_x64_6.1 jprt.my.windows.x64=${jprt.my.windows.x64.${jprt.tools.default.release}} # Standard list of jprt build targets for this source tree @@ -143,9 +121,7 @@ jprt.build.targets.embedded= \ jprt.build.targets.all=${jprt.build.targets.standard}, \ ${jprt.build.targets.embedded}, ${jprt.build.targets.open} -jprt.build.targets.jdk8=${jprt.build.targets.all} -jprt.build.targets.jdk7=${jprt.build.targets.all} -jprt.build.targets.jdk7u8=${jprt.build.targets.all} +jprt.build.targets.jdk9=${jprt.build.targets.all} jprt.build.targets=${jprt.build.targets.${jprt.tools.default.release}} # Subset lists of test targets for this source tree @@ -349,9 +325,7 @@ jprt.test.targets.embedded= \ ${jprt.my.windows.i586.test.targets}, \ ${jprt.my.windows.x64.test.targets} -jprt.test.targets.jdk8=${jprt.test.targets.standard} -jprt.test.targets.jdk7=${jprt.test.targets.standard} -jprt.test.targets.jdk7u8=${jprt.test.targets.jdk7} +jprt.test.targets.jdk9=${jprt.test.targets.standard} jprt.test.targets=${jprt.test.targets.${jprt.tools.default.release}} # The default test/Makefile targets that should be run @@ -399,9 +373,7 @@ jprt.make.rule.test.targets.standard = \ jprt.make.rule.test.targets.embedded = \ ${jprt.make.rule.test.targets.standard.client} -jprt.make.rule.test.targets.jdk8=${jprt.make.rule.test.targets.standard} -jprt.make.rule.test.targets.jdk7=${jprt.make.rule.test.targets.standard} -jprt.make.rule.test.targets.jdk7u8=${jprt.make.rule.test.targets.jdk7} +jprt.make.rule.test.targets.jdk9=${jprt.make.rule.test.targets.standard} jprt.make.rule.test.targets=${jprt.make.rule.test.targets.${jprt.tools.default.release}} # 7155453: Work-around to prevent popups on OSX from blocking test completion diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index 8321f8e15db..df450934810 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -66,8 +66,8 @@ ifndef CC_INTERP FORCE_TIERED=1 endif endif -# C1 is not ported on ppc64(le), so we cannot build a tiered VM: -ifneq (,$(filter $(ARCH),ppc64 pp64le)) +# C1 is not ported on ppc64, so we cannot build a tiered VM: +ifeq ($(ARCH),ppc64) FORCE_TIERED=0 endif diff --git a/hotspot/make/linux/makefiles/defs.make b/hotspot/make/linux/makefiles/defs.make index 377d4f9c59f..8922fdd8728 100644 --- a/hotspot/make/linux/makefiles/defs.make +++ b/hotspot/make/linux/makefiles/defs.make @@ -33,6 +33,11 @@ SLASH_JAVA ?= /java # ARCH can be set explicitly in spec.gmk ifndef ARCH ARCH := $(shell uname -m) + # Fold little endian PowerPC64 into big-endian (if ARCH is set in + # hotspot-spec.gmk, this will be done by the configure script). + ifeq ($(ARCH),ppc64le) + ARCH := ppc64 + endif endif PATH_SEP ?= : diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index 87ef16faed8..9d321ea7dc7 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -337,56 +337,20 @@ endif ifeq ($(DEBUG_BINARIES), true) CFLAGS += -g else - # Use the stabs format for debugging information (this is the default - # on gcc-2.91). It's good enough, has all the information about line - # numbers and local variables, and libjvm.so is only about 16M. - # Change this back to "-g" if you want the most expressive format. - # (warning: that could easily inflate libjvm.so to 150M!) - # Note: The Itanium gcc compiler crashes when using -gstabs. - DEBUG_CFLAGS/ia64 = -g - DEBUG_CFLAGS/amd64 = -g - DEBUG_CFLAGS/arm = -g - DEBUG_CFLAGS/ppc = -g - DEBUG_CFLAGS/ppc64 = -g DEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),) - ifeq ($(USE_CLANG), true) - # Clang doesn't understand -gstabs - DEBUG_CFLAGS += -g - else - DEBUG_CFLAGS += -gstabs - endif + DEBUG_CFLAGS += -g endif - + ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - FASTDEBUG_CFLAGS/ia64 = -g - FASTDEBUG_CFLAGS/amd64 = -g - FASTDEBUG_CFLAGS/arm = -g - FASTDEBUG_CFLAGS/ppc = -g - FASTDEBUG_CFLAGS/ppc64 = -g - FASTDEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) + FASTDEBUG_CFLAGS += $(FASTDEBUG_CFLAGS/$(BUILDARCH)) ifeq ($(FASTDEBUG_CFLAGS/$(BUILDARCH)),) - ifeq ($(USE_CLANG), true) - # Clang doesn't understand -gstabs - FASTDEBUG_CFLAGS += -g - else - FASTDEBUG_CFLAGS += -gstabs - endif + FASTDEBUG_CFLAGS += -g endif - - OPT_CFLAGS/ia64 = -g - OPT_CFLAGS/amd64 = -g - OPT_CFLAGS/arm = -g - OPT_CFLAGS/ppc = -g - OPT_CFLAGS/ppc64 = -g + OPT_CFLAGS += $(OPT_CFLAGS/$(BUILDARCH)) ifeq ($(OPT_CFLAGS/$(BUILDARCH)),) - ifeq ($(USE_CLANG), true) - # Clang doesn't understand -gstabs - OPT_CFLAGS += -g - else - OPT_CFLAGS += -gstabs - endif + OPT_CFLAGS += -g endif endif endif diff --git a/hotspot/make/linux/makefiles/ppc64.make b/hotspot/make/linux/makefiles/ppc64.make index b3e6f27b65e..f3392de49a6 100644 --- a/hotspot/make/linux/makefiles/ppc64.make +++ b/hotspot/make/linux/makefiles/ppc64.make @@ -26,14 +26,26 @@ # make c code know it is on a 64 bit platform. CFLAGS += -D_LP64=1 -# fixes `relocation truncated to fit' error for gcc 4.1. -CFLAGS += -mminimal-toc +ifeq ($(origin OPENJDK_TARGET_CPU_ENDIAN),undefined) + # This can happen during hotspot standalone build. Set endianness from + # uname. We assume build and target machines are the same. + OPENJDK_TARGET_CPU_ENDIAN:=$(if $(filter ppc64le,$(shell uname -m)),little,big) +endif -# finds use ppc64 instructions, but schedule for power5 -CFLAGS += -mcpu=powerpc64 -mtune=power5 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string +ifeq ($(filter $(OPENJDK_TARGET_CPU_ENDIAN),big little),) + $(error OPENJDK_TARGET_CPU_ENDIAN value should be 'big' or 'little') +endif -# let linker find external 64 bit libs. -LFLAGS_VM += -L/lib64 +ifeq ($(OPENJDK_TARGET_CPU_ENDIAN),big) + # fixes `relocation truncated to fit' error for gcc 4.1. + CFLAGS += -mminimal-toc -# specify lib format. -LFLAGS_VM += -Wl,-melf64ppc + # finds use ppc64 instructions, but schedule for power5 + CFLAGS += -mcpu=powerpc64 -mtune=power5 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string +else + # Little endian machine uses ELFv2 ABI. + CFLAGS += -DVM_LITTLE_ENDIAN -DABI_ELFv2 + + # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. + CFLAGS += -mcpu=power7 -mtune=power8 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string +endif diff --git a/hotspot/make/windows/makefiles/defs.make b/hotspot/make/windows/makefiles/defs.make index acf4d24d7e0..fe4b6c72fbf 100644 --- a/hotspot/make/windows/makefiles/defs.make +++ b/hotspot/make/windows/makefiles/defs.make @@ -260,7 +260,6 @@ ifeq ($(JVM_VARIANT_SERVER),true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/jvm.map endif endif - EXPORT_LIST += $(EXPORT_LIB_DIR)/jvm.lib endif ifeq ($(JVM_VARIANT_CLIENT),true) EXPORT_LIST += $(EXPORT_CLIENT_DIR)/Xusage.txt @@ -275,6 +274,8 @@ ifeq ($(JVM_VARIANT_CLIENT),true) endif endif +EXPORT_LIST += $(EXPORT_LIB_DIR)/jvm.lib + ifeq ($(BUILD_WIN_SA), 1) EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.$(LIBRARY_SUFFIX) ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp index 76a1cac53f3..f9e49e1f4a8 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ */ #include "precompiled.hpp" -#include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "interpreter/interpreter.hpp" @@ -37,6 +36,7 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" +#include "utilities/macros.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" @@ -384,10 +384,10 @@ int Assembler::load_const_optimized(Register d, long x, Register tmp, bool retur bool load_xa = (xa != 0) || (xb < 0); bool return_xd = false; - if (load_xa) lis(tmp, xa); - if (xc) lis(d, xc); + if (load_xa) { lis(tmp, xa); } + if (xc) { lis(d, xc); } if (load_xa) { - if (xb) ori(tmp, tmp, xb); // No addi, we support tmp == R0. + if (xb) { ori(tmp, tmp, (unsigned short)xb); } // No addi, we support tmp == R0. } else { li(tmp, xb); // non-negative } @@ -409,18 +409,18 @@ int Assembler::load_const_optimized(Register d, long x, Register tmp, bool retur // opt 4: avoid adding 0 if (xa) { // Highest 16-bit needed? lis(d, xa); - if (xb) addi(d, d, xb); + if (xb) { addi(d, d, xb); } } else { li(d, xb); } sldi(d, d, 32); - if (xc) addis(d, d, xc); + if (xc) { addis(d, d, xc); } } // opt 5: Return offset to be inserted into following instruction. if (return_simm16_rest) return xd; - if (xd) addi(d, d, xd); + if (xd) { addi(d, d, xd); } return 0; } @@ -696,4 +696,5 @@ void Assembler::test_asm() { tty->print_cr("\ntest_asm disassembly (0x%lx 0x%lx):", code()->insts_begin(), code()->insts_end()); code()->decode(); } + #endif // !PRODUCT diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp index 56b0b92db73..5a1c0f1d9c8 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp @@ -1025,15 +1025,14 @@ class Assembler : public AbstractAssembler { } static void set_imm(int* instr, short s) { - short* p = ((short *)instr) + 1; - *p = s; + // imm is always in the lower 16 bits of the instruction, + // so this is endian-neutral. Same for the get_imm below. + uint32_t w = *(uint32_t *)instr; + *instr = (int)((w & ~0x0000FFFF) | (s & 0x0000FFFF)); } static int get_imm(address a, int instruction_number) { - short imm; - short *p =((short *)a)+2*instruction_number+1; - imm = *p; - return (int)imm; + return (short)((int *)a)[instruction_number]; } static inline int hi16_signed( int x) { return (int)(int16_t)(x >> 16); } diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp index d96d9204dbc..3b7eb5f55e5 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -139,7 +139,8 @@ inline void Assembler::cmpldi(ConditionRegister crx, Register a, int ui16) { A inline void Assembler::cmplw( ConditionRegister crx, Register a, Register b) { Assembler::cmpl( crx, 0, a, b); } inline void Assembler::cmpld( ConditionRegister crx, Register a, Register b) { Assembler::cmpl( crx, 1, a, b); } -inline void Assembler::isel(Register d, Register a, Register b, int c) { emit_int32(ISEL_OPCODE | rt(d) | ra(a) | rb(b) | bc(c)); } +inline void Assembler::isel(Register d, Register a, Register b, int c) { guarantee(VM_Version::has_isel(), "opcode not supported on this hardware"); + emit_int32(ISEL_OPCODE | rt(d) | ra(a) | rb(b) | bc(c)); } // PPC 1, section 3.3.11, Fixed-Point Logical Instructions inline void Assembler::andi_( Register a, Register s, int ui16) { emit_int32(ANDI_OPCODE | rta(a) | rs(s) | uimm(ui16, 16)); } @@ -531,9 +532,12 @@ inline void Assembler::fmr_(FloatRegister d, FloatRegister b) { emit_int32( FMR_ //inline void Assembler::mffgpr( FloatRegister d, Register b) { emit_int32( MFFGPR_OPCODE | frt(d) | rb(b) | rc(0)); } //inline void Assembler::mftgpr( Register d, FloatRegister b) { emit_int32( MFTGPR_OPCODE | rt(d) | frb(b) | rc(0)); } // add cmpb and popcntb to detect ppc power version. -inline void Assembler::cmpb( Register a, Register s, Register b) { emit_int32( CMPB_OPCODE | rta(a) | rs(s) | rb(b) | rc(0)); } -inline void Assembler::popcntb(Register a, Register s) { emit_int32( POPCNTB_OPCODE | rta(a) | rs(s)); }; -inline void Assembler::popcntw(Register a, Register s) { emit_int32( POPCNTW_OPCODE | rta(a) | rs(s)); }; +inline void Assembler::cmpb( Register a, Register s, Register b) { guarantee(VM_Version::has_cmpb(), "opcode not supported on this hardware"); + emit_int32( CMPB_OPCODE | rta(a) | rs(s) | rb(b) | rc(0)); } +inline void Assembler::popcntb(Register a, Register s) { guarantee(VM_Version::has_popcntb(), "opcode not supported on this hardware"); + emit_int32( POPCNTB_OPCODE | rta(a) | rs(s)); }; +inline void Assembler::popcntw(Register a, Register s) { guarantee(VM_Version::has_popcntw(), "opcode not supported on this hardware"); + emit_int32( POPCNTW_OPCODE | rta(a) | rs(s)); }; inline void Assembler::popcntd(Register a, Register s) { emit_int32( POPCNTD_OPCODE | rta(a) | rs(s)); }; inline void Assembler::fneg( FloatRegister d, FloatRegister b) { emit_int32( FNEG_OPCODE | frt(d) | frb(b) | rc(0)); } @@ -568,14 +572,17 @@ inline void Assembler::fctidz(FloatRegister d, FloatRegister b) { emit_int32( FC inline void Assembler::fctiw( FloatRegister d, FloatRegister b) { emit_int32( FCTIW_OPCODE | frt(d) | frb(b) | rc(0)); } inline void Assembler::fctiwz(FloatRegister d, FloatRegister b) { emit_int32( FCTIWZ_OPCODE | frt(d) | frb(b) | rc(0)); } inline void Assembler::fcfid( FloatRegister d, FloatRegister b) { emit_int32( FCFID_OPCODE | frt(d) | frb(b) | rc(0)); } -inline void Assembler::fcfids(FloatRegister d, FloatRegister b) { emit_int32( FCFIDS_OPCODE | frt(d) | frb(b) | rc(0)); } +inline void Assembler::fcfids(FloatRegister d, FloatRegister b) { guarantee(VM_Version::has_fcfids(), "opcode not supported on this hardware"); + emit_int32( FCFIDS_OPCODE | frt(d) | frb(b) | rc(0)); } // PPC 1, section 4.6.7 Floating-Point Compare Instructions inline void Assembler::fcmpu( ConditionRegister crx, FloatRegister a, FloatRegister b) { emit_int32( FCMPU_OPCODE | bf(crx) | fra(a) | frb(b)); } // PPC 1, section 5.2.1 Floating-Point Arithmetic Instructions -inline void Assembler::fsqrt( FloatRegister d, FloatRegister b) { emit_int32( FSQRT_OPCODE | frt(d) | frb(b) | rc(0)); } -inline void Assembler::fsqrts(FloatRegister d, FloatRegister b) { emit_int32( FSQRTS_OPCODE | frt(d) | frb(b) | rc(0)); } +inline void Assembler::fsqrt( FloatRegister d, FloatRegister b) { guarantee(VM_Version::has_fsqrt(), "opcode not supported on this hardware"); + emit_int32( FSQRT_OPCODE | frt(d) | frb(b) | rc(0)); } +inline void Assembler::fsqrts(FloatRegister d, FloatRegister b) { guarantee(VM_Version::has_fsqrts(), "opcode not supported on this hardware"); + emit_int32( FSQRTS_OPCODE | frt(d) | frb(b) | rc(0)); } // Vector instructions for >= Power6. inline void Assembler::lvebx( VectorRegister d, Register s1, Register s2) { emit_int32( LVEBX_OPCODE | vrt(d) | ra0mem(s1) | rb(s2)); } @@ -703,7 +710,8 @@ inline void Assembler::vcmpgtsw_(VectorRegister d,VectorRegister a, VectorRegist inline void Assembler::vcmpgtub_(VectorRegister d,VectorRegister a, VectorRegister b) { emit_int32( VCMPGTUB_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(1)); } inline void Assembler::vcmpgtuh_(VectorRegister d,VectorRegister a, VectorRegister b) { emit_int32( VCMPGTUH_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(1)); } inline void Assembler::vcmpgtuw_(VectorRegister d,VectorRegister a, VectorRegister b) { emit_int32( VCMPGTUW_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(1)); } -inline void Assembler::vand( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VAND_OPCODE | vrt(d) | vra(a) | vrb(b)); } +inline void Assembler::vand( VectorRegister d, VectorRegister a, VectorRegister b) { guarantee(VM_Version::has_vand(), "opcode not supported on this hardware"); + emit_int32( VAND_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vandc( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VANDC_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vnor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VNOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } diff --git a/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp b/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp index 872aa6b2624..2a8fc59c892 100644 --- a/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp @@ -35,6 +35,126 @@ class Bytes: AllStatic { // Can I count on address always being a pointer to an unsigned char? Yes. +#if defined(VM_LITTLE_ENDIAN) + + // Returns true, if the byte ordering used by Java is different from the native byte ordering + // of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc. + static inline bool is_Java_byte_ordering_different() { return true; } + + // Forward declarations of the compiler-dependent implementation + static inline u2 swap_u2(u2 x); + static inline u4 swap_u4(u4 x); + static inline u8 swap_u8(u8 x); + + static inline u2 get_native_u2(address p) { + return (intptr_t(p) & 1) == 0 + ? *(u2*)p + : ( u2(p[1]) << 8 ) + | ( u2(p[0]) ); + } + + static inline u4 get_native_u4(address p) { + switch (intptr_t(p) & 3) { + case 0: return *(u4*)p; + + case 2: return ( u4( ((u2*)p)[1] ) << 16 ) + | ( u4( ((u2*)p)[0] ) ); + + default: return ( u4(p[3]) << 24 ) + | ( u4(p[2]) << 16 ) + | ( u4(p[1]) << 8 ) + | u4(p[0]); + } + } + + static inline u8 get_native_u8(address p) { + switch (intptr_t(p) & 7) { + case 0: return *(u8*)p; + + case 4: return ( u8( ((u4*)p)[1] ) << 32 ) + | ( u8( ((u4*)p)[0] ) ); + + case 2: return ( u8( ((u2*)p)[3] ) << 48 ) + | ( u8( ((u2*)p)[2] ) << 32 ) + | ( u8( ((u2*)p)[1] ) << 16 ) + | ( u8( ((u2*)p)[0] ) ); + + default: return ( u8(p[7]) << 56 ) + | ( u8(p[6]) << 48 ) + | ( u8(p[5]) << 40 ) + | ( u8(p[4]) << 32 ) + | ( u8(p[3]) << 24 ) + | ( u8(p[2]) << 16 ) + | ( u8(p[1]) << 8 ) + | u8(p[0]); + } + } + + + + static inline void put_native_u2(address p, u2 x) { + if ( (intptr_t(p) & 1) == 0 ) *(u2*)p = x; + else { + p[1] = x >> 8; + p[0] = x; + } + } + + static inline void put_native_u4(address p, u4 x) { + switch ( intptr_t(p) & 3 ) { + case 0: *(u4*)p = x; + break; + + case 2: ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + break; + } + } + + static inline void put_native_u8(address p, u8 x) { + switch ( intptr_t(p) & 7 ) { + case 0: *(u8*)p = x; + break; + + case 4: ((u4*)p)[1] = x >> 32; + ((u4*)p)[0] = x; + break; + + case 2: ((u2*)p)[3] = x >> 48; + ((u2*)p)[2] = x >> 32; + ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: ((u1*)p)[7] = x >> 56; + ((u1*)p)[6] = x >> 48; + ((u1*)p)[5] = x >> 40; + ((u1*)p)[4] = x >> 32; + ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + } + } + + // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) + // (no byte-order reversal is needed since Power CPUs are big-endian oriented). + static inline u2 get_Java_u2(address p) { return swap_u2(get_native_u2(p)); } + static inline u4 get_Java_u4(address p) { return swap_u4(get_native_u4(p)); } + static inline u8 get_Java_u8(address p) { return swap_u8(get_native_u8(p)); } + + static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, swap_u2(x)); } + static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, swap_u4(x)); } + static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, swap_u8(x)); } + +#else // !defined(VM_LITTLE_ENDIAN) + // Returns true, if the byte ordering used by Java is different from the nativ byte ordering // of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc. static inline bool is_Java_byte_ordering_different() { return false; } @@ -150,6 +270,12 @@ class Bytes: AllStatic { static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); } static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); } static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); } + +#endif // VM_LITTLE_ENDIAN }; +#if defined(TARGET_OS_ARCH_linux_ppc) +#include "bytes_linux_ppc.inline.hpp" +#endif + #endif // CPU_PPC_VM_BYTES_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp index 03e5a5d0b55..58e4f3887cb 100644 --- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ define_pd_global(uint64_t,MaxRAM, 4ULL*G); define_pd_global(uintx, CodeCacheMinBlockLength, 4); define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); -define_pd_global(bool, TrapBasedRangeChecks, false); +define_pd_global(bool, TrapBasedRangeChecks, true); // Heap related flags define_pd_global(uintx,MetaspaceSize, ScaleForWordSize(16*M)); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 2d3d9cf9713..8f026ac0d0c 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,6 @@ */ #include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "asm/assembler.inline.hpp" #include "asm/macroAssembler.inline.hpp" #include "compiler/disassembler.hpp" #include "gc_interface/collectedHeap.inline.hpp" @@ -1120,7 +1118,7 @@ address MacroAssembler::call_c_using_toc(const FunctionDescriptor* fd, } return _last_calls_return_pc; } -#endif +#endif // ABI_ELFv2 void MacroAssembler::call_VM_base(Register oop_result, Register last_java_sp, @@ -1794,7 +1792,7 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj cmpwi(cr_reg, temp_reg, markOopDesc::biased_lock_pattern); bne(cr_reg, cas_label); - load_klass_with_trap_null_check(temp_reg, obj_reg); + load_klass(temp_reg, obj_reg); load_const_optimized(temp2_reg, ~((int) markOopDesc::age_mask_in_place)); ld(temp_reg, in_bytes(Klass::prototype_header_offset()), temp_reg); @@ -1891,7 +1889,7 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // the bias from one thread to another directly in this situation. andi(temp_reg, mark_reg, markOopDesc::age_mask_in_place); orr(temp_reg, R16_thread, temp_reg); - load_klass_with_trap_null_check(temp2_reg, obj_reg); + load_klass(temp2_reg, obj_reg); ld(temp2_reg, in_bytes(Klass::prototype_header_offset()), temp2_reg); orr(temp_reg, temp_reg, temp2_reg); @@ -1927,7 +1925,7 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // that another thread raced us for the privilege of revoking the // bias of this particular object, so it's okay to continue in the // normal locking code. - load_klass_with_trap_null_check(temp_reg, obj_reg); + load_klass(temp_reg, obj_reg); ld(temp_reg, in_bytes(Klass::prototype_header_offset()), temp_reg); andi(temp2_reg, mark_reg, markOopDesc::age_mask_in_place); orr(temp_reg, temp_reg, temp2_reg); @@ -2213,8 +2211,7 @@ void MacroAssembler::card_table_write(jbyte* byte_map_base, Register Rtmp, Regis stbx(R0, Rtmp, Robj); } -#ifndef SERIALGC - +#if INCLUDE_ALL_GCS // General G1 pre-barrier generator. // Goal: record the previous value if it is not null. void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val, @@ -2328,14 +2325,17 @@ void MacroAssembler::g1_write_barrier_post(Register Rstore_addr, Register Rnew_v // Get the address of the card. lbzx(/*card value*/ Rtmp3, Rbase, Rcard_addr); + cmpwi(CCR0, Rtmp3, (int)G1SATBCardTableModRefBS::g1_young_card_val()); + beq(CCR0, filtered); - assert(CardTableModRefBS::dirty_card_val() == 0, "otherwise check this code"); - cmpwi(CCR0, Rtmp3 /* card value */, 0); + membar(Assembler::StoreLoad); + lbzx(/*card value*/ Rtmp3, Rbase, Rcard_addr); // Reload after membar. + cmpwi(CCR0, Rtmp3 /* card value */, CardTableModRefBS::dirty_card_val()); beq(CCR0, filtered); // Storing a region crossing, non-NULL oop, card is clean. // Dirty card and log. - li(Rtmp3, 0); // dirty + li(Rtmp3, CardTableModRefBS::dirty_card_val()); //release(); // G1: oops are allowed to get visible after dirty marking. stbx(Rtmp3, Rbase, Rcard_addr); @@ -2362,7 +2362,7 @@ void MacroAssembler::g1_write_barrier_post(Register Rstore_addr, Register Rnew_v bind(filtered_int); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Values for last_Java_pc, and last_Java_sp must comply to the rules // in frame_ppc64.hpp. @@ -2453,7 +2453,8 @@ void MacroAssembler::get_vm_result_2(Register metadata_result) { void MacroAssembler::encode_klass_not_null(Register dst, Register src) { Register current = (src != noreg) ? src : dst; // Klass is in dst if no src provided. if (Universe::narrow_klass_base() != 0) { - load_const(R0, Universe::narrow_klass_base(), (dst != current) ? dst : noreg); // Use dst as temp if it is free. + // Use dst as temp if it is free. + load_const(R0, Universe::narrow_klass_base(), (dst != current && dst != R0) ? dst : noreg); sub(dst, current, R0); current = dst; } diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index a6576a4c472..5bbea5ada2a 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -514,14 +514,14 @@ class MacroAssembler: public Assembler { void card_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp); void card_table_write(jbyte* byte_map_base, Register Rtmp, Register Robj); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // General G1 pre-barrier generator. void g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val, Register Rtmp1, Register Rtmp2, bool needs_frame = false); // General G1 post-barrier generator void g1_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp1, Register Rtmp2, Register Rtmp3, Label *filtered_ext = NULL); -#endif // SERIALGC +#endif // Support for managing the JavaThread pointer (i.e.; the reference to // thread-local information). diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp index 26363754b09..4383d61f7fd 100644 --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,6 +119,7 @@ void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Registe void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp, bool for_compiler_entry) { + Label L_no_such_method; assert(method == R19_method, "interpreter calling convention"); assert_different_registers(method, target, temp); @@ -131,17 +132,31 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ lwz(temp, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread); __ cmplwi(CCR0, temp, 0); __ beq(CCR0, run_compiled_code); + // Null method test is replicated below in compiled case, + // it might be able to address across the verify_thread() + __ cmplwi(CCR0, R19_method, 0); + __ beq(CCR0, L_no_such_method); __ ld(target, in_bytes(Method::interpreter_entry_offset()), R19_method); __ mtctr(target); __ bctr(); __ BIND(run_compiled_code); } + // Compiled case, either static or fall-through from runtime conditional + __ cmplwi(CCR0, R19_method, 0); + __ beq(CCR0, L_no_such_method); + const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : Method::from_interpreted_offset(); __ ld(target, in_bytes(entry_offset), R19_method); __ mtctr(target); __ bctr(); + + __ bind(L_no_such_method); + assert(StubRoutines::throw_AbstractMethodError_entry() != NULL, "not yet generated!"); + __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry()); + __ mtctr(target); + __ bctr(); } diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index c2854e68e16..2989ca5167d 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -891,6 +891,13 @@ definitions %{ // This is a block of C++ code which provides values, functions, and // definitions necessary in the rest of the architecture description. source_hpp %{ + // Header information of the source block. + // Method declarations/definitions which are used outside + // the ad-scope can conveniently be defined here. + // + // To keep related declarations/definitions/uses close together, + // we switch between source %{ }% and source_hpp %{ }% freely as needed. + // Returns true if Node n is followed by a MemBar node that // will do an acquire. If so, this node must not do the acquire // operation. @@ -1114,6 +1121,40 @@ static inline void emit_long(CodeBuffer &cbuf, int value) { //============================================================================= +%} // interrupt source + +source_hpp %{ // Header information of the source block. + +//-------------------------------------------------------------- +//---< Used for optimization in Compile::Shorten_branches >--- +//-------------------------------------------------------------- + +const uint trampoline_stub_size = 6 * BytesPerInstWord; + +class CallStubImpl { + + public: + + static void emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset); + + // Size of call trampoline stub. + // This doesn't need to be accurate to the byte, but it + // must be larger than or equal to the real size of the stub. + static uint size_call_trampoline() { + return trampoline_stub_size; + } + + // number of relocations needed by a call trampoline stub + static uint reloc_call_trampoline() { + return 5; + } + +}; + +%} // end source_hpp + +source %{ + // Emit a trampoline stub for a call to a target which is too far away. // // code sequences: @@ -1125,9 +1166,7 @@ static inline void emit_long(CodeBuffer &cbuf, int value) { // load the call target from the constant pool // branch via CTR (LR/link still points to the call-site above) -const uint trampoline_stub_size = 6 * BytesPerInstWord; - -void emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset) { +void CallStubImpl::emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset) { // Start the stub. address stub = __ start_a_stub(Compile::MAX_stubs_size/2); if (stub == NULL) { @@ -1170,19 +1209,6 @@ void emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int __ end_a_stub(); } -// Size of trampoline stub, this doesn't need to be accurate but it must -// be larger or equal to the real size of the stub. -// Used for optimization in Compile::Shorten_branches. -uint size_call_trampoline() { - return trampoline_stub_size; -} - -// Number of relocation entries needed by trampoline stub. -// Used for optimization in Compile::Shorten_branches. -uint reloc_call_trampoline() { - return 5; -} - //============================================================================= // Emit an inline branch-and-link call and a related trampoline stub. @@ -1221,7 +1247,7 @@ EmitCallOffsets emit_call_with_trampoline_stub(MacroAssembler &_masm, address en const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); // Emit the trampoline stub which will be related to the branch-and-link below. - emit_trampoline_stub(_masm, entry_point_toc_offset, offsets.insts_call_instruction_offset); + CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, offsets.insts_call_instruction_offset); __ relocate(rtype); } @@ -2023,17 +2049,34 @@ uint MachUEPNode::size(PhaseRegAlloc *ra_) const { //============================================================================= -uint size_exception_handler() { - // The exception_handler is a b64_patchable. - return MacroAssembler::b64_patchable_size; -} +%} // interrupt source -uint size_deopt_handler() { - // The deopt_handler is a bl64_patchable. - return MacroAssembler::bl64_patchable_size; -} +source_hpp %{ // Header information of the source block. -int emit_exception_handler(CodeBuffer &cbuf) { +class HandlerImpl { + + public: + + static int emit_exception_handler(CodeBuffer &cbuf); + static int emit_deopt_handler(CodeBuffer& cbuf); + + static uint size_exception_handler() { + // The exception_handler is a b64_patchable. + return MacroAssembler::b64_patchable_size; + } + + static uint size_deopt_handler() { + // The deopt_handler is a bl64_patchable. + return MacroAssembler::bl64_patchable_size; + } + +}; + +%} // end source_hpp + +source %{ + +int HandlerImpl::emit_exception_handler(CodeBuffer &cbuf) { MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); @@ -2050,7 +2093,7 @@ int emit_exception_handler(CodeBuffer &cbuf) { // The deopt_handler is like the exception handler, but it calls to // the deoptimization blob instead of jumping to the exception blob. -int emit_deopt_handler(CodeBuffer& cbuf) { +int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); @@ -3438,7 +3481,7 @@ encode %{ const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); // Emit the trampoline stub which will be related to the branch-and-link below. - emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); + CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); __ relocate(_optimized_virtual ? relocInfo::opt_virtual_call_type : relocInfo::static_call_type); } @@ -3481,7 +3524,7 @@ encode %{ const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); // Emit the trampoline stub which will be related to the branch-and-link below. - emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); + CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); assert(_optimized_virtual, "methodHandle call should be a virtual call"); __ relocate(relocInfo::opt_virtual_call_type); } @@ -3531,7 +3574,7 @@ encode %{ const address entry_point = !($meth$$method) ? 0 : (address)$meth$$method; const address entry_point_const = __ address_constant(entry_point, RelocationHolder::none); const int entry_point_const_toc_offset = __ offset_to_method_toc(entry_point_const); - emit_trampoline_stub(_masm, entry_point_const_toc_offset, __ offset()); + CallStubImpl::emit_trampoline_stub(_masm, entry_point_const_toc_offset, __ offset()); if (ra_->C->env()->failing()) return; @@ -8755,6 +8798,7 @@ instruct sqrtD_reg(regD dst, regD src) %{ // Single-precision sqrt. instruct sqrtF_reg(regF dst, regF src) %{ match(Set dst (ConvD2F (SqrtD (ConvF2D src)))); + predicate(VM_Version::has_fsqrts()); ins_cost(DEFAULT_COST); format %{ "FSQRTS $dst, $src" %} @@ -11550,8 +11594,7 @@ instruct safePoint_poll_conPollAddr(rscratch2RegP poll) %{ // effect no longer needs to be mentioned, since r0 is not contained // in a reg_class. - format %{ "LD R12, addr of polling page\n\t" - "LD R0, #0, R12 \t// Safepoint poll for GC" %} + format %{ "LD R0, #0, R12 \t// Safepoint poll for GC" %} ins_encode( enc_poll(0x0, poll) ); ins_pipe(pipe_class_default); %} diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index d556d7009fa..15a5812e881 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -34,6 +34,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" #include "vmreg_ppc.inline.hpp" +#include "adfiles/ad_ppc_64.hpp" #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif @@ -52,10 +53,6 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") -// Used by generate_deopt_blob. Defined in .ad file. -extern uint size_deopt_handler(); - - class RegisterSaver { // Used for saving volatile registers. public: @@ -2782,7 +2779,7 @@ void SharedRuntime::generate_deopt_blob() { // We can't grab a free register here, because all registers may // contain live values, so let the RegisterSaver do the adjustment // of the return pc. - const int return_pc_adjustment_no_exception = -size_deopt_handler(); + const int return_pc_adjustment_no_exception = -HandlerImpl::size_deopt_handler(); // Push the "unpack frame" // Save everything in sight. diff --git a/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp index 47735a8b1ba..0c1b93b6ba3 100644 --- a/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,17 +23,6 @@ * */ -#include "precompiled.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/stubRoutines.hpp" -#ifdef TARGET_OS_FAMILY_aix -# include "thread_aix.inline.hpp" -#endif -#ifdef TARGET_OS_FAMILY_linux -# include "thread_linux.inline.hpp" -#endif - // Implementation of the platform-specific part of StubRoutines - for // a description of how to extend it, see the stubRoutines.hpp file. diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp index 2e19fca081d..f22fbae29c3 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp @@ -1672,7 +1672,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) { //__ flush_bundle(); address entry = __ pc(); - char *bname = NULL; + const char *bname = NULL; uint tsize = 0; switch(state) { case ftos: diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 567a5d0d3f6..0a6261a21e8 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -402,6 +402,9 @@ void VM_Version::determine_features() { CodeBuffer cb("detect_cpu_features", code_size, 0); MacroAssembler* a = new MacroAssembler(&cb); + // Must be set to true so we can generate the test code. + _features = VM_Version::all_features_m; + // Emit code. void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->function_entry(); uint32_t *code = (uint32_t *)a->pc(); @@ -409,14 +412,15 @@ void VM_Version::determine_features() { // Keep R3_ARG1 unmodified, it contains &field (see below). // Keep R4_ARG2 unmodified, it contains offset = 0 (see below). a->fsqrt(F3, F4); // code[0] -> fsqrt_m - a->isel(R7, R5, R6, 0); // code[1] -> isel_m - a->ldarx_unchecked(R7, R3_ARG1, R4_ARG2, 1); // code[2] -> lxarx_m - a->cmpb(R7, R5, R6); // code[3] -> bcmp - //a->mftgpr(R7, F3); // code[4] -> mftgpr - a->popcntb(R7, R5); // code[5] -> popcntb - a->popcntw(R7, R5); // code[6] -> popcntw - a->fcfids(F3, F4); // code[7] -> fcfids - a->vand(VR0, VR0, VR0); // code[8] -> vand + a->fsqrts(F3, F4); // code[1] -> fsqrts_m + a->isel(R7, R5, R6, 0); // code[2] -> isel_m + a->ldarx_unchecked(R7, R3_ARG1, R4_ARG2, 1); // code[3] -> lxarx_m + a->cmpb(R7, R5, R6); // code[4] -> bcmp + //a->mftgpr(R7, F3); // code[5] -> mftgpr + a->popcntb(R7, R5); // code[6] -> popcntb + a->popcntw(R7, R5); // code[7] -> popcntw + a->fcfids(F3, F4); // code[8] -> fcfids + a->vand(VR0, VR0, VR0); // code[9] -> vand a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. @@ -426,6 +430,7 @@ void VM_Version::determine_features() { uint32_t *code_end = (uint32_t *)a->pc(); a->flush(); + _features = VM_Version::unknown_m; // Print the detection code. if (PrintAssembly) { @@ -450,6 +455,7 @@ void VM_Version::determine_features() { // determine which instructions are legal. int feature_cntr = 0; if (code[feature_cntr++]) features |= fsqrt_m; + if (code[feature_cntr++]) features |= fsqrts_m; if (code[feature_cntr++]) features |= isel_m; if (code[feature_cntr++]) features |= lxarxeh_m; if (code[feature_cntr++]) features |= cmpb_m; diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp index 59553a6bb0e..2bbfdddb21f 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ class VM_Version: public Abstract_VM_Version { protected: enum Feature_Flag { fsqrt, + fsqrts, isel, lxarxeh, cmpb, @@ -46,6 +47,7 @@ protected: enum Feature_Flag_Set { unknown_m = 0, fsqrt_m = (1 << fsqrt ), + fsqrts_m = (1 << fsqrts ), isel_m = (1 << isel ), lxarxeh_m = (1 << lxarxeh), cmpb_m = (1 << cmpb ), @@ -72,6 +74,7 @@ public: static bool is_determine_features_test_running() { return _is_determine_features_test_running; } // CPU instruction support static bool has_fsqrt() { return (_features & fsqrt_m) != 0; } + static bool has_fsqrts() { return (_features & fsqrts_m) != 0; } static bool has_isel() { return (_features & isel_m) != 0; } static bool has_lxarxeh() { return (_features & lxarxeh_m) !=0; } static bool has_cmpb() { return (_features & cmpb_m) != 0; } diff --git a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp index c9e5f5eccac..5931afd5c32 100644 --- a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { address npe_addr = __ pc(); // npe = null pointer exception __ load_klass_with_trap_null_check(rcvr_klass, R3); - // Set methodOop (in case of interpreted method), and destination address. + // Set method (in case of interpreted method), and destination address. int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); #ifndef PRODUCT @@ -161,8 +161,6 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { address npe_addr = __ pc(); // npe = null pointer exception __ load_klass_with_trap_null_check(rcvr_klass, R3_ARG1); - //__ ld(rcvr_klass, oopDesc::klass_offset_in_bytes(), R3_ARG1); - BLOCK_COMMENT("Load start of itable entries into itable_entry."); __ lwz(vtable_len, InstanceKlass::vtable_length_offset() * wordSize, rcvr_klass); __ slwi(vtable_len, vtable_len, exact_log2(vtableEntry::size() * wordSize)); @@ -199,7 +197,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { itable_offset_search_inc; __ lwz(vtable_offset, vtable_offset_offset, itable_entry_addr); - // Compute itableMethodEntry and get methodOop and entry point for compiler. + // Compute itableMethodEntry and get method and entry point for compiler. const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes(); @@ -211,7 +209,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { Label ok; __ cmpd(CCR0, R19_method, 0); __ bne(CCR0, ok); - __ stop("methodOop is null", 103); + __ stop("method is null", 103); __ bind(ok); } #endif diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 488a53d9b6e..b9105e92e9b 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -3320,7 +3320,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, // if tmp is invalid, then the function being called doesn't destroy the thread if (tmp->is_valid()) { - __ save_thread(tmp->as_register()); + __ save_thread(tmp->as_pointer_register()); } __ call(dest, relocInfo::runtime_call_type); __ delayed()->nop(); @@ -3328,7 +3328,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, add_call_info_here(info); } if (tmp->is_valid()) { - __ restore_thread(tmp->as_register()); + __ restore_thread(tmp->as_pointer_register()); } #ifdef ASSERT diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp index dc3bc8691ac..6f6d4c30e13 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp @@ -69,7 +69,7 @@ void LIRItem::load_nonconstant() { LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::Oexception_opr; } LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::Oissuing_pc_opr; } LIR_Opr LIRGenerator::syncTempOpr() { return new_register(T_OBJECT); } -LIR_Opr LIRGenerator::getThreadTemp() { return rlock_callee_saved(T_INT); } +LIR_Opr LIRGenerator::getThreadTemp() { return rlock_callee_saved(NOT_LP64(T_INT) LP64_ONLY(T_LONG)); } LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) { LIR_Opr opr; diff --git a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp index 57f871247b0..111f22730d3 100644 --- a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp @@ -66,6 +66,4 @@ define_pd_global(bool, OptimizeSinglePrecision, false); define_pd_global(bool, CSEArrayLength, true ); define_pd_global(bool, TwoOperandLIRForm, false); -define_pd_global(intx, SafepointPollOffset, 0 ); - #endif // CPU_SPARC_VM_C1_GLOBALS_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 15b5c7b524f..4a3a33dfd87 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -457,6 +457,13 @@ definitions %{ // This is a block of C++ code which provides values, functions, and // definitions necessary in the rest of the architecture description source_hpp %{ +// Header information of the source block. +// Method declarations/definitions which are used outside +// the ad-scope can conveniently be defined here. +// +// To keep related declarations/definitions/uses close together, +// we switch between source %{ }% and source_hpp %{ }% freely as needed. + // Must be visible to the DFA in dfa_sparc.cpp extern bool can_branch_register( Node *bol, Node *cmp ); @@ -468,6 +475,46 @@ extern bool use_block_zeroing(Node* count); #define LONG_HI_REG(x) (x) #define LONG_LO_REG(x) (x) +class CallStubImpl { + + //-------------------------------------------------------------- + //---< Used for optimization in Compile::Shorten_branches >--- + //-------------------------------------------------------------- + + public: + // Size of call trampoline stub. + static uint size_call_trampoline() { + return 0; // no call trampolines on this platform + } + + // number of relocations needed by a call trampoline stub + static uint reloc_call_trampoline() { + return 0; // no call trampolines on this platform + } +}; + +class HandlerImpl { + + public: + + static int emit_exception_handler(CodeBuffer &cbuf); + static int emit_deopt_handler(CodeBuffer& cbuf); + + static uint size_exception_handler() { + if (TraceJumps) { + return (400); // just a guess + } + return ( NativeJump::instruction_size ); // sethi;jmp;nop + } + + static uint size_deopt_handler() { + if (TraceJumps) { + return (400); // just a guess + } + return ( 4+ NativeJump::instruction_size ); // save;sethi;jmp;restore + } +}; + %} source %{ @@ -1710,22 +1757,9 @@ uint MachUEPNode::size(PhaseRegAlloc *ra_) const { //============================================================================= -uint size_exception_handler() { - if (TraceJumps) { - return (400); // just a guess - } - return ( NativeJump::instruction_size ); // sethi;jmp;nop -} - -uint size_deopt_handler() { - if (TraceJumps) { - return (400); // just a guess - } - return ( 4+ NativeJump::instruction_size ); // save;sethi;jmp;restore -} // Emit exception handler code. -int emit_exception_handler(CodeBuffer& cbuf) { +int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { Register temp_reg = G3; AddressLiteral exception_blob(OptoRuntime::exception_blob()->entry_point()); MacroAssembler _masm(&cbuf); @@ -1746,7 +1780,7 @@ int emit_exception_handler(CodeBuffer& cbuf) { return offset; } -int emit_deopt_handler(CodeBuffer& cbuf) { +int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { // Can't use any of the current frame's registers as we may have deopted // at a poll and everything (including G3) can be live. Register temp_reg = L0; diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index d305ac18537..2fc29eae21e 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -1112,7 +1112,6 @@ void Assembler::bsfl(Register dst, Register src) { } void Assembler::bsrl(Register dst, Register src) { - assert(!VM_Version::supports_lzcnt(), "encoding is treated as LZCNT"); int encode = prefix_and_encode(dst->encoding(), src->encoding()); emit_int8(0x0F); emit_int8((unsigned char)0xBD); @@ -2343,6 +2342,11 @@ void Assembler::vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector25 emit_int8(imm8); } +void Assembler::pause() { + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)0x90); +} + void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) { assert(VM_Version::supports_sse4_2(), ""); InstructionMark im(this); @@ -2667,6 +2671,11 @@ void Assembler::rcll(Register dst, int imm8) { } } +void Assembler::rdtsc() { + emit_int8((unsigned char)0x0F); + emit_int8((unsigned char)0x31); +} + // copies data from [esi] to [edi] using rcx pointer sized words // generic void Assembler::rep_mov() { @@ -2976,6 +2985,11 @@ void Assembler::ucomiss(XMMRegister dst, XMMRegister src) { emit_simd_arith_nonds(0x2E, dst, src, VEX_SIMD_NONE); } +void Assembler::xabort(int8_t imm8) { + emit_int8((unsigned char)0xC6); + emit_int8((unsigned char)0xF8); + emit_int8((unsigned char)(imm8 & 0xFF)); +} void Assembler::xaddl(Address dst, Register src) { InstructionMark im(this); @@ -2985,6 +2999,24 @@ void Assembler::xaddl(Address dst, Register src) { emit_operand(src, dst); } +void Assembler::xbegin(Label& abort, relocInfo::relocType rtype) { + InstructionMark im(this); + relocate(rtype); + if (abort.is_bound()) { + address entry = target(abort); + assert(entry != NULL, "abort entry NULL"); + intptr_t offset = entry - pc(); + emit_int8((unsigned char)0xC7); + emit_int8((unsigned char)0xF8); + emit_int32(offset - 6); // 2 opcode + 4 address + } else { + abort.add_patch_at(code(), locator()); + emit_int8((unsigned char)0xC7); + emit_int8((unsigned char)0xF8); + emit_int32(0); + } +} + void Assembler::xchgl(Register dst, Address src) { // xchg InstructionMark im(this); prefix(src, dst); @@ -2998,6 +3030,12 @@ void Assembler::xchgl(Register dst, Register src) { emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::xend() { + emit_int8((unsigned char)0x0F); + emit_int8((unsigned char)0x01); + emit_int8((unsigned char)0xD5); +} + void Assembler::xgetbv() { emit_int8(0x0F); emit_int8(0x01); @@ -4938,7 +4976,6 @@ void Assembler::bsfq(Register dst, Register src) { } void Assembler::bsrq(Register dst, Register src) { - assert(!VM_Version::supports_lzcnt(), "encoding is treated as LZCNT"); int encode = prefixq_and_encode(dst->encoding(), src->encoding()); emit_int8(0x0F); emit_int8((unsigned char)0xBD); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 95ca231cef4..12bc14e7195 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1451,6 +1451,8 @@ private: // Pemutation of 64bit words void vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector256); + void pause(); + // SSE4.2 string instructions void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8); void pcmpestri(XMMRegister xmm1, Address src, int imm8); @@ -1535,6 +1537,8 @@ private: void rclq(Register dst, int imm8); + void rdtsc(); + void ret(int imm16); void sahf(); @@ -1632,16 +1636,22 @@ private: void ucomiss(XMMRegister dst, Address src); void ucomiss(XMMRegister dst, XMMRegister src); + void xabort(int8_t imm8); + void xaddl(Address dst, Register src); void xaddq(Address dst, Register src); + void xbegin(Label& abort, relocInfo::relocType rtype = relocInfo::none); + void xchgl(Register reg, Address adr); void xchgl(Register dst, Register src); void xchgq(Register reg, Address adr); void xchgq(Register dst, Register src); + void xend(); + // Get Value of Extended Control Register void xgetbv(); diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index bf9c9347380..d6dff7bb47a 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -604,8 +604,7 @@ void LIR_Assembler::return_op(LIR_Opr result) { // Note: we do not need to round double result; float result has the right precision // the poll sets the condition code, but no data registers - AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), - relocInfo::poll_return_type); + AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_return_type); if (Assembler::is_polling_page_far()) { __ lea(rscratch1, polling_page); @@ -619,8 +618,7 @@ void LIR_Assembler::return_op(LIR_Opr result) { int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { - AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), - relocInfo::poll_type); + AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_type); guarantee(info != NULL, "Shouldn't be NULL"); int offset = __ offset(); if (Assembler::is_polling_page_far()) { @@ -801,7 +799,13 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi if (UseCompressedOops && !wide) { __ movl(as_Address(addr), (int32_t)NULL_WORD); } else { +#ifdef _LP64 + __ xorptr(rscratch1, rscratch1); + null_check_here = code_offset(); + __ movptr(as_Address(addr), rscratch1); +#else __ movptr(as_Address(addr), NULL_WORD); +#endif } } else { if (is_literal_address(addr)) { diff --git a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp index 2e99c41949f..742a5d8601d 100644 --- a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp @@ -65,6 +65,4 @@ define_pd_global(bool, OptimizeSinglePrecision, true ); define_pd_global(bool, CSEArrayLength, false); define_pd_global(bool, TwoOperandLIRForm, true ); -define_pd_global(intx, SafepointPollOffset, 256 ); - #endif // CPU_X86_VM_C1_GLOBALS_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index f29e5d6e322..fe5db1ce7fe 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -129,6 +129,42 @@ define_pd_global(uintx, TypeProfileLevel, 111); product(bool, UseFastStosb, false, \ "Use fast-string operation for zeroing: rep stosb") \ \ + /* Use Restricted Transactional Memory for lock eliding */ \ + product(bool, UseRTMLocking, false, \ + "Enable RTM lock eliding for inflated locks in compiled code") \ + \ + experimental(bool, UseRTMForStackLocks, false, \ + "Enable RTM lock eliding for stack locks in compiled code") \ + \ + product(bool, UseRTMDeopt, false, \ + "Perform deopt and recompilation based on RTM abort ratio") \ + \ + product(uintx, RTMRetryCount, 5, \ + "Number of RTM retries on lock abort or busy") \ + \ + experimental(intx, RTMSpinLoopCount, 100, \ + "Spin count for lock to become free before RTM retry") \ + \ + experimental(intx, RTMAbortThreshold, 1000, \ + "Calculate abort ratio after this number of aborts") \ + \ + experimental(intx, RTMLockingThreshold, 10000, \ + "Lock count at which to do RTM lock eliding without " \ + "abort ratio calculation") \ + \ + experimental(intx, RTMAbortRatio, 50, \ + "Lock abort ratio at which to stop use RTM lock eliding") \ + \ + experimental(intx, RTMTotalCountIncrRate, 64, \ + "Increment total RTM attempted lock count once every n times") \ + \ + experimental(intx, RTMLockingCalculationDelay, 0, \ + "Number of milliseconds to wait before start calculating aborts " \ + "for RTM locking") \ + \ + experimental(bool, UseRTMXendForLockBusy, false, \ + "Use RTM Xend instead of Xabort when lock busy") \ + \ /* assembler */ \ product(bool, Use486InstrsOnly, false, \ "Use 80486 Compliant instruction subset") \ diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 74fa1b298ac..3426d6d55cf 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -301,7 +301,9 @@ void MacroAssembler::mov_metadata(Address dst, Metadata* obj) { mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate()); } -void MacroAssembler::movptr(Register dst, AddressLiteral src) { +void MacroAssembler::movptr(Register dst, AddressLiteral src, Register scratch) { + // scratch register is not used, + // it is defined to match parameters of 64-bit version of this method. if (src.is_lval()) { mov_literal32(dst, (intptr_t)src.target(), src.rspec()); } else { @@ -613,6 +615,15 @@ void MacroAssembler::decrementq(Address dst, int value) { /* else */ { subq(dst, value) ; return; } } +void MacroAssembler::incrementq(AddressLiteral dst) { + if (reachable(dst)) { + incrementq(as_Address(dst)); + } else { + lea(rscratch1, dst); + incrementq(Address(rscratch1, 0)); + } +} + void MacroAssembler::incrementq(Register reg, int value) { if (value == min_jint) { addq(reg, value); return; } if (value < 0) { decrementq(reg, -value); return; } @@ -681,15 +692,15 @@ void MacroAssembler::mov_metadata(Address dst, Metadata* obj) { movq(dst, rscratch1); } -void MacroAssembler::movptr(Register dst, AddressLiteral src) { +void MacroAssembler::movptr(Register dst, AddressLiteral src, Register scratch) { if (src.is_lval()) { mov_literal64(dst, (intptr_t)src.target(), src.rspec()); } else { if (reachable(src)) { movq(dst, as_Address(src)); } else { - lea(rscratch1, src); - movq(dst, Address(rscratch1,0)); + lea(scratch, src); + movq(dst, Address(scratch, 0)); } } } @@ -988,21 +999,38 @@ void MacroAssembler::andptr(Register dst, int32_t imm32) { LP64_ONLY(andq(dst, imm32)) NOT_LP64(andl(dst, imm32)); } -void MacroAssembler::atomic_incl(AddressLiteral counter_addr) { - pushf(); - if (reachable(counter_addr)) { - if (os::is_MP()) - lock(); - incrementl(as_Address(counter_addr)); - } else { - lea(rscratch1, counter_addr); - if (os::is_MP()) - lock(); - incrementl(Address(rscratch1, 0)); - } - popf(); +void MacroAssembler::atomic_incl(Address counter_addr) { + if (os::is_MP()) + lock(); + incrementl(counter_addr); } +void MacroAssembler::atomic_incl(AddressLiteral counter_addr, Register scr) { + if (reachable(counter_addr)) { + atomic_incl(as_Address(counter_addr)); + } else { + lea(scr, counter_addr); + atomic_incl(Address(scr, 0)); + } +} + +#ifdef _LP64 +void MacroAssembler::atomic_incq(Address counter_addr) { + if (os::is_MP()) + lock(); + incrementq(counter_addr); +} + +void MacroAssembler::atomic_incq(AddressLiteral counter_addr, Register scr) { + if (reachable(counter_addr)) { + atomic_incq(as_Address(counter_addr)); + } else { + lea(scr, counter_addr); + atomic_incq(Address(scr, 0)); + } +} +#endif + // Writes to stack successive pages until offset reached to check for // stack overflow + shadow pages. This clobbers tmp. void MacroAssembler::bang_stack_size(Register size, Register tmp) { @@ -1274,6 +1302,325 @@ void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, La } #ifdef COMPILER2 + +#if INCLUDE_RTM_OPT + +// Update rtm_counters based on abort status +// input: abort_status +// rtm_counters (RTMLockingCounters*) +// flags are killed +void MacroAssembler::rtm_counters_update(Register abort_status, Register rtm_counters) { + + atomic_incptr(Address(rtm_counters, RTMLockingCounters::abort_count_offset())); + if (PrintPreciseRTMLockingStatistics) { + for (int i = 0; i < RTMLockingCounters::ABORT_STATUS_LIMIT; i++) { + Label check_abort; + testl(abort_status, (1< 0) { + // Delay calculation + movptr(tmpReg, ExternalAddress((address) RTMLockingCounters::rtm_calculation_flag_addr()), tmpReg); + testptr(tmpReg, tmpReg); + jccb(Assembler::equal, L_done); + } + // Abort ratio calculation only if abort_count > RTMAbortThreshold + // Aborted transactions = abort_count * 100 + // All transactions = total_count * RTMTotalCountIncrRate + // Set no_rtm bit if (Aborted transactions >= All transactions * RTMAbortRatio) + + movptr(tmpReg, Address(rtm_counters_Reg, RTMLockingCounters::abort_count_offset())); + cmpptr(tmpReg, RTMAbortThreshold); + jccb(Assembler::below, L_check_always_rtm2); + imulptr(tmpReg, tmpReg, 100); + + Register scrReg = rtm_counters_Reg; + movptr(scrReg, Address(rtm_counters_Reg, RTMLockingCounters::total_count_offset())); + imulptr(scrReg, scrReg, RTMTotalCountIncrRate); + imulptr(scrReg, scrReg, RTMAbortRatio); + cmpptr(tmpReg, scrReg); + jccb(Assembler::below, L_check_always_rtm1); + if (method_data != NULL) { + // set rtm_state to "no rtm" in MDO + mov_metadata(tmpReg, method_data); + if (os::is_MP()) { + lock(); + } + orl(Address(tmpReg, MethodData::rtm_state_offset_in_bytes()), NoRTM); + } + jmpb(L_done); + bind(L_check_always_rtm1); + // Reload RTMLockingCounters* address + lea(rtm_counters_Reg, ExternalAddress((address)rtm_counters)); + bind(L_check_always_rtm2); + movptr(tmpReg, Address(rtm_counters_Reg, RTMLockingCounters::total_count_offset())); + cmpptr(tmpReg, RTMLockingThreshold / RTMTotalCountIncrRate); + jccb(Assembler::below, L_done); + if (method_data != NULL) { + // set rtm_state to "always rtm" in MDO + mov_metadata(tmpReg, method_data); + if (os::is_MP()) { + lock(); + } + orl(Address(tmpReg, MethodData::rtm_state_offset_in_bytes()), UseRTM); + } + bind(L_done); +} + +// Update counters and perform abort ratio calculation +// input: abort_status_Reg +// rtm_counters_Reg, flags are killed +void MacroAssembler::rtm_profiling(Register abort_status_Reg, + Register rtm_counters_Reg, + RTMLockingCounters* rtm_counters, + Metadata* method_data, + bool profile_rtm) { + + assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); + // update rtm counters based on rax value at abort + // reads abort_status_Reg, updates flags + lea(rtm_counters_Reg, ExternalAddress((address)rtm_counters)); + rtm_counters_update(abort_status_Reg, rtm_counters_Reg); + if (profile_rtm) { + // Save abort status because abort_status_Reg is used by following code. + if (RTMRetryCount > 0) { + push(abort_status_Reg); + } + assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); + rtm_abort_ratio_calculation(abort_status_Reg, rtm_counters_Reg, rtm_counters, method_data); + // restore abort status + if (RTMRetryCount > 0) { + pop(abort_status_Reg); + } + } +} + +// Retry on abort if abort's status is 0x6: can retry (0x2) | memory conflict (0x4) +// inputs: retry_count_Reg +// : abort_status_Reg +// output: retry_count_Reg decremented by 1 +// flags are killed +void MacroAssembler::rtm_retry_lock_on_abort(Register retry_count_Reg, Register abort_status_Reg, Label& retryLabel) { + Label doneRetry; + assert(abort_status_Reg == rax, ""); + // The abort reason bits are in eax (see all states in rtmLocking.hpp) + // 0x6 = conflict on which we can retry (0x2) | memory conflict (0x4) + // if reason is in 0x6 and retry count != 0 then retry + andptr(abort_status_Reg, 0x6); + jccb(Assembler::zero, doneRetry); + testl(retry_count_Reg, retry_count_Reg); + jccb(Assembler::zero, doneRetry); + pause(); + decrementl(retry_count_Reg); + jmp(retryLabel); + bind(doneRetry); +} + +// Spin and retry if lock is busy, +// inputs: box_Reg (monitor address) +// : retry_count_Reg +// output: retry_count_Reg decremented by 1 +// : clear z flag if retry count exceeded +// tmp_Reg, scr_Reg, flags are killed +void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register box_Reg, + Register tmp_Reg, Register scr_Reg, Label& retryLabel) { + Label SpinLoop, SpinExit, doneRetry; + // Clean monitor_value bit to get valid pointer + int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + + testl(retry_count_Reg, retry_count_Reg); + jccb(Assembler::zero, doneRetry); + decrementl(retry_count_Reg); + movptr(scr_Reg, RTMSpinLoopCount); + + bind(SpinLoop); + pause(); + decrementl(scr_Reg); + jccb(Assembler::lessEqual, SpinExit); + movptr(tmp_Reg, Address(box_Reg, owner_offset)); + testptr(tmp_Reg, tmp_Reg); + jccb(Assembler::notZero, SpinLoop); + + bind(SpinExit); + jmp(retryLabel); + bind(doneRetry); + incrementl(retry_count_Reg); // clear z flag +} + +// Use RTM for normal stack locks +// Input: objReg (object to lock) +void MacroAssembler::rtm_stack_locking(Register objReg, Register tmpReg, Register scrReg, + Register retry_on_abort_count_Reg, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL, Label& IsInflated) { + assert(UseRTMForStackLocks, "why call this otherwise?"); + assert(!UseBiasedLocking, "Biased locking is not supported with RTM locking"); + assert(tmpReg == rax, ""); + assert(scrReg == rdx, ""); + Label L_rtm_retry, L_decrement_retry, L_on_abort; + + if (RTMRetryCount > 0) { + movl(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort + bind(L_rtm_retry); + } + if (!UseRTMXendForLockBusy) { + movptr(tmpReg, Address(objReg, 0)); + testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased + jcc(Assembler::notZero, IsInflated); + } + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + Label L_noincrement; + if (RTMTotalCountIncrRate > 1) { + // tmpReg, scrReg and flags are killed + branch_on_random_using_rdtsc(tmpReg, scrReg, (int)RTMTotalCountIncrRate, L_noincrement); + } + assert(stack_rtm_counters != NULL, "should not be NULL when profiling RTM"); + atomic_incptr(ExternalAddress((address)stack_rtm_counters->total_count_addr()), scrReg); + bind(L_noincrement); + } + xbegin(L_on_abort); + movptr(tmpReg, Address(objReg, 0)); // fetch markword + andptr(tmpReg, markOopDesc::biased_lock_mask_in_place); // look at 3 lock bits + cmpptr(tmpReg, markOopDesc::unlocked_value); // bits = 001 unlocked + jcc(Assembler::equal, DONE_LABEL); // all done if unlocked + + Register abort_status_Reg = tmpReg; // status of abort is stored in RAX + if (UseRTMXendForLockBusy) { + xend(); + movptr(tmpReg, Address(objReg, 0)); + testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased + jcc(Assembler::notZero, IsInflated); + movptr(abort_status_Reg, 0x1); // Set the abort status to 1 (as xabort does) + jmp(L_decrement_retry); + } + else { + xabort(0); + } + bind(L_on_abort); + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + rtm_profiling(abort_status_Reg, scrReg, stack_rtm_counters, method_data, profile_rtm); + } + bind(L_decrement_retry); + if (RTMRetryCount > 0) { + // retry on lock abort if abort status is 'can retry' (0x2) or 'memory conflict' (0x4) + rtm_retry_lock_on_abort(retry_on_abort_count_Reg, abort_status_Reg, L_rtm_retry); + } +} + +// Use RTM for inflating locks +// inputs: objReg (object to lock) +// boxReg (on-stack box address (displaced header location) - KILLED) +// tmpReg (ObjectMonitor address + 2(monitor_value)) +void MacroAssembler::rtm_inflated_locking(Register objReg, Register boxReg, Register tmpReg, + Register scrReg, Register retry_on_busy_count_Reg, + Register retry_on_abort_count_Reg, + RTMLockingCounters* rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL) { + assert(UseRTMLocking, "why call this otherwise?"); + assert(tmpReg == rax, ""); + assert(scrReg == rdx, ""); + Label L_rtm_retry, L_decrement_retry, L_on_abort; + // Clean monitor_value bit to get valid pointer + int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + + // Without cast to int32_t a movptr will destroy r10 which is typically obj + movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())); + movptr(boxReg, tmpReg); // Save ObjectMonitor address + + if (RTMRetryCount > 0) { + movl(retry_on_busy_count_Reg, RTMRetryCount); // Retry on lock busy + movl(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort + bind(L_rtm_retry); + } + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + Label L_noincrement; + if (RTMTotalCountIncrRate > 1) { + // tmpReg, scrReg and flags are killed + branch_on_random_using_rdtsc(tmpReg, scrReg, (int)RTMTotalCountIncrRate, L_noincrement); + } + assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); + atomic_incptr(ExternalAddress((address)rtm_counters->total_count_addr()), scrReg); + bind(L_noincrement); + } + xbegin(L_on_abort); + movptr(tmpReg, Address(objReg, 0)); + movptr(tmpReg, Address(tmpReg, owner_offset)); + testptr(tmpReg, tmpReg); + jcc(Assembler::zero, DONE_LABEL); + if (UseRTMXendForLockBusy) { + xend(); + jmp(L_decrement_retry); + } + else { + xabort(0); + } + bind(L_on_abort); + Register abort_status_Reg = tmpReg; // status of abort is stored in RAX + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + rtm_profiling(abort_status_Reg, scrReg, rtm_counters, method_data, profile_rtm); + } + if (RTMRetryCount > 0) { + // retry on lock abort if abort status is 'can retry' (0x2) or 'memory conflict' (0x4) + rtm_retry_lock_on_abort(retry_on_abort_count_Reg, abort_status_Reg, L_rtm_retry); + } + + movptr(tmpReg, Address(boxReg, owner_offset)) ; + testptr(tmpReg, tmpReg) ; + jccb(Assembler::notZero, L_decrement_retry) ; + + // Appears unlocked - try to swing _owner from null to non-null. + // Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand. +#ifdef _LP64 + Register threadReg = r15_thread; +#else + get_thread(scrReg); + Register threadReg = scrReg; +#endif + if (os::is_MP()) { + lock(); + } + cmpxchgptr(threadReg, Address(boxReg, owner_offset)); // Updates tmpReg + + if (RTMRetryCount > 0) { + // success done else retry + jccb(Assembler::equal, DONE_LABEL) ; + bind(L_decrement_retry); + // Spin and retry if lock is busy. + rtm_retry_lock_on_busy(retry_on_busy_count_Reg, boxReg, tmpReg, scrReg, L_rtm_retry); + } + else { + bind(L_decrement_retry); + } +} + +#endif // INCLUDE_RTM_OPT + // Fast_Lock and Fast_Unlock used by C2 // Because the transitions from emitted code to the runtime @@ -1350,17 +1697,26 @@ void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, La // box: on-stack box address (displaced header location) - KILLED // rax,: tmp -- KILLED // scr: tmp -- KILLED -void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg, Register scrReg, BiasedLockingCounters* counters) { +void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg, + Register scrReg, Register cx1Reg, Register cx2Reg, + BiasedLockingCounters* counters, + RTMLockingCounters* rtm_counters, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, + bool use_rtm, bool profile_rtm) { // Ensure the register assignents are disjoint - guarantee (objReg != boxReg, ""); - guarantee (objReg != tmpReg, ""); - guarantee (objReg != scrReg, ""); - guarantee (boxReg != tmpReg, ""); - guarantee (boxReg != scrReg, ""); - guarantee (tmpReg == rax, ""); + assert(tmpReg == rax, ""); + + if (use_rtm) { + assert_different_registers(objReg, boxReg, tmpReg, scrReg, cx1Reg, cx2Reg); + } else { + assert(cx1Reg == noreg, ""); + assert(cx2Reg == noreg, ""); + assert_different_registers(objReg, boxReg, tmpReg, scrReg); + } if (counters != NULL) { - atomic_incl(ExternalAddress((address)counters->total_entry_count_addr())); + atomic_incl(ExternalAddress((address)counters->total_entry_count_addr()), scrReg); } if (EmitSync & 1) { // set box->dhw = unused_mark (3) @@ -1419,12 +1775,20 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg biased_locking_enter(boxReg, objReg, tmpReg, scrReg, true, DONE_LABEL, NULL, counters); } +#if INCLUDE_RTM_OPT + if (UseRTMForStackLocks && use_rtm) { + rtm_stack_locking(objReg, tmpReg, scrReg, cx2Reg, + stack_rtm_counters, method_data, profile_rtm, + DONE_LABEL, IsInflated); + } +#endif // INCLUDE_RTM_OPT + movptr(tmpReg, Address(objReg, 0)); // [FETCH] - testl (tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased - jccb (Assembler::notZero, IsInflated); + testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased + jccb(Assembler::notZero, IsInflated); // Attempt stack-locking ... - orptr (tmpReg, 0x1); + orptr (tmpReg, markOopDesc::unlocked_value); movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS if (os::is_MP()) { lock(); @@ -1434,19 +1798,32 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg cond_inc32(Assembler::equal, ExternalAddress((address)counters->fast_path_entry_count_addr())); } - jccb(Assembler::equal, DONE_LABEL); + jcc(Assembler::equal, DONE_LABEL); // Success - // Recursive locking + // Recursive locking. + // The object is stack-locked: markword contains stack pointer to BasicLock. + // Locked by current thread if difference with current SP is less than one page. subptr(tmpReg, rsp); + // Next instruction set ZFlag == 1 (Success) if difference is less then one page. andptr(tmpReg, (int32_t) (NOT_LP64(0xFFFFF003) LP64_ONLY(7 - os::vm_page_size())) ); movptr(Address(boxReg, 0), tmpReg); if (counters != NULL) { cond_inc32(Assembler::equal, ExternalAddress((address)counters->fast_path_entry_count_addr())); } - jmpb(DONE_LABEL); + jmp(DONE_LABEL); bind(IsInflated); + // The object is inflated. tmpReg contains pointer to ObjectMonitor* + 2(monitor_value) + +#if INCLUDE_RTM_OPT + // Use the same RTM locking code in 32- and 64-bit VM. + if (use_rtm) { + rtm_inflated_locking(objReg, boxReg, tmpReg, scrReg, cx1Reg, cx2Reg, + rtm_counters, method_data, profile_rtm, DONE_LABEL); + } else { +#endif // INCLUDE_RTM_OPT + #ifndef _LP64 // The object is inflated. // @@ -1576,7 +1953,7 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg // Without cast to int32_t a movptr will destroy r10 which is typically obj movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())); - mov (boxReg, tmpReg); + movptr (boxReg, tmpReg); movptr (tmpReg, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)); testptr(tmpReg, tmpReg); jccb (Assembler::notZero, DONE_LABEL); @@ -1587,9 +1964,11 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg } cmpxchgptr(r15_thread, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)); // Intentional fall-through into DONE_LABEL ... +#endif // _LP64 +#if INCLUDE_RTM_OPT + } // use_rtm() #endif - // DONE_LABEL is a hot target - we'd really like to place it at the // start of cache line by padding with NOPs. // See the AMD and Intel software optimization manuals for the @@ -1631,11 +2010,9 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg // should not be unlocked by "normal" java-level locking and vice-versa. The specification // doesn't specify what will occur if a program engages in such mixed-mode locking, however. -void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg) { - guarantee (objReg != boxReg, ""); - guarantee (objReg != tmpReg, ""); - guarantee (boxReg != tmpReg, ""); - guarantee (boxReg == rax, ""); +void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg, bool use_rtm) { + assert(boxReg == rax, ""); + assert_different_registers(objReg, boxReg, tmpReg); if (EmitSync & 4) { // Disable - inhibit all inlining. Force control through the slow-path @@ -1667,14 +2044,41 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR biased_locking_exit(objReg, tmpReg, DONE_LABEL); } - cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD); // Examine the displaced header - movptr(tmpReg, Address(objReg, 0)); // Examine the object's markword - jccb (Assembler::zero, DONE_LABEL); // 0 indicates recursive stack-lock +#if INCLUDE_RTM_OPT + if (UseRTMForStackLocks && use_rtm) { + assert(!UseBiasedLocking, "Biased locking is not supported with RTM locking"); + Label L_regular_unlock; + movptr(tmpReg, Address(objReg, 0)); // fetch markword + andptr(tmpReg, markOopDesc::biased_lock_mask_in_place); // look at 3 lock bits + cmpptr(tmpReg, markOopDesc::unlocked_value); // bits = 001 unlocked + jccb(Assembler::notEqual, L_regular_unlock); // if !HLE RegularLock + xend(); // otherwise end... + jmp(DONE_LABEL); // ... and we're done + bind(L_regular_unlock); + } +#endif - testptr(tmpReg, 0x02); // Inflated? + cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD); // Examine the displaced header + jcc (Assembler::zero, DONE_LABEL); // 0 indicates recursive stack-lock + movptr(tmpReg, Address(objReg, 0)); // Examine the object's markword + testptr(tmpReg, markOopDesc::monitor_value); // Inflated? jccb (Assembler::zero, Stacked); // It's inflated. +#if INCLUDE_RTM_OPT + if (use_rtm) { + Label L_regular_inflated_unlock; + // Clean monitor_value bit to get valid pointer + int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + movptr(boxReg, Address(tmpReg, owner_offset)); + testptr(boxReg, boxReg); + jccb(Assembler::notZero, L_regular_inflated_unlock); + xend(); + jmpb(DONE_LABEL); + bind(L_regular_inflated_unlock); + } +#endif + // Despite our balanced locking property we still check that m->_owner == Self // as java routines or native JNI code called by this thread might // have released the lock. @@ -2448,7 +2852,9 @@ void MacroAssembler::cond_inc32(Condition cond, AddressLiteral counter_addr) { Condition negated_cond = negate_condition(cond); Label L; jcc(negated_cond, L); + pushf(); // Preserve flags atomic_incl(counter_addr); + popf(); bind(L); } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 6ac95774ba9..e154ae838c4 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -27,6 +27,7 @@ #include "asm/assembler.hpp" #include "utilities/macros.hpp" +#include "runtime/rtmLocking.hpp" // MacroAssembler extends Assembler by frequently used macros. @@ -111,7 +112,8 @@ class MacroAssembler: public Assembler { op == 0xE9 /* jmp */ || op == 0xEB /* short jmp */ || (op & 0xF0) == 0x70 /* short jcc */ || - op == 0x0F && (branch[1] & 0xF0) == 0x80 /* jcc */, + op == 0x0F && (branch[1] & 0xF0) == 0x80 /* jcc */ || + op == 0xC7 && branch[1] == 0xF8 /* xbegin */, "Invalid opcode at patch point"); if (op == 0xEB || (op & 0xF0) == 0x70) { @@ -121,7 +123,7 @@ class MacroAssembler: public Assembler { guarantee(this->is8bit(imm8), "Short forward jump exceeds 8-bit offset"); *disp = imm8; } else { - int* disp = (int*) &branch[(op == 0x0F)? 2: 1]; + int* disp = (int*) &branch[(op == 0x0F || op == 0xC7)? 2: 1]; int imm32 = target - (address) &disp[1]; *disp = imm32; } @@ -161,7 +163,6 @@ class MacroAssembler: public Assembler { void incrementq(Register reg, int value = 1); void incrementq(Address dst, int value = 1); - // Support optimal SSE move instructions. void movflt(XMMRegister dst, XMMRegister src) { if (UseXmmRegToRegMoveAll) { movaps(dst, src); return; } @@ -187,6 +188,8 @@ class MacroAssembler: public Assembler { void incrementl(AddressLiteral dst); void incrementl(ArrayAddress dst); + void incrementq(AddressLiteral dst); + // Alignment void align(int modulus); @@ -654,8 +657,36 @@ class MacroAssembler: public Assembler { #ifdef COMPILER2 // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. // See full desription in macroAssembler_x86.cpp. - void fast_lock(Register obj, Register box, Register tmp, Register scr, BiasedLockingCounters* counters); - void fast_unlock(Register obj, Register box, Register tmp); + void fast_lock(Register obj, Register box, Register tmp, + Register scr, Register cx1, Register cx2, + BiasedLockingCounters* counters, + RTMLockingCounters* rtm_counters, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, + bool use_rtm, bool profile_rtm); + void fast_unlock(Register obj, Register box, Register tmp, bool use_rtm); +#if INCLUDE_RTM_OPT + void rtm_counters_update(Register abort_status, Register rtm_counters); + void branch_on_random_using_rdtsc(Register tmp, Register scr, int count, Label& brLabel); + void rtm_abort_ratio_calculation(Register tmp, Register rtm_counters_reg, + RTMLockingCounters* rtm_counters, + Metadata* method_data); + void rtm_profiling(Register abort_status_Reg, Register rtm_counters_Reg, + RTMLockingCounters* rtm_counters, Metadata* method_data, bool profile_rtm); + void rtm_retry_lock_on_abort(Register retry_count, Register abort_status, Label& retryLabel); + void rtm_retry_lock_on_busy(Register retry_count, Register box, Register tmp, Register scr, Label& retryLabel); + void rtm_stack_locking(Register obj, Register tmp, Register scr, + Register retry_on_abort_count, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL, Label& IsInflated); + void rtm_inflated_locking(Register obj, Register box, Register tmp, + Register scr, Register retry_on_busy_count, + Register retry_on_abort_count, + RTMLockingCounters* rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL); +#endif #endif Condition negate_condition(Condition cond); @@ -721,6 +752,7 @@ class MacroAssembler: public Assembler { void imulptr(Register dst, Register src) { LP64_ONLY(imulq(dst, src)) NOT_LP64(imull(dst, src)); } + void imulptr(Register dst, Register src, int imm32) { LP64_ONLY(imulq(dst, src, imm32)) NOT_LP64(imull(dst, src, imm32)); } void negptr(Register dst) { LP64_ONLY(negq(dst)) NOT_LP64(negl(dst)); } @@ -762,7 +794,14 @@ class MacroAssembler: public Assembler { // Conditionally (atomically, on MPs) increments passed counter address, preserving condition codes. void cond_inc32(Condition cond, AddressLiteral counter_addr); // Unconditional atomic increment. - void atomic_incl(AddressLiteral counter_addr); + void atomic_incl(Address counter_addr); + void atomic_incl(AddressLiteral counter_addr, Register scr = rscratch1); +#ifdef _LP64 + void atomic_incq(Address counter_addr); + void atomic_incq(AddressLiteral counter_addr, Register scr = rscratch1); +#endif + void atomic_incptr(AddressLiteral counter_addr, Register scr = rscratch1) { LP64_ONLY(atomic_incq(counter_addr, scr)) NOT_LP64(atomic_incl(counter_addr, scr)) ; } + void atomic_incptr(Address counter_addr) { LP64_ONLY(atomic_incq(counter_addr)) NOT_LP64(atomic_incl(counter_addr)) ; } void lea(Register dst, AddressLiteral adr); void lea(Address dst, AddressLiteral adr); @@ -1074,7 +1113,11 @@ public: void movptr(Register dst, Address src); - void movptr(Register dst, AddressLiteral src); +#ifdef _LP64 + void movptr(Register dst, AddressLiteral src, Register scratch=rscratch1); +#else + void movptr(Register dst, AddressLiteral src, Register scratch=noreg); // Scratch reg is ignored in 32-bit +#endif void movptr(Register dst, intptr_t src); void movptr(Register dst, Register src); diff --git a/hotspot/src/cpu/x86/vm/rtmLocking.cpp b/hotspot/src/cpu/x86/vm/rtmLocking.cpp new file mode 100644 index 00000000000..e1b28654b03 --- /dev/null +++ b/hotspot/src/cpu/x86/vm/rtmLocking.cpp @@ -0,0 +1,60 @@ +/* + * 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/task.hpp" +#include "runtime/rtmLocking.hpp" + +// One-shot PeriodicTask subclass for enabling RTM locking +uintx RTMLockingCounters::_calculation_flag = 0; + +class RTMLockingCalculationTask : public PeriodicTask { + public: + RTMLockingCalculationTask(size_t interval_time) : PeriodicTask(interval_time){ } + + virtual void task() { + RTMLockingCounters::_calculation_flag = 1; + // Reclaim our storage and disenroll ourself + delete this; + } +}; + +void RTMLockingCounters::init() { + if (UseRTMLocking && RTMLockingCalculationDelay > 0) { + RTMLockingCalculationTask* task = new RTMLockingCalculationTask(RTMLockingCalculationDelay); + task->enroll(); + } else { + _calculation_flag = 1; + } +} + +//------------------------------print_on------------------------------- +void RTMLockingCounters::print_on(outputStream* st) { + tty->print_cr("# rtm locks total (estimated): " UINTX_FORMAT, _total_count * RTMTotalCountIncrRate); + tty->print_cr("# rtm lock aborts : " UINTX_FORMAT, _abort_count); + for (int i = 0; i < ABORT_STATUS_LIMIT; i++) { + tty->print_cr("# rtm lock aborts %d: " UINTX_FORMAT, i, _abortX_count[i]); + } +} diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 146d34c40a4..2f9ffd7feb7 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -1817,6 +1817,13 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Frame is now completed as far as size and linkage. int frame_complete = ((intptr_t)__ pc()) - start; + if (UseRTMLocking) { + // Abort RTM transaction before calling JNI + // because critical section will be large and will be + // aborted anyway. Also nmethod could be deoptimized. + __ xabort(0); + } + // Calculate the difference between rsp and rbp,. We need to know it // after the native call because on windows Java Natives will pop // the arguments and it is painful to do rsp relative addressing @@ -3170,6 +3177,12 @@ void SharedRuntime::generate_uncommon_trap_blob() { }; address start = __ pc(); + + if (UseRTMLocking) { + // Abort RTM transaction before possible nmethod deoptimization. + __ xabort(0); + } + // Push self-frame. __ subptr(rsp, return_off*wordSize); // Epilog! @@ -3355,6 +3368,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t address call_pc = NULL; bool cause_return = (poll_type == POLL_AT_RETURN); bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); + + if (UseRTMLocking) { + // Abort RTM transaction before calling runtime + // because critical section will be large and will be + // aborted anyway. Also nmethod could be deoptimized. + __ xabort(0); + } + // If cause_return is true we are at a poll_return and there is // the return address on the stack to the caller on the nmethod // that is safepoint. We can leave this return on the stack and diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 37cf1d5c2cf..bdb77a66351 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -2012,6 +2012,13 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Frame is now completed as far as size and linkage. int frame_complete = ((intptr_t)__ pc()) - start; + if (UseRTMLocking) { + // Abort RTM transaction before calling JNI + // because critical section will be large and will be + // aborted anyway. Also nmethod could be deoptimized. + __ xabort(0); + } + #ifdef ASSERT { Label L; @@ -3612,6 +3619,11 @@ void SharedRuntime::generate_uncommon_trap_blob() { address start = __ pc(); + if (UseRTMLocking) { + // Abort RTM transaction before possible nmethod deoptimization. + __ xabort(0); + } + // Push self-frame. We get here with a return address on the // stack, so rsp is 8-byte aligned until we allocate our frame. __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog! @@ -3792,6 +3804,13 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t bool cause_return = (poll_type == POLL_AT_RETURN); bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); + if (UseRTMLocking) { + // Abort RTM transaction before calling runtime + // because critical section will be large and will be + // aborted anyway. Also nmethod could be deoptimized. + __ xabort(0); + } + // Make room for return address (or push it again) if (!cause_return) { __ push(rbx); diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index b949e4e2998..ba5fcb383c6 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -50,13 +50,18 @@ int VM_Version::_cpuFeatures; const char* VM_Version::_features_str = ""; VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, }; +// Address of instruction which causes SEGV +address VM_Version::_cpuinfo_segv_addr = 0; +// Address of instruction after the one which causes SEGV +address VM_Version::_cpuinfo_cont_addr = 0; + static BufferBlob* stub_blob; -static const int stub_size = 550; +static const int stub_size = 600; extern "C" { - typedef void (*getPsrInfo_stub_t)(void*); + typedef void (*get_cpu_info_stub_t)(void*); } -static getPsrInfo_stub_t getPsrInfo_stub = NULL; +static get_cpu_info_stub_t get_cpu_info_stub = NULL; class VM_Version_StubGenerator: public StubCodeGenerator { @@ -64,7 +69,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {} - address generate_getPsrInfo() { + address generate_get_cpu_info() { // Flags to test CPU type. const uint32_t HS_EFL_AC = 0x40000; const uint32_t HS_EFL_ID = 0x200000; @@ -76,13 +81,13 @@ class VM_Version_StubGenerator: public StubCodeGenerator { Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4; Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done; - StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub"); + StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub"); # define __ _masm-> address start = __ pc(); // - // void getPsrInfo(VM_Version::CpuidInfo* cpuid_info); + // void get_cpu_info(VM_Version::CpuidInfo* cpuid_info); // // LP64: rcx and rdx are first and second argument registers on windows @@ -234,9 +239,9 @@ class VM_Version_StubGenerator: public StubCodeGenerator { // Check if OS has enabled XGETBV instruction to access XCR0 // (OSXSAVE feature flag) and CPU supports AVX // - __ andl(rcx, 0x18000000); + __ andl(rcx, 0x18000000); // cpuid1 bits osxsave | avx __ cmpl(rcx, 0x18000000); - __ jccb(Assembler::notEqual, sef_cpuid); + __ jccb(Assembler::notEqual, sef_cpuid); // jump if AVX is not supported // // XCR0, XFEATURE_ENABLED_MASK register @@ -247,6 +252,47 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movl(Address(rsi, 0), rax); __ movl(Address(rsi, 4), rdx); + __ andl(rax, 0x6); // xcr0 bits sse | ymm + __ cmpl(rax, 0x6); + __ jccb(Assembler::notEqual, sef_cpuid); // jump if AVX is not supported + + // + // Some OSs have a bug when upper 128bits of YMM + // registers are not restored after a signal processing. + // Generate SEGV here (reference through NULL) + // and check upper YMM bits after it. + // + VM_Version::set_avx_cpuFeatures(); // Enable temporary to pass asserts + + // load value into all 32 bytes of ymm7 register + __ movl(rcx, VM_Version::ymm_test_value()); + + __ movdl(xmm0, rcx); + __ pshufd(xmm0, xmm0, 0x00); + __ vinsertf128h(xmm0, xmm0, xmm0); + __ vmovdqu(xmm7, xmm0); +#ifdef _LP64 + __ vmovdqu(xmm8, xmm0); + __ vmovdqu(xmm15, xmm0); +#endif + + __ xorl(rsi, rsi); + VM_Version::set_cpuinfo_segv_addr( __ pc() ); + // Generate SEGV + __ movl(rax, Address(rsi, 0)); + + VM_Version::set_cpuinfo_cont_addr( __ pc() ); + // Returns here after signal. Save xmm0 to check it later. + __ lea(rsi, Address(rbp, in_bytes(VM_Version::ymm_save_offset()))); + __ vmovdqu(Address(rsi, 0), xmm0); + __ vmovdqu(Address(rsi, 32), xmm7); +#ifdef _LP64 + __ vmovdqu(Address(rsi, 64), xmm8); + __ vmovdqu(Address(rsi, 96), xmm15); +#endif + + VM_Version::clean_cpuFeatures(); + // // cpuid(0x7) Structured Extended Features // @@ -339,6 +385,14 @@ class VM_Version_StubGenerator: public StubCodeGenerator { }; +void VM_Version::get_cpu_info_wrapper() { + get_cpu_info_stub(&_cpuid_info); +} + +#ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED + #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f() +#endif + void VM_Version::get_processor_features() { _cpu = 4; // 486 by default @@ -349,7 +403,11 @@ void VM_Version::get_processor_features() { if (!Use486InstrsOnly) { // Get raw processor info - getPsrInfo_stub(&_cpuid_info); + + // Some platforms (like Win*) need a wrapper around here + // in order to properly handle SEGV for YMM registers test. + CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(get_cpu_info_wrapper); + assert_is_initialized(); _cpu = extended_cpu_family(); _model = extended_cpu_model(); @@ -429,7 +487,7 @@ void VM_Version::get_processor_features() { } char buf[256]; - jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, (supports_cmov() ? ", cmov" : ""), @@ -446,8 +504,9 @@ void VM_Version::get_processor_features() { (supports_avx() ? ", avx" : ""), (supports_avx2() ? ", avx2" : ""), (supports_aes() ? ", aes" : ""), - (supports_clmul() ? ", clmul" : ""), + (supports_clmul() ? ", clmul" : ""), (supports_erms() ? ", erms" : ""), + (supports_rtm() ? ", rtm" : ""), (supports_mmx_ext() ? ", mmxext" : ""), (supports_3dnow_prefetch() ? ", 3dnowpref" : ""), (supports_lzcnt() ? ", lzcnt": ""), @@ -488,7 +547,7 @@ void VM_Version::get_processor_features() { } } else if (UseAES) { if (!FLAG_IS_DEFAULT(UseAES)) - warning("AES instructions not available on this CPU"); + warning("AES instructions are not available on this CPU"); FLAG_SET_DEFAULT(UseAES, false); } @@ -521,10 +580,57 @@ void VM_Version::get_processor_features() { } } else if (UseAESIntrinsics) { if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) - warning("AES intrinsics not available on this CPU"); + warning("AES intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } + // Adjust RTM (Restricted Transactional Memory) flags + if (!supports_rtm() && UseRTMLocking) { + // Can't continue because UseRTMLocking affects UseBiasedLocking flag + // setting during arguments processing. See use_biased_locking(). + // VM_Version_init() is executed after UseBiasedLocking is used + // in Thread::allocate(). + vm_exit_during_initialization("RTM instructions are not available on this CPU"); + } + +#if INCLUDE_RTM_OPT + if (UseRTMLocking) { + if (!FLAG_IS_CMDLINE(UseRTMLocking)) { + // RTM locking should be used only for applications with + // high lock contention. For now we do not use it by default. + vm_exit_during_initialization("UseRTMLocking flag should be only set on command line"); + } + if (!is_power_of_2(RTMTotalCountIncrRate)) { + warning("RTMTotalCountIncrRate must be a power of 2, resetting it to 64"); + FLAG_SET_DEFAULT(RTMTotalCountIncrRate, 64); + } + if (RTMAbortRatio < 0 || RTMAbortRatio > 100) { + warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50"); + FLAG_SET_DEFAULT(RTMAbortRatio, 50); + } + } else { // !UseRTMLocking + if (UseRTMForStackLocks) { + if (!FLAG_IS_DEFAULT(UseRTMForStackLocks)) { + warning("UseRTMForStackLocks flag should be off when UseRTMLocking flag is off"); + } + FLAG_SET_DEFAULT(UseRTMForStackLocks, false); + } + if (UseRTMDeopt) { + FLAG_SET_DEFAULT(UseRTMDeopt, false); + } + if (PrintPreciseRTMLockingStatistics) { + FLAG_SET_DEFAULT(PrintPreciseRTMLockingStatistics, false); + } + } +#else + if (UseRTMLocking) { + // Only C2 does RTM locking optimization. + // Can't continue because UseRTMLocking affects UseBiasedLocking flag + // setting during arguments processing. See use_biased_locking(). + vm_exit_during_initialization("RTM locking optimization is not supported in this VM"); + } +#endif + #ifdef COMPILER2 if (UseFPUForSpilling) { if (UseSSE < 2) { @@ -540,14 +646,28 @@ void VM_Version::get_processor_features() { if (MaxVectorSize > 32) { FLAG_SET_DEFAULT(MaxVectorSize, 32); } - if (MaxVectorSize > 16 && UseAVX == 0) { - // Only supported with AVX+ + if (MaxVectorSize > 16 && (UseAVX == 0 || !os_supports_avx_vectors())) { + // 32 bytes vectors (in YMM) are only supported with AVX+ FLAG_SET_DEFAULT(MaxVectorSize, 16); } if (UseSSE < 2) { - // Only supported with SSE2+ + // Vectors (in XMM) are only supported with SSE2+ FLAG_SET_DEFAULT(MaxVectorSize, 0); } +#ifdef ASSERT + if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) { + tty->print_cr("State of YMM registers after signal handle:"); + int nreg = 2 LP64_ONLY(+2); + const char* ymm_name[4] = {"0", "7", "8", "15"}; + for (int i = 0; i < nreg; i++) { + tty->print("YMM%s:", ymm_name[i]); + for (int j = 7; j >=0; j--) { + tty->print(" %x", _cpuid_info.ymm_save[i*8 + j]); + } + tty->cr(); + } + } +#endif } #endif @@ -678,14 +798,6 @@ void VM_Version::get_processor_features() { } } } -#if defined(COMPILER2) && defined(_ALLBSD_SOURCE) - if (MaxVectorSize > 16) { - // Limit vectors size to 16 bytes on BSD until it fixes - // restoring upper 128bit of YMM registers on return - // from signal handler. - FLAG_SET_DEFAULT(MaxVectorSize, 16); - } -#endif // COMPILER2 // Use count leading zeros count instruction if available. if (supports_lzcnt()) { @@ -814,6 +926,11 @@ void VM_Version::get_processor_features() { if (UseAES) { tty->print(" UseAES=1"); } +#ifdef COMPILER2 + if (MaxVectorSize > 0) { + tty->print(" MaxVectorSize=%d", MaxVectorSize); + } +#endif tty->cr(); tty->print("Allocation"); if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow_prefetch()) { @@ -856,18 +973,39 @@ void VM_Version::get_processor_features() { #endif // !PRODUCT } +bool VM_Version::use_biased_locking() { +#if INCLUDE_RTM_OPT + // RTM locking is most useful when there is high lock contention and + // low data contention. With high lock contention the lock is usually + // inflated and biased locking is not suitable for that case. + // RTM locking code requires that biased locking is off. + // Note: we can't switch off UseBiasedLocking in get_processor_features() + // because it is used by Thread::allocate() which is called before + // VM_Version::initialize(). + if (UseRTMLocking && UseBiasedLocking) { + if (FLAG_IS_DEFAULT(UseBiasedLocking)) { + FLAG_SET_DEFAULT(UseBiasedLocking, false); + } else { + warning("Biased locking is not supported with RTM locking; ignoring UseBiasedLocking flag." ); + UseBiasedLocking = false; + } + } +#endif + return UseBiasedLocking; +} + void VM_Version::initialize() { ResourceMark rm; // Making this stub must be FIRST use of assembler - stub_blob = BufferBlob::create("getPsrInfo_stub", stub_size); + stub_blob = BufferBlob::create("get_cpu_info_stub", stub_size); if (stub_blob == NULL) { - vm_exit_during_initialization("Unable to allocate getPsrInfo_stub"); + vm_exit_during_initialization("Unable to allocate get_cpu_info_stub"); } CodeBuffer c(stub_blob); VM_Version_StubGenerator g(&c); - getPsrInfo_stub = CAST_TO_FN_PTR(getPsrInfo_stub_t, - g.generate_getPsrInfo()); + get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t, + g.generate_get_cpu_info()); get_processor_features(); } diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index 07d64451870..51f6e4f2f4a 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -207,7 +207,9 @@ public: : 2, bmi2 : 1, erms : 1, - : 22; + : 1, + rtm : 1, + : 20; } bits; }; @@ -229,6 +231,9 @@ protected: // 0 if this instruction is not available static const char* _features_str; + static address _cpuinfo_segv_addr; // address of instruction which causes SEGV + static address _cpuinfo_cont_addr; // address of instruction after the one which causes SEGV + enum { CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX) CPU_CMOV = (1 << 1), @@ -254,7 +259,8 @@ protected: CPU_ERMS = (1 << 20), // enhanced 'rep movsb/stosb' instructions CPU_CLMUL = (1 << 21), // carryless multiply for CRC CPU_BMI1 = (1 << 22), - CPU_BMI2 = (1 << 23) + CPU_BMI2 = (1 << 23), + CPU_RTM = (1 << 24) // Restricted Transactional Memory instructions } cpuFeatureFlags; enum { @@ -361,6 +367,9 @@ protected: // extended control register XCR0 (the XFEATURE_ENABLED_MASK register) XemXcr0Eax xem_xcr0_eax; uint32_t xem_xcr0_edx; // reserved + + // Space to save ymm registers after signal handle + int ymm_save[8*4]; // Save ymm0, ymm7, ymm8, ymm15 }; // The actual cpuid info block @@ -438,6 +447,8 @@ protected: result |= CPU_ERMS; if (_cpuid_info.std_cpuid1_ecx.bits.clmul != 0) result |= CPU_CLMUL; + if (_cpuid_info.sef_cpuid7_ebx.bits.rtm != 0) + result |= CPU_RTM; // AMD features. if (is_amd()) { @@ -460,6 +471,21 @@ protected: return result; } + static bool os_supports_avx_vectors() { + if (!supports_avx()) { + return false; + } + // Verify that OS save/restore all bits of AVX registers + // during signal processing. + int nreg = 2 LP64_ONLY(+2); + for (int i = 0; i < 8 * nreg; i++) { // 32 bytes per ymm register + if (_cpuid_info.ymm_save[i] != ymm_test_value()) { + return false; + } + } + return true; + } + static void get_processor_features(); public: @@ -476,10 +502,27 @@ public: static ByteSize tpl_cpuidB1_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB1_eax); } static ByteSize tpl_cpuidB2_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB2_eax); } static ByteSize xem_xcr0_offset() { return byte_offset_of(CpuidInfo, xem_xcr0_eax); } + static ByteSize ymm_save_offset() { return byte_offset_of(CpuidInfo, ymm_save); } + + // The value used to check ymm register after signal handle + static int ymm_test_value() { return 0xCAFEBABE; } + + static void get_cpu_info_wrapper(); + static void set_cpuinfo_segv_addr(address pc) { _cpuinfo_segv_addr = pc; } + static bool is_cpuinfo_segv_addr(address pc) { return _cpuinfo_segv_addr == pc; } + static void set_cpuinfo_cont_addr(address pc) { _cpuinfo_cont_addr = pc; } + static address cpuinfo_cont_addr() { return _cpuinfo_cont_addr; } + + static void clean_cpuFeatures() { _cpuFeatures = 0; } + static void set_avx_cpuFeatures() { _cpuFeatures = (CPU_SSE | CPU_SSE2 | CPU_AVX); } + // Initialization static void initialize(); + // Override Abstract_VM_Version implementation + static bool use_biased_locking(); + // Asserts static void assert_is_initialized() { assert(_cpuid_info.std_cpuid1_eax.bits.family != 0, "VM_Version not initialized"); @@ -572,6 +615,7 @@ public: static bool supports_aes() { return (_cpuFeatures & CPU_AES) != 0; } static bool supports_erms() { return (_cpuFeatures & CPU_ERMS) != 0; } static bool supports_clmul() { return (_cpuFeatures & CPU_CLMUL) != 0; } + static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; } static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; } static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; } // Intel features diff --git a/hotspot/src/cpu/x86/vm/x86.ad b/hotspot/src/cpu/x86/vm/x86.ad index b0077a5f58c..b575a98a816 100644 --- a/hotspot/src/cpu/x86/vm/x86.ad +++ b/hotspot/src/cpu/x86/vm/x86.ad @@ -474,7 +474,125 @@ reg_class vectory_reg(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM %} + +//----------SOURCE BLOCK------------------------------------------------------- +// This is a block of C++ code which provides values, functions, and +// definitions necessary in the rest of the architecture description + +source_hpp %{ +// Header information of the source block. +// Method declarations/definitions which are used outside +// the ad-scope can conveniently be defined here. +// +// To keep related declarations/definitions/uses close together, +// we switch between source %{ }% and source_hpp %{ }% freely as needed. + +class CallStubImpl { + + //-------------------------------------------------------------- + //---< Used for optimization in Compile::shorten_branches >--- + //-------------------------------------------------------------- + + public: + // Size of call trampoline stub. + static uint size_call_trampoline() { + return 0; // no call trampolines on this platform + } + + // number of relocations needed by a call trampoline stub + static uint reloc_call_trampoline() { + return 0; // no call trampolines on this platform + } +}; + +class HandlerImpl { + + public: + + static int emit_exception_handler(CodeBuffer &cbuf); + static int emit_deopt_handler(CodeBuffer& cbuf); + + static uint size_exception_handler() { + // NativeCall instruction size is the same as NativeJump. + // exception handler starts out as jump and can be patched to + // a call be deoptimization. (4932387) + // Note that this value is also credited (in output.cpp) to + // the size of the code section. + return NativeJump::instruction_size; + } + +#ifdef _LP64 + static uint size_deopt_handler() { + // three 5 byte instructions + return 15; + } +#else + static uint size_deopt_handler() { + // NativeCall instruction size is the same as NativeJump. + // exception handler starts out as jump and can be patched to + // a call be deoptimization. (4932387) + // Note that this value is also credited (in output.cpp) to + // the size of the code section. + return 5 + NativeJump::instruction_size; // pushl(); jmp; + } +#endif +}; + +%} // end source_hpp + source %{ + +// Emit exception handler code. +// Stuff framesize into a register and call a VM stub routine. +int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { + + // Note that the code buffer's insts_mark is always relative to insts. + // That's why we must use the macroassembler to generate a handler. + MacroAssembler _masm(&cbuf); + address base = __ start_a_stub(size_exception_handler()); + if (base == NULL) return 0; // CodeBuffer::expand failed + int offset = __ offset(); + __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); + assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); + __ end_a_stub(); + return offset; +} + +// Emit deopt handler code. +int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { + + // Note that the code buffer's insts_mark is always relative to insts. + // That's why we must use the macroassembler to generate a handler. + MacroAssembler _masm(&cbuf); + address base = __ start_a_stub(size_deopt_handler()); + if (base == NULL) return 0; // CodeBuffer::expand failed + int offset = __ offset(); + +#ifdef _LP64 + address the_pc = (address) __ pc(); + Label next; + // push a "the_pc" on the stack without destroying any registers + // as they all may be live. + + // push address of "next" + __ call(next, relocInfo::none); // reloc none is fine since it is a disp32 + __ bind(next); + // adjust it so it matches "the_pc" + __ subptr(Address(rsp, 0), __ offset() - offset); +#else + InternalAddress here(__ pc()); + __ pushptr(here.addr()); +#endif + + __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); + assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); + __ end_a_stub(); + return offset; +} + + +//============================================================================= + // Float masks come from different places depending on platform. #ifdef _LP64 static address float_signmask() { return StubRoutines::x86::float_sign_mask(); } diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index c4820db3b07..cd4b7c730ca 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -1297,59 +1297,6 @@ uint MachUEPNode::size(PhaseRegAlloc *ra_) const { //============================================================================= -uint size_exception_handler() { - // NativeCall instruction size is the same as NativeJump. - // exception handler starts out as jump and can be patched to - // a call be deoptimization. (4932387) - // Note that this value is also credited (in output.cpp) to - // the size of the code section. - return NativeJump::instruction_size; -} - -// Emit exception handler code. Stuff framesize into a register -// and call a VM stub routine. -int emit_exception_handler(CodeBuffer& cbuf) { - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a handler. - MacroAssembler _masm(&cbuf); - address base = - __ start_a_stub(size_exception_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed - int offset = __ offset(); - __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); - assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); - __ end_a_stub(); - return offset; -} - -uint size_deopt_handler() { - // NativeCall instruction size is the same as NativeJump. - // exception handler starts out as jump and can be patched to - // a call be deoptimization. (4932387) - // Note that this value is also credited (in output.cpp) to - // the size of the code section. - return 5 + NativeJump::instruction_size; // pushl(); jmp; -} - -// Emit deopt handler code. -int emit_deopt_handler(CodeBuffer& cbuf) { - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a handler. - MacroAssembler _masm(&cbuf); - address base = - __ start_a_stub(size_exception_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed - int offset = __ offset(); - InternalAddress here(__ pc()); - __ pushptr(here.addr()); - - __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); - assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); - __ end_a_stub(); - return offset; -} int Matcher::regnum_to_fpu_offset(int regnum) { return regnum - 32; // The FP registers are in the second chunk @@ -12925,13 +12872,31 @@ instruct RethrowException() // inlined locking and unlocking +instruct cmpFastLockRTM(eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI tmp, eDXRegI scr, rRegI cx1, rRegI cx2) %{ + predicate(Compile::current()->use_rtm()); + match(Set cr (FastLock object box)); + effect(TEMP tmp, TEMP scr, TEMP cx1, TEMP cx2, USE_KILL box); + ins_cost(300); + format %{ "FASTLOCK $object,$box\t! kills $box,$tmp,$scr,$cx1,$cx2" %} + ins_encode %{ + __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, + $scr$$Register, $cx1$$Register, $cx2$$Register, + _counters, _rtm_counters, _stack_rtm_counters, + ((Method*)(ra_->C->method()->constant_encoding()))->method_data(), + true, ra_->C->profile_rtm()); + %} + ins_pipe(pipe_slow); +%} + instruct cmpFastLock(eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI tmp, eRegP scr) %{ + predicate(!Compile::current()->use_rtm()); match(Set cr (FastLock object box)); effect(TEMP tmp, TEMP scr, USE_KILL box); ins_cost(300); format %{ "FASTLOCK $object,$box\t! kills $box,$tmp,$scr" %} ins_encode %{ - __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, $scr$$Register, _counters); + __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, + $scr$$Register, noreg, noreg, _counters, NULL, NULL, NULL, false, false); %} ins_pipe(pipe_slow); %} @@ -12942,7 +12907,7 @@ instruct cmpFastUnlock(eFlagsReg cr, eRegP object, eAXRegP box, eRegP tmp ) %{ ins_cost(300); format %{ "FASTUNLOCK $object,$box\t! kills $box,$tmp" %} ins_encode %{ - __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register); + __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register, ra_->C->use_rtm()); %} ins_pipe(pipe_slow); %} diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index cebc37cc25c..2a0e29900b9 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -1439,66 +1439,9 @@ uint MachUEPNode::size(PhaseRegAlloc* ra_) const return MachNode::size(ra_); // too many variables; just compute it // the hard way } - + //============================================================================= -uint size_exception_handler() -{ - // NativeCall instruction size is the same as NativeJump. - // Note that this value is also credited (in output.cpp) to - // the size of the code section. - return NativeJump::instruction_size; -} - -// Emit exception handler code. -int emit_exception_handler(CodeBuffer& cbuf) -{ - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a handler. - MacroAssembler _masm(&cbuf); - address base = - __ start_a_stub(size_exception_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed - int offset = __ offset(); - __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); - assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); - __ end_a_stub(); - return offset; -} - -uint size_deopt_handler() -{ - // three 5 byte instructions - return 15; -} - -// Emit deopt handler code. -int emit_deopt_handler(CodeBuffer& cbuf) -{ - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a handler. - MacroAssembler _masm(&cbuf); - address base = - __ start_a_stub(size_deopt_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed - int offset = __ offset(); - address the_pc = (address) __ pc(); - Label next; - // push a "the_pc" on the stack without destroying any registers - // as they all may be live. - - // push address of "next" - __ call(next, relocInfo::none); // reloc none is fine since it is a disp32 - __ bind(next); - // adjust it so it matches "the_pc" - __ subptr(Address(rsp, 0), __ offset() - offset); - __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); - assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); - __ end_a_stub(); - return offset; -} int Matcher::regnum_to_fpu_offset(int regnum) { @@ -11387,13 +11330,31 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ // ============================================================================ // inlined locking and unlocking +instruct cmpFastLockRTM(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rdx_RegI scr, rRegI cx1, rRegI cx2) %{ + predicate(Compile::current()->use_rtm()); + match(Set cr (FastLock object box)); + effect(TEMP tmp, TEMP scr, TEMP cx1, TEMP cx2, USE_KILL box); + ins_cost(300); + format %{ "fastlock $object,$box\t! kills $box,$tmp,$scr,$cx1,$cx2" %} + ins_encode %{ + __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, + $scr$$Register, $cx1$$Register, $cx2$$Register, + _counters, _rtm_counters, _stack_rtm_counters, + ((Method*)(ra_->C->method()->constant_encoding()))->method_data(), + true, ra_->C->profile_rtm()); + %} + ins_pipe(pipe_slow); +%} + instruct cmpFastLock(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rRegP scr) %{ + predicate(!Compile::current()->use_rtm()); match(Set cr (FastLock object box)); effect(TEMP tmp, TEMP scr, USE_KILL box); ins_cost(300); format %{ "fastlock $object,$box\t! kills $box,$tmp,$scr" %} ins_encode %{ - __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, $scr$$Register, _counters); + __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, + $scr$$Register, noreg, noreg, _counters, NULL, NULL, NULL, false, false); %} ins_pipe(pipe_slow); %} @@ -11404,7 +11365,7 @@ instruct cmpFastUnlock(rFlagsReg cr, rRegP object, rax_RegP box, rRegP tmp) %{ ins_cost(300); format %{ "fastunlock $object,$box\t! kills $box,$tmp" %} ins_encode %{ - __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register); + __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register, ra_->C->use_rtm()); %} ins_pipe(pipe_slow); %} diff --git a/hotspot/src/os/aix/vm/mutex_aix.inline.hpp b/hotspot/src/os/aix/vm/mutex_aix.inline.hpp index 479032f7297..82ae899e14d 100644 --- a/hotspot/src/os/aix/vm/mutex_aix.inline.hpp +++ b/hotspot/src/os/aix/vm/mutex_aix.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,6 @@ #include "os_aix.inline.hpp" #include "runtime/interfaceSupport.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/thread.inline.hpp" #endif // OS_AIX_VM_MUTEX_AIX_INLINE_HPP diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index 33385e7a09a..8167665f66b 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,26 +60,16 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/statSampler.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/thread.inline.hpp" #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" #include "services/runtimeService.hpp" -#include "thread_aix.inline.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" #include "utilities/vmError.hpp" -#ifdef TARGET_ARCH_ppc -# include "assembler_ppc.inline.hpp" -# include "nativeInst_ppc.hpp" -#endif -#ifdef COMPILER1 -#include "c1/c1_Runtime1.hpp" -#endif -#ifdef COMPILER2 -#include "opto/runtime.hpp" -#endif // put OS-includes here (sorted alphabetically) #include @@ -378,13 +368,14 @@ void os::Aix::query_multipage_support() { assert(_page_size == SIZE_4K, "surprise!"); - // query default data page size (default page size for C-Heap, pthread stacks and .bss). + // Query default data page size (default page size for C-Heap, pthread stacks and .bss). // Default data page size is influenced either by linker options (-bdatapsize) // or by environment variable LDR_CNTRL (suboption DATAPSIZE). If none is given, // default should be 4K. size_t data_page_size = SIZE_4K; { void* p = ::malloc(SIZE_16M); + guarantee(p != NULL, "malloc failed"); data_page_size = os::Aix::query_pagesize(p); ::free(p); } @@ -511,85 +502,76 @@ query_multipage_support_end: } // end os::Aix::query_multipage_support() - -// The code for this method was initially derived from the version in os_linux.cpp +// The code for this method was initially derived from the version in os_linux.cpp. void os::init_system_properties_values() { - // The next few definitions allow the code to be verbatim: -#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal) + #define DEFAULT_LIBPATH "/usr/lib:/lib" #define EXTENSIONS_DIR "/lib/ext" #define ENDORSED_DIR "/lib/endorsed" + // Buffer that fits several sprintfs. + // Note that the space for the trailing null is provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR), // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); + // sysclasspath, java_home, dll_dir - char *home_path; - char *dll_path; - char *pslash; - char buf[MAXPATHLEN]; - os::jvm_path(buf, sizeof(buf)); + { + char *pslash; + os::jvm_path(buf, bufsize); - // Found the full path to libjvm.so. - // Now cut the path to /jre if we can. - *(strrchr(buf, '/')) = '\0'; // get rid of /libjvm.so - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; // get rid of /{client|server|hotspot} - } - - dll_path = malloc(strlen(buf) + 1); - strcpy(dll_path, buf); - Arguments::set_dll_dir(dll_path); - - if (pslash != NULL) { + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. pslash = strrchr(buf, '/'); if (pslash != NULL) { - *pslash = '\0'; // get rid of / + *pslash = '\0'; // Get rid of /{client|server|hotspot}. + } + Arguments::set_dll_dir(buf); + + if (pslash != NULL) { pslash = strrchr(buf, '/'); if (pslash != NULL) { - *pslash = '\0'; // get rid of /lib + *pslash = '\0'; // Get rid of /. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /lib. + } } } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); } - home_path = malloc(strlen(buf) + 1); - strcpy(home_path, buf); - Arguments::set_java_home(home_path); + // Where to look for native libraries. - if (!set_boot_path('/', ':')) return; - - // Where to look for native libraries - - // On Aix we get the user setting of LIBPATH + // On Aix we get the user setting of LIBPATH. // Eventually, all the library path setting will be done here. - char *ld_library_path; - - // Construct the invariant part of ld_library_path. - ld_library_path = (char *) malloc(sizeof(DEFAULT_LIBPATH)); - sprintf(ld_library_path, DEFAULT_LIBPATH); - - // Get the user setting of LIBPATH, and prepended it. - char *v = ::getenv("LIBPATH"); - if (v == NULL) { - v = ""; - } - - char *t = ld_library_path; - // That's +1 for the colon and +1 for the trailing '\0' - ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1); - sprintf(ld_library_path, "%s:%s", v, t); + // Get the user setting of LIBPATH. + const char *v = ::getenv("LIBPATH"); + const char *v_colon = ":"; + if (v == NULL) { v = ""; v_colon = ""; } + // Concatenate user and invariant part of ld_library_path. + // That's +1 for the colon and +1 for the trailing '\0'. + char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char, strlen(v) + 1 + sizeof(DEFAULT_LIBPATH) + 1, mtInternal); + sprintf(ld_library_path, "%s%s" DEFAULT_LIBPATH, v, v_colon); Arguments::set_library_path(ld_library_path); + FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal); - // Extensions directories - char* cbuf = malloc(strlen(Arguments::get_java_home()) + sizeof(EXTENSIONS_DIR)); - sprintf(cbuf, "%s" EXTENSIONS_DIR, Arguments::get_java_home()); - Arguments::set_ext_dirs(cbuf); + // Extensions directories. + sprintf(buf, "%s" EXTENSIONS_DIR, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); // Endorsed standards default directory. - cbuf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR)); - sprintf(cbuf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(cbuf); + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); -#undef malloc #undef DEFAULT_LIBPATH #undef EXTENSIONS_DIR #undef ENDORSED_DIR @@ -3593,6 +3575,11 @@ void os::Aix::check_signal_handler(int sig) { tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if (os::Aix::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Aix::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Aix::get_our_sigflags(sig)); diff --git a/hotspot/src/os/aix/vm/threadCritical_aix.cpp b/hotspot/src/os/aix/vm/threadCritical_aix.cpp index a7cc96fce35..f2d651ff7e8 100644 --- a/hotspot/src/os/aix/vm/threadCritical_aix.cpp +++ b/hotspot/src/os/aix/vm/threadCritical_aix.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "runtime/threadCritical.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/thread.inline.hpp" // put OS-includes here # include diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 830ceb3a812..2a71edf0028 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -306,9 +306,6 @@ static const char *get_home() { #endif void os::init_system_properties_values() { -// char arch[12]; -// sysinfo(SI_ARCHITECTURE, arch, sizeof(arch)); - // The next steps are taken in the product version: // // Obtain the JAVA_HOME value from the location of libjvm.so. @@ -335,199 +332,205 @@ void os::init_system_properties_values() { // Important note: if the location of libjvm.so changes this // code needs to be changed accordingly. - // The next few definitions allow the code to be verbatim: -#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal) -#define getenv(n) ::getenv(n) - -/* - * See ld(1): - * The linker uses the following search paths to locate required - * shared libraries: - * 1: ... - * ... - * 7: The default directories, normally /lib and /usr/lib. - */ +// See ld(1): +// The linker uses the following search paths to locate required +// shared libraries: +// 1: ... +// ... +// 7: The default directories, normally /lib and /usr/lib. #ifndef DEFAULT_LIBPATH #define DEFAULT_LIBPATH "/lib:/usr/lib" #endif +// Base path of extensions installed on the system. +#define SYS_EXT_DIR "/usr/java/packages" #define EXTENSIONS_DIR "/lib/ext" #define ENDORSED_DIR "/lib/endorsed" -#define REG_DIR "/usr/java/packages" -#ifdef __APPLE__ -#define SYS_EXTENSIONS_DIR "/Library/Java/Extensions" -#define SYS_EXTENSIONS_DIRS SYS_EXTENSIONS_DIR ":/Network" SYS_EXTENSIONS_DIR ":/System" SYS_EXTENSIONS_DIR ":/usr/lib/java" - const char *user_home_dir = get_home(); - // the null in SYS_EXTENSIONS_DIRS counts for the size of the colon after user_home_dir - int system_ext_size = strlen(user_home_dir) + sizeof(SYS_EXTENSIONS_DIR) + - sizeof(SYS_EXTENSIONS_DIRS); -#endif - - { - /* sysclasspath, java_home, dll_dir */ - { - char *home_path; - char *dll_path; - char *pslash; - char buf[MAXPATHLEN]; - os::jvm_path(buf, sizeof(buf)); - - // Found the full path to libjvm.so. - // Now cut the path to /jre if we can. - *(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */ - pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /{client|server|hotspot} */ - dll_path = malloc(strlen(buf) + 1); - if (dll_path == NULL) - return; - strcpy(dll_path, buf); - Arguments::set_dll_dir(dll_path); - - if (pslash != NULL) { - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; /* get rid of / (/lib on macosx) */ #ifndef __APPLE__ - pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /lib */ -#endif - } - } - home_path = malloc(strlen(buf) + 1); - if (home_path == NULL) - return; - strcpy(home_path, buf); - Arguments::set_java_home(home_path); + // Buffer that fits several sprintfs. + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); - if (!set_boot_path('/', ':')) - return; + // sysclasspath, java_home, dll_dir + { + char *pslash; + os::jvm_path(buf, bufsize); + + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /{client|server|hotspot}. } + Arguments::set_dll_dir(buf); - /* - * Where to look for native libraries - * - * Note: Due to a legacy implementation, most of the library path - * is set in the launcher. This was to accomodate linking restrictions - * on legacy Bsd implementations (which are no longer supported). - * Eventually, all the library path setting will be done here. - * - * However, to prevent the proliferation of improperly built native - * libraries, the new path component /usr/java/packages is added here. - * Eventually, all the library path setting will be done here. - */ - { - char *ld_library_path; - - /* - * Construct the invariant part of ld_library_path. Note that the - * space for the colon and the trailing null are provided by the - * nulls included by the sizeof operator (so actually we allocate - * a byte more than necessary). - */ -#ifdef __APPLE__ - ld_library_path = (char *) malloc(system_ext_size); - sprintf(ld_library_path, "%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS, user_home_dir); -#else - ld_library_path = (char *) malloc(sizeof(REG_DIR) + sizeof("/lib/") + - strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH)); - sprintf(ld_library_path, REG_DIR "/lib/%s:" DEFAULT_LIBPATH, cpu_arch); -#endif - - /* - * Get the user setting of LD_LIBRARY_PATH, and prepended it. It - * should always exist (until the legacy problem cited above is - * addressed). - */ -#ifdef __APPLE__ - // Prepend the default path with the JAVA_LIBRARY_PATH so that the app launcher code can specify a directory inside an app wrapper - char *l = getenv("JAVA_LIBRARY_PATH"); - if (l != NULL) { - char *t = ld_library_path; - /* That's +1 for the colon and +1 for the trailing '\0' */ - ld_library_path = (char *) malloc(strlen(l) + 1 + strlen(t) + 1); - sprintf(ld_library_path, "%s:%s", l, t); - free(t); + if (pslash != NULL) { + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /lib. } - - char *v = getenv("DYLD_LIBRARY_PATH"); -#else - char *v = getenv("LD_LIBRARY_PATH"); -#endif - if (v != NULL) { - char *t = ld_library_path; - /* That's +1 for the colon and +1 for the trailing '\0' */ - ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1); - sprintf(ld_library_path, "%s:%s", v, t); - free(t); - } - -#ifdef __APPLE__ - // Apple's Java6 has "." at the beginning of java.library.path. - // OpenJDK on Windows has "." at the end of java.library.path. - // OpenJDK on Linux and Solaris don't have "." in java.library.path - // at all. To ease the transition from Apple's Java6 to OpenJDK7, - // "." is appended to the end of java.library.path. Yes, this - // could cause a change in behavior, but Apple's Java6 behavior - // can be achieved by putting "." at the beginning of the - // JAVA_LIBRARY_PATH environment variable. - { - char *t = ld_library_path; - // that's +3 for appending ":." and the trailing '\0' - ld_library_path = (char *) malloc(strlen(t) + 3); - sprintf(ld_library_path, "%s:%s", t, "."); - free(t); - } -#endif - - Arguments::set_library_path(ld_library_path); - } - - /* - * Extensions directories. - * - * Note that the space for the colon and the trailing null are provided - * by the nulls included by the sizeof operator (so actually one byte more - * than necessary is allocated). - */ - { -#ifdef __APPLE__ - char *buf = malloc(strlen(Arguments::get_java_home()) + - sizeof(EXTENSIONS_DIR) + system_ext_size); - sprintf(buf, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":" - SYS_EXTENSIONS_DIRS, user_home_dir, Arguments::get_java_home()); -#else - char *buf = malloc(strlen(Arguments::get_java_home()) + - sizeof(EXTENSIONS_DIR) + sizeof(REG_DIR) + sizeof(EXTENSIONS_DIR)); - sprintf(buf, "%s" EXTENSIONS_DIR ":" REG_DIR EXTENSIONS_DIR, - Arguments::get_java_home()); -#endif - - Arguments::set_ext_dirs(buf); - } - - /* Endorsed standards default directory. */ - { - char * buf; - buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR)); - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); + } } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); } -#ifdef __APPLE__ + // Where to look for native libraries. + // + // Note: Due to a legacy implementation, most of the library path + // is set in the launcher. This was to accomodate linking restrictions + // on legacy Bsd implementations (which are no longer supported). + // Eventually, all the library path setting will be done here. + // + // However, to prevent the proliferation of improperly built native + // libraries, the new path component /usr/java/packages is added here. + // Eventually, all the library path setting will be done here. + { + // Get the user setting of LD_LIBRARY_PATH, and prepended it. It + // should always exist (until the legacy problem cited above is + // addressed). + const char *v = ::getenv("LD_LIBRARY_PATH"); + const char *v_colon = ":"; + if (v == NULL) { v = ""; v_colon = ""; } + // That's +1 for the colon and +1 for the trailing '\0'. + char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char, + strlen(v) + 1 + + sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH) + 1, + mtInternal); + sprintf(ld_library_path, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch); + Arguments::set_library_path(ld_library_path); + FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal); + } + + // Extensions directories. + sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); + + // Endorsed standards default directory. + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + +#else // __APPLE__ + +#define SYS_EXTENSIONS_DIR "/Library/Java/Extensions" +#define SYS_EXTENSIONS_DIRS SYS_EXTENSIONS_DIR ":/Network" SYS_EXTENSIONS_DIR ":/System" SYS_EXTENSIONS_DIR ":/usr/lib/java" + + const char *user_home_dir = get_home(); + // The null in SYS_EXTENSIONS_DIRS counts for the size of the colon after user_home_dir. + size_t system_ext_size = strlen(user_home_dir) + sizeof(SYS_EXTENSIONS_DIR) + + sizeof(SYS_EXTENSIONS_DIRS); + + // Buffer that fits several sprintfs. + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX3((size_t)MAXPATHLEN, // for dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + system_ext_size, // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); + + // sysclasspath, java_home, dll_dir + { + char *pslash; + os::jvm_path(buf, bufsize); + + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /{client|server|hotspot}. + } + Arguments::set_dll_dir(buf); + + if (pslash != NULL) { + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /lib. + } + } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); + } + + // Where to look for native libraries. + // + // Note: Due to a legacy implementation, most of the library path + // is set in the launcher. This was to accomodate linking restrictions + // on legacy Bsd implementations (which are no longer supported). + // Eventually, all the library path setting will be done here. + // + // However, to prevent the proliferation of improperly built native + // libraries, the new path component /usr/java/packages is added here. + // Eventually, all the library path setting will be done here. + { + // Get the user setting of LD_LIBRARY_PATH, and prepended it. It + // should always exist (until the legacy problem cited above is + // addressed). + // Prepend the default path with the JAVA_LIBRARY_PATH so that the app launcher code + // can specify a directory inside an app wrapper + const char *l = ::getenv("JAVA_LIBRARY_PATH"); + const char *l_colon = ":"; + if (l == NULL) { l = ""; l_colon = ""; } + + const char *v = ::getenv("DYLD_LIBRARY_PATH"); + const char *v_colon = ":"; + if (v == NULL) { v = ""; v_colon = ""; } + + // Apple's Java6 has "." at the beginning of java.library.path. + // OpenJDK on Windows has "." at the end of java.library.path. + // OpenJDK on Linux and Solaris don't have "." in java.library.path + // at all. To ease the transition from Apple's Java6 to OpenJDK7, + // "." is appended to the end of java.library.path. Yes, this + // could cause a change in behavior, but Apple's Java6 behavior + // can be achieved by putting "." at the beginning of the + // JAVA_LIBRARY_PATH environment variable. + char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char, + strlen(v) + 1 + strlen(l) + 1 + + system_ext_size + 3, + mtInternal); + sprintf(ld_library_path, "%s%s%s%s%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS ":.", + v, v_colon, l, l_colon, user_home_dir); + Arguments::set_library_path(ld_library_path); + FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal); + } + + // Extensions directories. + // + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator (so actually one byte more + // than necessary is allocated). + sprintf(buf, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS, + user_home_dir, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); + + // Endorsed standards default directory. + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + #undef SYS_EXTENSIONS_DIR -#endif -#undef malloc -#undef getenv +#undef SYS_EXTENSIONS_DIRS + +#endif // __APPLE__ + +#undef SYS_EXT_DIR #undef EXTENSIONS_DIR #undef ENDORSED_DIR - - // Done - return; } //////////////////////////////////////////////////////////////////////////////// @@ -3091,7 +3094,7 @@ void os::Bsd::set_signal_handler(int sig, bool set_installed) { sigAct.sa_sigaction = signalHandler; sigAct.sa_flags = SA_SIGINFO|SA_RESTART; } -#if __APPLE__ +#ifdef __APPLE__ // Needed for main thread as XNU (Mac OS X kernel) will only deliver SIGSEGV // (which starts as SIGBUS) on main thread with faulting address inside "stack+guard pages" // if the signal handler declares it will handle it on alternate stack. @@ -3374,6 +3377,11 @@ void os::Bsd::check_signal_handler(int sig) { tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if(os::Bsd::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Bsd::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Bsd::get_our_sigflags(sig)); diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 20ef1e10fb4..8c8c503f4a3 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -109,6 +109,8 @@ #define MAX_PATH (2 * K) +#define MAX_SECS 100000000 + // for timer info max values which include all bits #define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) @@ -317,9 +319,6 @@ void os::Linux::initialize_system_info() { } void os::init_system_properties_values() { -// char arch[12]; -// sysinfo(SI_ARCHITECTURE, arch, sizeof(arch)); - // The next steps are taken in the product version: // // Obtain the JAVA_HOME value from the location of libjvm.so. @@ -346,140 +345,101 @@ void os::init_system_properties_values() { // Important note: if the location of libjvm.so changes this // code needs to be changed accordingly. - // The next few definitions allow the code to be verbatim: -#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal) -#define getenv(n) ::getenv(n) - -/* - * See ld(1): - * The linker uses the following search paths to locate required - * shared libraries: - * 1: ... - * ... - * 7: The default directories, normally /lib and /usr/lib. - */ +// See ld(1): +// The linker uses the following search paths to locate required +// shared libraries: +// 1: ... +// ... +// 7: The default directories, normally /lib and /usr/lib. #if defined(AMD64) || defined(_LP64) && (defined(SPARC) || defined(PPC) || defined(S390)) #define DEFAULT_LIBPATH "/usr/lib64:/lib64:/lib:/usr/lib" #else #define DEFAULT_LIBPATH "/lib:/usr/lib" #endif +// Base path of extensions installed on the system. +#define SYS_EXT_DIR "/usr/java/packages" #define EXTENSIONS_DIR "/lib/ext" #define ENDORSED_DIR "/lib/endorsed" -#define REG_DIR "/usr/java/packages" + // Buffer that fits several sprintfs. + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); + + // sysclasspath, java_home, dll_dir { - /* sysclasspath, java_home, dll_dir */ - { - char *home_path; - char *dll_path; - char *pslash; - char buf[MAXPATHLEN]; - os::jvm_path(buf, sizeof(buf)); + char *pslash; + os::jvm_path(buf, bufsize); - // Found the full path to libjvm.so. - // Now cut the path to /jre if we can. - *(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */ + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /{client|server|hotspot}. + } + Arguments::set_dll_dir(buf); + + if (pslash != NULL) { + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /. pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /{client|server|hotspot} */ - dll_path = malloc(strlen(buf) + 1); - if (dll_path == NULL) - return; - strcpy(dll_path, buf); - Arguments::set_dll_dir(dll_path); - if (pslash != NULL) { - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; /* get rid of / */ - pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /lib */ - } + *pslash = '\0'; // Get rid of /lib. } - - home_path = malloc(strlen(buf) + 1); - if (home_path == NULL) - return; - strcpy(home_path, buf); - Arguments::set_java_home(home_path); - - if (!set_boot_path('/', ':')) - return; - } - - /* - * Where to look for native libraries - * - * Note: Due to a legacy implementation, most of the library path - * is set in the launcher. This was to accomodate linking restrictions - * on legacy Linux implementations (which are no longer supported). - * Eventually, all the library path setting will be done here. - * - * However, to prevent the proliferation of improperly built native - * libraries, the new path component /usr/java/packages is added here. - * Eventually, all the library path setting will be done here. - */ - { - char *ld_library_path; - - /* - * Construct the invariant part of ld_library_path. Note that the - * space for the colon and the trailing null are provided by the - * nulls included by the sizeof operator (so actually we allocate - * a byte more than necessary). - */ - ld_library_path = (char *) malloc(sizeof(REG_DIR) + sizeof("/lib/") + - strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH)); - sprintf(ld_library_path, REG_DIR "/lib/%s:" DEFAULT_LIBPATH, cpu_arch); - - /* - * Get the user setting of LD_LIBRARY_PATH, and prepended it. It - * should always exist (until the legacy problem cited above is - * addressed). - */ - char *v = getenv("LD_LIBRARY_PATH"); - if (v != NULL) { - char *t = ld_library_path; - /* That's +1 for the colon and +1 for the trailing '\0' */ - ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1); - sprintf(ld_library_path, "%s:%s", v, t); - } - Arguments::set_library_path(ld_library_path); - } - - /* - * Extensions directories. - * - * Note that the space for the colon and the trailing null are provided - * by the nulls included by the sizeof operator (so actually one byte more - * than necessary is allocated). - */ - { - char *buf = malloc(strlen(Arguments::get_java_home()) + - sizeof(EXTENSIONS_DIR) + sizeof(REG_DIR) + sizeof(EXTENSIONS_DIR)); - sprintf(buf, "%s" EXTENSIONS_DIR ":" REG_DIR EXTENSIONS_DIR, - Arguments::get_java_home()); - Arguments::set_ext_dirs(buf); - } - - /* Endorsed standards default directory. */ - { - char * buf; - buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR)); - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); + } } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); } -#undef malloc -#undef getenv + // Where to look for native libraries. + // + // Note: Due to a legacy implementation, most of the library path + // is set in the launcher. This was to accomodate linking restrictions + // on legacy Linux implementations (which are no longer supported). + // Eventually, all the library path setting will be done here. + // + // However, to prevent the proliferation of improperly built native + // libraries, the new path component /usr/java/packages is added here. + // Eventually, all the library path setting will be done here. + { + // Get the user setting of LD_LIBRARY_PATH, and prepended it. It + // should always exist (until the legacy problem cited above is + // addressed). + const char *v = ::getenv("LD_LIBRARY_PATH"); + const char *v_colon = ":"; + if (v == NULL) { v = ""; v_colon = ""; } + // That's +1 for the colon and +1 for the trailing '\0'. + char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char, + strlen(v) + 1 + + sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH) + 1, + mtInternal); + sprintf(ld_library_path, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch); + Arguments::set_library_path(ld_library_path); + FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal); + } + + // Extensions directories. + sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); + + // Endorsed standards default directory. + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + +#undef DEFAULT_LIBPATH +#undef SYS_EXT_DIR #undef EXTENSIONS_DIR #undef ENDORSED_DIR - - // Done - return; } //////////////////////////////////////////////////////////////////////////////// @@ -1961,7 +1921,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, +#if defined(VM_LITTLE_ENDIAN) + {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64"}, +#else {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, +#endif {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, {EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"}, {EM_ALPHA, EM_ALPHA, ELFCLASS64, ELFDATA2LSB, (char*)"Alpha"}, @@ -2434,7 +2398,6 @@ class Semaphore : public StackObj { sem_t _semaphore; }; - Semaphore::Semaphore() { sem_init(&_semaphore, 0, 0); } @@ -2456,8 +2419,22 @@ bool Semaphore::trywait() { } bool Semaphore::timedwait(unsigned int sec, int nsec) { + struct timespec ts; - unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec); + // Semaphore's are always associated with CLOCK_REALTIME + os::Linux::clock_gettime(CLOCK_REALTIME, &ts); + // see unpackTime for discussion on overflow checking + if (sec >= MAX_SECS) { + ts.tv_sec += MAX_SECS; + ts.tv_nsec = 0; + } else { + ts.tv_sec += sec; + ts.tv_nsec += nsec; + if (ts.tv_nsec >= NANOSECS_PER_SEC) { + ts.tv_nsec -= NANOSECS_PER_SEC; + ++ts.tv_sec; // note: this must be <= max_secs + } + } while (1) { int result = sem_timedwait(&_semaphore, &ts); @@ -4560,6 +4537,11 @@ void os::Linux::check_signal_handler(int sig) { tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if(os::Linux::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Linux::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Linux::get_our_sigflags(sig)); @@ -5656,7 +5638,6 @@ void os::PlatformEvent::unpark() { * is no need to track notifications. */ -#define MAX_SECS 100000000 /* * This code is common to linux and solaris and will be moved to a * common place in dolphin. diff --git a/hotspot/src/os/solaris/vm/osThread_solaris.cpp b/hotspot/src/os/solaris/vm/osThread_solaris.cpp index 9cbd632e578..76f4bd88f4a 100644 --- a/hotspot/src/os/solaris/vm/osThread_solaris.cpp +++ b/hotspot/src/os/solaris/vm/osThread_solaris.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 @@ -41,7 +41,6 @@ void OSThread::pd_initialize() { _thread_id = 0; sigemptyset(&_caller_sigmask); - _saved_interrupt_thread_state = _thread_new; _vm_created_thread = false; } diff --git a/hotspot/src/os/solaris/vm/osThread_solaris.hpp b/hotspot/src/os/solaris/vm/osThread_solaris.hpp index c3f96699421..06b5fc2ca85 100644 --- a/hotspot/src/os/solaris/vm/osThread_solaris.hpp +++ b/hotspot/src/os/solaris/vm/osThread_solaris.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 @@ -82,20 +82,6 @@ void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; } static void SR_handler(Thread* thread, ucontext_t* uc); - // *************************************************************** - // java.lang.Thread.interrupt state. - // *************************************************************** - - private: - - JavaThreadState _saved_interrupt_thread_state; // the thread state before a system call -- restored afterward - - public: - - - JavaThreadState saved_interrupt_thread_state() { return _saved_interrupt_thread_state; } - void set_saved_interrupt_thread_state(JavaThreadState state) { _saved_interrupt_thread_state = state; } - static void handle_spinlock_contention(int tries); // Used for thread local eden locking // *************************************************************** diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index d6f1341d1b5..16976d65f97 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -311,33 +311,6 @@ struct tm* os::localtime_pd(const time_t* clock, struct tm* res) { return localtime_r(clock, res); } -// interruptible infrastructure - -// setup_interruptible saves the thread state before going into an -// interruptible system call. -// The saved state is used to restore the thread to -// its former state whether or not an interrupt is received. -// Used by classloader os::read -// os::restartable_read calls skip this layer and stay in _thread_in_native - -void os::Solaris::setup_interruptible(JavaThread* thread) { - - JavaThreadState thread_state = thread->thread_state(); - - assert(thread_state != _thread_blocked, "Coming from the wrong thread"); - assert(thread_state != _thread_in_native, "Native threads skip setup_interruptible"); - OSThread* osthread = thread->osthread(); - osthread->set_saved_interrupt_thread_state(thread_state); - thread->frame_anchor()->make_walkable(thread); - ThreadStateTransition::transition(thread, thread_state, _thread_blocked); -} - -JavaThread* os::Solaris::setup_interruptible() { - JavaThread* thread = (JavaThread*)ThreadLocalStorage::thread(); - setup_interruptible(thread); - return thread; -} - void os::Solaris::try_enable_extended_io() { typedef int (*enable_extended_FILE_stdio_t)(int, int); @@ -353,41 +326,6 @@ void os::Solaris::try_enable_extended_io() { } } - -#ifdef ASSERT - -JavaThread* os::Solaris::setup_interruptible_native() { - JavaThread* thread = (JavaThread*)ThreadLocalStorage::thread(); - JavaThreadState thread_state = thread->thread_state(); - assert(thread_state == _thread_in_native, "Assumed thread_in_native"); - return thread; -} - -void os::Solaris::cleanup_interruptible_native(JavaThread* thread) { - JavaThreadState thread_state = thread->thread_state(); - assert(thread_state == _thread_in_native, "Assumed thread_in_native"); -} -#endif - -// cleanup_interruptible reverses the effects of setup_interruptible -// setup_interruptible_already_blocked() does not need any cleanup. - -void os::Solaris::cleanup_interruptible(JavaThread* thread) { - OSThread* osthread = thread->osthread(); - - ThreadStateTransition::transition(thread, _thread_blocked, osthread->saved_interrupt_thread_state()); -} - -// I/O interruption related counters called in _INTERRUPTIBLE - -void os::Solaris::bump_interrupted_before_count() { - RuntimeService::record_interrupted_before_count(); -} - -void os::Solaris::bump_interrupted_during_count() { - RuntimeService::record_interrupted_during_count(); -} - static int _processors_online = 0; jint os::Solaris::_os_thread_limit = 0; @@ -642,9 +580,6 @@ bool os::have_special_privileges() { void os::init_system_properties_values() { - char arch[12]; - sysinfo(SI_ARCHITECTURE, arch, sizeof(arch)); - // The next steps are taken in the product version: // // Obtain the JAVA_HOME value from the location of libjvm.so. @@ -671,218 +606,174 @@ void os::init_system_properties_values() { // Important note: if the location of libjvm.so changes this // code needs to be changed accordingly. - // The next few definitions allow the code to be verbatim: -#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal) -#define free(p) FREE_C_HEAP_ARRAY(char, p, mtInternal) -#define getenv(n) ::getenv(n) - +// Base path of extensions installed on the system. +#define SYS_EXT_DIR "/usr/jdk/packages" #define EXTENSIONS_DIR "/lib/ext" #define ENDORSED_DIR "/lib/endorsed" -#define COMMON_DIR "/usr/jdk/packages" + char cpu_arch[12]; + // Buffer that fits several sprintfs. + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX4((size_t)MAXPATHLEN, // For dll_dir & friends. + sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch), // invariant ld_library_path + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); + + // sysclasspath, java_home, dll_dir { - /* sysclasspath, java_home, dll_dir */ - { - char *home_path; - char *dll_path; - char *pslash; - char buf[MAXPATHLEN]; - os::jvm_path(buf, sizeof(buf)); + char *pslash; + os::jvm_path(buf, bufsize); - // Found the full path to libjvm.so. - // Now cut the path to /jre if we can. - *(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */ + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /{client|server|hotspot}. + } + Arguments::set_dll_dir(buf); + + if (pslash != NULL) { + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /. pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /{client|server|hotspot} */ - dll_path = malloc(strlen(buf) + 1); - if (dll_path == NULL) - return; - strcpy(dll_path, buf); - Arguments::set_dll_dir(dll_path); - if (pslash != NULL) { - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; /* get rid of / */ - pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /lib */ - } + *pslash = '\0'; // Get rid of /lib. } - - home_path = malloc(strlen(buf) + 1); - if (home_path == NULL) - return; - strcpy(home_path, buf); - Arguments::set_java_home(home_path); - - if (!set_boot_path('/', ':')) - return; - } - - /* - * Where to look for native libraries - */ - { - // Use dlinfo() to determine the correct java.library.path. - // - // If we're launched by the Java launcher, and the user - // does not set java.library.path explicitly on the commandline, - // the Java launcher sets LD_LIBRARY_PATH for us and unsets - // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64. In this case - // dlinfo returns LD_LIBRARY_PATH + crle settings (including - // /usr/lib), which is exactly what we want. - // - // If the user does set java.library.path, it completely - // overwrites this setting, and always has. - // - // If we're not launched by the Java launcher, we may - // get here with any/all of the LD_LIBRARY_PATH[_32|64] - // settings. Again, dlinfo does exactly what we want. - - Dl_serinfo _info, *info = &_info; - Dl_serpath *path; - char* library_path; - char *common_path; - int i; - - // determine search path count and required buffer size - if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) { - vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror()); - } - - // allocate new buffer and initialize - info = (Dl_serinfo*)malloc(_info.dls_size); - if (info == NULL) { - vm_exit_out_of_memory(_info.dls_size, OOM_MALLOC_ERROR, - "init_system_properties_values info"); - } - info->dls_size = _info.dls_size; - info->dls_cnt = _info.dls_cnt; - - // obtain search path information - if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) { - free(info); - vm_exit_during_initialization("dlinfo SERINFO request", dlerror()); - } - - path = &info->dls_serpath[0]; - - // Note: Due to a legacy implementation, most of the library path - // is set in the launcher. This was to accomodate linking restrictions - // on legacy Solaris implementations (which are no longer supported). - // Eventually, all the library path setting will be done here. - // - // However, to prevent the proliferation of improperly built native - // libraries, the new path component /usr/jdk/packages is added here. - - // Determine the actual CPU architecture. - char cpu_arch[12]; - sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch)); -#ifdef _LP64 - // If we are a 64-bit vm, perform the following translations: - // sparc -> sparcv9 - // i386 -> amd64 - if (strcmp(cpu_arch, "sparc") == 0) - strcat(cpu_arch, "v9"); - else if (strcmp(cpu_arch, "i386") == 0) - strcpy(cpu_arch, "amd64"); -#endif - - // Construct the invariant part of ld_library_path. Note that the - // space for the colon and the trailing null are provided by the - // nulls included by the sizeof operator. - size_t bufsize = sizeof(COMMON_DIR) + sizeof("/lib/") + strlen(cpu_arch); - common_path = malloc(bufsize); - if (common_path == NULL) { - free(info); - vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR, - "init_system_properties_values common_path"); - } - sprintf(common_path, COMMON_DIR "/lib/%s", cpu_arch); - - // struct size is more than sufficient for the path components obtained - // through the dlinfo() call, so only add additional space for the path - // components explicitly added here. - bufsize = info->dls_size + strlen(common_path); - library_path = malloc(bufsize); - if (library_path == NULL) { - free(info); - free(common_path); - vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR, - "init_system_properties_values library_path"); - } - library_path[0] = '\0'; - - // Construct the desired Java library path from the linker's library - // search path. - // - // For compatibility, it is optimal that we insert the additional path - // components specific to the Java VM after those components specified - // in LD_LIBRARY_PATH (if any) but before those added by the ld.so - // infrastructure. - if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it - strcpy(library_path, common_path); - } else { - int inserted = 0; - for (i = 0; i < info->dls_cnt; i++, path++) { - uint_t flags = path->dls_flags & LA_SER_MASK; - if (((flags & LA_SER_LIBPATH) == 0) && !inserted) { - strcat(library_path, common_path); - strcat(library_path, os::path_separator()); - inserted = 1; - } - strcat(library_path, path->dls_name); - strcat(library_path, os::path_separator()); - } - // eliminate trailing path separator - library_path[strlen(library_path)-1] = '\0'; - } - - // happens before argument parsing - can't use a trace flag - // tty->print_raw("init_system_properties_values: native lib path: "); - // tty->print_raw_cr(library_path); - - // callee copies into its own buffer - Arguments::set_library_path(library_path); - - free(common_path); - free(library_path); - free(info); - } - - /* - * Extensions directories. - * - * Note that the space for the colon and the trailing null are provided - * by the nulls included by the sizeof operator (so actually one byte more - * than necessary is allocated). - */ - { - char *buf = (char *) malloc(strlen(Arguments::get_java_home()) + - sizeof(EXTENSIONS_DIR) + sizeof(COMMON_DIR) + - sizeof(EXTENSIONS_DIR)); - sprintf(buf, "%s" EXTENSIONS_DIR ":" COMMON_DIR EXTENSIONS_DIR, - Arguments::get_java_home()); - Arguments::set_ext_dirs(buf); - } - - /* Endorsed standards default directory. */ - { - char * buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR)); - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); + } } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); } -#undef malloc -#undef free -#undef getenv + // Where to look for native libraries. + { + // Use dlinfo() to determine the correct java.library.path. + // + // If we're launched by the Java launcher, and the user + // does not set java.library.path explicitly on the commandline, + // the Java launcher sets LD_LIBRARY_PATH for us and unsets + // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64. In this case + // dlinfo returns LD_LIBRARY_PATH + crle settings (including + // /usr/lib), which is exactly what we want. + // + // If the user does set java.library.path, it completely + // overwrites this setting, and always has. + // + // If we're not launched by the Java launcher, we may + // get here with any/all of the LD_LIBRARY_PATH[_32|64] + // settings. Again, dlinfo does exactly what we want. + + Dl_serinfo info_sz, *info = &info_sz; + Dl_serpath *path; + char *library_path; + char *common_path = buf; + + // Determine search path count and required buffer size. + if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) { + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror()); + } + + // Allocate new buffer and initialize. + info = (Dl_serinfo*)NEW_C_HEAP_ARRAY(char, info_sz.dls_size, mtInternal); + info->dls_size = info_sz.dls_size; + info->dls_cnt = info_sz.dls_cnt; + + // Obtain search path information. + if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) { + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + FREE_C_HEAP_ARRAY(char, info, mtInternal); + vm_exit_during_initialization("dlinfo SERINFO request", dlerror()); + } + + path = &info->dls_serpath[0]; + + // Note: Due to a legacy implementation, most of the library path + // is set in the launcher. This was to accomodate linking restrictions + // on legacy Solaris implementations (which are no longer supported). + // Eventually, all the library path setting will be done here. + // + // However, to prevent the proliferation of improperly built native + // libraries, the new path component /usr/jdk/packages is added here. + + // Determine the actual CPU architecture. + sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch)); +#ifdef _LP64 + // If we are a 64-bit vm, perform the following translations: + // sparc -> sparcv9 + // i386 -> amd64 + if (strcmp(cpu_arch, "sparc") == 0) { + strcat(cpu_arch, "v9"); + } else if (strcmp(cpu_arch, "i386") == 0) { + strcpy(cpu_arch, "amd64"); + } +#endif + + // Construct the invariant part of ld_library_path. + sprintf(common_path, SYS_EXT_DIR "/lib/%s", cpu_arch); + + // Struct size is more than sufficient for the path components obtained + // through the dlinfo() call, so only add additional space for the path + // components explicitly added here. + size_t library_path_size = info->dls_size + strlen(common_path); + library_path = (char *)NEW_C_HEAP_ARRAY(char, library_path_size, mtInternal); + library_path[0] = '\0'; + + // Construct the desired Java library path from the linker's library + // search path. + // + // For compatibility, it is optimal that we insert the additional path + // components specific to the Java VM after those components specified + // in LD_LIBRARY_PATH (if any) but before those added by the ld.so + // infrastructure. + if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it. + strcpy(library_path, common_path); + } else { + int inserted = 0; + int i; + for (i = 0; i < info->dls_cnt; i++, path++) { + uint_t flags = path->dls_flags & LA_SER_MASK; + if (((flags & LA_SER_LIBPATH) == 0) && !inserted) { + strcat(library_path, common_path); + strcat(library_path, os::path_separator()); + inserted = 1; + } + strcat(library_path, path->dls_name); + strcat(library_path, os::path_separator()); + } + // Eliminate trailing path separator. + library_path[strlen(library_path)-1] = '\0'; + } + + // happens before argument parsing - can't use a trace flag + // tty->print_raw("init_system_properties_values: native lib path: "); + // tty->print_raw_cr(library_path); + + // Callee copies into its own buffer. + Arguments::set_library_path(library_path); + + FREE_C_HEAP_ARRAY(char, library_path, mtInternal); + FREE_C_HEAP_ARRAY(char, info, mtInternal); + } + + // Extensions directories. + sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); + + // Endorsed standards default directory. + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + +#undef SYS_EXT_DIR #undef EXTENSIONS_DIR #undef ENDORSED_DIR -#undef COMMON_DIR - } void os::breakpoint() { @@ -3366,11 +3257,20 @@ bool os::can_execute_large_page_memory() { // Read calls from inside the vm need to perform state transitions size_t os::read(int fd, void *buf, unsigned int nBytes) { - INTERRUPTIBLE_RETURN_INT_VM(::read(fd, buf, nBytes), os::Solaris::clear_interrupted); + size_t res; + JavaThread* thread = (JavaThread*)Thread::current(); + assert(thread->thread_state() == _thread_in_vm, "Assumed _thread_in_vm"); + ThreadBlockInVM tbiv(thread); + RESTARTABLE(::read(fd, buf, (size_t) nBytes), res); + return res; } size_t os::restartable_read(int fd, void *buf, unsigned int nBytes) { - INTERRUPTIBLE_RETURN_INT(::read(fd, buf, nBytes), os::Solaris::clear_interrupted); + size_t res; + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE(::read(fd, buf, (size_t) nBytes), res); + return res; } void os::naked_short_sleep(jlong ms) { @@ -4471,6 +4371,11 @@ void os::Solaris::check_signal_handler(int sig) { tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if(os::Solaris::get_our_sigflags(sig) != 0 && act.sa_flags != os::Solaris::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Solaris::get_our_sigflags(sig)); @@ -5305,6 +5210,8 @@ int os::fsync(int fd) { } int os::available(int fd, jlong *bytes) { + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); jlong cur, end; int mode; struct stat64 buf64; @@ -5312,14 +5219,9 @@ int os::available(int fd, jlong *bytes) { if (::fstat64(fd, &buf64) >= 0) { mode = buf64.st_mode; if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) { - /* - * XXX: is the following call interruptible? If so, this might - * need to go through the INTERRUPT_IO() wrapper as for other - * blocking, interruptible calls in this file. - */ int n,ioctl_return; - INTERRUPTIBLE(::ioctl(fd, FIONREAD, &n),ioctl_return,os::Solaris::clear_interrupted); + RESTARTABLE(::ioctl(fd, FIONREAD, &n), ioctl_return); if (ioctl_return>= 0) { *bytes = n; return 1; @@ -6250,7 +6152,11 @@ bool os::is_headless_jre() { } size_t os::write(int fd, const void *buf, unsigned int nBytes) { - INTERRUPTIBLE_RETURN_INT(::write(fd, buf, nBytes), os::Solaris::clear_interrupted); + size_t res; + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE((size_t) ::write(fd, buf, (size_t) nBytes), res); + return res; } int os::close(int fd) { @@ -6262,11 +6168,15 @@ int os::socket_close(int fd) { } int os::recv(int fd, char* buf, size_t nBytes, uint flags) { - INTERRUPTIBLE_RETURN_INT((int)::recv(fd, buf, nBytes, flags), os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::recv(fd, buf, nBytes, flags)); } int os::send(int fd, char* buf, size_t nBytes, uint flags) { - INTERRUPTIBLE_RETURN_INT((int)::send(fd, buf, nBytes, flags), os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::send(fd, buf, nBytes, flags)); } int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { @@ -6287,11 +6197,14 @@ int os::timeout(int fd, long timeout) { pfd.fd = fd; pfd.events = POLLIN; + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + gettimeofday(&t, &aNull); prevtime = ((julong)t.tv_sec * 1000) + t.tv_usec / 1000; for(;;) { - INTERRUPTIBLE_NORESTART(::poll(&pfd, 1, timeout), res, os::Solaris::clear_interrupted); + res = ::poll(&pfd, 1, timeout); if(res == OS_ERR && errno == EINTR) { if(timeout != -1) { gettimeofday(&t, &aNull); @@ -6307,17 +6220,30 @@ int os::timeout(int fd, long timeout) { int os::connect(int fd, struct sockaddr *him, socklen_t len) { int _result; - INTERRUPTIBLE_NORESTART(::connect(fd, him, len), _result,\ - os::Solaris::clear_interrupted); + _result = ::connect(fd, him, len); - // Depending on when thread interruption is reset, _result could be - // one of two values when errno == EINTR - - if (((_result == OS_INTRPT) || (_result == OS_ERR)) - && (errno == EINTR)) { + // On Solaris, when a connect() call is interrupted, the connection + // can be established asynchronously (see 6343810). Subsequent calls + // to connect() must check the errno value which has the semantic + // described below (copied from the connect() man page). Handling + // of asynchronously established connections is required for both + // blocking and non-blocking sockets. + // EINTR The connection attempt was interrupted + // before any data arrived by the delivery of + // a signal. The connection, however, will be + // established asynchronously. + // + // EINPROGRESS The socket is non-blocking, and the connec- + // tion cannot be completed immediately. + // + // EALREADY The socket is non-blocking, and a previous + // connection attempt has not yet been com- + // pleted. + // + // EISCONN The socket is already connected. + if (_result == OS_ERR && errno == EINTR) { /* restarting a connect() changes its errno semantics */ - INTERRUPTIBLE(::connect(fd, him, len), _result,\ - os::Solaris::clear_interrupted); + RESTARTABLE(::connect(fd, him, len), _result); /* undo these changes */ if (_result == OS_ERR) { if (errno == EALREADY) { @@ -6335,20 +6261,23 @@ int os::accept(int fd, struct sockaddr* him, socklen_t* len) { if (fd < 0) { return OS_ERR; } - INTERRUPTIBLE_RETURN_INT((int)::accept(fd, him, len),\ - os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::accept(fd, him, len)); } int os::recvfrom(int fd, char* buf, size_t nBytes, uint flags, sockaddr* from, socklen_t* fromlen) { - INTERRUPTIBLE_RETURN_INT((int)::recvfrom(fd, buf, nBytes, flags, from, fromlen),\ - os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::recvfrom(fd, buf, nBytes, flags, from, fromlen)); } int os::sendto(int fd, char* buf, size_t len, uint flags, struct sockaddr* to, socklen_t tolen) { - INTERRUPTIBLE_RETURN_INT((int)::sendto(fd, buf, len, flags, to, tolen),\ - os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::sendto(fd, buf, len, flags, to, tolen)); } int os::socket_available(int fd, jint *pbytes) { @@ -6363,8 +6292,9 @@ int os::socket_available(int fd, jint *pbytes) { } int os::bind(int fd, struct sockaddr* him, socklen_t len) { - INTERRUPTIBLE_RETURN_INT_NORESTART(::bind(fd, him, len),\ - os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + return ::bind(fd, him, len); } // Get the default path to the core file diff --git a/hotspot/src/os/solaris/vm/os_solaris.hpp b/hotspot/src/os/solaris/vm/os_solaris.hpp index 0485346914a..99a0da0f279 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 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 @@ -311,24 +311,6 @@ class Solaris { outdata, validity) : -1; } - enum { - clear_interrupted = true - }; - static void setup_interruptible(JavaThread* thread); - static void setup_interruptible_already_blocked(JavaThread* thread); - static JavaThread* setup_interruptible(); - static void cleanup_interruptible(JavaThread* thread); - - // perf counter incrementers used by _INTERRUPTIBLE - - static void bump_interrupted_before_count(); - static void bump_interrupted_during_count(); - -#ifdef ASSERT - static JavaThread* setup_interruptible_native(); - static void cleanup_interruptible_native(JavaThread* thread); -#endif - static sigset_t* unblocked_signals(); static sigset_t* vm_signals(); static sigset_t* allowdebug_blocked_signals(); diff --git a/hotspot/src/os/solaris/vm/os_solaris.inline.hpp b/hotspot/src/os/solaris/vm/os_solaris.inline.hpp index d7d53f223fc..72a9b0b7059 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.inline.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.inline.hpp @@ -111,104 +111,7 @@ inline int os::closedir(DIR *dirp) { ////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -// macros for interruptible io and system calls and system call restarting - -#define _INTERRUPTIBLE(_setup, _cmd, _result, _thread, _clear, _before, _after, _int_enable) \ -do { \ - _setup; \ - _before; \ - OSThread* _osthread = _thread->osthread(); \ - if (_int_enable && _thread->has_last_Java_frame()) { \ - /* this is java interruptible io stuff */ \ - if (os::is_interrupted(_thread, _clear)) { \ - os::Solaris::bump_interrupted_before_count(); \ - _result = OS_INTRPT; \ - } else { \ - /* _cmd always expands to an assignment to _result */ \ - if ((_cmd) < 0 && errno == EINTR \ - && os::is_interrupted(_thread, _clear)) { \ - os::Solaris::bump_interrupted_during_count(); \ - _result = OS_INTRPT; \ - } \ - } \ - } else { \ - /* this is normal blocking io stuff */ \ - _cmd; \ - } \ - _after; \ -} while(false) - -// Interruptible io support + restarting of interrupted system calls - -#ifndef ASSERT - -#define INTERRUPTIBLE(_cmd, _result, _clear) do { \ - _INTERRUPTIBLE( JavaThread* _thread = (JavaThread*)ThreadLocalStorage::thread(),_result = _cmd, _result, _thread, _clear, , , UseVMInterruptibleIO); \ -} while((_result == OS_ERR) && (errno == EINTR)) - -#else - -// This adds an assertion that it is only called from thread_in_native -// The call overhead is skipped for performance in product mode -#define INTERRUPTIBLE(_cmd, _result, _clear) do { \ - _INTERRUPTIBLE(JavaThread* _thread = os::Solaris::setup_interruptible_native(), _result = _cmd, _result, _thread, _clear, , os::Solaris::cleanup_interruptible_native(_thread), UseVMInterruptibleIO ); \ -} while((_result == OS_ERR) && (errno == EINTR)) - -#endif - -// Used for calls from _thread_in_vm, not from _thread_in_native -#define INTERRUPTIBLE_VM(_cmd, _result, _clear) do { \ - _INTERRUPTIBLE(JavaThread* _thread = os::Solaris::setup_interruptible(), _result = _cmd, _result, _thread, _clear, , os::Solaris::cleanup_interruptible(_thread), UseVMInterruptibleIO ); \ -} while((_result == OS_ERR) && (errno == EINTR)) - -/* Use NORESTART when the system call cannot return EINTR, when something other - than a system call is being invoked, or when the caller must do EINTR - handling. */ - -#ifndef ASSERT - -#define INTERRUPTIBLE_NORESTART(_cmd, _result, _clear) \ - _INTERRUPTIBLE( JavaThread* _thread = (JavaThread*)ThreadLocalStorage::thread(),_result = _cmd, _result, _thread, _clear, , , UseVMInterruptibleIO) - -#else - -// This adds an assertion that it is only called from thread_in_native -// The call overhead is skipped for performance in product mode -#define INTERRUPTIBLE_NORESTART(_cmd, _result, _clear) \ - _INTERRUPTIBLE(JavaThread* _thread = os::Solaris::setup_interruptible_native(), _result = _cmd, _result, _thread, _clear, , os::Solaris::cleanup_interruptible_native(_thread), UseVMInterruptibleIO ) - -#endif - -// Don't attend to UseVMInterruptibleIO. Always allow interruption. -// Also assumes that it is called from the _thread_blocked state. -// Used by os_sleep(). - -#define INTERRUPTIBLE_NORESTART_VM_ALWAYS(_cmd, _result, _thread, _clear) \ - _INTERRUPTIBLE(os::Solaris::setup_interruptible_already_blocked(_thread), _result = _cmd, _result, _thread, _clear, , , true ) - -#define INTERRUPTIBLE_RETURN_INT(_cmd, _clear) do { \ - int _result; \ - do { \ - INTERRUPTIBLE(_cmd, _result, _clear); \ - } while((_result == OS_ERR) && (errno == EINTR)); \ - return _result; \ -} while(false) - -#define INTERRUPTIBLE_RETURN_INT_VM(_cmd, _clear) do { \ - int _result; \ - do { \ - INTERRUPTIBLE_VM(_cmd, _result, _clear); \ - } while((_result == OS_ERR) && (errno == EINTR)); \ - return _result; \ -} while(false) - -#define INTERRUPTIBLE_RETURN_INT_NORESTART(_cmd, _clear) do { \ - int _result; \ - INTERRUPTIBLE_NORESTART(_cmd, _result, _clear); \ - return _result; \ -} while(false) - -/* Use the RESTARTABLE macros when interruptible io is not needed */ +// macros for restartable system calls #define RESTARTABLE(_cmd, _result) do { \ do { \ diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 69fb8bc0600..9f0f8a40ca6 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -2425,6 +2425,12 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { } } + if ((exception_code == EXCEPTION_ACCESS_VIOLATION) && + VM_Version::is_cpuinfo_segv_addr(pc)) { + // Verify that OS save/restore AVX registers. + return Handle_Exception(exceptionInfo, VM_Version::cpuinfo_cont_addr()); + } + if (t != NULL && t->is_Java_thread()) { JavaThread* thread = (JavaThread*) t; bool in_java = thread->thread_state() == _thread_in_Java; @@ -2696,7 +2702,6 @@ address os::win32::fast_jni_accessor_wrapper(BasicType type) { } #endif -#ifndef PRODUCT void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) { // Install a win32 structured exception handler around the test // function call so the VM can generate an error dump if needed. @@ -2707,7 +2712,6 @@ void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) { // Nothing to do. } } -#endif // Virtual Memory diff --git a/hotspot/src/os/windows/vm/os_windows.hpp b/hotspot/src/os/windows/vm/os_windows.hpp index eaf751ec561..f3ea83d8242 100644 --- a/hotspot/src/os/windows/vm/os_windows.hpp +++ b/hotspot/src/os/windows/vm/os_windows.hpp @@ -101,9 +101,7 @@ class win32 { static address fast_jni_accessor_wrapper(BasicType); #endif -#ifndef PRODUCT static void call_test_func_with_wrapper(void (*funcPtr)(void)); -#endif // filter function to ignore faults on serializations page static LONG WINAPI serialize_fault_filter(struct _EXCEPTION_POINTERS* e); diff --git a/hotspot/src/os/windows/vm/os_windows.inline.hpp b/hotspot/src/os/windows/vm/os_windows.inline.hpp index a6d20d90b33..f014fc9eb56 100644 --- a/hotspot/src/os/windows/vm/os_windows.inline.hpp +++ b/hotspot/src/os/windows/vm/os_windows.inline.hpp @@ -111,9 +111,7 @@ inline bool os::supports_monotonic_clock() { return win32::_has_performance_count; } -#ifndef PRODUCT - #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \ - os::win32::call_test_func_with_wrapper(f) -#endif +#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \ + os::win32::call_test_func_with_wrapper(f) #endif // OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP diff --git a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp index f2bbfb34b9e..8573cf33e73 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,8 +49,8 @@ #include "runtime/osThread.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/thread.inline.hpp" #include "runtime/timer.hpp" -#include "thread_aix.inline.hpp" #include "utilities/events.hpp" #include "utilities/vmError.hpp" #ifdef COMPILER1 diff --git a/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp index fa7ebf72bc4..69d2f1dd5ca 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,14 @@ #include "precompiled.hpp" #include "runtime/threadLocalStorage.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/thread.hpp" void ThreadLocalStorage::generate_code_for_get_thread() { - // nothing we can do here for user-level thread + // Nothing we can do here for user-level thread. } void ThreadLocalStorage::pd_init() { - // Nothing to do + // Nothing to do. } void ThreadLocalStorage::pd_set_thread(Thread* thread) { diff --git a/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp index 6e8572490ca..96a09b2787f 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ */ #include "precompiled.hpp" -#include "runtime/frame.inline.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/frame.hpp" +#include "runtime/thread.hpp" // Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Aix/PPC. bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) { diff --git a/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp b/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp index 0da430230a8..4bc678e9d59 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp @@ -42,7 +42,6 @@ define_pd_global(intx, VMThreadStackSize, 512); #endif // AMD64 define_pd_global(intx, CompilerThreadStackSize, 0); -define_pd_global(uintx, SurvivorRatio, 8); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); diff --git a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp index df24bcdc594..5718a791959 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp @@ -492,6 +492,11 @@ JVM_handle_bsd_signal(int sig, } } + if ((sig == SIGSEGV || sig == SIGBUS) && VM_Version::is_cpuinfo_segv_addr(pc)) { + // Verify that OS save/restore AVX registers. + stub = VM_Version::cpuinfo_cont_addr(); + } + // We test if stub is already set (by the stack overflow code // above) so it is not overwritten by the code that follows. This // check is not required on other platforms, because on other diff --git a/hotspot/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp b/hotspot/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp new file mode 100644 index 00000000000..d1a9e98d677 --- /dev/null +++ b/hotspot/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Google Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP +#define OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP + +#if defined(VM_LITTLE_ENDIAN) +#include + +// Efficient swapping of data bytes from Java byte +// ordering to native byte ordering and vice versa. +inline u2 Bytes::swap_u2(u2 x) { return bswap_16(x); } +inline u4 Bytes::swap_u4(u4 x) { return bswap_32(x); } +inline u8 Bytes::swap_u8(u8 x) { return bswap_64(x); } +#endif // VM_LITTLE_ENDIAN + +#endif // OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP diff --git a/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp b/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp index 77bfacd390c..92661222b07 100644 --- a/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp +++ b/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ */ #include "precompiled.hpp" -#include "runtime/frame.inline.hpp" -#include "thread_linux.inline.hpp" +#include "runtime/frame.hpp" +#include "runtime/thread.hpp" // Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Linux/PPC. bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) { diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index a7fa497c871..d269d38ac59 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -338,6 +338,11 @@ JVM_handle_linux_signal(int sig, } } + if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) { + // Verify that OS save/restore AVX registers. + stub = VM_Version::cpuinfo_cont_addr(); + } + if (thread->thread_state() == _thread_in_Java) { // Java thread running in Java code => find exception handler if any // a fault inside compiled code, the interpreter, or a stub diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index 054a8132b3b..36bf8058a9f 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -459,6 +459,11 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, } } + if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) { + // Verify that OS save/restore AVX registers. + stub = VM_Version::cpuinfo_cont_addr(); + } + if (thread->thread_state() == _thread_in_vm) { if (sig == SIGBUS && info->si_code == BUS_OBJERR && thread->doing_unsafe_access()) { stub = StubRoutines::handler_for_unsafe_access(); diff --git a/hotspot/src/share/vm/adlc/main.cpp b/hotspot/src/share/vm/adlc/main.cpp index 0e0ea74dc1a..614f0d43f10 100644 --- a/hotspot/src/share/vm/adlc/main.cpp +++ b/hotspot/src/share/vm/adlc/main.cpp @@ -243,7 +243,6 @@ int main(int argc, char *argv[]) AD.addInclude(AD._CPP_file, "vmreg_arm.inline.hpp"); #endif #ifdef TARGET_ARCH_ppc - AD.addInclude(AD._CPP_file, "assembler_ppc.inline.hpp"); AD.addInclude(AD._CPP_file, "nativeInst_ppc.hpp"); AD.addInclude(AD._CPP_file, "vmreg_ppc.inline.hpp"); #endif @@ -274,6 +273,7 @@ int main(int argc, char *argv[]) AD.addInclude(AD._DFA_file, "opto/cfgnode.hpp"); // Use PROB_MAX in predicate. AD.addInclude(AD._DFA_file, "opto/matcher.hpp"); AD.addInclude(AD._DFA_file, "opto/opcodes.hpp"); + AD.addInclude(AD._DFA_file, "opto/convertnode.hpp"); // Make sure each .cpp file starts with include lines: // files declaring and defining generators for Mach* Objects (hpp,cpp) // Generate the result files: diff --git a/hotspot/src/share/vm/adlc/output_c.cpp b/hotspot/src/share/vm/adlc/output_c.cpp index c351ed323d2..bd2393c578c 100644 --- a/hotspot/src/share/vm/adlc/output_c.cpp +++ b/hotspot/src/share/vm/adlc/output_c.cpp @@ -1582,6 +1582,8 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { if( node->is_ideal_fastlock() && new_inst->is_ideal_fastlock() ) { fprintf(fp, " ((MachFastLockNode*)n%d)->_counters = _counters;\n",cnt); + fprintf(fp, " ((MachFastLockNode*)n%d)->_rtm_counters = _rtm_counters;\n",cnt); + fprintf(fp, " ((MachFastLockNode*)n%d)->_stack_rtm_counters = _stack_rtm_counters;\n",cnt); } // Fill in the bottom_type where requested @@ -3963,6 +3965,8 @@ void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *inden } if( inst->is_ideal_fastlock() ) { fprintf(fp_cpp, "%s node->_counters = _leaf->as_FastLock()->counters();\n", indent); + fprintf(fp_cpp, "%s node->_rtm_counters = _leaf->as_FastLock()->rtm_counters();\n", indent); + fprintf(fp_cpp, "%s node->_stack_rtm_counters = _leaf->as_FastLock()->stack_rtm_counters();\n", indent); } } diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index ca8383b2542..6d7ed620be3 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -2526,7 +2526,7 @@ void LIRGenerator::do_Goto(Goto* x) { // need to free up storage used for OSR entry point LIR_Opr osrBuffer = block()->next()->operand(); BasicTypeList signature; - signature.append(T_INT); + signature.append(NOT_LP64(T_INT) LP64_ONLY(T_LONG)); // pass a pointer to osrBuffer CallingConvention* cc = frame_map()->c_calling_convention(&signature); __ move(osrBuffer, cc->args()->at(0)); __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_end), diff --git a/hotspot/src/share/vm/c1/c1_globals.hpp b/hotspot/src/share/vm/c1/c1_globals.hpp index 272d2bd2620..048a94a59d6 100644 --- a/hotspot/src/share/vm/c1/c1_globals.hpp +++ b/hotspot/src/share/vm/c1/c1_globals.hpp @@ -308,9 +308,6 @@ develop(intx, InstructionCountCutoff, 37000, \ "If GraphBuilder adds this many instructions, bails out") \ \ - product_pd(intx, SafepointPollOffset, \ - "Offset added to polling address (Intel only)") \ - \ develop(bool, ComputeExactFPURegisterUsage, true, \ "Compute additional live set for fpu registers to simplify fpu stack merge (Intel only)") \ \ diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 17764f12ad1..9da5f98ded5 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -961,7 +961,8 @@ void ciEnv::register_method(ciMethod* target, AbstractCompiler* compiler, int comp_level, bool has_unsafe_access, - bool has_wide_vectors) { + bool has_wide_vectors, + RTMState rtm_state) { VM_ENTRY_MARK; nmethod* nm = NULL; { @@ -1002,6 +1003,15 @@ void ciEnv::register_method(ciMethod* target, methodHandle method(THREAD, target->get_Method()); +#if INCLUDE_RTM_OPT + if (!failing() && (rtm_state != NoRTM) && + (method()->method_data() != NULL) && + (method()->method_data()->rtm_state() != rtm_state)) { + // Preemptive decompile if rtm state was changed. + record_failure("RTM state change invalidated rtm code"); + } +#endif + if (failing()) { // While not a true deoptimization, it is a preemptive decompile. MethodData* mdo = method()->method_data(); @@ -1028,13 +1038,15 @@ void ciEnv::register_method(ciMethod* target, frame_words, oop_map_set, handler_table, inc_table, compiler, comp_level); - // Free codeBlobs code_buffer->free_blob(); if (nm != NULL) { nm->set_has_unsafe_access(has_unsafe_access); nm->set_has_wide_vectors(has_wide_vectors); +#if INCLUDE_RTM_OPT + nm->set_rtm_state(rtm_state); +#endif // Record successful registration. // (Put nm into the task handle *before* publishing to the Java heap.) diff --git a/hotspot/src/share/vm/ci/ciEnv.hpp b/hotspot/src/share/vm/ci/ciEnv.hpp index 2b847f0af3c..65e4bb39434 100644 --- a/hotspot/src/share/vm/ci/ciEnv.hpp +++ b/hotspot/src/share/vm/ci/ciEnv.hpp @@ -365,7 +365,8 @@ public: AbstractCompiler* compiler, int comp_level, bool has_unsafe_access, - bool has_wide_vectors); + bool has_wide_vectors, + RTMState rtm_state = NoRTM); // Access to certain well known ciObjects. diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index c927b10a030..9cbed6f0d69 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -581,14 +581,14 @@ void ciMethod::assert_call_type_ok(int bci) { * Check whether profiling provides a type for the argument i to the * call at bci bci * - * @param bci bci of the call - * @param i argument number - * @return profiled type + * @param [in]bci bci of the call + * @param [in]i argument number + * @param [out]type profiled type of argument, NULL if none + * @param [out]maybe_null true if null was seen for argument + * @return true if profiling exists * - * If the profile reports that the argument may be null, return false - * at least for now. */ -ciKlass* ciMethod::argument_profiled_type(int bci, int i) { +bool ciMethod::argument_profiled_type(int bci, int i, ciKlass*& type, bool& maybe_null) { if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) { ciProfileData* data = method_data()->bci_to_data(bci); if (data != NULL) { @@ -596,82 +596,77 @@ ciKlass* ciMethod::argument_profiled_type(int bci, int i) { assert_virtual_call_type_ok(bci); ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData(); if (i >= call->number_of_arguments()) { - return NULL; - } - ciKlass* type = call->valid_argument_type(i); - if (type != NULL && !call->argument_maybe_null(i)) { - return type; + return false; } + type = call->valid_argument_type(i); + maybe_null = call->argument_maybe_null(i); + return true; } else if (data->is_CallTypeData()) { assert_call_type_ok(bci); ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData(); if (i >= call->number_of_arguments()) { - return NULL; - } - ciKlass* type = call->valid_argument_type(i); - if (type != NULL && !call->argument_maybe_null(i)) { - return type; + return false; } + type = call->valid_argument_type(i); + maybe_null = call->argument_maybe_null(i); + return true; } } } - return NULL; + return false; } /** * Check whether profiling provides a type for the return value from * the call at bci bci * - * @param bci bci of the call - * @return profiled type + * @param [in]bci bci of the call + * @param [out]type profiled type of argument, NULL if none + * @param [out]maybe_null true if null was seen for argument + * @return true if profiling exists * - * If the profile reports that the argument may be null, return false - * at least for now. */ -ciKlass* ciMethod::return_profiled_type(int bci) { +bool ciMethod::return_profiled_type(int bci, ciKlass*& type, bool& maybe_null) { if (MethodData::profile_return() && method_data() != NULL && method_data()->is_mature()) { ciProfileData* data = method_data()->bci_to_data(bci); if (data != NULL) { if (data->is_VirtualCallTypeData()) { assert_virtual_call_type_ok(bci); ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData(); - ciKlass* type = call->valid_return_type(); - if (type != NULL && !call->return_maybe_null()) { - return type; - } + type = call->valid_return_type(); + maybe_null = call->return_maybe_null(); + return true; } else if (data->is_CallTypeData()) { assert_call_type_ok(bci); ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData(); - ciKlass* type = call->valid_return_type(); - if (type != NULL && !call->return_maybe_null()) { - return type; - } + type = call->valid_return_type(); + maybe_null = call->return_maybe_null(); + return true; } } } - return NULL; + return false; } /** * Check whether profiling provides a type for the parameter i * - * @param i parameter number - * @return profiled type + * @param [in]i parameter number + * @param [out]type profiled type of parameter, NULL if none + * @param [out]maybe_null true if null was seen for parameter + * @return true if profiling exists * - * If the profile reports that the argument may be null, return false - * at least for now. */ -ciKlass* ciMethod::parameter_profiled_type(int i) { +bool ciMethod::parameter_profiled_type(int i, ciKlass*& type, bool& maybe_null) { if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) { ciParametersTypeData* parameters = method_data()->parameters_type_data(); if (parameters != NULL && i < parameters->number_of_parameters()) { - ciKlass* type = parameters->valid_parameter_type(i); - if (type != NULL && !parameters->parameter_maybe_null(i)) { - return type; - } + type = parameters->valid_parameter_type(i); + maybe_null = parameters->parameter_maybe_null(i); + return true; } } - return NULL; + return false; } diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index d7ddba87b8e..959867410cd 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -234,10 +234,10 @@ class ciMethod : public ciMetadata { ciCallProfile call_profile_at_bci(int bci); int interpreter_call_site_count(int bci); - // Does type profiling provide a useful type at this point? - ciKlass* argument_profiled_type(int bci, int i); - ciKlass* parameter_profiled_type(int i); - ciKlass* return_profiled_type(int bci); + // Does type profiling provide any useful information at this point? + bool argument_profiled_type(int bci, int i, ciKlass*& type, bool& maybe_null); + bool parameter_profiled_type(int i, ciKlass*& type, bool& maybe_null); + bool return_profiled_type(int bci, ciKlass*& type, bool& maybe_null); ciField* get_field_at_bci( int bci, bool &will_link); ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature); diff --git a/hotspot/src/share/vm/ci/ciMethodData.hpp b/hotspot/src/share/vm/ci/ciMethodData.hpp index e5b380fe70f..b1809a19d10 100644 --- a/hotspot/src/share/vm/ci/ciMethodData.hpp +++ b/hotspot/src/share/vm/ci/ciMethodData.hpp @@ -478,6 +478,18 @@ public: int invocation_count() { return _invocation_counter; } int backedge_count() { return _backedge_counter; } + +#if INCLUDE_RTM_OPT + // return cached value + int rtm_state() { + if (is_empty()) { + return NoRTM; + } else { + return get_MethodData()->rtm_state(); + } + } +#endif + // Transfer information about the method to MethodData*. // would_profile means we would like to profile this method, // meaning it's not trivial. diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 269007adcab..efd141332dc 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -135,6 +135,14 @@ void ClassLoaderData::classes_do(void f(Klass * const)) { } } +void ClassLoaderData::methods_do(void f(Method*)) { + for (Klass* k = _klasses; k != NULL; k = k->next_link()) { + if (k->oop_is_instance()) { + InstanceKlass::cast(k)->methods_do(f); + } + } +} + void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { // Lock to avoid classes being modified/added/removed during iteration MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); @@ -624,6 +632,12 @@ void ClassLoaderDataGraph::classes_do(void f(Klass* const)) { } } +void ClassLoaderDataGraph::methods_do(void f(Method*)) { + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->methods_do(f); + } +} + void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->loaded_classes_do(klass_closure); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index de29726d844..e03d1625045 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -78,6 +78,7 @@ class ClassLoaderDataGraph : public AllStatic { static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim); static void classes_do(KlassClosure* klass_closure); static void classes_do(void f(Klass* const)); + static void methods_do(void f(Method*)); static void loaded_classes_do(KlassClosure* klass_closure); static void classes_unloading_do(void f(Klass* const)); static bool do_unloading(BoolObjectClosure* is_alive); @@ -189,6 +190,7 @@ class ClassLoaderData : public CHeapObj { void classes_do(void f(Klass*)); void loaded_classes_do(KlassClosure* klass_closure); void classes_do(void f(InstanceKlass*)); + void methods_do(void f(Method*)); // Deallocate free list during class unloading. void free_deallocate_list(); diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 7cbaac925e7..c7a162960d9 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.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 @@ -61,10 +61,6 @@ class java_lang_String : AllStatic { static Handle basic_create(int length, TRAPS); - static void set_value( oop string, typeArrayOop buffer) { - assert(initialized, "Must be initialized"); - string->obj_field_put(value_offset, (oop)buffer); - } static void set_offset(oop string, int offset) { assert(initialized, "Must be initialized"); if (offset_offset > 0) { @@ -122,12 +118,26 @@ class java_lang_String : AllStatic { return hash_offset; } + static void set_value(oop string, typeArrayOop buffer) { + assert(initialized && (value_offset > 0), "Must be initialized"); + string->obj_field_put(value_offset, (oop)buffer); + } + static void set_hash(oop string, unsigned int hash) { + assert(initialized && (hash_offset > 0), "Must be initialized"); + string->int_field_put(hash_offset, hash); + } + // Accessors static typeArrayOop value(oop java_string) { assert(initialized && (value_offset > 0), "Must be initialized"); assert(is_instance(java_string), "must be java_string"); return (typeArrayOop) java_string->obj_field(value_offset); } + static unsigned int hash(oop java_string) { + assert(initialized && (hash_offset > 0), "Must be initialized"); + assert(is_instance(java_string), "must be java_string"); + return java_string->int_field(hash_offset); + } static int offset(oop java_string) { assert(initialized, "Must be initialized"); assert(is_instance(java_string), "must be java_string"); diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index d20673b1a19..e7c1a73e067 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.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 @@ -35,6 +35,9 @@ #include "oops/oop.inline2.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/hashtable.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/g1/g1StringDedup.hpp" +#endif // -------------------------------------------------------------------------- @@ -728,6 +731,15 @@ oop StringTable::intern(Handle string_or_null, jchar* name, string = java_lang_String::create_from_unicode(name, len, CHECK_NULL); } +#if INCLUDE_ALL_GCS + if (G1StringDedup::is_enabled()) { + // Deduplicate the string before it is interned. Note that we should never + // deduplicate a string after it has been interned. Doing so will counteract + // compiler optimizations done on e.g. interned string literals. + G1StringDedup::deduplicate(string()); + } +#endif + // Grab the StringTable_lock before getting the_table() because it could // change at safepoint. MutexLocker ml(StringTable_lock, THREAD); diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index ed3c0dbcb0c..655792688d3 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.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 @@ -497,6 +497,7 @@ template(int_StringBuffer_signature, "(I)Ljava/lang/StringBuffer;") \ template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \ template(int_String_signature, "(I)Ljava/lang/String;") \ + template(codesource_permissioncollection_signature, "(Ljava/security/CodeSource;Ljava/security/PermissionCollection;)V") \ /* signature symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \ \ diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index a002ee76ea4..16b4cce17ed 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -460,7 +460,9 @@ void nmethod::init_defaults() { _scavenge_root_link = NULL; _scavenge_root_state = 0; _compiler = NULL; - +#if INCLUDE_RTM_OPT + _rtm_state = NoRTM; +#endif #ifdef HAVE_DTRACE_H _trap_offset = 0; #endif // def HAVE_DTRACE_H diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 294160cdd3b..2c36de2c9dd 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -193,6 +193,12 @@ class nmethod : public CodeBlob { jbyte _scavenge_root_state; +#if INCLUDE_RTM_OPT + // RTM state at compile time. Used during deoptimization to decide + // whether to restart collecting RTM locking abort statistic again. + RTMState _rtm_state; +#endif + // Nmethod Flushing lock. If non-zero, then the nmethod is not removed // and is not made into a zombie. However, once the nmethod is made into // a zombie, it will be locked one final time if CompiledMethodUnload @@ -414,6 +420,12 @@ class nmethod : public CodeBlob { bool is_zombie() const { return _state == zombie; } bool is_unloaded() const { return _state == unloaded; } +#if INCLUDE_RTM_OPT + // rtm state accessing and manipulating + RTMState rtm_state() const { return _rtm_state; } + void set_rtm_state(RTMState state) { _rtm_state = state; } +#endif + // Make the nmethod non entrant. The nmethod will continue to be // alive. It is used when an uncommon trap happens. Returns true // if this thread changed the state of the nmethod or false if diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp index 6c911328a77..1c9f4cba5f2 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp @@ -116,10 +116,6 @@ class MarkRefsIntoClosure: public CMSOopsInGenClosure { MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; class Par_MarkRefsIntoClosure: public CMSOopsInGenClosure { @@ -132,10 +128,6 @@ class Par_MarkRefsIntoClosure: public CMSOopsInGenClosure { Par_MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; // A variant of the above used in certain kinds of CMS @@ -152,10 +144,6 @@ class MarkRefsIntoVerifyClosure: public CMSOopsInGenClosure { CMSBitMap* cms_bm); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; // The non-parallel version (the parallel version appears further below). @@ -181,10 +169,6 @@ class PushAndMarkClosure: public CMSOopClosure { virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p) { PushAndMarkClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { PushAndMarkClosure::do_oop_work(p); } - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; // In the parallel case, the bit map and the @@ -211,10 +195,6 @@ class Par_PushAndMarkClosure: public CMSOopClosure { virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p) { Par_PushAndMarkClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { Par_PushAndMarkClosure::do_oop_work(p); } - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; // The non-parallel version (the parallel version appears further below). @@ -245,9 +225,6 @@ class MarkRefsIntoAndScanClosure: public CMSOopsInGenClosure { inline void do_oop_nv(oop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); } - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } void set_freelistLock(Mutex* m) { _freelistLock = m; } @@ -282,9 +259,6 @@ class Par_MarkRefsIntoAndScanClosure: public CMSOopsInGenClosure { inline void do_oop_nv(oop* p) { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); } - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } void trim_queue(uint size); }; diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index cd3e7ddc21c..00157d7eccd 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -793,53 +793,6 @@ void CompactibleFreeListSpace::oop_iterate(ExtendedOopClosure* cl) { } } -// Apply the given closure to each oop in the space \intersect memory region. -void CompactibleFreeListSpace::oop_iterate(MemRegion mr, ExtendedOopClosure* cl) { - assert_lock_strong(freelistLock()); - if (is_empty()) { - return; - } - MemRegion cur = MemRegion(bottom(), end()); - mr = mr.intersection(cur); - if (mr.is_empty()) { - return; - } - if (mr.equals(cur)) { - oop_iterate(cl); - return; - } - assert(mr.end() <= end(), "just took an intersection above"); - HeapWord* obj_addr = block_start(mr.start()); - HeapWord* t = mr.end(); - - SpaceMemRegionOopsIterClosure smr_blk(cl, mr); - if (block_is_obj(obj_addr)) { - // Handle first object specially. - oop obj = oop(obj_addr); - obj_addr += adjustObjectSize(obj->oop_iterate(&smr_blk)); - } else { - FreeChunk* fc = (FreeChunk*)obj_addr; - obj_addr += fc->size(); - } - while (obj_addr < t) { - HeapWord* obj = obj_addr; - obj_addr += block_size(obj_addr); - // If "obj_addr" is not greater than top, then the - // entire object "obj" is within the region. - if (obj_addr <= t) { - if (block_is_obj(obj)) { - oop(obj)->oop_iterate(cl); - } - } else { - // "obj" extends beyond end of region - if (block_is_obj(obj)) { - oop(obj)->oop_iterate(&smr_blk); - } - break; - } - } -} - // NOTE: In the following methods, in order to safely be able to // apply the closure to an object, we need to be sure that the // object has been initialized. We are guaranteed that an object @@ -898,42 +851,60 @@ void CompactibleFreeListSpace::object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl) { assert_locked(freelistLock()); NOT_PRODUCT(verify_objects_initialized()); - Space::object_iterate_mem(mr, cl); + assert(!mr.is_empty(), "Should be non-empty"); + // We use MemRegion(bottom(), end()) rather than used_region() below + // because the two are not necessarily equal for some kinds of + // spaces, in particular, certain kinds of free list spaces. + // We could use the more complicated but more precise: + // MemRegion(used_region().start(), round_to(used_region().end(), CardSize)) + // but the slight imprecision seems acceptable in the assertion check. + assert(MemRegion(bottom(), end()).contains(mr), + "Should be within used space"); + HeapWord* prev = cl->previous(); // max address from last time + if (prev >= mr.end()) { // nothing to do + return; + } + // This assert will not work when we go from cms space to perm + // space, and use same closure. Easy fix deferred for later. XXX YSR + // assert(prev == NULL || contains(prev), "Should be within space"); + + bool last_was_obj_array = false; + HeapWord *blk_start_addr, *region_start_addr; + if (prev > mr.start()) { + region_start_addr = prev; + blk_start_addr = prev; + // The previous invocation may have pushed "prev" beyond the + // last allocated block yet there may be still be blocks + // in this region due to a particular coalescing policy. + // Relax the assertion so that the case where the unallocated + // block is maintained and "prev" is beyond the unallocated + // block does not cause the assertion to fire. + assert((BlockOffsetArrayUseUnallocatedBlock && + (!is_in(prev))) || + (blk_start_addr == block_start(region_start_addr)), "invariant"); + } else { + region_start_addr = mr.start(); + blk_start_addr = block_start(region_start_addr); + } + HeapWord* region_end_addr = mr.end(); + MemRegion derived_mr(region_start_addr, region_end_addr); + while (blk_start_addr < region_end_addr) { + const size_t size = block_size(blk_start_addr); + if (block_is_obj(blk_start_addr)) { + last_was_obj_array = cl->do_object_bm(oop(blk_start_addr), derived_mr); + } else { + last_was_obj_array = false; + } + blk_start_addr += size; + } + if (!last_was_obj_array) { + assert((bottom() <= blk_start_addr) && (blk_start_addr <= end()), + "Should be within (closed) used space"); + assert(blk_start_addr > prev, "Invariant"); + cl->set_previous(blk_start_addr); // min address for next time + } } -// Callers of this iterator beware: The closure application should -// be robust in the face of uninitialized objects and should (always) -// return a correct size so that the next addr + size below gives us a -// valid block boundary. [See for instance, -// ScanMarkedObjectsAgainCarefullyClosure::do_object_careful() -// in ConcurrentMarkSweepGeneration.cpp.] -HeapWord* -CompactibleFreeListSpace::object_iterate_careful(ObjectClosureCareful* cl) { - assert_lock_strong(freelistLock()); - HeapWord *addr, *last; - size_t size; - for (addr = bottom(), last = end(); - addr < last; addr += size) { - FreeChunk* fc = (FreeChunk*)addr; - if (fc->is_free()) { - // Since we hold the free list lock, which protects direct - // allocation in this generation by mutators, a free object - // will remain free throughout this iteration code. - size = fc->size(); - } else { - // Note that the object need not necessarily be initialized, - // because (for instance) the free list lock does NOT protect - // object initialization. The closure application below must - // therefore be correct in the face of uninitialized objects. - size = cl->do_object_careful(oop(addr)); - if (size == 0) { - // An unparsable object found. Signal early termination. - return addr; - } - } - } - return NULL; -} // Callers of this iterator beware: The closure application should // be robust in the face of uninitialized objects and should (always) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index 59ea6c30fb8..9f01fcd54a4 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -338,10 +338,6 @@ class CompactibleFreeListSpace: public CompactibleSpace { unallocated_block() : end()); } - bool is_in(const void* p) const { - return used_region().contains(p); - } - virtual bool is_free_block(const HeapWord* p) const; // Resizing support @@ -351,7 +347,6 @@ class CompactibleFreeListSpace: public CompactibleSpace { Mutex* freelistLock() const { return &_freelistLock; } // Iteration support - void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); void oop_iterate(ExtendedOopClosure* cl); void object_iterate(ObjectClosure* blk); @@ -364,6 +359,12 @@ class CompactibleFreeListSpace: public CompactibleSpace { // obj_is_alive() to determine whether it is safe to iterate of // an object. void safe_object_iterate(ObjectClosure* blk); + + // Iterate over all objects that intersect with mr, calling "cl->do_object" + // on each. There is an exception to this: if this closure has already + // been invoked on an object, it may skip such objects in some cases. This is + // Most likely to happen in an "upwards" (ascending address) iteration of + // MemRegions. void object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl); // Requires that "mr" be entirely within the space. @@ -372,11 +373,8 @@ class CompactibleFreeListSpace: public CompactibleSpace { // terminate the iteration and return the address of the start of the // subregion that isn't done. Return of "NULL" indicates that the // iteration completed. - virtual HeapWord* - object_iterate_careful_m(MemRegion mr, - ObjectClosureCareful* cl); - virtual HeapWord* - object_iterate_careful(ObjectClosureCareful* cl); + HeapWord* object_iterate_careful_m(MemRegion mr, + ObjectClosureCareful* cl); // Override: provides a DCTO_CL specific to this kind of space. DirtyCardToOopClosure* new_dcto_cl(ExtendedOopClosure* cl, diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 5807db38eed..d71e82799d2 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -2496,7 +2496,8 @@ void CMSCollector::save_heap_summary() { } void CMSCollector::report_heap_summary(GCWhen::Type when) { - _gc_tracer_cm->report_gc_heap_summary(when, _last_heap_summary, _last_metaspace_summary); + _gc_tracer_cm->report_gc_heap_summary(when, _last_heap_summary); + _gc_tracer_cm->report_metaspace_summary(when, _last_metaspace_summary); } void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) { @@ -3162,16 +3163,6 @@ ConcurrentMarkSweepGeneration::younger_refs_iterate(OopsInGenClosure* cl) { cl->reset_generation(); } -void -ConcurrentMarkSweepGeneration::oop_iterate(MemRegion mr, ExtendedOopClosure* cl) { - if (freelistLock()->owned_by_self()) { - Generation::oop_iterate(mr, cl); - } else { - MutexLockerEx x(freelistLock(), Mutex::_no_safepoint_check_flag); - Generation::oop_iterate(mr, cl); - } -} - void ConcurrentMarkSweepGeneration::oop_iterate(ExtendedOopClosure* cl) { if (freelistLock()->owned_by_self()) { diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index 3c771ef3946..6cf2f4270b6 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -1285,7 +1285,6 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { void save_sweep_limit(); // More iteration support - virtual void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); virtual void oop_iterate(ExtendedOopClosure* cl); virtual void safe_object_iterate(ObjectClosure* cl); virtual void object_iterate(ObjectClosure* cl); @@ -1499,6 +1498,19 @@ class FalseBitMapClosure: public BitMapClosure { } }; +// A version of ObjectClosure with "memory" (see _previous_address below) +class UpwardsObjectClosure: public BoolObjectClosure { + HeapWord* _previous_address; + public: + UpwardsObjectClosure() : _previous_address(NULL) { } + void set_previous(HeapWord* addr) { _previous_address = addr; } + HeapWord* previous() { return _previous_address; } + // A return value of "true" can be used by the caller to decide + // if this object's end should *NOT* be recorded in + // _previous_address above. + virtual bool do_object_bm(oop obj, MemRegion mr) = 0; +}; + // This closure is used during the second checkpointing phase // to rescan the marked objects on the dirty cards in the mod // union table and the card table proper. It's invoked via diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index c874f56d3c2..727be275ab4 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -1809,8 +1809,8 @@ class G1NoteEndOfConcMarkClosure : public HeapRegionClosure { uint _regions_claimed; size_t _freed_bytes; FreeRegionList* _local_cleanup_list; - OldRegionSet* _old_proxy_set; - HumongousRegionSet* _humongous_proxy_set; + HeapRegionSetCount _old_regions_removed; + HeapRegionSetCount _humongous_regions_removed; HRRSCleanupTask* _hrrs_cleanup_task; double _claimed_region_time; double _max_region_time; @@ -1819,19 +1819,19 @@ public: G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1, int worker_num, FreeRegionList* local_cleanup_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, HRRSCleanupTask* hrrs_cleanup_task) : _g1(g1), _worker_num(worker_num), _max_live_bytes(0), _regions_claimed(0), _freed_bytes(0), _claimed_region_time(0.0), _max_region_time(0.0), _local_cleanup_list(local_cleanup_list), - _old_proxy_set(old_proxy_set), - _humongous_proxy_set(humongous_proxy_set), + _old_regions_removed(), + _humongous_regions_removed(), _hrrs_cleanup_task(hrrs_cleanup_task) { } size_t freed_bytes() { return _freed_bytes; } + const HeapRegionSetCount& old_regions_removed() { return _old_regions_removed; } + const HeapRegionSetCount& humongous_regions_removed() { return _humongous_regions_removed; } bool doHeapRegion(HeapRegion *hr) { if (hr->continuesHumongous()) { @@ -1844,13 +1844,22 @@ public: _regions_claimed++; hr->note_end_of_marking(); _max_live_bytes += hr->max_live_bytes(); - _g1->free_region_if_empty(hr, - &_freed_bytes, - _local_cleanup_list, - _old_proxy_set, - _humongous_proxy_set, - _hrrs_cleanup_task, - true /* par */); + + if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) { + _freed_bytes += hr->used(); + hr->set_containing_set(NULL); + if (hr->isHumongous()) { + assert(hr->startsHumongous(), "we should only see starts humongous"); + _humongous_regions_removed.increment(1u, hr->capacity()); + _g1->free_humongous_region(hr, _local_cleanup_list, true); + } else { + _old_regions_removed.increment(1u, hr->capacity()); + _g1->free_region(hr, _local_cleanup_list, true); + } + } else { + hr->rem_set()->do_cleanup_work(_hrrs_cleanup_task); + } + double region_time = (os::elapsedTime() - start); _claimed_region_time += region_time; if (region_time > _max_region_time) { @@ -1883,12 +1892,8 @@ public: void work(uint worker_id) { double start = os::elapsedTime(); FreeRegionList local_cleanup_list("Local Cleanup List"); - OldRegionSet old_proxy_set("Local Cleanup Old Proxy Set"); - HumongousRegionSet humongous_proxy_set("Local Cleanup Humongous Proxy Set"); HRRSCleanupTask hrrs_cleanup_task; G1NoteEndOfConcMarkClosure g1_note_end(_g1h, worker_id, &local_cleanup_list, - &old_proxy_set, - &humongous_proxy_set, &hrrs_cleanup_task); if (G1CollectedHeap::use_parallel_gc_threads()) { _g1h->heap_region_par_iterate_chunked(&g1_note_end, worker_id, @@ -1900,13 +1905,10 @@ public: assert(g1_note_end.complete(), "Shouldn't have yielded!"); // Now update the lists - _g1h->update_sets_after_freeing_regions(g1_note_end.freed_bytes(), - NULL /* free_list */, - &old_proxy_set, - &humongous_proxy_set, - true /* par */); + _g1h->remove_from_old_sets(g1_note_end.old_regions_removed(), g1_note_end.humongous_regions_removed()); { MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); + _g1h->decrement_summary_bytes(g1_note_end.freed_bytes()); _max_live_bytes += g1_note_end.max_live_bytes(); _freed_bytes += g1_note_end.freed_bytes(); @@ -1920,14 +1922,14 @@ public: G1HRPrinter* hr_printer = _g1h->hr_printer(); if (hr_printer->is_active()) { - HeapRegionLinkedListIterator iter(&local_cleanup_list); + FreeRegionListIterator iter(&local_cleanup_list); while (iter.more_available()) { HeapRegion* hr = iter.get_next(); hr_printer->cleanup(hr); } } - _cleanup_list->add_as_tail(&local_cleanup_list); + _cleanup_list->add_ordered(&local_cleanup_list); assert(local_cleanup_list.is_empty(), "post-condition"); HeapRegionRemSet::finish_cleanup_task(&hrrs_cleanup_task); @@ -1971,7 +1973,6 @@ void ConcurrentMark::cleanup() { return; } - HRSPhaseSetter x(HRSPhaseCleanup); g1h->verify_region_sets_optional(); if (VerifyDuringGC) { @@ -2017,8 +2018,8 @@ void ConcurrentMark::cleanup() { // that calculated by walking the marking bitmap. // Bitmaps to hold expected values - BitMap expected_region_bm(_region_bm.size(), false); - BitMap expected_card_bm(_card_bm.size(), false); + BitMap expected_region_bm(_region_bm.size(), true); + BitMap expected_card_bm(_card_bm.size(), true); G1ParVerifyFinalCountTask g1_par_verify_task(g1h, &_region_bm, @@ -2144,7 +2145,7 @@ void ConcurrentMark::completeCleanup() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - _cleanup_list.verify_optional(); + _cleanup_list.verify_list(); FreeRegionList tmp_free_list("Tmp Free List"); if (G1ConcRegionFreeingVerbose) { @@ -2157,9 +2158,9 @@ void ConcurrentMark::completeCleanup() { // so it's not necessary to take any locks while (!_cleanup_list.is_empty()) { HeapRegion* hr = _cleanup_list.remove_head(); - assert(hr != NULL, "the list was not empty"); + assert(hr != NULL, "Got NULL from a non-empty list"); hr->par_clear(); - tmp_free_list.add_as_tail(hr); + tmp_free_list.add_ordered(hr); // Instead of adding one region at a time to the secondary_free_list, // we accumulate them in the local list and move them a few at a @@ -2179,7 +2180,7 @@ void ConcurrentMark::completeCleanup() { { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); - g1h->secondary_free_list_add_as_tail(&tmp_free_list); + g1h->secondary_free_list_add(&tmp_free_list); SecondaryFreeList_lock->notify_all(); } @@ -2528,6 +2529,11 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { assert(!rp->discovery_enabled(), "Post condition"); } + if (has_overflown()) { + // We can not trust g1_is_alive if the marking stack overflowed + return; + } + g1h->unlink_string_and_symbol_table(&g1_is_alive, /* process_strings */ false, // currently strings are always roots /* process_symbols */ true); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index 383bb4a6be2..355bddfa2e0 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_HPP -#include "gc_implementation/g1/heapRegionSets.hpp" +#include "gc_implementation/g1/heapRegionSet.hpp" #include "utilities/taskqueue.hpp" class G1CollectedHeap; diff --git a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp index 7bdb98f161f..ddebcf53088 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc_implementation/g1/dirtyCardQueue.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.cpp index 7f5023b422b..d5851a6d467 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.cpp @@ -24,6 +24,14 @@ #include "precompiled.hpp" #include "gc_implementation/g1/g1BiasedArray.hpp" +#include "memory/padded.inline.hpp" + +// Allocate a new array, generic version. +address G1BiasedMappedArrayBase::create_new_base_array(size_t length, size_t elem_size) { + assert(length > 0, "just checking"); + assert(elem_size > 0, "just checking"); + return PaddedPrimitiveArray::create_unfreeable(length * elem_size); +} #ifndef PRODUCT void G1BiasedMappedArrayBase::verify_index(idx_t index) const { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp index 6b19f708556..b0b7a76e1fe 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1BIASEDARRAY_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_G1BIASEDARRAY_HPP +#include "memory/allocation.hpp" #include "utilities/debug.hpp" -#include "memory/allocation.inline.hpp" // Implements the common base functionality for arrays that contain provisions // for accessing its elements using a biased index. @@ -48,11 +48,7 @@ protected: _bias(0), _shift_by(0) { } // Allocate a new array, generic version. - static address create_new_base_array(size_t length, size_t elem_size) { - assert(length > 0, "just checking"); - assert(elem_size > 0, "just checking"); - return NEW_C_HEAP_ARRAY(u_char, length * elem_size, mtGC); - } + static address create_new_base_array(size_t length, size_t elem_size); // Initialize the members of this class. The biased start address of this array // is the bias (in elements) multiplied by the element size. diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp new file mode 100644 index 00000000000..7b23022777f --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp @@ -0,0 +1,317 @@ +/* + * 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 "code/nmethod.hpp" +#include "gc_implementation/g1/g1CodeCacheRemSet.hpp" +#include "memory/iterator.hpp" + +G1CodeRootChunk::G1CodeRootChunk() : _top(NULL), _next(NULL), _prev(NULL) { + _top = bottom(); +} + +void G1CodeRootChunk::reset() { + _next = _prev = NULL; + _top = bottom(); +} + +void G1CodeRootChunk::nmethods_do(CodeBlobClosure* cl) { + nmethod** cur = bottom(); + while (cur != _top) { + cl->do_code_blob(*cur); + cur++; + } +} + +FreeList G1CodeRootSet::_free_list; +size_t G1CodeRootSet::_num_chunks_handed_out = 0; + +G1CodeRootChunk* G1CodeRootSet::new_chunk() { + G1CodeRootChunk* result = _free_list.get_chunk_at_head(); + if (result == NULL) { + result = new G1CodeRootChunk(); + } + G1CodeRootSet::_num_chunks_handed_out++; + result->reset(); + return result; +} + +void G1CodeRootSet::free_chunk(G1CodeRootChunk* chunk) { + _free_list.return_chunk_at_head(chunk); + G1CodeRootSet::_num_chunks_handed_out--; +} + +void G1CodeRootSet::free_all_chunks(FreeList* list) { + G1CodeRootSet::_num_chunks_handed_out -= list->count(); + _free_list.prepend(list); +} + +void G1CodeRootSet::purge_chunks(size_t keep_ratio) { + size_t keep = G1CodeRootSet::_num_chunks_handed_out * keep_ratio / 100; + + if (keep >= (size_t)_free_list.count()) { + return; + } + + FreeList temp; + temp.initialize(); + temp.set_size(G1CodeRootChunk::word_size()); + + _free_list.getFirstNChunksFromList((size_t)_free_list.count() - keep, &temp); + + G1CodeRootChunk* cur = temp.get_chunk_at_head(); + while (cur != NULL) { + delete cur; + cur = temp.get_chunk_at_head(); + } +} + +size_t G1CodeRootSet::static_mem_size() { + return sizeof(_free_list) + sizeof(_num_chunks_handed_out); +} + +size_t G1CodeRootSet::fl_mem_size() { + return _free_list.count() * _free_list.size(); +} + +void G1CodeRootSet::initialize() { + _free_list.initialize(); + _free_list.set_size(G1CodeRootChunk::word_size()); +} + +G1CodeRootSet::G1CodeRootSet() : _list(), _length(0) { + _list.initialize(); + _list.set_size(G1CodeRootChunk::word_size()); +} + +G1CodeRootSet::~G1CodeRootSet() { + clear(); +} + +void G1CodeRootSet::add(nmethod* method) { + if (!contains(method)) { + // Try to add the nmethod. If there is not enough space, get a new chunk. + if (_list.head() == NULL || _list.head()->is_full()) { + G1CodeRootChunk* cur = new_chunk(); + _list.return_chunk_at_head(cur); + } + bool result = _list.head()->add(method); + guarantee(result, err_msg("Not able to add nmethod "PTR_FORMAT" to newly allocated chunk.", method)); + _length++; + } +} + +void G1CodeRootSet::remove(nmethod* method) { + G1CodeRootChunk* found = find(method); + if (found != NULL) { + bool result = found->remove(method); + guarantee(result, err_msg("could not find nmethod "PTR_FORMAT" during removal although we previously found it", method)); + // eventually free completely emptied chunk + if (found->is_empty()) { + _list.remove_chunk(found); + free(found); + } + _length--; + } + assert(!contains(method), err_msg(PTR_FORMAT" still contains nmethod "PTR_FORMAT, this, method)); +} + +nmethod* G1CodeRootSet::pop() { + do { + G1CodeRootChunk* cur = _list.head(); + if (cur == NULL) { + assert(_length == 0, "when there are no chunks, there should be no elements"); + return NULL; + } + nmethod* result = cur->pop(); + if (result != NULL) { + _length--; + return result; + } else { + free(_list.get_chunk_at_head()); + } + } while (true); +} + +G1CodeRootChunk* G1CodeRootSet::find(nmethod* method) { + G1CodeRootChunk* cur = _list.head(); + while (cur != NULL) { + if (cur->contains(method)) { + return cur; + } + cur = (G1CodeRootChunk*)cur->next(); + } + return NULL; +} + +void G1CodeRootSet::free(G1CodeRootChunk* chunk) { + free_chunk(chunk); +} + +bool G1CodeRootSet::contains(nmethod* method) { + return find(method) != NULL; +} + +void G1CodeRootSet::clear() { + free_all_chunks(&_list); + _length = 0; +} + +void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const { + G1CodeRootChunk* cur = _list.head(); + while (cur != NULL) { + cur->nmethods_do(blk); + cur = (G1CodeRootChunk*)cur->next(); + } +} + +size_t G1CodeRootSet::mem_size() { + return sizeof(this) + _list.count() * _list.size(); +} + +#ifndef PRODUCT + +void G1CodeRootSet::test() { + initialize(); + + assert(_free_list.count() == 0, "Free List must be empty"); + assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet"); + + // The number of chunks that we allocate for purge testing. + size_t const num_chunks = 10; + { + G1CodeRootSet set1; + assert(set1.is_empty(), "Code root set must be initially empty but is not."); + + set1.add((nmethod*)1); + assert(_num_chunks_handed_out == 1, + err_msg("Must have allocated and handed out one chunk, but handed out " + SIZE_FORMAT" chunks", _num_chunks_handed_out)); + assert(set1.length() == 1, err_msg("Added exactly one element, but set contains " + SIZE_FORMAT" elements", set1.length())); + + // G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which + // we cannot access. + for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) { + set1.add((nmethod*)1); + } + assert(_num_chunks_handed_out == 1, + err_msg("Duplicate detection must have prevented allocation of further " + "chunks but contains "SIZE_FORMAT, _num_chunks_handed_out)); + assert(set1.length() == 1, + err_msg("Duplicate detection should not have increased the set size but " + "is "SIZE_FORMAT, set1.length())); + + size_t num_total_after_add = G1CodeRootChunk::word_size() + 1; + for (size_t i = 0; i < num_total_after_add - 1; i++) { + set1.add((nmethod*)(2 + i)); + } + assert(_num_chunks_handed_out > 1, + "After adding more code roots, more than one chunks should have been handed out"); + assert(set1.length() == num_total_after_add, + err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they " + "need to be in the set, but there are only "SIZE_FORMAT, + num_total_after_add, set1.length())); + + size_t num_popped = 0; + while (set1.pop() != NULL) { + num_popped++; + } + assert(num_popped == num_total_after_add, + err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" " + "were added", num_popped, num_total_after_add)); + assert(_num_chunks_handed_out == 0, + err_msg("After popping all elements, all chunks must have been returned " + "but are still "SIZE_FORMAT, _num_chunks_handed_out)); + + purge_chunks(0); + assert(_free_list.count() == 0, + err_msg("After purging everything, the free list must be empty but still " + "contains "SIZE_FORMAT" chunks", _free_list.count())); + + // Add some more handed out chunks. + size_t i = 0; + while (_num_chunks_handed_out < num_chunks) { + set1.add((nmethod*)i); + i++; + } + + { + // Generate chunks on the free list. + G1CodeRootSet set2; + size_t i = 0; + while (_num_chunks_handed_out < num_chunks * 2) { + set2.add((nmethod*)i); + i++; + } + // Exit of the scope of the set2 object will call the destructor that generates + // num_chunks elements on the free list. + } + + assert(_num_chunks_handed_out == num_chunks, + err_msg("Deletion of the second set must have resulted in giving back " + "those, but there is still "SIZE_FORMAT" handed out, expecting " + SIZE_FORMAT, _num_chunks_handed_out, num_chunks)); + assert((size_t)_free_list.count() == num_chunks, + err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " + "but there are only "SIZE_FORMAT, num_chunks, _free_list.count())); + + size_t const test_percentage = 50; + purge_chunks(test_percentage); + assert(_num_chunks_handed_out == num_chunks, + err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT, + _num_chunks_handed_out)); + assert((size_t)_free_list.count() == (ssize_t)(num_chunks * test_percentage / 100), + err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks" + "but there are "SSIZE_FORMAT, test_percentage, num_chunks, + _free_list.count())); + // Purge the remainder of the chunks on the free list. + purge_chunks(0); + assert(_free_list.count() == 0, "Free List must be empty"); + assert(_num_chunks_handed_out == num_chunks, + err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set " + "but there are "SIZE_FORMAT, num_chunks, _num_chunks_handed_out)); + + // Exit of the scope of the set1 object will call the destructor that generates + // num_chunks additional elements on the free list. + } + + assert(_num_chunks_handed_out == 0, + err_msg("Deletion of the only set must have resulted in no chunks handed " + "out, but there is still "SIZE_FORMAT" handed out", _num_chunks_handed_out)); + assert((size_t)_free_list.count() == num_chunks, + err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " + "but there are only "SSIZE_FORMAT, num_chunks, _free_list.count())); + + // Restore initial state. + purge_chunks(0); + assert(_free_list.count() == 0, "Free List must be empty"); + assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet"); +} + +void TestCodeCacheRemSet_test() { + G1CodeRootSet::test(); +} +#endif diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp new file mode 100644 index 00000000000..ad8025c4b03 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp @@ -0,0 +1,188 @@ +/* + * 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_G1CODECACHEREMSET_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP + +#include "memory/allocation.hpp" +#include "memory/freeList.hpp" +#include "runtime/globals.hpp" + +class CodeBlobClosure; + +class G1CodeRootChunk : public CHeapObj { + private: + static const int NUM_ENTRIES = 32; + public: + G1CodeRootChunk* _next; + G1CodeRootChunk* _prev; + + nmethod** _top; + + nmethod* _data[NUM_ENTRIES]; + + nmethod** bottom() const { + return (nmethod**) &(_data[0]); + } + + nmethod** end() const { + return (nmethod**) &(_data[NUM_ENTRIES]); + } + + public: + G1CodeRootChunk(); + ~G1CodeRootChunk() {} + + static size_t word_size() { return (size_t)(align_size_up_(sizeof(G1CodeRootChunk), HeapWordSize) / HeapWordSize); } + + // FreeList "interface" methods + + G1CodeRootChunk* next() const { return _next; } + G1CodeRootChunk* prev() const { return _prev; } + void set_next(G1CodeRootChunk* v) { _next = v; assert(v != this, "Boom");} + void set_prev(G1CodeRootChunk* v) { _prev = v; assert(v != this, "Boom");} + void clear_next() { set_next(NULL); } + void clear_prev() { set_prev(NULL); } + + size_t size() const { return word_size(); } + + void link_next(G1CodeRootChunk* ptr) { set_next(ptr); } + void link_prev(G1CodeRootChunk* ptr) { set_prev(ptr); } + void link_after(G1CodeRootChunk* ptr) { + link_next(ptr); + if (ptr != NULL) ptr->link_prev((G1CodeRootChunk*)this); + } + + bool is_free() { return true; } + + // New G1CodeRootChunk routines + + void reset(); + + bool is_empty() const { + return _top == bottom(); + } + + bool is_full() const { + return _top == (nmethod**)end(); + } + + bool contains(nmethod* method) { + nmethod** cur = bottom(); + while (cur != _top) { + if (*cur == method) return true; + cur++; + } + return false; + } + + bool add(nmethod* method) { + if (is_full()) return false; + *_top = method; + _top++; + return true; + } + + bool remove(nmethod* method) { + nmethod** cur = bottom(); + while (cur != _top) { + if (*cur == method) { + memmove(cur, cur + 1, (_top - (cur + 1)) * sizeof(nmethod**)); + _top--; + return true; + } + cur++; + } + return false; + } + + void nmethods_do(CodeBlobClosure* blk); + + nmethod* pop() { + if (is_empty()) { + return NULL; + } + _top--; + return *_top; + } +}; + +// Implements storage for a set of code roots. +// All methods that modify the set are not thread-safe except if otherwise noted. +class G1CodeRootSet VALUE_OBJ_CLASS_SPEC { + private: + // Global free chunk list management + static FreeList _free_list; + // Total number of chunks handed out + static size_t _num_chunks_handed_out; + + static G1CodeRootChunk* new_chunk(); + static void free_chunk(G1CodeRootChunk* chunk); + // Free all elements of the given list. + static void free_all_chunks(FreeList* list); + + // Return the chunk that contains the given nmethod, NULL otherwise. + // Scans the list of chunks backwards, as this method is used to add new + // entries, which are typically added in bulk for a single nmethod. + G1CodeRootChunk* find(nmethod* method); + void free(G1CodeRootChunk* chunk); + + size_t _length; + FreeList _list; + + public: + G1CodeRootSet(); + ~G1CodeRootSet(); + + static void initialize(); + static void purge_chunks(size_t keep_ratio); + + static size_t static_mem_size(); + static size_t fl_mem_size(); + + // Search for the code blob from the recently allocated ones to find duplicates more quickly, as this + // method is likely to be repeatedly called with the same nmethod. + void add(nmethod* method); + + void remove(nmethod* method); + nmethod* pop(); + + bool contains(nmethod* method); + + void clear(); + + void nmethods_do(CodeBlobClosure* blk) const; + + bool is_empty() { return length() == 0; } + + // Length in elements + size_t length() const { return _length; } + + // Memory size in bytes taken by this set. + size_t mem_size(); + + static void test() PRODUCT_RETURN; +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index aacb4969da3..e9ef8ff5d6c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -39,6 +39,7 @@ #include "gc_implementation/g1/g1MarkSweep.hpp" #include "gc_implementation/g1/g1OopClosures.inline.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" @@ -169,14 +170,6 @@ public: int calls() { return _calls; } }; -class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure { -public: - bool do_card_ptr(jbyte* card_ptr, int worker_i) { - *card_ptr = CardTableModRefBS::dirty_card_val(); - return true; - } -}; - YoungList::YoungList(G1CollectedHeap* g1h) : _g1h(g1h), _head(NULL), _length(0), _last_sampled_rs_lengths(0), _survivor_head(NULL), _survivor_tail(NULL), _survivor_length(0) { @@ -524,7 +517,7 @@ G1CollectedHeap* G1CollectedHeap::_g1h; // Private methods. HeapRegion* -G1CollectedHeap::new_region_try_secondary_free_list() { +G1CollectedHeap::new_region_try_secondary_free_list(bool is_old) { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); while (!_secondary_free_list.is_empty() || free_regions_coming()) { if (!_secondary_free_list.is_empty()) { @@ -540,7 +533,7 @@ G1CollectedHeap::new_region_try_secondary_free_list() { assert(!_free_list.is_empty(), "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_head(); + HeapRegion* res = _free_list.remove_region(is_old); if (G1ConcRegionFreeingVerbose) { gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " "allocated "HR_FORMAT" from secondary_free_list", @@ -562,7 +555,7 @@ G1CollectedHeap::new_region_try_secondary_free_list() { return NULL; } -HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool do_expand) { +HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool is_old, bool do_expand) { assert(!isHumongous(word_size) || word_size <= HeapRegion::GrainWords, "the only time we use this to allocate a humongous region is " "when we are allocating a single humongous region"); @@ -574,19 +567,21 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool do_expand) { gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " "forced to look at the secondary_free_list"); } - res = new_region_try_secondary_free_list(); + res = new_region_try_secondary_free_list(is_old); if (res != NULL) { return res; } } } - res = _free_list.remove_head_or_null(); + + res = _free_list.remove_region(is_old); + if (res == NULL) { if (G1ConcRegionFreeingVerbose) { gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " "res == NULL, trying the secondary_free_list"); } - res = new_region_try_secondary_free_list(); + res = new_region_try_secondary_free_list(is_old); } if (res == NULL && do_expand && _expand_heap_after_alloc_failure) { // Currently, only attempts to allocate GC alloc regions set @@ -603,12 +598,9 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool do_expand) { if (expand(word_size * HeapWordSize)) { // Given that expand() succeeded in expanding the heap, and we // always expand the heap by an amount aligned to the heap - // region size, the free list should in theory not be empty. So - // it would probably be OK to use remove_head(). But the extra - // check for NULL is unlikely to be a performance issue here (we - // just expanded the heap!) so let's just be conservative and - // use remove_head_or_null(). - res = _free_list.remove_head_or_null(); + // 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); } else { _expand_heap_after_alloc_failure = false; } @@ -626,7 +618,7 @@ uint G1CollectedHeap::humongous_obj_allocate_find_first(uint num_regions, // 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, false /* do_expand */); + HeapRegion* hr = new_region(word_size, true /* is_old */, false /* do_expand */); if (hr != NULL) { first = hr->hrs_index(); } else { @@ -1298,7 +1290,6 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes(); - HRSPhaseSetter x(HRSPhaseFullGC); verify_region_sets_optional(); const bool do_clear_all_soft_refs = clear_all_soft_refs || @@ -1928,10 +1919,10 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _g1mm(NULL), _refine_cte_cl(NULL), _full_collection(false), - _free_list("Master Free List"), - _secondary_free_list("Secondary Free List"), - _old_set("Old Set"), - _humongous_set("Master Humongous Set"), + _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()), _free_regions_coming(false), _young_list(new YoungList(this)), _gc_time_stamp(0), @@ -1963,7 +1954,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : int n_queues = MAX2((int)ParallelGCThreads, 1); _task_queues = new RefToScanQueueSet(n_queues); - int n_rem_sets = HeapRegionRemSet::num_par_rem_sets(); + uint n_rem_sets = HeapRegionRemSet::num_par_rem_sets(); assert(n_rem_sets > 0, "Invariant."); _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC); @@ -2079,7 +2070,7 @@ jint G1CollectedHeap::initialize() { guarantee(HeapRegion::CardsPerRegion < max_cards_per_region, "too many cards per region"); - HeapRegionSet::set_unrealistically_long_length(max_regions() + 1); + FreeRegionList::set_unrealistically_long_length(max_regions() + 1); _bot_shared = new G1BlockOffsetSharedArray(_reserved, heap_word_size(init_byte_size)); @@ -2182,6 +2173,8 @@ jint G1CollectedHeap::initialize() { // values in the heap have been properly initialized. _g1mm = new G1MonitoringSupport(this); + G1StringDedup::initialize(); + return JNI_OK; } @@ -2369,8 +2362,12 @@ public: }; size_t G1CollectedHeap::recalculate_used() const { + double recalculate_used_start = os::elapsedTime(); + SumUsedClosure blk; heap_region_iterate(&blk); + + g1_policy()->phase_times()->record_evac_fail_recalc_used_time((os::elapsedTime() - recalculate_used_start) * 1000.0); return blk.result(); } @@ -3462,6 +3459,11 @@ void G1CollectedHeap::verify(bool silent, VerifyOption vo) { if (!silent) gclog_or_tty->print("RemSet "); rem_set()->verify(); + if (G1StringDedup::is_enabled()) { + if (!silent) gclog_or_tty->print("StrDedup "); + G1StringDedup::verify(); + } + if (failures) { gclog_or_tty->print_cr("Heap:"); // It helps to have the per-region information in the output to @@ -3479,8 +3481,13 @@ void G1CollectedHeap::verify(bool silent, VerifyOption vo) { } guarantee(!failures, "there should not have been any failures"); } else { - if (!silent) - gclog_or_tty->print("(SKIPPING roots, heapRegionSets, heapRegions, remset) "); + if (!silent) { + gclog_or_tty->print("(SKIPPING Roots, HeapRegionSets, HeapRegions, RemSet"); + if (G1StringDedup::is_enabled()) { + gclog_or_tty->print(", StrDedup"); + } + gclog_or_tty->print(") "); + } } } @@ -3522,6 +3529,29 @@ public: } }; +bool G1CollectedHeap::is_obj_dead_cond(const oop obj, + const HeapRegion* hr, + const VerifyOption vo) const { + switch (vo) { + case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj, hr); + case VerifyOption_G1UseNextMarking: return is_obj_ill(obj, hr); + case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked(); + default: ShouldNotReachHere(); + } + return false; // keep some compilers happy +} + +bool G1CollectedHeap::is_obj_dead_cond(const oop obj, + const VerifyOption vo) const { + switch (vo) { + case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj); + case VerifyOption_G1UseNextMarking: return is_obj_ill(obj); + case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked(); + default: ShouldNotReachHere(); + } + return false; // keep some compilers happy +} + void G1CollectedHeap::print_on(outputStream* st) const { st->print(" %-20s", "garbage-first heap"); st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", @@ -3573,6 +3603,9 @@ void G1CollectedHeap::print_gc_threads_on(outputStream* st) const { st->cr(); _cm->print_worker_threads_on(st); _cg1r->print_worker_threads_on(st); + if (G1StringDedup::is_enabled()) { + G1StringDedup::print_worker_threads_on(st); + } } void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const { @@ -3581,6 +3614,9 @@ void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const { } tc->do_thread(_cmThread); _cg1r->threads_do(tc); + if (G1StringDedup::is_enabled()) { + G1StringDedup::threads_do(tc); + } } void G1CollectedHeap::print_tracing_info() const { @@ -3887,7 +3923,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { print_heap_before_gc(); trace_heap_before_gc(_gc_tracer_stw); - HRSPhaseSetter x(HRSPhaseEvacuation); verify_region_sets_optional(); verify_dirty_young_regions(); @@ -4386,6 +4421,8 @@ void G1CollectedHeap::finalize_for_evac_failure() { void G1CollectedHeap::remove_self_forwarding_pointers() { assert(check_cset_heap_region_claim_values(HeapRegion::InitialClaimValue), "sanity"); + double remove_self_forwards_start = os::elapsedTime(); + G1ParRemoveSelfForwardPtrsTask rsfp_task(this); if (G1CollectedHeap::use_parallel_gc_threads()) { @@ -4413,6 +4450,8 @@ void G1CollectedHeap::remove_self_forwarding_pointers() { } _objs_with_preserved_marks.clear(true); _preserved_marks_of_objs.clear(true); + + g1_policy()->phase_times()->record_evac_fail_remove_self_forwards((os::elapsedTime() - remove_self_forwards_start) * 1000.0); } void G1CollectedHeap::push_on_evac_failure_scan_stack(oop obj) { @@ -4634,9 +4673,7 @@ bool G1ParScanThreadState::verify_task(StarTask ref) const { #endif // ASSERT void G1ParScanThreadState::trim_queue() { - assert(_evac_cl != NULL, "not set"); assert(_evac_failure_cl != NULL, "not set"); - assert(_partial_scan_cl != NULL, "not set"); StarTask ref; do { @@ -4727,6 +4764,12 @@ oop G1ParScanThreadState::copy_to_survivor_space(oop const old) { oop forward_ptr = old->forward_to_atomic(obj); if (forward_ptr == NULL) { Copy::aligned_disjoint_words((HeapWord*) old, obj_ptr, word_sz); + + // alloc_purpose is just a hint to allocate() above, recheck the type of region + // we actually allocated from and update alloc_purpose accordingly + HeapRegion* to_region = _g1h->heap_region_containing_raw(obj_ptr); + alloc_purpose = to_region->is_young() ? GCAllocForSurvived : GCAllocForTenured; + if (g1p->track_object_age(alloc_purpose)) { // We could simply do obj->incr_age(). However, this causes a // performance issue. obj->incr_age() will first check whether @@ -4754,6 +4797,13 @@ oop G1ParScanThreadState::copy_to_survivor_space(oop const old) { obj->set_mark(m); } + if (G1StringDedup::is_enabled()) { + G1StringDedup::enqueue_from_evacuation(from_region->is_young(), + to_region->is_young(), + queue_num(), + obj); + } + size_t* surv_young_words = surviving_young_words(); surv_young_words[young_index] += word_sz; @@ -4832,55 +4882,6 @@ void G1ParCopyClosure::do_oop_work(T* p) { template void G1ParCopyClosure::do_oop_work(oop* p); template void G1ParCopyClosure::do_oop_work(narrowOop* p); -template void G1ParScanPartialArrayClosure::do_oop_nv(T* p) { - assert(has_partial_array_mask(p), "invariant"); - oop from_obj = clear_partial_array_mask(p); - - assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap."); - assert(from_obj->is_objArray(), "must be obj array"); - objArrayOop from_obj_array = objArrayOop(from_obj); - // The from-space object contains the real length. - int length = from_obj_array->length(); - - assert(from_obj->is_forwarded(), "must be forwarded"); - oop to_obj = from_obj->forwardee(); - assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); - objArrayOop to_obj_array = objArrayOop(to_obj); - // We keep track of the next start index in the length field of the - // to-space object. - int next_index = to_obj_array->length(); - assert(0 <= next_index && next_index < length, - err_msg("invariant, next index: %d, length: %d", next_index, length)); - - int start = next_index; - int end = length; - int remainder = end - start; - // We'll try not to push a range that's smaller than ParGCArrayScanChunk. - if (remainder > 2 * ParGCArrayScanChunk) { - end = start + ParGCArrayScanChunk; - to_obj_array->set_length(end); - // Push the remainder before we process the range in case another - // worker has run out of things to do and can steal it. - oop* from_obj_p = set_partial_array_mask(from_obj); - _par_scan_state->push_on_queue(from_obj_p); - } else { - assert(length == end, "sanity"); - // We'll process the final range for this object. Restore the length - // so that the heap remains parsable in case of evacuation failure. - to_obj_array->set_length(end); - } - _scanner.set_region(_g1->heap_region_containing_raw(to_obj)); - // Process indexes [start,end). It will also process the header - // along with the first chunk (i.e., the chunk with start == 0). - // Note that at this point the length field of to_obj_array is not - // correct given that we are using it to keep track of the next - // start index. oop_iterate_range() (thankfully!) ignores the length - // field and only relies on the start / end parameters. It does - // however return the size of the object which will be incorrect. So - // we have to ignore it even if we wanted to use it. - to_obj_array->oop_iterate_range(&_scanner, start, end); -} - class G1ParEvacuateFollowersClosure : public VoidClosure { protected: G1CollectedHeap* _g1h; @@ -5022,13 +5023,9 @@ public: ReferenceProcessor* rp = _g1h->ref_processor_stw(); G1ParScanThreadState pss(_g1h, worker_id, rp); - G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, rp); G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, rp); - G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, rp); - pss.set_evac_closure(&scan_evac_cl); pss.set_evac_failure_closure(&evac_failure_cl); - pss.set_partial_scan_closure(&partial_scan_cl); G1ParScanExtRootClosure only_scan_root_cl(_g1h, &pss, rp); G1ParScanMetadataClosure only_scan_metadata_cl(_g1h, &pss, rp); @@ -5270,6 +5267,33 @@ void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive g1_unlink_task.strings_processed(), g1_unlink_task.strings_removed(), g1_unlink_task.symbols_processed(), g1_unlink_task.symbols_removed()); } + + if (G1StringDedup::is_enabled()) { + G1StringDedup::unlink(is_alive); + } +} + +class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure { +public: + bool do_card_ptr(jbyte* card_ptr, int worker_i) { + *card_ptr = CardTableModRefBS::dirty_card_val(); + return true; + } +}; + +void G1CollectedHeap::redirty_logged_cards() { + guarantee(G1DeferredRSUpdate, "Must only be called when using deferred RS updates."); + double redirty_logged_cards_start = os::elapsedTime(); + + RedirtyLoggedCardTableEntryFastClosure redirty; + dirty_card_queue_set().set_closure(&redirty); + dirty_card_queue_set().apply_closure_to_all_completed_buffers(); + + DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set(); + dcq.merge_bufferlists(&dirty_card_queue_set()); + assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); + + g1_policy()->phase_times()->record_redirty_logged_cards_time_ms((os::elapsedTime() - redirty_logged_cards_start) * 1000.0); } // Weak Reference Processing support @@ -5453,14 +5477,9 @@ public: G1STWIsAliveClosure is_alive(_g1h); G1ParScanThreadState pss(_g1h, worker_id, NULL); - - G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, NULL); G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL); - G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, NULL); - pss.set_evac_closure(&scan_evac_cl); pss.set_evac_failure_closure(&evac_failure_cl); - pss.set_partial_scan_closure(&partial_scan_cl); G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, &pss, NULL); G1ParScanMetadataClosure only_copy_metadata_cl(_g1h, &pss, NULL); @@ -5565,13 +5584,9 @@ public: HandleMark hm; G1ParScanThreadState pss(_g1h, worker_id, NULL); - G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, NULL); G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL); - G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, NULL); - pss.set_evac_closure(&scan_evac_cl); pss.set_evac_failure_closure(&evac_failure_cl); - pss.set_partial_scan_closure(&partial_scan_cl); assert(pss.refs()->is_empty(), "both queue and overflow should be empty"); @@ -5695,13 +5710,9 @@ void G1CollectedHeap::process_discovered_references(uint no_of_gc_workers) { // We do not embed a reference processor in the copying/scanning // closures while we're actually processing the discovered // reference objects. - G1ParScanHeapEvacClosure scan_evac_cl(this, &pss, NULL); G1ParScanHeapEvacFailureClosure evac_failure_cl(this, &pss, NULL); - G1ParScanPartialArrayClosure partial_scan_cl(this, &pss, NULL); - pss.set_evac_closure(&scan_evac_cl); pss.set_evac_failure_closure(&evac_failure_cl); - pss.set_partial_scan_closure(&partial_scan_cl); assert(pss.refs()->is_empty(), "pre-condition"); @@ -5883,6 +5894,9 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { G1STWIsAliveClosure is_alive(this); G1KeepAliveClosure keep_alive(this); JNIHandles::weak_oops_do(&is_alive, &keep_alive); + if (G1StringDedup::is_enabled()) { + G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive); + } } release_gc_alloc_regions(n_workers, evacuation_info); @@ -5900,6 +5914,8 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { // strong code roots for a particular heap region. migrate_strong_code_roots(); + purge_code_root_memory(); + if (g1_policy()->during_initial_mark_pause()) { // Reset the claim values set during marking the strong code roots reset_heap_region_claim_values(); @@ -5926,41 +5942,15 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { enqueue_discovered_references(n_workers); if (G1DeferredRSUpdate) { - RedirtyLoggedCardTableEntryFastClosure redirty; - dirty_card_queue_set().set_closure(&redirty); - dirty_card_queue_set().apply_closure_to_all_completed_buffers(); - - DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set(); - dcq.merge_bufferlists(&dirty_card_queue_set()); - assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); + redirty_logged_cards(); } COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } -void G1CollectedHeap::free_region_if_empty(HeapRegion* hr, - size_t* pre_used, - FreeRegionList* free_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, - HRRSCleanupTask* hrrs_cleanup_task, - bool par) { - if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) { - if (hr->isHumongous()) { - assert(hr->startsHumongous(), "we should only see starts humongous"); - free_humongous_region(hr, pre_used, free_list, humongous_proxy_set, par); - } else { - _old_set.remove_with_proxy(hr, old_proxy_set); - free_region(hr, pre_used, free_list, par); - } - } else { - hr->rem_set()->do_cleanup_work(hrrs_cleanup_task); - } -} - void G1CollectedHeap::free_region(HeapRegion* hr, - size_t* pre_used, FreeRegionList* free_list, - bool par) { + bool par, + bool locked) { assert(!hr->isHumongous(), "this is only for non-humongous regions"); assert(!hr->is_empty(), "the region should not be empty"); assert(free_list != NULL, "pre-condition"); @@ -5971,72 +5961,58 @@ void G1CollectedHeap::free_region(HeapRegion* hr, if (!hr->is_young()) { _cg1r->hot_card_cache()->reset_card_counts(hr); } - *pre_used += hr->used(); - hr->hr_clear(par, true /* clear_space */); - free_list->add_as_head(hr); + hr->hr_clear(par, true /* clear_space */, locked /* locked */); + free_list->add_ordered(hr); } void G1CollectedHeap::free_humongous_region(HeapRegion* hr, - size_t* pre_used, FreeRegionList* free_list, - HumongousRegionSet* humongous_proxy_set, bool par) { assert(hr->startsHumongous(), "this is only for starts humongous regions"); assert(free_list != NULL, "pre-condition"); - assert(humongous_proxy_set != NULL, "pre-condition"); - size_t hr_used = hr->used(); size_t hr_capacity = hr->capacity(); - size_t hr_pre_used = 0; - _humongous_set.remove_with_proxy(hr, humongous_proxy_set); // We need to read this before we make the region non-humongous, // otherwise the information will be gone. uint last_index = hr->last_hc_index(); hr->set_notHumongous(); - free_region(hr, &hr_pre_used, free_list, par); + free_region(hr, free_list, par); uint i = hr->hrs_index() + 1; while (i < last_index) { HeapRegion* curr_hr = region_at(i); assert(curr_hr->continuesHumongous(), "invariant"); curr_hr->set_notHumongous(); - free_region(curr_hr, &hr_pre_used, free_list, par); + free_region(curr_hr, free_list, par); i += 1; } - assert(hr_pre_used == hr_used, - err_msg("hr_pre_used: "SIZE_FORMAT" and hr_used: "SIZE_FORMAT" " - "should be the same", hr_pre_used, hr_used)); - *pre_used += hr_pre_used; } -void G1CollectedHeap::update_sets_after_freeing_regions(size_t pre_used, - FreeRegionList* free_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, - bool par) { - if (pre_used > 0) { - Mutex* lock = (par) ? ParGCRareEvent_lock : NULL; - MutexLockerEx x(lock, Mutex::_no_safepoint_check_flag); - assert(_summary_bytes_used >= pre_used, - err_msg("invariant: _summary_bytes_used: "SIZE_FORMAT" " - "should be >= pre_used: "SIZE_FORMAT, - _summary_bytes_used, pre_used)); - _summary_bytes_used -= pre_used; +void G1CollectedHeap::remove_from_old_sets(const HeapRegionSetCount& old_regions_removed, + const HeapRegionSetCount& humongous_regions_removed) { + if (old_regions_removed.length() > 0 || humongous_regions_removed.length() > 0) { + MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag); + _old_set.bulk_remove(old_regions_removed); + _humongous_set.bulk_remove(humongous_regions_removed); } - if (free_list != NULL && !free_list->is_empty()) { + +} + +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_as_head(free_list); - } - if (old_proxy_set != NULL && !old_proxy_set->is_empty()) { - MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag); - _old_set.update_from_proxy(old_proxy_set); - } - if (humongous_proxy_set != NULL && !humongous_proxy_set->is_empty()) { - MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag); - _humongous_set.update_from_proxy(humongous_proxy_set); + _free_list.add_ordered(list); } } +void G1CollectedHeap::decrement_summary_bytes(size_t bytes) { + assert(_summary_bytes_used >= bytes, + err_msg("invariant: _summary_bytes_used: "SIZE_FORMAT" should be >= bytes: "SIZE_FORMAT, + _summary_bytes_used, bytes)); + _summary_bytes_used -= bytes; +} + class G1ParCleanupCTTask : public AbstractGangTask { G1SATBCardTableModRefBS* _ct_bs; G1CollectedHeap* _g1h; @@ -6194,7 +6170,7 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e } } - rs_lengths += cur->rem_set()->occupied(); + rs_lengths += cur->rem_set()->occupied_locked(); HeapRegion* next = cur->next_in_collection_set(); assert(cur->in_collection_set(), "bad CS"); @@ -6227,7 +6203,8 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e // And the region is empty. assert(!used_mr.is_empty(), "Should not have empty regions in a CS."); - free_region(cur, &pre_used, &local_free_list, false /* par */); + pre_used += cur->used(); + free_region(cur, &local_free_list, false /* par */, true /* locked */); } else { cur->uninstall_surv_rate_group(); if (cur->is_young()) { @@ -6255,10 +6232,8 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e young_time_ms += elapsed_ms; } - update_sets_after_freeing_regions(pre_used, &local_free_list, - NULL /* old_proxy_set */, - NULL /* humongous_proxy_set */, - false /* par */); + prepend_to_freelist(&local_free_list); + decrement_summary_bytes(pre_used); policy->phase_times()->record_young_free_cset_time_ms(young_time_ms); policy->phase_times()->record_non_young_free_cset_time_ms(non_young_time_ms); } @@ -6370,10 +6345,10 @@ bool G1CollectedHeap::check_young_list_empty(bool check_heap, bool check_sample) class TearDownRegionSetsClosure : public HeapRegionClosure { private: - OldRegionSet *_old_set; + HeapRegionSet *_old_set; public: - TearDownRegionSetsClosure(OldRegionSet* old_set) : _old_set(old_set) { } + TearDownRegionSetsClosure(HeapRegionSet* old_set) : _old_set(old_set) { } bool doHeapRegion(HeapRegion* r) { if (r->is_empty()) { @@ -6402,9 +6377,10 @@ void G1CollectedHeap::tear_down_region_sets(bool free_list_only) { TearDownRegionSetsClosure cl(&_old_set); heap_region_iterate(&cl); - // Need to do this after the heap iteration to be able to - // recognize the young regions and ignore them during the iteration. - _young_list->empty_list(); + // Note that emptying the _young_list is postponed and instead done as + // the first step when rebuilding the regions sets again. The reason for + // 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(); } @@ -6412,13 +6388,13 @@ void G1CollectedHeap::tear_down_region_sets(bool free_list_only) { class RebuildRegionSetsClosure : public HeapRegionClosure { private: bool _free_list_only; - OldRegionSet* _old_set; + HeapRegionSet* _old_set; FreeRegionList* _free_list; size_t _total_used; public: RebuildRegionSetsClosure(bool free_list_only, - OldRegionSet* old_set, FreeRegionList* free_list) : + HeapRegionSet* old_set, FreeRegionList* free_list) : _free_list_only(free_list_only), _old_set(old_set), _free_list(free_list), _total_used(0) { assert(_free_list->is_empty(), "pre-condition"); @@ -6458,6 +6434,10 @@ public: void G1CollectedHeap::rebuild_region_sets(bool free_list_only) { assert_at_safepoint(true /* should_be_vm_thread */); + if (!free_list_only) { + _young_list->empty_list(); + } + RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_free_list); heap_region_iterate(&cl); @@ -6493,6 +6473,7 @@ HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, bool young_list_full = g1_policy()->is_young_list_full(); if (force || !young_list_full) { HeapRegion* new_alloc_region = new_region(word_size, + false /* is_old */, false /* do_expand */); if (new_alloc_region != NULL) { set_region_short_lived_locked(new_alloc_region); @@ -6551,14 +6532,16 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, assert(FreeList_lock->owned_by_self(), "pre-condition"); if (count < g1_policy()->max_regions(ap)) { + bool survivor = (ap == GCAllocForSurvived); HeapRegion* new_alloc_region = new_region(word_size, + !survivor, true /* do_expand */); if (new_alloc_region != NULL) { // We really only need to do this for old regions given that we // should never scan survivors. But it doesn't hurt to do it // for survivors too. new_alloc_region->set_saved_mark(); - if (ap == GCAllocForSurvived) { + if (survivor) { new_alloc_region->set_survivor(); _hr_printer.alloc(new_alloc_region, G1HRPrinter::Survivor); } else { @@ -6615,23 +6598,22 @@ void OldGCAllocRegion::retire_region(HeapRegion* alloc_region, class VerifyRegionListsClosure : public HeapRegionClosure { private: - FreeRegionList* _free_list; - OldRegionSet* _old_set; - HumongousRegionSet* _humongous_set; - uint _region_count; + HeapRegionSet* _old_set; + HeapRegionSet* _humongous_set; + FreeRegionList* _free_list; public: - VerifyRegionListsClosure(OldRegionSet* old_set, - HumongousRegionSet* humongous_set, - FreeRegionList* free_list) : - _old_set(old_set), _humongous_set(humongous_set), - _free_list(free_list), _region_count(0) { } + HeapRegionSetCount _old_count; + HeapRegionSetCount _humongous_count; + HeapRegionSetCount _free_count; - uint region_count() { return _region_count; } + VerifyRegionListsClosure(HeapRegionSet* old_set, + HeapRegionSet* humongous_set, + FreeRegionList* free_list) : + _old_set(old_set), _humongous_set(humongous_set), _free_list(free_list), + _old_count(), _humongous_count(), _free_count(){ } bool doHeapRegion(HeapRegion* hr) { - _region_count += 1; - if (hr->continuesHumongous()) { return false; } @@ -6639,14 +6621,31 @@ public: if (hr->is_young()) { // TODO } else if (hr->startsHumongous()) { - _humongous_set->verify_next_region(hr); + 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()) { - _free_list->verify_next_region(hr); + assert(hr->containing_set() == _free_list, err_msg("Heap region %u is empty but not on the free list.", hr->hrs_index())); + _free_count.increment(1u, hr->capacity()); } else { - _old_set->verify_next_region(hr); + assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrs_index())); + _old_count.increment(1u, hr->capacity()); } return false; } + + void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, FreeRegionList* 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())); + + guarantee(humongous_set->length() == _humongous_count.length(), err_msg("Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count.length())); + 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->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, @@ -6662,16 +6661,14 @@ void G1CollectedHeap::verify_region_sets() { assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); // First, check the explicit lists. - _free_list.verify(); + _free_list.verify_list(); { // Given that a concurrent operation might be adding regions to // the secondary free list we have to take the lock before // verifying it. MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); - _secondary_free_list.verify(); + _secondary_free_list.verify_list(); } - _old_set.verify(); - _humongous_set.verify(); // If a concurrent region freeing operation is in progress it will // be difficult to correctly attributed any free regions we come @@ -6694,16 +6691,10 @@ void G1CollectedHeap::verify_region_sets() { // Finally, make sure that the region accounting in the lists is // consistent with what we see in the heap. - _old_set.verify_start(); - _humongous_set.verify_start(); - _free_list.verify_start(); VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_free_list); heap_region_iterate(&cl); - - _old_set.verify_end(); - _humongous_set.verify_end(); - _free_list.verify_end(); + cl.verify_counts(&_old_set, &_humongous_set, &_free_list); } // Optimized nmethod scanning @@ -6804,6 +6795,13 @@ void G1CollectedHeap::migrate_strong_code_roots() { g1_policy()->phase_times()->record_strong_code_root_migration_time(migration_time_ms); } +void G1CollectedHeap::purge_code_root_memory() { + double purge_start = os::elapsedTime(); + G1CodeRootSet::purge_chunks(G1CodeRootsChunkCacheKeepPercent); + double purge_time_ms = (os::elapsedTime() - purge_start) * 1000.0; + g1_policy()->phase_times()->record_strong_code_root_purge_time(purge_time_ms); +} + // Mark all the code roots that point into regions *not* in the // collection set. // @@ -6874,7 +6872,7 @@ public: // Code roots should never be attached to a continuation of a humongous region assert(hrrs->strong_code_roots_list_length() == 0, err_msg("code roots should never be attached to continuations of humongous region "HR_FORMAT - " starting at "HR_FORMAT", but has "INT32_FORMAT, + " starting at "HR_FORMAT", but has "SIZE_FORMAT, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()), hrrs->strong_code_roots_list_length())); return false; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index c1601e1c8a6..8716c60c592 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -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 @@ -34,7 +34,7 @@ #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/g1YCTypes.hpp" #include "gc_implementation/g1/heapRegionSeq.hpp" -#include "gc_implementation/g1/heapRegionSets.hpp" +#include "gc_implementation/g1/heapRegionSet.hpp" #include "gc_implementation/shared/hSpaceCounters.hpp" #include "gc_implementation/shared/parGCAllocBuffer.hpp" #include "memory/barrierSet.hpp" @@ -243,18 +243,18 @@ private: MemRegion _g1_committed; // The master free list. It will satisfy all new region allocations. - MasterFreeRegionList _free_list; + 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. - SecondaryFreeRegionList _secondary_free_list; + FreeRegionList _secondary_free_list; // It keeps track of the old regions. - MasterOldRegionSet _old_set; + HeapRegionSet _old_set; // It keeps track of the humongous regions. - MasterHumongousRegionSet _humongous_set; + HeapRegionSet _humongous_set; // The number of regions we could create by expansion. uint _expansion_regions; @@ -497,13 +497,14 @@ protected: // check whether there's anything available on the // secondary_free_list and/or wait for more regions to appear on // that list, if _free_regions_coming is set. - HeapRegion* new_region_try_secondary_free_list(); + HeapRegion* new_region_try_secondary_free_list(bool is_old); // Try to allocate a single non-humongous HeapRegion sufficient for // an allocation of the given word_size. If do_expand is true, // attempt to expand the heap if necessary to satisfy the allocation - // request. - HeapRegion* new_region(size_t word_size, bool do_expand); + // request. If the region is to be used as an old region or for a + // 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 @@ -705,19 +706,7 @@ public: // This is a fast test on whether a reference points into the // collection set or not. Assume that the reference // points into the heap. - bool in_cset_fast_test(oop obj) { - assert(_in_cset_fast_test != NULL, "sanity"); - assert(_g1_committed.contains((HeapWord*) obj), err_msg("Given reference outside of heap, is "PTR_FORMAT, (HeapWord*)obj)); - // no need to subtract the bottom of the heap from obj, - // _in_cset_fast_test is biased - uintx index = cast_from_oop(obj) >> HeapRegion::LogOfHRGrainBytes; - bool ret = _in_cset_fast_test[index]; - // let's make sure the result is consistent with what the slower - // test returns - assert( ret || !obj_in_cs(obj), "sanity"); - assert(!ret || obj_in_cs(obj), "sanity"); - return ret; - } + inline bool in_cset_fast_test(oop obj); void clear_cset_fast_test() { assert(_in_cset_fast_test_base != NULL, "sanity"); @@ -757,6 +746,29 @@ public: G1HRPrinter* hr_printer() { return &_hr_printer; } + // Frees a non-humongous region by initializing its contents and + // adding it to the free list that's passed as a parameter (this is + // usually a local list which will be appended to the master free + // list later). The used bytes of freed regions are accumulated in + // pre_used. If par is true, the region's RSet will not be freed + // up. The assumption is that this will be done later. + // The locked parameter indicates if the caller has already taken + // care of proper synchronization. This may allow some optimizations. + void free_region(HeapRegion* hr, + FreeRegionList* free_list, + bool par, + bool locked = false); + + // Frees a humongous region by collapsing it into individual regions + // and calling free_region() for each of them. The freed regions + // will be added to the free list that's passed as a parameter (this + // is usually a local list which will be appended to the master free + // list later). The used bytes of freed regions are accumulated in + // pre_used. If par is true, the region's RSet will not be freed + // up. The assumption is that this will be done later. + void free_humongous_region(HeapRegion* hr, + FreeRegionList* free_list, + bool par); protected: // Shrink the garbage-first heap by at most the given size (in bytes!). @@ -835,30 +847,6 @@ protected: G1KlassScanClosure* scan_klasses, int worker_i); - // Frees a non-humongous region by initializing its contents and - // adding it to the free list that's passed as a parameter (this is - // usually a local list which will be appended to the master free - // list later). The used bytes of freed regions are accumulated in - // pre_used. If par is true, the region's RSet will not be freed - // up. The assumption is that this will be done later. - void free_region(HeapRegion* hr, - size_t* pre_used, - FreeRegionList* free_list, - bool par); - - // Frees a humongous region by collapsing it into individual regions - // and calling free_region() for each of them. The freed regions - // will be added to the free list that's passed as a parameter (this - // is usually a local list which will be appended to the master free - // list later). The used bytes of freed regions are accumulated in - // pre_used. If par is true, the region's RSet will not be freed - // up. The assumption is that this will be done later. - void free_humongous_region(HeapRegion* hr, - size_t* pre_used, - FreeRegionList* free_list, - HumongousRegionSet* humongous_proxy_set, - bool par); - // 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. @@ -1228,21 +1216,17 @@ public: bool is_on_master_free_list(HeapRegion* hr) { return hr->containing_set() == &_free_list; } - - bool is_in_humongous_set(HeapRegion* hr) { - return hr->containing_set() == &_humongous_set; - } #endif // ASSERT // Wrapper for the region list operations that can be called from // methods outside this class. - void secondary_free_list_add_as_tail(FreeRegionList* list) { - _secondary_free_list.add_as_tail(list); + void secondary_free_list_add(FreeRegionList* list) { + _secondary_free_list.add_ordered(list); } void append_secondary_free_list() { - _free_list.add_as_head(&_secondary_free_list); + _free_list.add_ordered(&_secondary_free_list); } void append_secondary_free_list_if_not_empty_with_lock() { @@ -1254,9 +1238,7 @@ public: } } - void old_set_remove(HeapRegion* hr) { - _old_set.remove(hr); - } + inline void old_set_remove(HeapRegion* hr); size_t non_young_capacity_bytes() { return _old_set.total_capacity_bytes() + _humongous_set.total_capacity_bytes(); @@ -1284,27 +1266,9 @@ public: // True iff an evacuation has failed in the most-recent collection. bool evacuation_failed() { return _evacuation_failed; } - // It will free a region if it has allocated objects in it that are - // all dead. It calls either free_region() or - // free_humongous_region() depending on the type of the region that - // is passed to it. - void free_region_if_empty(HeapRegion* hr, - size_t* pre_used, - FreeRegionList* free_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, - HRRSCleanupTask* hrrs_cleanup_task, - bool par); - - // It appends the free list to the master free list and updates the - // master humongous list according to the contents of the proxy - // list. It also adjusts the total used bytes according to pre_used - // (if par is true, it will do so by taking the ParGCRareEvent_lock). - void update_sets_after_freeing_regions(size_t pre_used, - FreeRegionList* free_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, - bool par); + void remove_from_old_sets(const HeapRegionSetCount& old_regions_removed, const HeapRegionSetCount& humongous_regions_removed); + void prepend_to_freelist(FreeRegionList* list); + void decrement_summary_bytes(size_t bytes); // Returns "TRUE" iff "p" points into the committed areas of the heap. virtual bool is_in(const void* p) const; @@ -1365,7 +1329,7 @@ public: void heap_region_iterate(HeapRegionClosure* blk) const; // Return the region with the given index. It assumes the index is valid. - HeapRegion* region_at(uint index) const { return _hrs.at(index); } + inline HeapRegion* region_at(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 @@ -1494,10 +1458,7 @@ public: return true; } - bool is_in_young(const oop obj) { - HeapRegion* hr = heap_region_containing(obj); - return hr != NULL && hr->is_young(); - } + inline bool is_in_young(const oop obj); #ifdef ASSERT virtual bool is_in_partial_collection(const void* p); @@ -1510,9 +1471,7 @@ public: // pre-value that needs to be remembered; for the remembered-set // update logging post-barrier, we don't maintain remembered set // information for young gen objects. - virtual bool can_elide_initializing_store_barrier(oop new_obj) { - return is_in_young(new_obj); - } + virtual inline bool can_elide_initializing_store_barrier(oop new_obj); // Returns "true" iff the given word_size is "very large". static bool isHumongous(size_t word_size) { @@ -1606,23 +1565,9 @@ public: // Added if it is NULL it isn't dead. - bool is_obj_dead(const oop obj) const { - const HeapRegion* hr = heap_region_containing(obj); - if (hr == NULL) { - if (obj == NULL) return false; - else return true; - } - else return is_obj_dead(obj, hr); - } + inline bool is_obj_dead(const oop obj) const; - bool is_obj_ill(const oop obj) const { - const HeapRegion* hr = heap_region_containing(obj); - if (hr == NULL) { - if (obj == NULL) return false; - else return true; - } - else return is_obj_ill(obj, hr); - } + inline bool is_obj_ill(const oop obj) const; bool allocated_since_marking(oop obj, HeapRegion* hr, VerifyOption vo); HeapWord* top_at_mark_start(HeapRegion* hr, VerifyOption vo); @@ -1659,6 +1604,9 @@ public: // that were not successfully evacuated are not migrated. void migrate_strong_code_roots(); + // Free up superfluous code root memory. + void purge_code_root_memory(); + // During an initial mark pause, mark all the code roots that // point into regions *not* in the collection set. void mark_strong_code_roots(uint worker_id); @@ -1671,6 +1619,8 @@ public: // in symbol table, possibly in parallel. void unlink_string_and_symbol_table(BoolObjectClosure* is_alive, bool unlink_strings = true, bool unlink_symbols = true); + // Redirty logged cards in the refinement queue. + void redirty_logged_cards(); // Verification // The following is just to alert the verification code @@ -1711,26 +1661,10 @@ public: bool is_obj_dead_cond(const oop obj, const HeapRegion* hr, - const VerifyOption vo) const { - switch (vo) { - case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj, hr); - case VerifyOption_G1UseNextMarking: return is_obj_ill(obj, hr); - case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked(); - default: ShouldNotReachHere(); - } - return false; // keep some compilers happy - } + const VerifyOption vo) const; bool is_obj_dead_cond(const oop obj, - const VerifyOption vo) const { - switch (vo) { - case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj); - case VerifyOption_G1UseNextMarking: return is_obj_ill(obj); - case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked(); - default: ShouldNotReachHere(); - } - return false; // keep some compilers happy - } + const VerifyOption vo) const; // Printing @@ -1797,8 +1731,6 @@ protected: size_t _undo_waste; OopsInHeapRegionClosure* _evac_failure_cl; - G1ParScanHeapEvacClosure* _evac_cl; - G1ParScanPartialArrayClosure* _partial_scan_cl; int _hash_seed; uint _queue_num; @@ -1826,11 +1758,7 @@ protected: DirtyCardQueue& dirty_card_queue() { return _dcq; } G1SATBCardTableModRefBS* ctbs() { return _ct_bs; } - template void immediate_rs_update(HeapRegion* from, T* p, int tid) { - if (!from->is_survivor()) { - _g1_rem->par_write_ref(from, p, tid); - } - } + template inline void immediate_rs_update(HeapRegion* from, T* p, int tid); template void deferred_rs_update(HeapRegion* from, T* p, int tid) { // If the new value of the field points to the same region or @@ -1872,13 +1800,7 @@ public: refs()->push(ref); } - template void update_rs(HeapRegion* from, T* p, int tid) { - if (G1DeferredRSUpdate) { - deferred_rs_update(from, p, tid); - } else { - immediate_rs_update(from, p, tid); - } - } + template inline void update_rs(HeapRegion* from, T* p, int tid); HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz) { HeapWord* obj = NULL; @@ -1926,14 +1848,6 @@ public: return _evac_failure_cl; } - void set_evac_closure(G1ParScanHeapEvacClosure* evac_cl) { - _evac_cl = evac_cl; - } - - void set_partial_scan_closure(G1ParScanPartialArrayClosure* partial_scan_cl) { - _partial_scan_cl = partial_scan_cl; - } - int* hash_seed() { return &_hash_seed; } uint queue_num() { return _queue_num; } @@ -1981,30 +1895,68 @@ public: false /* retain */); } } +private: + #define G1_PARTIAL_ARRAY_MASK 0x2 + + inline bool has_partial_array_mask(oop* ref) const { + return ((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) == G1_PARTIAL_ARRAY_MASK; + } + + // We never encode partial array oops as narrowOop*, so return false immediately. + // This allows the compiler to create optimized code when popping references from + // the work queue. + inline bool has_partial_array_mask(narrowOop* ref) const { + assert(((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) != G1_PARTIAL_ARRAY_MASK, "Partial array oop reference encoded as narrowOop*"); + return false; + } + + // Only implement set_partial_array_mask() for regular oops, not for narrowOops. + // We always encode partial arrays as regular oop, to allow the + // specialization for has_partial_array_mask() for narrowOops above. + // This means that unintentional use of this method with narrowOops are caught + // by the compiler. + inline oop* set_partial_array_mask(oop obj) const { + assert(((uintptr_t)(void *)obj & G1_PARTIAL_ARRAY_MASK) == 0, "Information loss!"); + return (oop*) ((uintptr_t)(void *)obj | G1_PARTIAL_ARRAY_MASK); + } + + inline oop clear_partial_array_mask(oop* ref) const { + return cast_to_oop((intptr_t)ref & ~G1_PARTIAL_ARRAY_MASK); + } + + inline void do_oop_partial_array(oop* p); + + // This method is applied to the fields of the objects that have just been copied. + template void do_oop_evac(T* p, HeapRegion* from) { + assert(!oopDesc::is_null(oopDesc::load_decode_heap_oop(p)), + "Reference should not be NULL here as such are never pushed to the task queue."); + oop obj = oopDesc::load_decode_heap_oop_not_null(p); + + // Although we never intentionally push references outside of the collection + // 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)) { + 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); + } + + assert(obj != NULL, "Must be"); + update_rs(from, p, queue_num()); + } +public: oop copy_to_survivor_space(oop const obj); - template void deal_with_reference(T* ref_to_scan) { - if (has_partial_array_mask(ref_to_scan)) { - _partial_scan_cl->do_oop_nv(ref_to_scan); - } else { - // Note: we can use "raw" versions of "region_containing" because - // "obj_to_scan" is definitely in the heap, and is not in a - // humongous region. - HeapRegion* r = _g1h->heap_region_containing_raw(ref_to_scan); - _evac_cl->set_region(r); - _evac_cl->do_oop_nv(ref_to_scan); - } - } + template inline void deal_with_reference(T* ref_to_scan); - void deal_with_reference(StarTask ref) { - assert(verify_task(ref), "sanity"); - if (ref.is_narrow()) { - deal_with_reference((narrowOop*)ref); - } else { - deal_with_reference((oop*)ref); - } - } + inline void deal_with_reference(StarTask ref); public: void trim_queue(); 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 498e65f9b8d..e3b8fd061a3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp @@ -29,12 +29,17 @@ #include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/g1AllocRegion.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" +#include "gc_implementation/g1/g1RemSet.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#include "gc_implementation/g1/heapRegionSet.inline.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "utilities/taskqueue.hpp" // Inline functions for G1CollectedHeap +// 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); } + template inline HeapRegion* G1CollectedHeap::heap_region_containing(const T addr) const { @@ -54,6 +59,10 @@ G1CollectedHeap::heap_region_containing_raw(const T addr) const { return res; } +inline void G1CollectedHeap::old_set_remove(HeapRegion* hr) { + _old_set.remove(hr); +} + inline bool G1CollectedHeap::obj_in_cs(oop obj) { HeapRegion* r = _hrs.addr_to_region((HeapWord*) obj); return r != NULL && r->in_collection_set(); @@ -150,6 +159,24 @@ 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) { + assert(_in_cset_fast_test != NULL, "sanity"); + assert(_g1_committed.contains((HeapWord*) obj), err_msg("Given reference outside of heap, is "PTR_FORMAT, (HeapWord*)obj)); + // no need to subtract the bottom of the heap from obj, + // _in_cset_fast_test is biased + uintx index = cast_from_oop(obj) >> HeapRegion::LogOfHRGrainBytes; + bool ret = _in_cset_fast_test[index]; + // let's make sure the result is consistent with what the slower + // test returns + assert( ret || !obj_in_cs(obj), "sanity"); + assert(!ret || obj_in_cs(obj), "sanity"); + return ret; +} + #ifndef PRODUCT // Support for G1EvacuationFailureALot @@ -223,4 +250,121 @@ inline void G1CollectedHeap::reset_evacuation_should_fail() { } #endif // #ifndef PRODUCT +inline bool G1CollectedHeap::is_in_young(const oop obj) { + HeapRegion* hr = heap_region_containing(obj); + return hr != NULL && hr->is_young(); +} + +// We don't need barriers for initializing stores to objects +// in the young gen: for the SATB pre-barrier, there is no +// pre-value that needs to be remembered; for the remembered-set +// update logging post-barrier, we don't maintain remembered set +// information for young gen objects. +inline bool G1CollectedHeap::can_elide_initializing_store_barrier(oop new_obj) { + return is_in_young(new_obj); +} + +inline bool G1CollectedHeap::is_obj_dead(const oop obj) const { + const HeapRegion* hr = heap_region_containing(obj); + if (hr == NULL) { + if (obj == NULL) return false; + else return true; + } + else return is_obj_dead(obj, hr); +} + +inline bool G1CollectedHeap::is_obj_ill(const oop obj) const { + const HeapRegion* hr = heap_region_containing(obj); + if (hr == NULL) { + if (obj == NULL) return false; + else return true; + } + else return is_obj_ill(obj, hr); +} + +template inline void G1ParScanThreadState::immediate_rs_update(HeapRegion* from, T* p, int tid) { + if (!from->is_survivor()) { + _g1_rem->par_write_ref(from, p, tid); + } +} + +template void G1ParScanThreadState::update_rs(HeapRegion* from, T* p, int tid) { + if (G1DeferredRSUpdate) { + deferred_rs_update(from, p, tid); + } else { + immediate_rs_update(from, p, tid); + } +} + + +inline void G1ParScanThreadState::do_oop_partial_array(oop* p) { + assert(has_partial_array_mask(p), "invariant"); + oop from_obj = clear_partial_array_mask(p); + + assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap."); + assert(from_obj->is_objArray(), "must be obj array"); + objArrayOop from_obj_array = objArrayOop(from_obj); + // The from-space object contains the real length. + int length = from_obj_array->length(); + + assert(from_obj->is_forwarded(), "must be forwarded"); + oop to_obj = from_obj->forwardee(); + assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); + objArrayOop to_obj_array = objArrayOop(to_obj); + // We keep track of the next start index in the length field of the + // to-space object. + int next_index = to_obj_array->length(); + assert(0 <= next_index && next_index < length, + err_msg("invariant, next index: %d, length: %d", next_index, length)); + + int start = next_index; + int end = length; + int remainder = end - start; + // We'll try not to push a range that's smaller than ParGCArrayScanChunk. + if (remainder > 2 * ParGCArrayScanChunk) { + end = start + ParGCArrayScanChunk; + to_obj_array->set_length(end); + // Push the remainder before we process the range in case another + // worker has run out of things to do and can steal it. + oop* from_obj_p = set_partial_array_mask(from_obj); + push_on_queue(from_obj_p); + } else { + assert(length == end, "sanity"); + // We'll process the final range for this object. Restore the length + // so that the heap remains parsable in case of evacuation failure. + to_obj_array->set_length(end); + } + _scanner.set_region(_g1h->heap_region_containing_raw(to_obj)); + // Process indexes [start,end). It will also process the header + // along with the first chunk (i.e., the chunk with start == 0). + // Note that at this point the length field of to_obj_array is not + // correct given that we are using it to keep track of the next + // start index. oop_iterate_range() (thankfully!) ignores the length + // field and only relies on the start / end parameters. It does + // however return the size of the object which will be incorrect. So + // we have to ignore it even if we wanted to use it. + to_obj_array->oop_iterate_range(&_scanner, start, end); +} + +template inline void G1ParScanThreadState::deal_with_reference(T* ref_to_scan) { + if (!has_partial_array_mask(ref_to_scan)) { + // Note: we can use "raw" versions of "region_containing" because + // "obj_to_scan" is definitely in the heap, and is not in a + // humongous region. + HeapRegion* r = _g1h->heap_region_containing_raw(ref_to_scan); + do_oop_evac(ref_to_scan, r); + } else { + do_oop_partial_array((oop*)ref_to_scan); + } +} + +inline void G1ParScanThreadState::deal_with_reference(StarTask ref) { + assert(verify_task(ref), "sanity"); + if (ref.is_narrow()) { + deal_with_reference((narrowOop*)ref); + } else { + deal_with_reference((oop*)ref); + } +} + #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTEDHEAP_INLINE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index 0eda4b35d71..0f1a5e345ad 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.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 @@ -27,6 +27,7 @@ #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1GCPhaseTimes.hpp" #include "gc_implementation/g1/g1Log.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" // Helper class for avoiding interleaved logging class LineBuffer: public StackObj { @@ -168,7 +169,9 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _last_termination_attempts(_max_gc_threads, SIZE_FORMAT), _last_gc_worker_end_times_ms(_max_gc_threads, "%.1lf", false), _last_gc_worker_times_ms(_max_gc_threads, "%.1lf"), - _last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf") + _last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf"), + _cur_string_dedup_queue_fixup_worker_times_ms(_max_gc_threads, "%.1lf"), + _cur_string_dedup_table_fixup_worker_times_ms(_max_gc_threads, "%.1lf") { assert(max_gc_threads > 0, "Must have some GC threads"); } @@ -229,6 +232,16 @@ void G1GCPhaseTimes::note_gc_end() { _last_gc_worker_other_times_ms.verify(); } +void G1GCPhaseTimes::note_string_dedup_fixup_start() { + _cur_string_dedup_queue_fixup_worker_times_ms.reset(); + _cur_string_dedup_table_fixup_worker_times_ms.reset(); +} + +void G1GCPhaseTimes::note_string_dedup_fixup_end() { + _cur_string_dedup_queue_fixup_worker_times_ms.verify(); + _cur_string_dedup_table_fixup_worker_times_ms.verify(); +} + void G1GCPhaseTimes::print_stats(int level, const char* str, double value) { LineBuffer(level).append_and_print_cr("[%s: %.1lf ms]", str, value); } @@ -250,6 +263,14 @@ double G1GCPhaseTimes::accounted_time_ms() { // Strong code root migration time misc_time_ms += _cur_strong_code_root_migration_time_ms; + // Strong code root purge time + misc_time_ms += _cur_strong_code_root_purge_time_ms; + + if (G1StringDedup::is_enabled()) { + // String dedup fixup time + misc_time_ms += _cur_string_dedup_fixup_time_ms; + } + // Subtract the time taken to clean the card table from the // current value of "other time" misc_time_ms += _cur_clear_ct_time_ms; @@ -299,20 +320,43 @@ void G1GCPhaseTimes::print(double pause_time_sec) { } print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms); + print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms); + if (G1StringDedup::is_enabled()) { + print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads); + _cur_string_dedup_queue_fixup_worker_times_ms.print(2, "Queue Fixup (ms)"); + _cur_string_dedup_table_fixup_worker_times_ms.print(2, "Table Fixup (ms)"); + } print_stats(1, "Clear CT", _cur_clear_ct_time_ms); double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms(); print_stats(1, "Other", misc_time_ms); if (_cur_verify_before_time_ms > 0.0) { print_stats(2, "Verify Before", _cur_verify_before_time_ms); } + if (G1CollectedHeap::heap()->evacuation_failed()) { + double evac_fail_handling = _cur_evac_fail_recalc_used + _cur_evac_fail_remove_self_forwards + + _cur_evac_fail_restore_remsets; + print_stats(2, "Evacuation Failure", evac_fail_handling); + if (G1Log::finest()) { + print_stats(3, "Recalculate Used", _cur_evac_fail_recalc_used); + print_stats(3, "Remove Self Forwards", _cur_evac_fail_remove_self_forwards); + print_stats(3, "Restore RemSet", _cur_evac_fail_restore_remsets); + } + } print_stats(2, "Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); print_stats(2, "Ref Proc", _cur_ref_proc_time_ms); print_stats(2, "Ref Enq", _cur_ref_enq_time_ms); + if (G1DeferredRSUpdate) { + print_stats(2, "Redirty Cards", _recorded_redirty_logged_cards_time_ms); + } print_stats(2, "Free CSet", (_recorded_young_free_cset_time_ms + _recorded_non_young_free_cset_time_ms)); + if (G1Log::finest()) { + print_stats(3, "Young Free CSet", _recorded_young_free_cset_time_ms); + print_stats(3, "Non-Young Free CSet", _recorded_non_young_free_cset_time_ms); + } if (_cur_verify_after_time_ms > 0.0) { print_stats(2, "Verify After", _cur_verify_after_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 b2de97dc4b6..d8517b9b46c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp @@ -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 @@ -131,6 +131,15 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_collection_par_time_ms; double _cur_collection_code_root_fixup_time_ms; double _cur_strong_code_root_migration_time_ms; + double _cur_strong_code_root_purge_time_ms; + + double _cur_evac_fail_recalc_used; + double _cur_evac_fail_restore_remsets; + double _cur_evac_fail_remove_self_forwards; + + double _cur_string_dedup_fixup_time_ms; + WorkerDataArray _cur_string_dedup_queue_fixup_worker_times_ms; + WorkerDataArray _cur_string_dedup_table_fixup_worker_times_ms; double _cur_clear_ct_time_ms; double _cur_ref_proc_time_ms; @@ -142,6 +151,8 @@ class G1GCPhaseTimes : public CHeapObj { double _recorded_young_cset_choice_time_ms; double _recorded_non_young_cset_choice_time_ms; + double _recorded_redirty_logged_cards_time_ms; + double _recorded_young_free_cset_time_ms; double _recorded_non_young_free_cset_time_ms; @@ -223,6 +234,37 @@ class G1GCPhaseTimes : public CHeapObj { _cur_strong_code_root_migration_time_ms = ms; } + void record_strong_code_root_purge_time(double ms) { + _cur_strong_code_root_purge_time_ms = ms; + } + + void record_evac_fail_recalc_used_time(double ms) { + _cur_evac_fail_recalc_used = ms; + } + + void record_evac_fail_restore_remsets(double ms) { + _cur_evac_fail_restore_remsets = ms; + } + + void record_evac_fail_remove_self_forwards(double ms) { + _cur_evac_fail_remove_self_forwards = ms; + } + + void note_string_dedup_fixup_start(); + void note_string_dedup_fixup_end(); + + void record_string_dedup_fixup_time(double ms) { + _cur_string_dedup_fixup_time_ms = ms; + } + + void record_string_dedup_queue_fixup_worker_time(uint worker_id, double ms) { + _cur_string_dedup_queue_fixup_worker_times_ms.set(worker_id, ms); + } + + void record_string_dedup_table_fixup_worker_time(uint worker_id, double ms) { + _cur_string_dedup_table_fixup_worker_times_ms.set(worker_id, ms); + } + void record_ref_proc_time(double ms) { _cur_ref_proc_time_ms = ms; } @@ -251,6 +293,10 @@ class G1GCPhaseTimes : public CHeapObj { _recorded_non_young_cset_choice_time_ms = time_ms; } + void record_redirty_logged_cards_time_ms(double time_ms) { + _recorded_redirty_logged_cards_time_ms = time_ms; + } + void record_cur_collection_start_sec(double time_ms) { _cur_collection_start_sec = time_ms; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp index dee7ce0b72e..d8bda059bb8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.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 @@ -31,6 +31,7 @@ #include "code/icBuffer.hpp" #include "gc_implementation/g1/g1Log.hpp" #include "gc_implementation/g1/g1MarkSweep.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/shared/gcHeapSummary.hpp" #include "gc_implementation/shared/gcTimer.hpp" #include "gc_implementation/shared/gcTrace.hpp" @@ -194,17 +195,19 @@ class G1PrepareCompactClosure: public HeapRegionClosure { G1CollectedHeap* _g1h; ModRefBarrierSet* _mrbs; CompactPoint _cp; - HumongousRegionSet _humongous_proxy_set; + HeapRegionSetCount _humongous_regions_removed; void free_humongous_region(HeapRegion* hr) { HeapWord* end = hr->end(); - size_t dummy_pre_used; FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); assert(hr->startsHumongous(), "Only the start of a humongous region should be freed."); - _g1h->free_humongous_region(hr, &dummy_pre_used, &dummy_free_list, - &_humongous_proxy_set, false /* par */); + + hr->set_containing_set(NULL); + _humongous_regions_removed.increment(1u, hr->capacity()); + + _g1h->free_humongous_region(hr, &dummy_free_list, false /* par */); hr->prepare_for_compaction(&_cp); // Also clear the part of the card table that will be unused after // compaction. @@ -217,16 +220,13 @@ public: : _g1h(G1CollectedHeap::heap()), _mrbs(_g1h->g1_barrier_set()), _cp(NULL, cs, cs->initialize_threshold()), - _humongous_proxy_set("G1MarkSweep Humongous Proxy Set") { } + _humongous_regions_removed() { } void update_sets() { // We'll recalculate total used bytes and recreate the free list // at the end of the GC, so no point in updating those values here. - _g1h->update_sets_after_freeing_regions(0, /* pre_used */ - NULL, /* free_list */ - NULL, /* old_proxy_set */ - &_humongous_proxy_set, - false /* par */); + HeapRegionSetCount empty_set; + _g1h->remove_from_old_sets(empty_set, _humongous_regions_removed); } bool doHeapRegion(HeapRegion* hr) { @@ -317,6 +317,10 @@ void G1MarkSweep::mark_sweep_phase3() { // have been cleared if they pointed to non-surviving objects.) sh->process_weak_roots(&GenMarkSweep::adjust_pointer_closure); + if (G1StringDedup::is_enabled()) { + G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure); + } + GenMarkSweep::adjust_marks(); G1AdjustPointersClosure blk; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp index 5eb5691c98b..fbcbd9b533e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp @@ -80,53 +80,6 @@ public: virtual void do_oop(narrowOop* p) { do_oop_nv(p); } }; -#define G1_PARTIAL_ARRAY_MASK 0x2 - -inline bool has_partial_array_mask(oop* ref) { - return ((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) == G1_PARTIAL_ARRAY_MASK; -} - -// We never encode partial array oops as narrowOop*, so return false immediately. -// This allows the compiler to create optimized code when popping references from -// the work queue. -inline bool has_partial_array_mask(narrowOop* ref) { - assert(((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) != G1_PARTIAL_ARRAY_MASK, "Partial array oop reference encoded as narrowOop*"); - return false; -} - -// Only implement set_partial_array_mask() for regular oops, not for narrowOops. -// We always encode partial arrays as regular oop, to allow the -// specialization for has_partial_array_mask() for narrowOops above. -// This means that unintentional use of this method with narrowOops are caught -// by the compiler. -inline oop* set_partial_array_mask(oop obj) { - assert(((uintptr_t)(void *)obj & G1_PARTIAL_ARRAY_MASK) == 0, "Information loss!"); - return (oop*) ((uintptr_t)(void *)obj | G1_PARTIAL_ARRAY_MASK); -} - -template inline oop clear_partial_array_mask(T* ref) { - return cast_to_oop((intptr_t)ref & ~G1_PARTIAL_ARRAY_MASK); -} - -class G1ParScanPartialArrayClosure : public G1ParClosureSuper { - G1ParScanClosure _scanner; - -public: - G1ParScanPartialArrayClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state, ReferenceProcessor* rp) : - G1ParClosureSuper(g1, par_scan_state), _scanner(g1, par_scan_state, rp) - { - assert(_ref_processor == NULL, "sanity"); - } - - G1ParScanClosure* scanner() { - return &_scanner; - } - - template void do_oop_nv(T* p); - virtual void do_oop(oop* p) { do_oop_nv(p); } - virtual void do_oop(narrowOop* p) { do_oop_nv(p); } -}; - // Add back base class for metadata class G1ParCopyHelper : public G1ParClosureSuper { protected: @@ -173,15 +126,8 @@ typedef G1ParCopyClosure G1ParScanMetadataClosure; typedef G1ParCopyClosure G1ParScanAndMarkExtRootClosure; typedef G1ParCopyClosure G1ParScanAndMarkMetadataClosure; -// The following closure type is defined in g1_specialized_oop_closures.hpp: -// -// typedef G1ParCopyClosure G1ParScanHeapEvacClosure; - // We use a separate closure to handle references during evacuation // failure processing. -// We could have used another instance of G1ParScanHeapEvacClosure -// (since that closure no longer assumes that the references it -// handles point into the collection set). typedef G1ParCopyClosure G1ParScanHeapEvacFailureClosure; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 48e70a1c984..0267e4ea61f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -462,8 +462,9 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() { int into_cset_n_buffers = into_cset_dcqs.completed_buffers_num(); if (_g1->evacuation_failed()) { - // Restore remembered sets for the regions pointing into the collection set. + double restore_remembered_set_start = os::elapsedTime(); + // Restore remembered sets for the regions pointing into the collection set. if (G1DeferredRSUpdate) { // If deferred RS updates are enabled then we just need to transfer // the completed buffers from (a) the DirtyCardQueueSet used to hold @@ -482,6 +483,8 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() { } assert(n_completed_buffers == into_cset_n_buffers, "missed some buffers"); } + + _g1->g1_policy()->phase_times()->record_evac_fail_restore_remsets((os::elapsedTime() - restore_remembered_set_start) * 1000.0); } // Free any completed buffers in the DirtyCardQueueSet used to hold cards diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp new file mode 100644 index 00000000000..b1f8e01524e --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp @@ -0,0 +1,208 @@ +/* + * 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/javaClasses.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1GCPhaseTimes.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" +#include "gc_implementation/g1/g1StringDedupQueue.hpp" +#include "gc_implementation/g1/g1StringDedupStat.hpp" +#include "gc_implementation/g1/g1StringDedupTable.hpp" +#include "gc_implementation/g1/g1StringDedupThread.hpp" + +bool G1StringDedup::_enabled = false; + +void G1StringDedup::initialize() { + assert(UseG1GC, "String deduplication only available with G1"); + if (UseStringDeduplication) { + _enabled = true; + G1StringDedupQueue::create(); + G1StringDedupTable::create(); + G1StringDedupThread::create(); + } +} + +bool G1StringDedup::is_candidate_from_mark(oop obj) { + if (java_lang_String::is_instance(obj)) { + bool from_young = G1CollectedHeap::heap()->heap_region_containing_raw(obj)->is_young(); + if (from_young && obj->age() < StringDeduplicationAgeThreshold) { + // Candidate found. String is being evacuated from young to old but has not + // reached the deduplication age threshold, i.e. has not previously been a + // candidate during its life in the young generation. + return true; + } + } + + // Not a candidate + return false; +} + +void G1StringDedup::enqueue_from_mark(oop java_string) { + assert(is_enabled(), "String deduplication not enabled"); + if (is_candidate_from_mark(java_string)) { + G1StringDedupQueue::push(0 /* worker_id */, java_string); + } +} + +bool G1StringDedup::is_candidate_from_evacuation(bool from_young, bool to_young, oop obj) { + if (from_young && java_lang_String::is_instance(obj)) { + if (to_young && obj->age() == StringDeduplicationAgeThreshold) { + // Candidate found. String is being evacuated from young to young and just + // reached the deduplication age threshold. + return true; + } + if (!to_young && obj->age() < StringDeduplicationAgeThreshold) { + // Candidate found. String is being evacuated from young to old but has not + // reached the deduplication age threshold, i.e. has not previously been a + // candidate during its life in the young generation. + return true; + } + } + + // Not a candidate + return false; +} + +void G1StringDedup::enqueue_from_evacuation(bool from_young, bool to_young, uint worker_id, oop java_string) { + assert(is_enabled(), "String deduplication not enabled"); + if (is_candidate_from_evacuation(from_young, to_young, java_string)) { + G1StringDedupQueue::push(worker_id, java_string); + } +} + +void G1StringDedup::deduplicate(oop java_string) { + assert(is_enabled(), "String deduplication not enabled"); + G1StringDedupStat dummy; // Statistics from this path is never used + G1StringDedupTable::deduplicate(java_string, dummy); +} + +void G1StringDedup::oops_do(OopClosure* keep_alive) { + assert(is_enabled(), "String deduplication not enabled"); + unlink_or_oops_do(NULL, keep_alive); +} + +void G1StringDedup::unlink(BoolObjectClosure* is_alive) { + assert(is_enabled(), "String deduplication not enabled"); + // Don't allow a potential resize or rehash during unlink, as the unlink + // operation itself might remove enough entries to invalidate such a decision. + unlink_or_oops_do(is_alive, NULL, false /* allow_resize_and_rehash */); +} + +// +// Task for parallel unlink_or_oops_do() operation on the deduplication queue +// and table. +// +class G1StringDedupUnlinkOrOopsDoTask : public AbstractGangTask { +private: + G1StringDedupUnlinkOrOopsDoClosure _cl; + +public: + G1StringDedupUnlinkOrOopsDoTask(BoolObjectClosure* is_alive, + OopClosure* keep_alive, + bool allow_resize_and_rehash) : + AbstractGangTask("G1StringDedupUnlinkOrOopsDoTask"), + _cl(is_alive, keep_alive, allow_resize_and_rehash) { + } + + virtual void work(uint worker_id) { + double queue_fixup_start = os::elapsedTime(); + G1StringDedupQueue::unlink_or_oops_do(&_cl); + + double table_fixup_start = os::elapsedTime(); + G1StringDedupTable::unlink_or_oops_do(&_cl, worker_id); + + double queue_fixup_time_ms = (table_fixup_start - queue_fixup_start) * 1000.0; + double table_fixup_time_ms = (os::elapsedTime() - table_fixup_start) * 1000.0; + G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); + g1p->phase_times()->record_string_dedup_queue_fixup_worker_time(worker_id, queue_fixup_time_ms); + g1p->phase_times()->record_string_dedup_table_fixup_worker_time(worker_id, table_fixup_time_ms); + } +}; + +void G1StringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, bool allow_resize_and_rehash) { + assert(is_enabled(), "String deduplication not enabled"); + G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); + g1p->phase_times()->note_string_dedup_fixup_start(); + double fixup_start = os::elapsedTime(); + + G1StringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash); + if (G1CollectedHeap::use_parallel_gc_threads()) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + g1h->set_par_threads(); + g1h->workers()->run_task(&task); + g1h->set_par_threads(0); + } else { + task.work(0); + } + + double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0; + g1p->phase_times()->record_string_dedup_fixup_time(fixup_time_ms); + g1p->phase_times()->note_string_dedup_fixup_end(); +} + +void G1StringDedup::threads_do(ThreadClosure* tc) { + assert(is_enabled(), "String deduplication not enabled"); + tc->do_thread(G1StringDedupThread::thread()); +} + +void G1StringDedup::print_worker_threads_on(outputStream* st) { + assert(is_enabled(), "String deduplication not enabled"); + G1StringDedupThread::thread()->print_on(st); + st->cr(); +} + +void G1StringDedup::verify() { + assert(is_enabled(), "String deduplication not enabled"); + G1StringDedupQueue::verify(); + G1StringDedupTable::verify(); +} + +G1StringDedupUnlinkOrOopsDoClosure::G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive, + OopClosure* keep_alive, + bool allow_resize_and_rehash) : + _is_alive(is_alive), + _keep_alive(keep_alive), + _resized_table(NULL), + _rehashed_table(NULL), + _next_queue(0), + _next_bucket(0) { + if (allow_resize_and_rehash) { + // If both resize and rehash is needed, only do resize. Rehash of + // the table will eventually happen if the situation persists. + _resized_table = G1StringDedupTable::prepare_resize(); + if (!is_resizing()) { + _rehashed_table = G1StringDedupTable::prepare_rehash(); + } + } +} + +G1StringDedupUnlinkOrOopsDoClosure::~G1StringDedupUnlinkOrOopsDoClosure() { + assert(!is_resizing() || !is_rehashing(), "Can not both resize and rehash"); + if (is_resizing()) { + G1StringDedupTable::finish_resize(_resized_table); + } else if (is_rehashing()) { + G1StringDedupTable::finish_rehash(_rehashed_table); + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp new file mode 100644 index 00000000000..80af6b661d2 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp @@ -0,0 +1,202 @@ +/* + * 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_G1STRINGDEDUP_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP + +// +// String Deduplication +// +// String deduplication aims to reduce the heap live-set by deduplicating identical +// instances of String so that they share the same backing character array. +// +// The deduplication process is divided in two main parts, 1) finding the objects to +// deduplicate, and 2) deduplicating those objects. The first part is done as part of +// a normal GC cycle when objects are marked or evacuated. At this time a check is +// applied on each object to check if it is a candidate for deduplication. If so, the +// object is placed on the deduplication queue for later processing. The second part, +// processing the objects on the deduplication queue, is a concurrent phase which +// starts right after the stop-the-wold marking/evacuation phase. This phase is +// executed by the deduplication thread, which pulls deduplication candidates of the +// deduplication queue and tries to deduplicate them. +// +// A deduplication hashtable is used to keep track of all unique character arrays +// used by String objects. When deduplicating, a lookup is made in this table to see +// if there is already an identical character array somewhere on the heap. If so, the +// String object is adjusted to point to that character array, releasing the reference +// to the original array allowing it to eventually be garbage collected. If the lookup +// fails the character array is instead inserted into the hashtable so that this array +// can be shared at some point in the future. +// +// Candidate selection +// +// An object is considered a deduplication candidate if all of the following +// statements are true: +// +// - The object is an instance of java.lang.String +// +// - The object is being evacuated from a young heap region +// +// - The object is being evacuated to a young/survivor heap region and the +// object's age is equal to the deduplication age threshold +// +// or +// +// The object is being evacuated to an old heap region and the object's age is +// less than the deduplication age threshold +// +// Once an string object has been promoted to an old region, or its age is higher +// than the deduplication age threshold, is will never become a candidate again. +// This approach avoids making the same object a candidate more than once. +// +// Interned strings are a bit special. They are explicitly deduplicated just before +// being inserted into the StringTable (to avoid counteracting C2 optimizations done +// on string literals), then they also become deduplication candidates if they reach +// the deduplication age threshold or are evacuated to an old heap region. The second +// attempt to deduplicate such strings will be in vain, but we have no fast way of +// filtering them out. This has not shown to be a problem, as the number of interned +// strings is usually dwarfed by the number of normal (non-interned) strings. +// +// For additional information on string deduplication, please see JEP 192, +// http://openjdk.java.net/jeps/192 +// + +#include "memory/allocation.hpp" +#include "oops/oop.hpp" + +class OopClosure; +class BoolObjectClosure; +class ThreadClosure; +class outputStream; +class G1StringDedupTable; + +// +// Main interface for interacting with string deduplication. +// +class G1StringDedup : public AllStatic { +private: + // Single state for checking if both G1 and string deduplication is enabled. + static bool _enabled; + + // Candidate selection policies, returns true if the given object is + // candidate for string deduplication. + static bool is_candidate_from_mark(oop obj); + static bool is_candidate_from_evacuation(bool from_young, bool to_young, oop obj); + +public: + // Returns true if both G1 and string deduplication is enabled. + static bool is_enabled() { + return _enabled; + } + + static void initialize(); + + // Immediately deduplicates the given String object, bypassing the + // the deduplication queue. + static void deduplicate(oop java_string); + + // Enqueues a deduplication candidate for later processing by the deduplication + // thread. Before enqueuing, these functions apply the appropriate candidate + // selection policy to filters out non-candidates. + static void enqueue_from_mark(oop java_string); + static void enqueue_from_evacuation(bool from_young, bool to_young, + unsigned int queue, oop java_string); + + static void oops_do(OopClosure* keep_alive); + static void unlink(BoolObjectClosure* is_alive); + static void unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, + bool allow_resize_and_rehash = true); + + static void threads_do(ThreadClosure* tc); + static void print_worker_threads_on(outputStream* st); + static void verify(); +}; + +// +// This closure encapsulates the state and the closures needed when scanning +// the deduplication queue and table during the unlink_or_oops_do() operation. +// A single instance of this closure is created and then shared by all worker +// threads participating in the scan. The _next_queue and _next_bucket fields +// provide a simple mechanism for GC workers to claim exclusive access to a +// queue or a table partition. +// +class G1StringDedupUnlinkOrOopsDoClosure : public StackObj { +private: + BoolObjectClosure* _is_alive; + OopClosure* _keep_alive; + G1StringDedupTable* _resized_table; + G1StringDedupTable* _rehashed_table; + size_t _next_queue; + size_t _next_bucket; + +public: + G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive, + OopClosure* keep_alive, + bool allow_resize_and_rehash); + ~G1StringDedupUnlinkOrOopsDoClosure(); + + bool is_resizing() { + return _resized_table != NULL; + } + + G1StringDedupTable* resized_table() { + return _resized_table; + } + + bool is_rehashing() { + return _rehashed_table != NULL; + } + + // Atomically claims the next available queue for exclusive access by + // the current thread. Returns the queue number of the claimed queue. + size_t claim_queue() { + return (size_t)Atomic::add_ptr(1, &_next_queue) - 1; + } + + // Atomically claims the next available table partition for exclusive + // access by the current thread. Returns the table bucket number where + // the claimed partition starts. + size_t claim_table_partition(size_t partition_size) { + return (size_t)Atomic::add_ptr(partition_size, &_next_bucket) - partition_size; + } + + // Applies and returns the result from the is_alive closure, or + // returns true if no such closure was provided. + bool is_alive(oop o) { + if (_is_alive != NULL) { + return _is_alive->do_object_b(o); + } + return true; + } + + // Applies the keep_alive closure, or does nothing if no such + // closure was provided. + void keep_alive(oop* p) { + if (_keep_alive != NULL) { + _keep_alive->do_oop(p); + } + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp new file mode 100644 index 00000000000..330b5a434c2 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp @@ -0,0 +1,162 @@ +/* + * 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/javaClasses.hpp" +#include "gc_implementation/g1/g1StringDedupQueue.hpp" +#include "memory/gcLocker.hpp" +#include "runtime/mutexLocker.hpp" +#include "utilities/stack.inline.hpp" + +G1StringDedupQueue* G1StringDedupQueue::_queue = NULL; +const size_t G1StringDedupQueue::_max_size = 1000000; // Max number of elements per queue +const size_t G1StringDedupQueue::_max_cache_size = 0; // Max cache size per queue + +G1StringDedupQueue::G1StringDedupQueue() : + _cursor(0), + _empty(true), + _dropped(0) { + _nqueues = MAX2(ParallelGCThreads, (size_t)1); + _queues = NEW_C_HEAP_ARRAY(G1StringDedupWorkerQueue, _nqueues, mtGC); + for (size_t i = 0; i < _nqueues; i++) { + new (_queues + i) G1StringDedupWorkerQueue(G1StringDedupWorkerQueue::default_segment_size(), _max_cache_size, _max_size); + } +} + +G1StringDedupQueue::~G1StringDedupQueue() { + ShouldNotReachHere(); +} + +void G1StringDedupQueue::create() { + assert(_queue == NULL, "One string deduplication queue allowed"); + _queue = new G1StringDedupQueue(); +} + +void G1StringDedupQueue::wait() { + MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); + while (_queue->_empty) { + ml.wait(Mutex::_no_safepoint_check_flag); + } +} + +void G1StringDedupQueue::push(uint worker_id, oop java_string) { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); + assert(worker_id < _queue->_nqueues, "Invalid queue"); + + // Push and notify waiter + G1StringDedupWorkerQueue& worker_queue = _queue->_queues[worker_id]; + if (!worker_queue.is_full()) { + worker_queue.push(java_string); + if (_queue->_empty) { + MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); + if (_queue->_empty) { + // Mark non-empty and notify waiter + _queue->_empty = false; + ml.notify(); + } + } + } else { + // Queue is full, drop the string and update the statistics + Atomic::inc_ptr(&_queue->_dropped); + } +} + +oop G1StringDedupQueue::pop() { + assert(!SafepointSynchronize::is_at_safepoint(), "Must not be at safepoint"); + No_Safepoint_Verifier nsv; + + // Try all queues before giving up + for (size_t tries = 0; tries < _queue->_nqueues; tries++) { + // The cursor indicates where we left of last time + G1StringDedupWorkerQueue* queue = &_queue->_queues[_queue->_cursor]; + while (!queue->is_empty()) { + oop obj = queue->pop(); + // The oop we pop can be NULL if it was marked + // dead. Just ignore those and pop the next oop. + if (obj != NULL) { + return obj; + } + } + + // Try next queue + _queue->_cursor = (_queue->_cursor + 1) % _queue->_nqueues; + } + + // Mark empty + _queue->_empty = true; + + return NULL; +} + +void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl) { + // A worker thread first claims a queue, which ensures exclusive + // access to that queue, then continues to process it. + for (;;) { + // Grab next queue to scan + size_t queue = cl->claim_queue(); + if (queue >= _queue->_nqueues) { + // End of queues + break; + } + + // Scan the queue + unlink_or_oops_do(cl, queue); + } +} + +void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) { + assert(queue < _queue->_nqueues, "Invalid queue"); + StackIterator iter(_queue->_queues[queue]); + while (!iter.is_empty()) { + oop* p = iter.next_addr(); + if (*p != NULL) { + if (cl->is_alive(*p)) { + cl->keep_alive(p); + } else { + // Clear dead reference + *p = NULL; + } + } + } +} + +void G1StringDedupQueue::print_statistics(outputStream* st) { + st->print_cr( + " [Queue]\n" + " [Dropped: "UINTX_FORMAT"]", _queue->_dropped); +} + +void G1StringDedupQueue::verify() { + for (size_t i = 0; i < _queue->_nqueues; i++) { + StackIterator iter(_queue->_queues[i]); + while (!iter.is_empty()) { + oop obj = iter.next(); + if (obj != NULL) { + guarantee(Universe::heap()->is_in_reserved(obj), "Object must be on the heap"); + guarantee(!obj->is_forwarded(), "Object must not be forwarded"); + guarantee(java_lang_String::is_instance(obj), "Object must be a String"); + } + } + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp new file mode 100644 index 00000000000..1690247b769 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp @@ -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. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP + +#include "memory/allocation.hpp" +#include "oops/oop.hpp" +#include "utilities/stack.hpp" + +class G1StringDedupUnlinkOrOopsDoClosure; + +// +// The deduplication queue acts as the communication channel between the stop-the-world +// mark/evacuation phase and the concurrent deduplication phase. Deduplication candidates +// found during mark/evacuation are placed on this queue for later processing in the +// deduplication thread. A queue entry is an oop pointing to a String object (as opposed +// to entries in the deduplication hashtable which points to character arrays). +// +// While users of the queue treat it as a single queue, it is implemented as a set of +// queues, one queue per GC worker thread, to allow lock-free and cache-friendly enqueue +// operations by the GC workers. +// +// The oops in the queue are treated as weak pointers, meaning the objects they point to +// can become unreachable and pruned (cleared) before being popped by the deduplication +// thread. +// +// Pushing to the queue is thread safe (this relies on each thread using a unique worker +// id), but only allowed during a safepoint. Popping from the queue is NOT thread safe +// and can only be done by the deduplication thread outside a safepoint. +// +// The StringDedupQueue_lock is only used for blocking and waking up the deduplication +// thread in case the queue is empty or becomes non-empty, respectively. This lock does +// not otherwise protect the queue content. +// +class G1StringDedupQueue : public CHeapObj { +private: + typedef Stack G1StringDedupWorkerQueue; + + static G1StringDedupQueue* _queue; + static const size_t _max_size; + static const size_t _max_cache_size; + + G1StringDedupWorkerQueue* _queues; + size_t _nqueues; + size_t _cursor; + volatile bool _empty; + + // Statistics counter, only used for logging. + uintx _dropped; + + G1StringDedupQueue(); + ~G1StringDedupQueue(); + + static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue); + +public: + static void create(); + + // Blocks and waits for the queue to become non-empty. + static void wait(); + + // Pushes a deduplication candidate onto a specific GC worker queue. + static void push(uint worker_id, oop java_string); + + // Pops a deduplication candidate from any queue, returns NULL if + // all queues are empty. + static oop pop(); + + static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl); + + static void print_statistics(outputStream* st); + static void verify(); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.cpp new file mode 100644 index 00000000000..2d5523cce9e --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.cpp @@ -0,0 +1,162 @@ +/* + * 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/g1StringDedupStat.hpp" + +G1StringDedupStat::G1StringDedupStat() : + _inspected(0), + _skipped(0), + _hashed(0), + _known(0), + _new(0), + _new_bytes(0), + _deduped(0), + _deduped_bytes(0), + _deduped_young(0), + _deduped_young_bytes(0), + _deduped_old(0), + _deduped_old_bytes(0), + _idle(0), + _exec(0), + _block(0), + _start(0.0), + _idle_elapsed(0.0), + _exec_elapsed(0.0), + _block_elapsed(0.0) { +} + +void G1StringDedupStat::add(const G1StringDedupStat& stat) { + _inspected += stat._inspected; + _skipped += stat._skipped; + _hashed += stat._hashed; + _known += stat._known; + _new += stat._new; + _new_bytes += stat._new_bytes; + _deduped += stat._deduped; + _deduped_bytes += stat._deduped_bytes; + _deduped_young += stat._deduped_young; + _deduped_young_bytes += stat._deduped_young_bytes; + _deduped_old += stat._deduped_old; + _deduped_old_bytes += stat._deduped_old_bytes; + _idle += stat._idle; + _exec += stat._exec; + _block += stat._block; + _idle_elapsed += stat._idle_elapsed; + _exec_elapsed += stat._exec_elapsed; + _block_elapsed += stat._block_elapsed; +} + +void G1StringDedupStat::print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { + double total_deduped_bytes_percent = 0.0; + + if (total_stat._new_bytes > 0) { + // Avoid division by zero + total_deduped_bytes_percent = (double)total_stat._deduped_bytes / (double)total_stat._new_bytes * 100.0; + } + + st->date_stamp(PrintGCDateStamps); + st->stamp(PrintGCTimeStamps); + st->print_cr( + "[GC concurrent-string-deduplication, " + G1_STRDEDUP_BYTES_FORMAT_NS"->"G1_STRDEDUP_BYTES_FORMAT_NS"("G1_STRDEDUP_BYTES_FORMAT_NS"), avg " + G1_STRDEDUP_PERCENT_FORMAT_NS", "G1_STRDEDUP_TIME_FORMAT"]", + G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes), + G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes - last_stat._deduped_bytes), + G1_STRDEDUP_BYTES_PARAM(last_stat._deduped_bytes), + total_deduped_bytes_percent, + last_stat._exec_elapsed); +} + +void G1StringDedupStat::print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total) { + double young_percent = 0.0; + double old_percent = 0.0; + double skipped_percent = 0.0; + double hashed_percent = 0.0; + double known_percent = 0.0; + double new_percent = 0.0; + double deduped_percent = 0.0; + double deduped_bytes_percent = 0.0; + double deduped_young_percent = 0.0; + double deduped_young_bytes_percent = 0.0; + double deduped_old_percent = 0.0; + double deduped_old_bytes_percent = 0.0; + + if (stat._inspected > 0) { + // Avoid division by zero + skipped_percent = (double)stat._skipped / (double)stat._inspected * 100.0; + hashed_percent = (double)stat._hashed / (double)stat._inspected * 100.0; + known_percent = (double)stat._known / (double)stat._inspected * 100.0; + new_percent = (double)stat._new / (double)stat._inspected * 100.0; + } + + if (stat._new > 0) { + // Avoid division by zero + deduped_percent = (double)stat._deduped / (double)stat._new * 100.0; + } + + if (stat._deduped > 0) { + // Avoid division by zero + deduped_young_percent = (double)stat._deduped_young / (double)stat._deduped * 100.0; + deduped_old_percent = (double)stat._deduped_old / (double)stat._deduped * 100.0; + } + + if (stat._new_bytes > 0) { + // Avoid division by zero + deduped_bytes_percent = (double)stat._deduped_bytes / (double)stat._new_bytes * 100.0; + } + + if (stat._deduped_bytes > 0) { + // Avoid division by zero + deduped_young_bytes_percent = (double)stat._deduped_young_bytes / (double)stat._deduped_bytes * 100.0; + deduped_old_bytes_percent = (double)stat._deduped_old_bytes / (double)stat._deduped_bytes * 100.0; + } + + if (total) { + st->print_cr( + " [Total Exec: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT", Idle: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT", Blocked: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT"]", + stat._exec, stat._exec_elapsed, stat._idle, stat._idle_elapsed, stat._block, stat._block_elapsed); + } else { + st->print_cr( + " [Last Exec: "G1_STRDEDUP_TIME_FORMAT", Idle: "G1_STRDEDUP_TIME_FORMAT", Blocked: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT"]", + stat._exec_elapsed, stat._idle_elapsed, stat._block, stat._block_elapsed); + } + st->print_cr( + " [Inspected: "G1_STRDEDUP_OBJECTS_FORMAT"]\n" + " [Skipped: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [Hashed: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [Known: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [New: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"]\n" + " [Deduplicated: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [Young: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [Old: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]", + stat._inspected, + stat._skipped, skipped_percent, + stat._hashed, hashed_percent, + stat._known, known_percent, + stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes), + stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent, + stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent, + stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent); +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.hpp new file mode 100644 index 00000000000..bfb55caa720 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.hpp @@ -0,0 +1,142 @@ +/* + * 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_G1STRINGDEDUPSTAT_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP + +#include "memory/allocation.hpp" +#include "runtime/os.hpp" + +// Macros for GC log output formating +#define G1_STRDEDUP_OBJECTS_FORMAT UINTX_FORMAT_W(12) +#define G1_STRDEDUP_TIME_FORMAT "%1.7lf secs" +#define G1_STRDEDUP_PERCENT_FORMAT "%5.1lf%%" +#define G1_STRDEDUP_PERCENT_FORMAT_NS "%.1lf%%" +#define G1_STRDEDUP_BYTES_FORMAT "%8.1lf%s" +#define G1_STRDEDUP_BYTES_FORMAT_NS "%.1lf%s" +#define G1_STRDEDUP_BYTES_PARAM(bytes) byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes)) + +// +// Statistics gathered by the deduplication thread. +// +class G1StringDedupStat : public StackObj { +private: + // Counters + uintx _inspected; + uintx _skipped; + uintx _hashed; + uintx _known; + uintx _new; + uintx _new_bytes; + uintx _deduped; + uintx _deduped_bytes; + uintx _deduped_young; + uintx _deduped_young_bytes; + uintx _deduped_old; + uintx _deduped_old_bytes; + uintx _idle; + uintx _exec; + uintx _block; + + // Time spent by the deduplication thread in different phases + double _start; + double _idle_elapsed; + double _exec_elapsed; + double _block_elapsed; + +public: + G1StringDedupStat(); + + void inc_inspected() { + _inspected++; + } + + void inc_skipped() { + _skipped++; + } + + void inc_hashed() { + _hashed++; + } + + void inc_known() { + _known++; + } + + void inc_new(uintx bytes) { + _new++; + _new_bytes += bytes; + } + + void inc_deduped_young(uintx bytes) { + _deduped++; + _deduped_bytes += bytes; + _deduped_young++; + _deduped_young_bytes += bytes; + } + + void inc_deduped_old(uintx bytes) { + _deduped++; + _deduped_bytes += bytes; + _deduped_old++; + _deduped_old_bytes += bytes; + } + + void mark_idle() { + _start = os::elapsedTime(); + _idle++; + } + + void mark_exec() { + double now = os::elapsedTime(); + _idle_elapsed = now - _start; + _start = now; + _exec++; + } + + void mark_block() { + double now = os::elapsedTime(); + _exec_elapsed += now - _start; + _start = now; + _block++; + } + + void mark_unblock() { + double now = os::elapsedTime(); + _block_elapsed += now - _start; + _start = now; + } + + void mark_done() { + double now = os::elapsedTime(); + _exec_elapsed += now - _start; + } + + void add(const G1StringDedupStat& stat); + + static void print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); + static void print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp new file mode 100644 index 00000000000..2b41688a3e5 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp @@ -0,0 +1,569 @@ +/* + * 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/altHashing.hpp" +#include "classfile/javaClasses.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#include "gc_implementation/g1/g1StringDedupTable.hpp" +#include "memory/gcLocker.hpp" +#include "memory/padded.inline.hpp" +#include "oops/typeArrayOop.hpp" +#include "runtime/mutexLocker.hpp" + +// +// Freelist in the deduplication table entry cache. Links table +// entries together using their _next fields. +// +class G1StringDedupEntryFreeList : public CHeapObj { +private: + G1StringDedupEntry* _list; + size_t _length; + +public: + G1StringDedupEntryFreeList() : + _list(NULL), + _length(0) { + } + + void add(G1StringDedupEntry* entry) { + entry->set_next(_list); + _list = entry; + _length++; + } + + G1StringDedupEntry* remove() { + G1StringDedupEntry* entry = _list; + if (entry != NULL) { + _list = entry->next(); + _length--; + } + return entry; + } + + size_t length() { + return _length; + } +}; + +// +// Cache of deduplication table entries. This cache provides fast allocation and +// reuse of table entries to lower the pressure on the underlying allocator. +// But more importantly, it provides fast/deferred freeing of table entries. This +// is important because freeing of table entries is done during stop-the-world +// phases and it is not uncommon for large number of entries to be freed at once. +// Tables entries that are freed during these phases are placed onto a freelist in +// the cache. The deduplication thread, which executes in a concurrent phase, will +// later reuse or free the underlying memory for these entries. +// +// The cache allows for single-threaded allocations and multi-threaded frees. +// Allocations are synchronized by StringDedupTable_lock as part of a table +// modification. +// +class G1StringDedupEntryCache : public CHeapObj { +private: + // One freelist per GC worker to allow lock less freeing of + // entries while doing a parallel scan of the table. Using + // PaddedEnd to avoid false sharing. + PaddedEnd* _lists; + size_t _nlists; + +public: + G1StringDedupEntryCache(); + ~G1StringDedupEntryCache(); + + // Get a table entry from the cache freelist, or allocate a new + // entry if the cache is empty. + G1StringDedupEntry* alloc(); + + // Insert a table entry into the cache freelist. + void free(G1StringDedupEntry* entry, uint worker_id); + + // Returns current number of entries in the cache. + size_t size(); + + // If the cache has grown above the given max size, trim it down + // and deallocate the memory occupied by trimmed of entries. + void trim(size_t max_size); +}; + +G1StringDedupEntryCache::G1StringDedupEntryCache() { + _nlists = MAX2(ParallelGCThreads, (size_t)1); + _lists = PaddedArray::create_unfreeable((uint)_nlists); +} + +G1StringDedupEntryCache::~G1StringDedupEntryCache() { + ShouldNotReachHere(); +} + +G1StringDedupEntry* G1StringDedupEntryCache::alloc() { + for (size_t i = 0; i < _nlists; i++) { + G1StringDedupEntry* entry = _lists[i].remove(); + if (entry != NULL) { + return entry; + } + } + return new G1StringDedupEntry(); +} + +void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) { + assert(entry->obj() != NULL, "Double free"); + assert(worker_id < _nlists, "Invalid worker id"); + entry->set_obj(NULL); + entry->set_hash(0); + _lists[worker_id].add(entry); +} + +size_t G1StringDedupEntryCache::size() { + size_t size = 0; + for (size_t i = 0; i < _nlists; i++) { + size += _lists[i].length(); + } + return size; +} + +void G1StringDedupEntryCache::trim(size_t max_size) { + size_t cache_size = 0; + for (size_t i = 0; i < _nlists; i++) { + G1StringDedupEntryFreeList* list = &_lists[i]; + cache_size += list->length(); + while (cache_size > max_size) { + G1StringDedupEntry* entry = list->remove(); + assert(entry != NULL, "Should not be null"); + cache_size--; + delete entry; + } + } +} + +G1StringDedupTable* G1StringDedupTable::_table = NULL; +G1StringDedupEntryCache* G1StringDedupTable::_entry_cache = NULL; + +const size_t G1StringDedupTable::_min_size = (1 << 10); // 1024 +const size_t G1StringDedupTable::_max_size = (1 << 24); // 16777216 +const double G1StringDedupTable::_grow_load_factor = 2.0; // Grow table at 200% load +const double G1StringDedupTable::_shrink_load_factor = _grow_load_factor / 3.0; // Shrink table at 67% load +const double G1StringDedupTable::_max_cache_factor = 0.1; // Cache a maximum of 10% of the table size +const uintx G1StringDedupTable::_rehash_multiple = 60; // Hash bucket has 60 times more collisions than expected +const uintx G1StringDedupTable::_rehash_threshold = (uintx)(_rehash_multiple * _grow_load_factor); + +uintx G1StringDedupTable::_entries_added = 0; +uintx G1StringDedupTable::_entries_removed = 0; +uintx G1StringDedupTable::_resize_count = 0; +uintx G1StringDedupTable::_rehash_count = 0; + +G1StringDedupTable::G1StringDedupTable(size_t size, jint hash_seed) : + _size(size), + _entries(0), + _grow_threshold((uintx)(size * _grow_load_factor)), + _shrink_threshold((uintx)(size * _shrink_load_factor)), + _rehash_needed(false), + _hash_seed(hash_seed) { + assert(is_power_of_2(size), "Table size must be a power of 2"); + _buckets = NEW_C_HEAP_ARRAY(G1StringDedupEntry*, _size, mtGC); + memset(_buckets, 0, _size * sizeof(G1StringDedupEntry*)); +} + +G1StringDedupTable::~G1StringDedupTable() { + FREE_C_HEAP_ARRAY(G1StringDedupEntry*, _buckets, mtGC); +} + +void G1StringDedupTable::create() { + assert(_table == NULL, "One string deduplication table allowed"); + _entry_cache = new G1StringDedupEntryCache(); + _table = new G1StringDedupTable(_min_size); +} + +void G1StringDedupTable::add(typeArrayOop value, unsigned int hash, G1StringDedupEntry** list) { + G1StringDedupEntry* entry = _entry_cache->alloc(); + entry->set_obj(value); + entry->set_hash(hash); + entry->set_next(*list); + *list = entry; + _entries++; +} + +void G1StringDedupTable::remove(G1StringDedupEntry** pentry, uint worker_id) { + G1StringDedupEntry* entry = *pentry; + *pentry = entry->next(); + _entry_cache->free(entry, worker_id); +} + +void G1StringDedupTable::transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest) { + G1StringDedupEntry* entry = *pentry; + *pentry = entry->next(); + unsigned int hash = entry->hash(); + size_t index = dest->hash_to_index(hash); + G1StringDedupEntry** list = dest->bucket(index); + entry->set_next(*list); + *list = entry; +} + +bool G1StringDedupTable::equals(typeArrayOop value1, typeArrayOop value2) { + return (value1 == value2 || + (value1->length() == value2->length() && + (!memcmp(value1->base(T_CHAR), + value2->base(T_CHAR), + value1->length() * sizeof(jchar))))); +} + +typeArrayOop G1StringDedupTable::lookup(typeArrayOop value, unsigned int hash, + G1StringDedupEntry** list, uintx &count) { + for (G1StringDedupEntry* entry = *list; entry != NULL; entry = entry->next()) { + if (entry->hash() == hash) { + typeArrayOop existing_value = entry->obj(); + if (equals(value, existing_value)) { + // Match found + return existing_value; + } + } + count++; + } + + // Not found + return NULL; +} + +typeArrayOop G1StringDedupTable::lookup_or_add_inner(typeArrayOop value, unsigned int hash) { + size_t index = hash_to_index(hash); + G1StringDedupEntry** list = bucket(index); + uintx count = 0; + + // Lookup in list + typeArrayOop existing_value = lookup(value, hash, list, count); + + // Check if rehash is needed + if (count > _rehash_threshold) { + _rehash_needed = true; + } + + if (existing_value == NULL) { + // Not found, add new entry + add(value, hash, list); + + // Update statistics + _entries_added++; + } + + return existing_value; +} + +unsigned int G1StringDedupTable::hash_code(typeArrayOop value) { + unsigned int hash; + int length = value->length(); + const jchar* data = (jchar*)value->base(T_CHAR); + + if (use_java_hash()) { + hash = java_lang_String::hash_code(data, length); + } else { + hash = AltHashing::murmur3_32(_table->_hash_seed, data, length); + } + + return hash; +} + +void G1StringDedupTable::deduplicate(oop java_string, G1StringDedupStat& stat) { + assert(java_lang_String::is_instance(java_string), "Must be a string"); + No_Safepoint_Verifier nsv; + + stat.inc_inspected(); + + typeArrayOop value = java_lang_String::value(java_string); + if (value == NULL) { + // String has no value + stat.inc_skipped(); + return; + } + + unsigned int hash = 0; + + if (use_java_hash()) { + // Get hash code from cache + hash = java_lang_String::hash(java_string); + } + + if (hash == 0) { + // Compute hash + hash = hash_code(value); + stat.inc_hashed(); + } + + if (use_java_hash() && hash != 0) { + // Store hash code in cache + java_lang_String::set_hash(java_string, hash); + } + + typeArrayOop existing_value = lookup_or_add(value, hash); + if (existing_value == value) { + // Same value, already known + stat.inc_known(); + return; + } + + // Get size of value array + uintx size_in_bytes = value->size() * HeapWordSize; + stat.inc_new(size_in_bytes); + + if (existing_value != NULL) { + // Enqueue the reference to make sure it is kept alive. Concurrent mark might + // otherwise declare it dead if there are no other strong references to this object. + G1SATBCardTableModRefBS::enqueue(existing_value); + + // Existing value found, deduplicate string + java_lang_String::set_value(java_string, existing_value); + + if (G1CollectedHeap::heap()->is_in_young(value)) { + stat.inc_deduped_young(size_in_bytes); + } else { + stat.inc_deduped_old(size_in_bytes); + } + } +} + +G1StringDedupTable* G1StringDedupTable::prepare_resize() { + size_t size = _table->_size; + + // Check if the hashtable needs to be resized + if (_table->_entries > _table->_grow_threshold) { + // Grow table, double the size + size *= 2; + if (size > _max_size) { + // Too big, don't resize + return NULL; + } + } else if (_table->_entries < _table->_shrink_threshold) { + // Shrink table, half the size + size /= 2; + if (size < _min_size) { + // Too small, don't resize + return NULL; + } + } else if (StringDeduplicationResizeALot) { + // Force grow + size *= 2; + if (size > _max_size) { + // Too big, force shrink instead + size /= 4; + } + } else { + // Resize not needed + return NULL; + } + + // Update statistics + _resize_count++; + + // Allocate the new table. The new table will be populated by workers + // calling unlink_or_oops_do() and finally installed by finish_resize(). + return new G1StringDedupTable(size, _table->_hash_seed); +} + +void G1StringDedupTable::finish_resize(G1StringDedupTable* resized_table) { + assert(resized_table != NULL, "Invalid table"); + + resized_table->_entries = _table->_entries; + + // Free old table + delete _table; + + // Install new table + _table = resized_table; +} + +void G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id) { + // The table is divided into partitions to allow lock-less parallel processing by + // multiple worker threads. A worker thread first claims a partition, which ensures + // exclusive access to that part of the table, then continues to process it. To allow + // shrinking of the table in parallel we also need to make sure that the same worker + // thread processes all partitions where entries will hash to the same destination + // partition. Since the table size is always a power of two and we always shrink by + // dividing the table in half, we know that for a given partition there is only one + // other partition whoes entries will hash to the same destination partition. That + // other partition is always the sibling partition in the second half of the table. + // For example, if the table is divided into 8 partitions, the sibling of partition 0 + // is partition 4, the sibling of partition 1 is partition 5, etc. + size_t table_half = _table->_size / 2; + + // Let each partition be one page worth of buckets + size_t partition_size = MIN2(table_half, os::vm_page_size() / sizeof(G1StringDedupEntry*)); + assert(table_half % partition_size == 0, "Invalid partition size"); + + // Number of entries removed during the scan + uintx removed = 0; + + for (;;) { + // Grab next partition to scan + size_t partition_begin = cl->claim_table_partition(partition_size); + size_t partition_end = partition_begin + partition_size; + if (partition_begin >= table_half) { + // End of table + break; + } + + // Scan the partition followed by the sibling partition in the second half of the table + removed += unlink_or_oops_do(cl, partition_begin, partition_end, worker_id); + removed += unlink_or_oops_do(cl, table_half + partition_begin, table_half + partition_end, worker_id); + } + + // Delayed update avoid contention on the table lock + if (removed > 0) { + MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); + _table->_entries -= removed; + _entries_removed += removed; + } +} + +uintx G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, + size_t partition_begin, + size_t partition_end, + uint worker_id) { + uintx removed = 0; + for (size_t bucket = partition_begin; bucket < partition_end; bucket++) { + G1StringDedupEntry** entry = _table->bucket(bucket); + while (*entry != NULL) { + oop* p = (oop*)(*entry)->obj_addr(); + if (cl->is_alive(*p)) { + cl->keep_alive(p); + if (cl->is_resizing()) { + // We are resizing the table, transfer entry to the new table + _table->transfer(entry, cl->resized_table()); + } else { + if (cl->is_rehashing()) { + // We are rehashing the table, rehash the entry but keep it + // in the table. We can't transfer entries into the new table + // at this point since we don't have exclusive access to all + // destination partitions. finish_rehash() will do a single + // threaded transfer of all entries. + typeArrayOop value = (typeArrayOop)*p; + unsigned int hash = hash_code(value); + (*entry)->set_hash(hash); + } + + // Move to next entry + entry = (*entry)->next_addr(); + } + } else { + // Not alive, remove entry from table + _table->remove(entry, worker_id); + removed++; + } + } + } + + return removed; +} + +G1StringDedupTable* G1StringDedupTable::prepare_rehash() { + if (!_table->_rehash_needed && !StringDeduplicationRehashALot) { + // Rehash not needed + return NULL; + } + + // Update statistics + _rehash_count++; + + // Compute new hash seed + _table->_hash_seed = AltHashing::compute_seed(); + + // Allocate the new table, same size and hash seed + return new G1StringDedupTable(_table->_size, _table->_hash_seed); +} + +void G1StringDedupTable::finish_rehash(G1StringDedupTable* rehashed_table) { + assert(rehashed_table != NULL, "Invalid table"); + + // Move all newly rehashed entries into the correct buckets in the new table + for (size_t bucket = 0; bucket < _table->_size; bucket++) { + G1StringDedupEntry** entry = _table->bucket(bucket); + while (*entry != NULL) { + _table->transfer(entry, rehashed_table); + } + } + + rehashed_table->_entries = _table->_entries; + + // Free old table + delete _table; + + // Install new table + _table = rehashed_table; +} + +void G1StringDedupTable::verify() { + for (size_t bucket = 0; bucket < _table->_size; bucket++) { + // Verify entries + G1StringDedupEntry** entry = _table->bucket(bucket); + while (*entry != NULL) { + typeArrayOop value = (*entry)->obj(); + guarantee(value != NULL, "Object must not be NULL"); + guarantee(Universe::heap()->is_in_reserved(value), "Object must be on the heap"); + guarantee(!value->is_forwarded(), "Object must not be forwarded"); + guarantee(value->is_typeArray(), "Object must be a typeArrayOop"); + unsigned int hash = hash_code(value); + guarantee((*entry)->hash() == hash, "Table entry has inorrect hash"); + guarantee(_table->hash_to_index(hash) == bucket, "Table entry has incorrect index"); + entry = (*entry)->next_addr(); + } + + // Verify that we do not have entries with identical oops or identical arrays. + // We only need to compare entries in the same bucket. If the same oop or an + // identical array has been inserted more than once into different/incorrect + // buckets the verification step above will catch that. + G1StringDedupEntry** entry1 = _table->bucket(bucket); + while (*entry1 != NULL) { + typeArrayOop value1 = (*entry1)->obj(); + G1StringDedupEntry** entry2 = (*entry1)->next_addr(); + while (*entry2 != NULL) { + typeArrayOop value2 = (*entry2)->obj(); + guarantee(!equals(value1, value2), "Table entries must not have identical arrays"); + entry2 = (*entry2)->next_addr(); + } + entry1 = (*entry1)->next_addr(); + } + } +} + +void G1StringDedupTable::trim_entry_cache() { + MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); + size_t max_cache_size = (size_t)(_table->_size * _max_cache_factor); + _entry_cache->trim(max_cache_size); +} + +void G1StringDedupTable::print_statistics(outputStream* st) { + st->print_cr( + " [Table]\n" + " [Memory Usage: "G1_STRDEDUP_BYTES_FORMAT_NS"]\n" + " [Size: "SIZE_FORMAT", Min: "SIZE_FORMAT", Max: "SIZE_FORMAT"]\n" + " [Entries: "UINTX_FORMAT", Load: "G1_STRDEDUP_PERCENT_FORMAT_NS", Cached: " UINTX_FORMAT ", Added: "UINTX_FORMAT", Removed: "UINTX_FORMAT"]\n" + " [Resize Count: "UINTX_FORMAT", Shrink Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS"), Grow Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS")]\n" + " [Rehash Count: "UINTX_FORMAT", Rehash Threshold: "UINTX_FORMAT", Hash Seed: 0x%x]\n" + " [Age Threshold: "UINTX_FORMAT"]", + G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)), + _table->_size, _min_size, _max_size, + _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed, + _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0, + _rehash_count, _rehash_threshold, _table->_hash_seed, + StringDeduplicationAgeThreshold); +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp new file mode 100644 index 00000000000..f357523c513 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp @@ -0,0 +1,230 @@ +/* + * 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_G1STRINGDEDUPTABLE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP + +#include "gc_implementation/g1/g1StringDedupStat.hpp" +#include "runtime/mutexLocker.hpp" + +class G1StringDedupEntryCache; + +// +// Table entry in the deduplication hashtable. Points weakly to the +// character array. Can be chained in a linked list in case of hash +// collisions or when placed in a freelist in the entry cache. +// +class G1StringDedupEntry : public CHeapObj { +private: + G1StringDedupEntry* _next; + unsigned int _hash; + typeArrayOop _obj; + +public: + G1StringDedupEntry() : + _next(NULL), + _hash(0), + _obj(NULL) { + } + + G1StringDedupEntry* next() { + return _next; + } + + G1StringDedupEntry** next_addr() { + return &_next; + } + + void set_next(G1StringDedupEntry* next) { + _next = next; + } + + unsigned int hash() { + return _hash; + } + + void set_hash(unsigned int hash) { + _hash = hash; + } + + typeArrayOop obj() { + return _obj; + } + + typeArrayOop* obj_addr() { + return &_obj; + } + + void set_obj(typeArrayOop obj) { + _obj = obj; + } +}; + +// +// The deduplication hashtable keeps track of all unique character arrays used +// by String objects. Each table entry weakly points to an character array, allowing +// otherwise unreachable character arrays to be declared dead and pruned from the +// table. +// +// The table is dynamically resized to accommodate the current number of table entries. +// The table has hash buckets with chains for hash collision. If the average chain +// length goes above or below given thresholds the table grows or shrinks accordingly. +// +// The table is also dynamically rehashed (using a new hash seed) if it becomes severely +// unbalanced, i.e., a hash chain is significantly longer than average. +// +// All access to the table is protected by the StringDedupTable_lock, except under +// safepoints in which case GC workers are allowed to access a table partitions they +// have claimed without first acquiring the lock. Note however, that this applies only +// the table partition (i.e. a range of elements in _buckets), not other parts of the +// table such as the _entries field, statistics counters, etc. +// +class G1StringDedupTable : public CHeapObj { +private: + // The currently active hashtable instance. Only modified when + // the table is resizes or rehashed. + static G1StringDedupTable* _table; + + // Cache for reuse and fast alloc/free of table entries. + static G1StringDedupEntryCache* _entry_cache; + + G1StringDedupEntry** _buckets; + size_t _size; + uintx _entries; + uintx _shrink_threshold; + uintx _grow_threshold; + bool _rehash_needed; + + // The hash seed also dictates which hash function to use. A + // zero hash seed means we will use the Java compatible hash + // function (which doesn't use a seed), and a non-zero hash + // seed means we use the murmur3 hash function. + jint _hash_seed; + + // Constants governing table resize/rehash/cache. + static const size_t _min_size; + static const size_t _max_size; + static const double _grow_load_factor; + static const double _shrink_load_factor; + static const uintx _rehash_multiple; + static const uintx _rehash_threshold; + static const double _max_cache_factor; + + // Table statistics, only used for logging. + static uintx _entries_added; + static uintx _entries_removed; + static uintx _resize_count; + static uintx _rehash_count; + + G1StringDedupTable(size_t size, jint hash_seed = 0); + ~G1StringDedupTable(); + + // Returns the hash bucket at the given index. + G1StringDedupEntry** bucket(size_t index) { + return _buckets + index; + } + + // Returns the hash bucket index for the given hash code. + size_t hash_to_index(unsigned int hash) { + return (size_t)hash & (_size - 1); + } + + // Adds a new table entry to the given hash bucket. + void add(typeArrayOop value, unsigned int hash, G1StringDedupEntry** list); + + // Removes the given table entry from the table. + void remove(G1StringDedupEntry** pentry, uint worker_id); + + // Transfers a table entry from the current table to the destination table. + void transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest); + + // Returns an existing character array in the given hash bucket, or NULL + // if no matching character array exists. + typeArrayOop lookup(typeArrayOop value, unsigned int hash, + G1StringDedupEntry** list, uintx &count); + + // Returns an existing character array in the table, or inserts a new + // table entry if no matching character array exists. + typeArrayOop lookup_or_add_inner(typeArrayOop value, unsigned int hash); + + // Thread safe lookup or add of table entry + static typeArrayOop lookup_or_add(typeArrayOop value, unsigned int hash) { + // Protect the table from concurrent access. Also note that this lock + // acts as a fence for _table, which could have been replaced by a new + // instance if the table was resized or rehashed. + MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); + return _table->lookup_or_add_inner(value, hash); + } + + // Returns true if the hashtable is currently using a Java compatible + // hash function. + static bool use_java_hash() { + return _table->_hash_seed == 0; + } + + static bool equals(typeArrayOop value1, typeArrayOop value2); + + // Computes the hash code for the given character array, using the + // currently active hash function and hash seed. + static unsigned int hash_code(typeArrayOop value); + + static uintx unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, + size_t partition_begin, + size_t partition_end, + uint worker_id); + +public: + static void create(); + + // Deduplicates the given String object, or adds its backing + // character array to the deduplication hashtable. + static void deduplicate(oop java_string, G1StringDedupStat& stat); + + // If a table resize is needed, returns a newly allocated empty + // hashtable of the proper size. + static G1StringDedupTable* prepare_resize(); + + // Installs a newly resized table as the currently active table + // and deletes the previously active table. + static void finish_resize(G1StringDedupTable* resized_table); + + // If a table rehash is needed, returns a newly allocated empty + // hashtable and updates the hash seed. + static G1StringDedupTable* prepare_rehash(); + + // Transfers rehashed entries from the currently active table into + // the new table. Installs the new table as the currently active table + // and deletes the previously active table. + static void finish_rehash(G1StringDedupTable* rehashed_table); + + // If the table entry cache has grown too large, trim it down according to policy + static void trim_entry_cache(); + + static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id); + + static void print_statistics(outputStream* st); + static void verify(); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp new file mode 100644 index 00000000000..7263220a391 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp @@ -0,0 +1,124 @@ +/* + * 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/g1Log.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" +#include "gc_implementation/g1/g1StringDedupTable.hpp" +#include "gc_implementation/g1/g1StringDedupThread.hpp" +#include "gc_implementation/g1/g1StringDedupQueue.hpp" + +G1StringDedupThread* G1StringDedupThread::_thread = NULL; + +G1StringDedupThread::G1StringDedupThread() : + ConcurrentGCThread() { + set_name("String Deduplication Thread"); + create_and_start(); +} + +G1StringDedupThread::~G1StringDedupThread() { + ShouldNotReachHere(); +} + +void G1StringDedupThread::create() { + assert(G1StringDedup::is_enabled(), "String deduplication not enabled"); + assert(_thread == NULL, "One string deduplication thread allowed"); + _thread = new G1StringDedupThread(); +} + +G1StringDedupThread* G1StringDedupThread::thread() { + assert(G1StringDedup::is_enabled(), "String deduplication not enabled"); + assert(_thread != NULL, "String deduplication thread not created"); + return _thread; +} + +void G1StringDedupThread::print_on(outputStream* st) const { + st->print("\"%s\" ", name()); + Thread::print_on(st); + st->cr(); +} + +void G1StringDedupThread::run() { + G1StringDedupStat total_stat; + + initialize_in_thread(); + wait_for_universe_init(); + + // Main loop + for (;;) { + G1StringDedupStat stat; + + stat.mark_idle(); + + // Wait for the queue to become non-empty + G1StringDedupQueue::wait(); + + // Include this thread in safepoints + stsJoin(); + + stat.mark_exec(); + + // Process the queue + for (;;) { + oop java_string = G1StringDedupQueue::pop(); + if (java_string == NULL) { + break; + } + + G1StringDedupTable::deduplicate(java_string, stat); + + // Safepoint this thread if needed + if (stsShouldYield()) { + stat.mark_block(); + stsYield(NULL); + stat.mark_unblock(); + } + } + + G1StringDedupTable::trim_entry_cache(); + + stat.mark_done(); + + // Print statistics + total_stat.add(stat); + print(gclog_or_tty, stat, total_stat); + + // Exclude this thread from safepoints + stsLeave(); + } + + ShouldNotReachHere(); +} + +void G1StringDedupThread::print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { + if (G1Log::fine() || PrintStringDeduplicationStatistics) { + G1StringDedupStat::print_summary(st, last_stat, total_stat); + if (PrintStringDeduplicationStatistics) { + G1StringDedupStat::print_statistics(st, last_stat, false); + G1StringDedupStat::print_statistics(st, total_stat, true); + G1StringDedupTable::print_statistics(st); + G1StringDedupQueue::print_statistics(st); + } + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp new file mode 100644 index 00000000000..8a93058fd1e --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp @@ -0,0 +1,56 @@ +/* + * 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_G1STRINGDEDUPTHREAD_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP + +#include "gc_implementation/g1/g1StringDedupStat.hpp" +#include "gc_implementation/shared/concurrentGCThread.hpp" + +// +// The deduplication thread is where the actual deduplication occurs. It waits for +// deduplication candidates to appear on the deduplication queue, removes them from +// the queue and tries to deduplicate them. It uses the deduplication hashtable to +// find identical, already existing, character arrays on the heap. The thread runs +// concurrently with the Java application but participates in safepoints to allow +// the GC to adjust and unlink oops from the deduplication queue and table. +// +class G1StringDedupThread: public ConcurrentGCThread { +private: + static G1StringDedupThread* _thread; + + G1StringDedupThread(); + ~G1StringDedupThread(); + + void print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); + +public: + static void create(); + static G1StringDedupThread* thread(); + + virtual void run(); + virtual void print_on(outputStream* st) const; +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP 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 74158edb7c3..8c8a30bae38 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -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 @@ -285,6 +285,10 @@ product(uintx, G1MixedGCCountTarget, 8, \ "The target number of mixed GCs after a marking cycle.") \ \ + experimental(uintx, G1CodeRootsChunkCacheKeepPercent, 10, \ + "The amount of code root chunks that should be kept at most " \ + "as percentage of already allocated.") \ + \ 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/g1_specialized_oop_closures.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp index e10a658a543..538ca4452b9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp @@ -43,8 +43,6 @@ class G1ParCopyClosure; class G1ParScanClosure; class G1ParPushHeapRSClosure; -typedef G1ParCopyClosure G1ParScanHeapEvacClosure; - class FilterIntoCSClosure; class FilterOutOfRegionClosure; class G1CMOopClosure; @@ -61,7 +59,6 @@ class G1UpdateRSOrPushRefOopClosure; #endif #define FURTHER_SPECIALIZED_OOP_OOP_ITERATE_CLOSURES(f) \ - f(G1ParScanHeapEvacClosure,_nv) \ f(G1ParScanClosure,_nv) \ f(G1ParPushHeapRSClosure,_nv) \ f(FilterIntoCSClosure,_nv) \ diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 587ad1e1812..a82a9435d0b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.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 @@ -205,7 +205,7 @@ void HeapRegion::reset_after_compaction() { init_top_at_mark_start(); } -void HeapRegion::hr_clear(bool par, bool clear_space) { +void HeapRegion::hr_clear(bool par, bool clear_space, bool locked) { assert(_humongous_type == NotHumongous, "we should have already filtered out humongous regions"); assert(_humongous_start_region == NULL, @@ -223,7 +223,11 @@ void HeapRegion::hr_clear(bool par, bool clear_space) { if (!par) { // If this is parallel, this will be done later. HeapRegionRemSet* hrrs = rem_set(); - hrrs->clear(); + if (locked) { + hrrs->clear_locked(); + } else { + hrrs->clear(); + } _claimed = InitialClaimValue; } zero_marked_bytes(); @@ -352,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), _pending_removal(false), + _next_dirty_cards_region(NULL), _next(NULL), _prev(NULL), _pending_removal(false), #ifdef ASSERT _containing_set(NULL), #endif // ASSERT @@ -468,9 +472,6 @@ HeapRegion::object_iterate_mem_careful(MemRegion mr, } else if (!g1h->is_obj_dead(obj)) { cl->do_object(obj); } - if (cl->abort()) return cur; - // The check above must occur before the operation below, since an - // abort might invalidate the "size" operation. cur += obj->size(); } return NULL; @@ -710,14 +711,14 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const } HeapRegionRemSet* hrrs = rem_set(); - int strong_code_roots_length = hrrs->strong_code_roots_list_length(); + size_t strong_code_roots_length = hrrs->strong_code_roots_list_length(); // if this region is empty then there should be no entries // on its strong code root list if (is_empty()) { if (strong_code_roots_length > 0) { gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is empty " - "but has "INT32_FORMAT" code root entries", + "but has "SIZE_FORMAT" code root entries", bottom(), end(), strong_code_roots_length); *failures = true; } @@ -727,7 +728,7 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const if (continuesHumongous()) { if (strong_code_roots_length > 0) { gclog_or_tty->print_cr("region "HR_FORMAT" is a continuation of a humongous " - "region but has "INT32_FORMAT" code root entries", + "region but has "SIZE_FORMAT" code root entries", HR_FORMAT_PARAMS(this), strong_code_roots_length); *failures = true; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index ad2b0649795..b10f32674cc 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -271,6 +271,7 @@ class HeapRegion: public G1OffsetTableContigSpace { // Fields used by the HeapRegionSetBase class and subclasses. HeapRegion* _next; + HeapRegion* _prev; #ifdef ASSERT HeapRegionSetBase* _containing_set; #endif // ASSERT @@ -531,11 +532,13 @@ class HeapRegion: public G1OffsetTableContigSpace { // Methods used by the HeapRegionSetBase class and subclasses. - // Getter and setter for the next field used to link regions into + // Getter and setter for the next and prev fields used to link regions into // linked lists. HeapRegion* next() { return _next; } + HeapRegion* prev() { return _prev; } void set_next(HeapRegion* next) { _next = next; } + void set_prev(HeapRegion* prev) { _prev = prev; } // Every region added to a set is tagged with a reference to that // set. This is used for doing consistency checking to make sure that @@ -596,7 +599,7 @@ class HeapRegion: public G1OffsetTableContigSpace { void save_marks(); // Reset HR stuff to default values. - void hr_clear(bool par, bool clear_space); + void hr_clear(bool par, bool clear_space, bool locked = false); void par_clear(); // Get the start of the unmarked area in this region. diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index 4308fc01873..56d151d0eff 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.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 "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "memory/allocation.hpp" +#include "memory/padded.inline.hpp" #include "memory/space.inline.hpp" #include "oops/oop.inline.hpp" #include "utilities/bitMap.inline.hpp" @@ -259,10 +260,9 @@ size_t OtherRegionsTable::_mod_max_fine_entries_mask = 0; size_t OtherRegionsTable::_fine_eviction_stride = 0; size_t OtherRegionsTable::_fine_eviction_sample_size = 0; -OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) : +OtherRegionsTable::OtherRegionsTable(HeapRegion* hr, Mutex* m) : _g1h(G1CollectedHeap::heap()), - _m(Mutex::leaf, "An OtherRegionsTable lock", true), - _hr(hr), + _hr(hr), _m(m), _coarse_map(G1CollectedHeap::heap()->max_regions(), false /* in-resource-area */), _fine_grain_regions(NULL), @@ -358,46 +358,66 @@ void OtherRegionsTable::unlink_from_all(PerRegionTable* prt) { "just checking"); } -int** OtherRegionsTable::_from_card_cache = NULL; -size_t OtherRegionsTable::_from_card_cache_max_regions = 0; -size_t OtherRegionsTable::_from_card_cache_mem_size = 0; +int** FromCardCache::_cache = NULL; +uint FromCardCache::_max_regions = 0; +size_t FromCardCache::_static_mem_size = 0; -void OtherRegionsTable::init_from_card_cache(size_t max_regions) { - _from_card_cache_max_regions = max_regions; +void FromCardCache::initialize(uint n_par_rs, uint max_num_regions) { + guarantee(_cache == NULL, "Should not call this multiple times"); - int n_par_rs = HeapRegionRemSet::num_par_rem_sets(); - _from_card_cache = NEW_C_HEAP_ARRAY(int*, n_par_rs, mtGC); - for (int i = 0; i < n_par_rs; i++) { - _from_card_cache[i] = NEW_C_HEAP_ARRAY(int, max_regions, mtGC); - for (size_t j = 0; j < max_regions; j++) { - _from_card_cache[i][j] = -1; // An invalid value. + _max_regions = max_num_regions; + _cache = Padded2DArray::create_unfreeable(n_par_rs, + _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); } } - _from_card_cache_mem_size = n_par_rs * max_regions * sizeof(int); } -void OtherRegionsTable::shrink_from_card_cache(size_t new_n_regs) { - for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { - assert(new_n_regs <= _from_card_cache_max_regions, "Must be within max."); - for (size_t j = new_n_regs; j < _from_card_cache_max_regions; j++) { - _from_card_cache[i][j] = -1; // An invalid value. +void FromCardCache::shrink(uint 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++) { + set(i, j, InvalidCard); } } } #ifndef PRODUCT -void OtherRegionsTable::print_from_card_cache() { - for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { - for (size_t j = 0; j < _from_card_cache_max_regions; j++) { - gclog_or_tty->print_cr("_from_card_cache[%d][%d] = %d.", - i, j, _from_card_cache[i][j]); +void FromCardCache::print(outputStream* out) { + for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { + for (uint j = 0; j < _max_regions; j++) { + out->print_cr("_from_card_cache["UINT32_FORMAT"]["UINT32_FORMAT"] = "INT32_FORMAT".", + i, j, at(i, j)); } } } #endif +void FromCardCache::clear(uint region_idx) { + uint num_par_remsets = HeapRegionRemSet::num_par_rem_sets(); + for (uint i = 0; i < num_par_remsets; i++) { + set(i, region_idx, InvalidCard); + } +} + +void OtherRegionsTable::init_from_card_cache(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::print_from_card_cache() { + FromCardCache::print(); +} + void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { - size_t cur_hrs_ind = (size_t) hr()->hrs_index(); + uint cur_hrs_ind = hr()->hrs_index(); if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").", @@ -410,19 +430,17 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift); if (G1TraceHeapRegionRememberedSet) { - gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)", + gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = "INT32_FORMAT")", hr()->bottom(), from_card, - _from_card_cache[tid][cur_hrs_ind]); + FromCardCache::at((uint)tid, cur_hrs_ind)); } - if (from_card == _from_card_cache[tid][cur_hrs_ind]) { + if (FromCardCache::contains_or_replace((uint)tid, cur_hrs_ind, from_card)) { if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" from-card cache hit."); } assert(contains_reference(from), "We just added it!"); return; - } else { - _from_card_cache[tid][cur_hrs_ind] = from_card; } // Note that this may be a continued H region. @@ -442,7 +460,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { size_t ind = from_hrs_ind & _mod_max_fine_entries_mask; PerRegionTable* prt = find_region_table(ind, from_hr); if (prt == NULL) { - MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); + MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); // Confirm that it's really not there... prt = find_region_table(ind, from_hr); if (prt == NULL) { @@ -544,7 +562,7 @@ OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const { jint OtherRegionsTable::_n_coarsenings = 0; PerRegionTable* OtherRegionsTable::delete_region_table() { - assert(_m.owned_by_self(), "Precondition"); + assert(_m->owned_by_self(), "Precondition"); assert(_n_fine_entries == _max_fine_entries, "Precondition"); PerRegionTable* max = NULL; jint max_occ = 0; @@ -676,8 +694,6 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs, size_t OtherRegionsTable::occupied() const { - // Cast away const in this case. - MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag); size_t sum = occ_fine(); sum += occ_sparse(); sum += occ_coarse(); @@ -707,8 +723,6 @@ size_t OtherRegionsTable::occ_sparse() const { } size_t OtherRegionsTable::mem_size() const { - // Cast away const in this case. - MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag); size_t sum = 0; // all PRTs are of the same size so it is sufficient to query only one of them. if (_first_all_fine_prts != NULL) { @@ -724,7 +738,7 @@ size_t OtherRegionsTable::mem_size() const { } size_t OtherRegionsTable::static_mem_size() { - return _from_card_cache_mem_size; + return FromCardCache::static_mem_size(); } size_t OtherRegionsTable::fl_mem_size() { @@ -732,14 +746,10 @@ size_t OtherRegionsTable::fl_mem_size() { } void OtherRegionsTable::clear_fcc() { - size_t hrs_idx = hr()->hrs_index(); - for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { - _from_card_cache[i][hrs_idx] = -1; - } + FromCardCache::clear(hr()->hrs_index()); } void OtherRegionsTable::clear() { - MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); // if there are no entries, skip this step if (_first_all_fine_prts != NULL) { guarantee(_first_all_fine_prts != NULL && _last_all_fine_prts != NULL, "just checking"); @@ -759,7 +769,7 @@ void OtherRegionsTable::clear() { } void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) { - MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); + MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); size_t hrs_ind = (size_t) from_hr->hrs_index(); size_t ind = hrs_ind & _mod_max_fine_entries_mask; if (del_single_region_table(ind, from_hr)) { @@ -768,15 +778,15 @@ void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) { _coarse_map.par_at_put(hrs_ind, 0); } // Check to see if any of the fcc entries come from here. - size_t hr_ind = (size_t) hr()->hrs_index(); - for (int tid = 0; tid < HeapRegionRemSet::num_par_rem_sets(); tid++) { - int fcc_ent = _from_card_cache[tid][hr_ind]; - if (fcc_ent != -1) { + uint hr_ind = hr()->hrs_index(); + for (uint tid = 0; tid < HeapRegionRemSet::num_par_rem_sets(); tid++) { + int fcc_ent = FromCardCache::at(tid, hr_ind); + if (fcc_ent != FromCardCache::InvalidCard) { HeapWord* card_addr = (HeapWord*) (uintptr_t(fcc_ent) << CardTableModRefBS::card_shift); if (hr()->is_in_reserved(card_addr)) { // Clear the from card cache. - _from_card_cache[tid][hr_ind] = -1; + FromCardCache::set(tid, hr_ind, FromCardCache::InvalidCard); } } } @@ -805,7 +815,7 @@ bool OtherRegionsTable::del_single_region_table(size_t ind, bool OtherRegionsTable::contains_reference(OopOrNarrowOopStar from) const { // Cast away const in this case. - MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag); + MutexLockerEx x((Mutex*)_m, Mutex::_no_safepoint_check_flag); return contains_reference_locked(from); } @@ -832,8 +842,6 @@ bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const "Must be in range."); return _sparse_table.contains_card(hr_ind, card_index); } - - } void @@ -844,13 +852,15 @@ OtherRegionsTable::do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task) { // Determines how many threads can add records to an rset in parallel. // This can be done by either mutator threads together with the // concurrent refinement threads or GC threads. -int HeapRegionRemSet::num_par_rem_sets() { - return (int)MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads); +uint HeapRegionRemSet::num_par_rem_sets() { + return (uint)MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads); } HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr) - : _bosa(bosa), _strong_code_roots_list(NULL), _other_regions(hr) { + : _bosa(bosa), + _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #"UINT32_FORMAT, hr->hrs_index()), true), + _code_roots(), _other_regions(hr, &_m) { reset_for_par_iteration(); } @@ -883,7 +893,7 @@ bool HeapRegionRemSet::iter_is_complete() { } #ifndef PRODUCT -void HeapRegionRemSet::print() const { +void HeapRegionRemSet::print() { HeapRegionRemSetIterator iter(this); size_t card_index; while (iter.has_next(card_index)) { @@ -909,14 +919,14 @@ void HeapRegionRemSet::cleanup() { } void HeapRegionRemSet::clear() { - if (_strong_code_roots_list != NULL) { - delete _strong_code_roots_list; - } - _strong_code_roots_list = new (ResourceObj::C_HEAP, mtGC) - GrowableArray(10, 0, NULL, true); + MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); + clear_locked(); +} +void HeapRegionRemSet::clear_locked() { + _code_roots.clear(); _other_regions.clear(); - assert(occupied() == 0, "Should be clear."); + assert(occupied_locked() == 0, "Should be clear."); reset_for_par_iteration(); } @@ -932,27 +942,18 @@ void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs, _other_regions.scrub(ctbs, region_bm, card_bm); } - // Code roots support void HeapRegionRemSet::add_strong_code_root(nmethod* nm) { assert(nm != NULL, "sanity"); - // Search for the code blob from the RHS to avoid - // duplicate entries as much as possible - if (_strong_code_roots_list->find_from_end(nm) < 0) { - // Code blob isn't already in the list - _strong_code_roots_list->push(nm); - } + _code_roots.add(nm); } void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) { assert(nm != NULL, "sanity"); - int idx = _strong_code_roots_list->find(nm); - if (idx >= 0) { - _strong_code_roots_list->remove_at(idx); - } + _code_roots.remove(nm); // Check that there were no duplicates - guarantee(_strong_code_roots_list->find(nm) < 0, "duplicate entry found"); + guarantee(!_code_roots.contains(nm), "duplicate entry found"); } class NMethodMigrationOopClosure : public OopClosure { @@ -1014,8 +1015,8 @@ void HeapRegionRemSet::migrate_strong_code_roots() { GrowableArray to_be_retained(10); G1CollectedHeap* g1h = G1CollectedHeap::heap(); - while (_strong_code_roots_list->is_nonempty()) { - nmethod *nm = _strong_code_roots_list->pop(); + while (!_code_roots.is_empty()) { + nmethod *nm = _code_roots.pop(); if (nm != NULL) { NMethodMigrationOopClosure oop_cl(g1h, hr(), nm); nm->oops_do(&oop_cl); @@ -1038,20 +1039,16 @@ void HeapRegionRemSet::migrate_strong_code_roots() { } void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const { - for (int i = 0; i < _strong_code_roots_list->length(); i += 1) { - nmethod* nm = _strong_code_roots_list->at(i); - blk->do_code_blob(nm); - } + _code_roots.nmethods_do(blk); } size_t HeapRegionRemSet::strong_code_roots_mem_size() { - return sizeof(GrowableArray) + - _strong_code_roots_list->max_length() * sizeof(nmethod*); + return _code_roots.mem_size(); } //-------------------- Iteration -------------------- -HeapRegionRemSetIterator:: HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs) : +HeapRegionRemSetIterator:: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs) : _hrrs(hrrs), _g1h(G1CollectedHeap::heap()), _coarse_map(&hrrs->_other_regions._coarse_map), diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index 068f64f412e..0a080dbbf45 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -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 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONREMSET_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONREMSET_HPP +#include "gc_implementation/g1/g1CodeCacheRemSet.hpp" #include "gc_implementation/g1/sparsePRT.hpp" // Remembered set for a heap region. Represent a set of "cards" that @@ -44,6 +45,54 @@ class nmethod; class HRRSCleanupTask : public SparsePRTCleanupTask { }; +// The FromCardCache remembers the most recently processed card on the heap on +// a per-region and per-thread basis. +class FromCardCache : public AllStatic { + private: + // Array of card indices. Indexed by thread X and heap region to minimize + // thread contention. + static int** _cache; + static uint _max_regions; + static size_t _static_mem_size; + + public: + enum { + InvalidCard = -1 // Card value of an invalid card, i.e. a card index not otherwise used. + }; + + static void clear(uint region_idx); + + // Returns true if the given card is in the cache at the given location, or + // replaces the card at that location and returns false. + static bool contains_or_replace(uint worker_id, uint region_idx, int card) { + int card_in_cache = at(worker_id, region_idx); + if (card_in_cache == card) { + return true; + } else { + set(worker_id, region_idx, card); + return false; + } + } + + static int at(uint worker_id, uint region_idx) { + return _cache[worker_id][region_idx]; + } + + static void set(uint worker_id, uint region_idx, int val) { + _cache[worker_id][region_idx] = val; + } + + static void initialize(uint n_par_rs, uint max_num_regions); + + static void shrink(uint new_num_regions); + + static void print(outputStream* out = gclog_or_tty) PRODUCT_RETURN; + + static size_t static_mem_size() { + return _static_mem_size; + } +}; + // The "_coarse_map" is a bitmap with one bit for each region, where set // bits indicate that the corresponding region may contain some pointer // into the owning region. @@ -72,7 +121,7 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC { friend class HeapRegionRemSetIterator; G1CollectedHeap* _g1h; - Mutex _m; + Mutex* _m; HeapRegion* _hr; // These are protected by "_m". @@ -118,18 +167,13 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC { // false. bool del_single_region_table(size_t ind, HeapRegion* hr); - // Indexed by thread X heap region, to minimize thread contention. - static int** _from_card_cache; - static size_t _from_card_cache_max_regions; - static size_t _from_card_cache_mem_size; - // link/add the given fine grain remembered set into the "all" list void link_to_all(PerRegionTable * prt); // unlink/remove the given fine grain remembered set into the "all" list void unlink_from_all(PerRegionTable * prt); public: - OtherRegionsTable(HeapRegion* hr); + OtherRegionsTable(HeapRegion* hr, Mutex* m); HeapRegion* hr() const { return _hr; } @@ -141,7 +185,6 @@ public: // objects. void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm); - // Not const because it takes a lock. size_t occupied() const; size_t occ_fine() const; size_t occ_coarse() const; @@ -170,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(size_t max_regions); + static void init_from_card_cache(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(size_t new_n_regs); + static void shrink_from_card_cache(uint new_num_regions); static void print_from_card_cache(); }; @@ -192,15 +235,17 @@ private: G1BlockOffsetSharedArray* _bosa; G1BlockOffsetSharedArray* bosa() const { return _bosa; } - // A list of code blobs (nmethods) whose code contains pointers into + // A set of code blobs (nmethods) whose code contains pointers into // the region that owns this RSet. - GrowableArray* _strong_code_roots_list; + G1CodeRootSet _code_roots; + + Mutex _m; OtherRegionsTable _other_regions; enum ParIterState { Unclaimed, Claimed, Complete }; volatile ParIterState _iter_state; - volatile jlong _iter_claimed; + volatile size_t _iter_claimed; // Unused unless G1RecordHRRSOops is true. @@ -218,17 +263,20 @@ private: static void print_event(outputStream* str, Event evnt); public: - HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, - HeapRegion* hr); + HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr); - static int num_par_rem_sets(); + static uint num_par_rem_sets(); static void setup_remset_size(); HeapRegion* hr() const { return _other_regions.hr(); } - size_t occupied() const { + size_t occupied() { + MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); + return occupied_locked(); + } + size_t occupied_locked() { return _other_regions.occupied(); } size_t occ_fine() const { @@ -260,6 +308,7 @@ public: // The region is being reclaimed; clear its remset, and any mention of // entries for this region in other remsets. void clear(); + void clear_locked(); // Attempt to claim the region. Returns true iff this call caused an // atomic transition from Unclaimed to Claimed. @@ -270,16 +319,12 @@ public: bool iter_is_complete(); // Support for claiming blocks of cards during iteration - size_t iter_claimed() const { return (size_t)_iter_claimed; } + size_t iter_claimed() const { return _iter_claimed; } // Claim the next block of cards size_t iter_claimed_next(size_t step) { - size_t current, next; - do { - current = iter_claimed(); - next = current + step; - } while (Atomic::cmpxchg((jlong)next, &_iter_claimed, (jlong)current) != (jlong)current); - return current; + return Atomic::add(step, &_iter_claimed) - step; } + void reset_for_par_iteration(); bool verify_ready_for_par_iteration() { @@ -289,6 +334,7 @@ public: // The actual # of bytes this hr_remset takes up. // Note also includes the strong code root set. size_t mem_size() { + MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); return _other_regions.mem_size() // This correction is necessary because the above includes the second // part. @@ -299,13 +345,13 @@ public: // Returns the memory occupancy of all static data structures associated // with remembered sets. static size_t static_mem_size() { - return OtherRegionsTable::static_mem_size(); + return OtherRegionsTable::static_mem_size() + G1CodeRootSet::static_mem_size(); } // Returns the memory occupancy of all free_list data structures associated // with remembered sets. static size_t fl_mem_size() { - return OtherRegionsTable::fl_mem_size(); + return OtherRegionsTable::fl_mem_size() + G1CodeRootSet::fl_mem_size(); } bool contains_reference(OopOrNarrowOopStar from) const { @@ -328,21 +374,21 @@ public: void strong_code_roots_do(CodeBlobClosure* blk) const; // Returns the number of elements in the strong code roots list - int strong_code_roots_list_length() { - return _strong_code_roots_list->length(); + size_t strong_code_roots_list_length() { + return _code_roots.length(); } // Returns true if the strong code roots contains the given // nmethod. bool strong_code_roots_list_contains(nmethod* nm) { - return _strong_code_roots_list->contains(nm); + return _code_roots.contains(nm); } // Returns the amount of memory, in bytes, currently // consumed by the strong code roots. size_t strong_code_roots_mem_size(); - void print() const; + void print() PRODUCT_RETURN; // Called during a stop-world phase to perform any deferred cleanups. static void cleanup(); @@ -350,12 +396,13 @@ 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((size_t) max_regions); + G1CodeRootSet::initialize(); + OtherRegionsTable::init_from_card_cache(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((size_t) new_n_regs); + OtherRegionsTable::shrink_from_card_cache(new_n_regs); } #ifndef PRODUCT @@ -384,7 +431,7 @@ public: class HeapRegionRemSetIterator : public StackObj { // The region RSet over which we're iterating. - const HeapRegionRemSet* _hrrs; + HeapRegionRemSet* _hrrs; // Local caching of HRRS fields. const BitMap* _coarse_map; @@ -441,7 +488,7 @@ class HeapRegionRemSetIterator : public StackObj { public: // We require an iterator to be initialized before use, so the // constructor does little. - HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs); + HeapRegionRemSetIterator(HeapRegionRemSet* hrrs); // If there remains one or more cards to be yielded, returns true and // sets "card_index" to one of those cards (which is then considered diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp index c7b42b5cdc4..c047dccab0d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" -#include "gc_implementation/g1/heapRegionSets.hpp" +#include "gc_implementation/g1/heapRegionSet.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "memory/allocation.hpp" diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp index c0533c6bf55..6ec03d5ceae 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 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 @@ -23,171 +23,60 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSet.inline.hpp" -uint HeapRegionSetBase::_unrealistically_long_length = 0; -HRSPhase HeapRegionSetBase::_phase = HRSPhaseNone; - -//////////////////// HeapRegionSetBase //////////////////// - -void HeapRegionSetBase::set_unrealistically_long_length(uint len) { - guarantee(_unrealistically_long_length == 0, "should only be set once"); - _unrealistically_long_length = len; -} +uint FreeRegionList::_unrealistically_long_length = 0; void HeapRegionSetBase::fill_in_ext_msg(hrs_ext_msg* msg, const char* message) { - msg->append("[%s] %s ln: %u rn: %u cy: "SIZE_FORMAT" ud: "SIZE_FORMAT, - name(), message, length(), region_num(), - total_capacity_bytes(), total_used_bytes()); + msg->append("[%s] %s ln: %u cy: "SIZE_FORMAT, + name(), message, length(), total_capacity_bytes()); fill_in_ext_msg_extra(msg); } -bool HeapRegionSetBase::verify_region(HeapRegion* hr, - HeapRegionSetBase* expected_containing_set) { - const char* error_message = NULL; - - if (!regions_humongous()) { - if (hr->isHumongous()) { - error_message = "the region should not be humongous"; - } - } else { - if (!hr->isHumongous() || !hr->startsHumongous()) { - error_message = "the region should be 'starts humongous'"; - } - } - - if (!regions_empty()) { - if (hr->is_empty()) { - error_message = "the region should not be empty"; - } - } else { - if (!hr->is_empty()) { - error_message = "the region should be empty"; - } - } - -#ifdef ASSERT - // The _containing_set field is only available when ASSERT is defined. - if (hr->containing_set() != expected_containing_set) { - error_message = "inconsistent containing set found"; - } -#endif // ASSERT - - const char* extra_error_message = verify_region_extra(hr); - if (extra_error_message != NULL) { - error_message = extra_error_message; - } - - if (error_message != NULL) { - outputStream* out = tty; - out->cr(); - out->print_cr("## [%s] %s", name(), error_message); - out->print_cr("## Offending Region: "PTR_FORMAT, hr); - out->print_cr(" "HR_FORMAT, HR_FORMAT_PARAMS(hr)); -#ifdef ASSERT - out->print_cr(" containing set: "PTR_FORMAT, hr->containing_set()); -#endif // ASSERT - out->print_cr("## Offending Region Set: "PTR_FORMAT, this); - print_on(out); - return false; - } else { - return true; - } +#ifndef PRODUCT +void HeapRegionSetBase::verify_region(HeapRegion* hr) { + assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrs_index())); + assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrs_index())); // currently we don't use these sets for young regions + assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrs_index(), name())); + assert(hr->is_empty() == regions_empty(), err_msg("Wrong empty state for region %u and set %s", hr->hrs_index(), name())); + assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrs_index())); } +#endif void HeapRegionSetBase::verify() { // It's important that we also observe the MT safety protocol even // for the verification calls. If we do verification without the // appropriate locks and the set changes underneath our feet // verification might fail and send us on a wild goose chase. - hrs_assert_mt_safety_ok(this); + check_mt_safety(); - guarantee(( is_empty() && length() == 0 && region_num() == 0 && - total_used_bytes() == 0 && total_capacity_bytes() == 0) || - (!is_empty() && length() >= 0 && region_num() >= 0 && - total_used_bytes() >= 0 && total_capacity_bytes() >= 0), - hrs_ext_msg(this, "invariant")); - - guarantee((!regions_humongous() && region_num() == length()) || - ( regions_humongous() && region_num() >= length()), - hrs_ext_msg(this, "invariant")); - - guarantee(!regions_empty() || total_used_bytes() == 0, - hrs_ext_msg(this, "invariant")); - - guarantee(total_used_bytes() <= total_capacity_bytes(), + guarantee(( is_empty() && length() == 0 && total_capacity_bytes() == 0) || + (!is_empty() && length() >= 0 && total_capacity_bytes() >= 0), hrs_ext_msg(this, "invariant")); } void HeapRegionSetBase::verify_start() { // See comment in verify() about MT safety and verification. - hrs_assert_mt_safety_ok(this); + check_mt_safety(); assert(!_verify_in_progress, hrs_ext_msg(this, "verification should not be in progress")); // Do the basic verification first before we do the checks over the regions. HeapRegionSetBase::verify(); - _calc_length = 0; - _calc_region_num = 0; - _calc_total_capacity_bytes = 0; - _calc_total_used_bytes = 0; _verify_in_progress = true; } -void HeapRegionSetBase::verify_next_region(HeapRegion* hr) { - // See comment in verify() about MT safety and verification. - hrs_assert_mt_safety_ok(this); - assert(_verify_in_progress, - hrs_ext_msg(this, "verification should be in progress")); - - guarantee(verify_region(hr, this), hrs_ext_msg(this, "region verification")); - - _calc_length += 1; - _calc_region_num += hr->region_num(); - _calc_total_capacity_bytes += hr->capacity(); - _calc_total_used_bytes += hr->used(); -} - void HeapRegionSetBase::verify_end() { // See comment in verify() about MT safety and verification. - hrs_assert_mt_safety_ok(this); + check_mt_safety(); assert(_verify_in_progress, hrs_ext_msg(this, "verification should be in progress")); - guarantee(length() == _calc_length, - hrs_err_msg("[%s] length: %u should be == calc length: %u", - name(), length(), _calc_length)); - - guarantee(region_num() == _calc_region_num, - hrs_err_msg("[%s] region num: %u should be == calc region num: %u", - name(), region_num(), _calc_region_num)); - - guarantee(total_capacity_bytes() == _calc_total_capacity_bytes, - hrs_err_msg("[%s] capacity bytes: "SIZE_FORMAT" should be == " - "calc capacity bytes: "SIZE_FORMAT, - name(), - total_capacity_bytes(), _calc_total_capacity_bytes)); - - guarantee(total_used_bytes() == _calc_total_used_bytes, - hrs_err_msg("[%s] used bytes: "SIZE_FORMAT" should be == " - "calc used bytes: "SIZE_FORMAT, - name(), total_used_bytes(), _calc_total_used_bytes)); - _verify_in_progress = false; } -void HeapRegionSetBase::clear_phase() { - assert(_phase != HRSPhaseNone, "pre-condition"); - _phase = HRSPhaseNone; -} - -void HeapRegionSetBase::set_phase(HRSPhase phase) { - assert(_phase == HRSPhaseNone, "pre-condition"); - assert(phase != HRSPhaseNone, "pre-condition"); - _phase = phase; -} - void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) { out->cr(); out->print_cr("Set: %s ("PTR_FORMAT")", name(), this); @@ -196,76 +85,38 @@ void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) { out->print_cr(" empty : %s", BOOL_TO_STR(regions_empty())); out->print_cr(" Attributes"); out->print_cr(" length : %14u", length()); - out->print_cr(" region num : %14u", region_num()); out->print_cr(" total capacity : "SIZE_FORMAT_W(14)" bytes", total_capacity_bytes()); - out->print_cr(" total used : "SIZE_FORMAT_W(14)" bytes", - total_used_bytes()); } -void HeapRegionSetBase::clear() { - _length = 0; - _region_num = 0; - _total_used_bytes = 0; -} - -HeapRegionSetBase::HeapRegionSetBase(const char* name) +HeapRegionSetBase::HeapRegionSetBase(const char* name, bool humongous, bool empty, HRSMtSafeChecker* mt_safety_checker) : _name(name), _verify_in_progress(false), - _calc_length(0), _calc_region_num(0), - _calc_total_capacity_bytes(0), _calc_total_used_bytes(0) { } + _is_humongous(humongous), _is_empty(empty), _mt_safety_checker(mt_safety_checker), + _count() +{ } -//////////////////// HeapRegionSet //////////////////// - -void HeapRegionSet::update_from_proxy(HeapRegionSet* proxy_set) { - hrs_assert_mt_safety_ok(this); - hrs_assert_mt_safety_ok(proxy_set); - hrs_assert_sets_match(this, proxy_set); - - verify_optional(); - proxy_set->verify_optional(); - - if (proxy_set->is_empty()) return; - - assert(proxy_set->length() <= _length, - hrs_err_msg("[%s] proxy set length: %u should be <= length: %u", - name(), proxy_set->length(), _length)); - _length -= proxy_set->length(); - - assert(proxy_set->region_num() <= _region_num, - hrs_err_msg("[%s] proxy set region num: %u should be <= region num: %u", - name(), proxy_set->region_num(), _region_num)); - _region_num -= proxy_set->region_num(); - - assert(proxy_set->total_used_bytes() <= _total_used_bytes, - hrs_err_msg("[%s] proxy set used bytes: "SIZE_FORMAT" " - "should be <= used bytes: "SIZE_FORMAT, - name(), proxy_set->total_used_bytes(), - _total_used_bytes)); - _total_used_bytes -= proxy_set->total_used_bytes(); - - proxy_set->clear(); - - verify_optional(); - proxy_set->verify_optional(); +void FreeRegionList::set_unrealistically_long_length(uint len) { + guarantee(_unrealistically_long_length == 0, "should only be set once"); + _unrealistically_long_length = len; } -//////////////////// HeapRegionLinkedList //////////////////// - -void HeapRegionLinkedList::fill_in_ext_msg_extra(hrs_ext_msg* msg) { +void FreeRegionList::fill_in_ext_msg_extra(hrs_ext_msg* msg) { msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, head(), tail()); } -void HeapRegionLinkedList::add_as_head(HeapRegionLinkedList* from_list) { - hrs_assert_mt_safety_ok(this); - hrs_assert_mt_safety_ok(from_list); +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; + if (from_list->is_empty()) { + return; + } #ifdef ASSERT - HeapRegionLinkedListIterator iter(from_list); + 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 @@ -276,73 +127,49 @@ void HeapRegionLinkedList::add_as_head(HeapRegionLinkedList* from_list) { } #endif // ASSERT - if (_head != NULL) { - assert(length() > 0 && _tail != NULL, hrs_ext_msg(this, "invariant")); - from_list->_tail->set_next(_head); - } else { + if (_head == NULL) { assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant")); - _tail = from_list->_tail; - } - _head = from_list->_head; - - _length += from_list->length(); - _region_num += from_list->region_num(); - _total_used_bytes += from_list->total_used_bytes(); - from_list->clear(); - - verify_optional(); - from_list->verify_optional(); -} - -void HeapRegionLinkedList::add_as_tail(HeapRegionLinkedList* from_list) { - hrs_assert_mt_safety_ok(this); - hrs_assert_mt_safety_ok(from_list); - - verify_optional(); - from_list->verify_optional(); - - if (from_list->is_empty()) return; - -#ifdef ASSERT - HeapRegionLinkedListIterator 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 (_tail != NULL) { - assert(length() > 0 && _head != NULL, hrs_ext_msg(this, "invariant")); - _tail->set_next(from_list->_head); - } else { - assert(length() == 0 && _head == 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; + } } - _tail = from_list->_tail; - _length += from_list->length(); - _region_num += from_list->region_num(); - _total_used_bytes += from_list->total_used_bytes(); + _count.increment(from_list->length(), from_list->total_capacity_bytes()); from_list->clear(); verify_optional(); from_list->verify_optional(); } -void HeapRegionLinkedList::remove_all() { - hrs_assert_mt_safety_ok(this); +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 */); +} + +void FreeRegionList::remove_all() { + check_mt_safety(); verify_optional(); HeapRegion* curr = _head; while (curr != NULL) { - hrs_assert_region_ok(this, curr, this); + verify_region(curr); HeapRegion* next = curr->next(); curr->set_next(NULL); + curr->set_prev(NULL); curr->set_containing_set(NULL); curr = next; } @@ -351,8 +178,76 @@ void HeapRegionLinkedList::remove_all() { verify_optional(); } -void HeapRegionLinkedList::remove_all_pending(uint target_count) { - hrs_assert_mt_safety_ok(this); +void FreeRegionList::add_ordered(FreeRegionList* from_list) { + check_mt_safety(); + from_list->check_mt_safety(); + + verify_optional(); + from_list->verify_optional(); + + if (from_list->is_empty()) { + return; + } + + if (is_empty()) { + add_as_head(from_list); + 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 + + 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()); + from_list->clear(); + + verify_optional(); + from_list->verify_optional(); +} + +void FreeRegionList::remove_all_pending(uint target_count) { + check_mt_safety(); assert(target_count > 1, hrs_ext_msg(this, "pre-condition")); assert(!is_empty(), hrs_ext_msg(this, "pre-condition")); @@ -360,11 +255,11 @@ void HeapRegionLinkedList::remove_all_pending(uint target_count) { DEBUG_ONLY(uint old_length = length();) HeapRegion* curr = _head; - HeapRegion* prev = NULL; uint count = 0; while (curr != NULL) { - hrs_assert_region_ok(this, curr, this); + verify_region(curr); HeapRegion* next = curr->next(); + HeapRegion* prev = curr->prev(); if (curr->pending_removal()) { assert(count < target_count, @@ -384,10 +279,15 @@ void HeapRegionLinkedList::remove_all_pending(uint target_count) { _tail = prev; } else { assert(_tail != curr, hrs_ext_msg(this, "invariant")); + next->set_prev(prev); + } + if (_last = curr) { + _last = NULL; } curr->set_next(NULL); - remove_internal(curr); + curr->set_prev(NULL); + remove(curr); curr->set_pending_removal(false); count += 1; @@ -397,8 +297,6 @@ void HeapRegionLinkedList::remove_all_pending(uint target_count) { // carry on iterating to make sure there are not more regions // tagged with pending removal. DEBUG_ONLY(if (count == target_count) break;) - } else { - prev = curr; } curr = next; } @@ -414,46 +312,27 @@ void HeapRegionLinkedList::remove_all_pending(uint target_count) { verify_optional(); } -void HeapRegionLinkedList::verify() { +void FreeRegionList::verify() { // See comment in HeapRegionSetBase::verify() about MT safety and // verification. - hrs_assert_mt_safety_ok(this); + check_mt_safety(); // This will also do the basic verification too. verify_start(); - HeapRegion* curr = _head; - HeapRegion* prev1 = NULL; - HeapRegion* prev0 = NULL; - uint count = 0; - while (curr != NULL) { - verify_next_region(curr); - - count += 1; - guarantee(count < _unrealistically_long_length, - hrs_err_msg("[%s] the calculated length: %u " - "seems very long, is there maybe a cycle? " - "curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " - "prev1: "PTR_FORMAT" length: %u", - name(), count, curr, prev0, prev1, length())); - - prev1 = prev0; - prev0 = curr; - curr = curr->next(); - } - - guarantee(_tail == prev0, hrs_ext_msg(this, "post-condition")); + verify_list(); verify_end(); } -void HeapRegionLinkedList::clear() { - HeapRegionSetBase::clear(); +void FreeRegionList::clear() { + _count = HeapRegionSetCount(); _head = NULL; _tail = NULL; + _last = NULL; } -void HeapRegionLinkedList::print_on(outputStream* out, bool print_contents) { +void FreeRegionList::print_on(outputStream* out, bool print_contents) { HeapRegionSetBase::print_on(out, print_contents); out->print_cr(" Linking"); out->print_cr(" head : "PTR_FORMAT, _head); @@ -461,10 +340,124 @@ void HeapRegionLinkedList::print_on(outputStream* out, bool print_contents) { if (print_contents) { out->print_cr(" Contents"); - HeapRegionLinkedListIterator iter(this); + FreeRegionListIterator iter(this); while (iter.more_available()) { HeapRegion* hr = iter.get_next(); hr->print_on(out); } } } + +void FreeRegionList::verify_list() { + HeapRegion* curr = head(); + HeapRegion* prev1 = NULL; + HeapRegion* prev0 = NULL; + uint count = 0; + size_t capacity = 0; + uint last_index = 0; + + guarantee(_head == NULL || _head->prev() == NULL, "_head should not have a prev"); + while (curr != NULL) { + verify_region(curr); + + count++; + guarantee(count < _unrealistically_long_length, + hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " "prev1: "PTR_FORMAT" length: %u", name(), count, curr, prev0, prev1, length())); + + if (curr->next() != NULL) { + guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up"); + } + guarantee(curr->hrs_index() == 0 || curr->hrs_index() > last_index, "List should be sorted"); + last_index = curr->hrs_index(); + + capacity += curr->capacity(); + + prev1 = prev0; + prev0 = curr; + 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 == 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, + name(), total_capacity_bytes(), capacity)); +} + +// Note on the check_mt_safety() methods below: +// +// Verification of the "master" heap region sets / lists that are +// maintained by G1CollectedHeap is always done during a STW pause and +// by the VM thread at the start / end of the pause. The standard +// verification methods all assert check_mt_safety(). This is +// important as it ensures that verification is done without +// concurrent updates taking place at the same time. It follows, that, +// for the "master" heap region sets / lists, the check_mt_safety() +// method should include the VM thread / STW case. + +void MasterFreeRegionListMtSafeChecker::check() { + // Master Free List MT safety protocol: + // (a) If we're at a safepoint, operations on the master free list + // should be invoked by either the VM thread (which will serialize + // them) or by the GC workers while holding the + // FreeList_lock. + // (b) If we're not at a safepoint, operations on the master free + // list should be invoked while holding the Heap_lock. + + if (SafepointSynchronize::is_at_safepoint()) { + guarantee(Thread::current()->is_VM_thread() || + FreeList_lock->owned_by_self(), "master free list MT safety protocol at a safepoint"); + } else { + guarantee(Heap_lock->owned_by_self(), "master free list MT safety protocol outside a safepoint"); + } +} + +void SecondaryFreeRegionListMtSafeChecker::check() { + // Secondary Free List MT safety protocol: + // Operations on the secondary free list should always be invoked + // while holding the SecondaryFreeList_lock. + + guarantee(SecondaryFreeList_lock->owned_by_self(), "secondary free list MT safety protocol"); +} + +void OldRegionSetMtSafeChecker::check() { + // Master Old Set MT safety protocol: + // (a) If we're at a safepoint, operations on the master old set + // should be invoked: + // - by the VM thread (which will serialize them), or + // - by the GC workers while holding the FreeList_lock, if we're + // at a safepoint for an evacuation pause (this lock is taken + // anyway when an GC alloc region is retired so that a new one + // is allocated from the free list), or + // - by the GC workers while holding the OldSets_lock, if we're at a + // safepoint for a cleanup pause. + // (b) If we're not at a safepoint, operations on the master old set + // should be invoked while holding the Heap_lock. + + if (SafepointSynchronize::is_at_safepoint()) { + guarantee(Thread::current()->is_VM_thread() + || FreeList_lock->owned_by_self() || OldSets_lock->owned_by_self(), + "master old set MT safety protocol at a safepoint"); + } else { + guarantee(Heap_lock->owned_by_self(), "master old set MT safety protocol outside a safepoint"); + } +} + +void HumongousRegionSetMtSafeChecker::check() { + // Humongous Set MT safety protocol: + // (a) If we're at a safepoint, operations on the master humongous + // set should be invoked by either the VM thread (which will + // serialize them) or by the GC workers while holding the + // OldSets_lock. + // (b) If we're not at a safepoint, operations on the master + // humongous set should be invoked while holding the Heap_lock. + + if (SafepointSynchronize::is_at_safepoint()) { + guarantee(Thread::current()->is_VM_thread() || + OldSets_lock->owned_by_self(), + "master humongous set MT safety protocol at a safepoint"); + } else { + guarantee(Heap_lock->owned_by_self(), + "master humongous set MT safety protocol outside a safepoint"); + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp index f2f10d81548..c54fc784719 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 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 @@ -38,135 +38,108 @@ typedef FormatBuffer hrs_err_msg; #define HEAP_REGION_SET_FORCE_VERIFY defined(ASSERT) #endif // HEAP_REGION_SET_FORCE_VERIFY -//////////////////// HeapRegionSetBase //////////////////// +class hrs_ext_msg; + +class HRSMtSafeChecker : public CHeapObj { +public: + virtual void check() = 0; +}; + +class MasterFreeRegionListMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; +class SecondaryFreeRegionListMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; +class HumongousRegionSetMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; +class OldRegionSetMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; + +class HeapRegionSetCount VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + uint _length; + size_t _capacity; + +public: + HeapRegionSetCount() : _length(0), _capacity(0) { } + + const uint length() const { return _length; } + const size_t capacity() const { return _capacity; } + + void increment(uint length_to_add, size_t capacity_to_add) { + _length += length_to_add; + _capacity += capacity_to_add; + } + + void decrement(const uint length_to_remove, const size_t capacity_to_remove) { + _length -= length_to_remove; + _capacity -= capacity_to_remove; + } +}; // Base class for all the classes that represent heap region sets. It // contains the basic attributes that each set needs to maintain // (e.g., length, region num, used bytes sum) plus any shared // functionality (e.g., verification). -class hrs_ext_msg; - -typedef enum { - HRSPhaseNone, - HRSPhaseEvacuation, - HRSPhaseCleanup, - HRSPhaseFullGC -} HRSPhase; - -class HRSPhaseSetter; - class HeapRegionSetBase VALUE_OBJ_CLASS_SPEC { - friend class hrs_ext_msg; - friend class HRSPhaseSetter; friend class VMStructs; +private: + bool _is_humongous; + bool _is_empty; + HRSMtSafeChecker* _mt_safety_checker; protected: - static uint _unrealistically_long_length; - // The number of regions added to the set. If the set contains // only humongous regions, this reflects only 'starts humongous' // regions and does not include 'continues humongous' ones. - uint _length; - - // The total number of regions represented by the set. If the set - // does not contain humongous regions, this should be the same as - // _length. If the set contains only humongous regions, this will - // include the 'continues humongous' regions. - uint _region_num; - - // We don't keep track of the total capacity explicitly, we instead - // recalculate it based on _region_num and the heap region size. - - // The sum of used bytes in the all the regions in the set. - size_t _total_used_bytes; + HeapRegionSetCount _count; const char* _name; - bool _verify_in_progress; - uint _calc_length; - uint _calc_region_num; - size_t _calc_total_capacity_bytes; - size_t _calc_total_used_bytes; - - // This is here so that it can be used in the subclasses to assert - // something different depending on which phase the GC is in. This - // can be particularly helpful in the check_mt_safety() methods. - static HRSPhase _phase; - - // Only used by HRSPhaseSetter. - static void clear_phase(); - static void set_phase(HRSPhase phase); + bool _verify_in_progress; // verify_region() is used to ensure that the contents of a region - // added to / removed from a set are consistent. Different sets - // make different assumptions about the regions added to them. So - // each set can override verify_region_extra(), which is called - // from verify_region(), and do any extra verification it needs to - // perform in that. - virtual const char* verify_region_extra(HeapRegion* hr) { return NULL; } - bool verify_region(HeapRegion* hr, - HeapRegionSetBase* expected_containing_set); + // added to / removed from a set are consistent. + void verify_region(HeapRegion* hr) PRODUCT_RETURN; // Indicates whether all regions in the set should be humongous or // not. Only used during verification. - virtual bool regions_humongous() = 0; + bool regions_humongous() { return _is_humongous; } // Indicates whether all regions in the set should be empty or // not. Only used during verification. - virtual bool regions_empty() = 0; + bool regions_empty() { return _is_empty; } - // Subclasses can optionally override this to do MT safety protocol - // checks. It is called in an assert from all methods that perform - // updates on the set (and subclasses should also call it too). - virtual bool check_mt_safety() { return true; } + void check_mt_safety() { + if (_mt_safety_checker != NULL) { + _mt_safety_checker->check(); + } + } + + virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg) { } + + HeapRegionSetBase(const char* name, bool humongous, bool empty, HRSMtSafeChecker* mt_safety_checker); + +public: + const char* name() { return _name; } + + uint length() { return _count.length(); } + + bool is_empty() { return _count.length() == 0; } + + size_t total_capacity_bytes() { + return _count.capacity(); + } + + // It updates the fields of the set to reflect hr being added to + // the set and tags the region appropriately. + inline void add(HeapRegion* hr); + + // It updates the fields of the set to reflect hr being removed + // from the set and tags the region appropriately. + inline void remove(HeapRegion* hr); // fill_in_ext_msg() writes the the values of the set's attributes // in the custom err_msg (hrs_ext_msg). fill_in_ext_msg_extra() // allows subclasses to append further information. - virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg) { } void fill_in_ext_msg(hrs_ext_msg* msg, const char* message); - // It updates the fields of the set to reflect hr being added to - // the set. - inline void update_for_addition(HeapRegion* hr); - - // It updates the fields of the set to reflect hr being added to - // the set and tags the region appropriately. - inline void add_internal(HeapRegion* hr); - - // It updates the fields of the set to reflect hr being removed - // from the set. - inline void update_for_removal(HeapRegion* hr); - - // It updates the fields of the set to reflect hr being removed - // from the set and tags the region appropriately. - inline void remove_internal(HeapRegion* hr); - - // It clears all the fields of the sets. Note: it will not iterate - // over the set and remove regions from it. It assumes that the - // caller has already done so. It will literally just clear the fields. - virtual void clear(); - - HeapRegionSetBase(const char* name); - -public: - static void set_unrealistically_long_length(uint len); - - const char* name() { return _name; } - - uint length() { return _length; } - - bool is_empty() { return _length == 0; } - - uint region_num() { return _region_num; } - - size_t total_capacity_bytes() { - return (size_t) region_num() << HeapRegion::LogOfHRGrainBytes; - } - - size_t total_used_bytes() { return _total_used_bytes; } - virtual void verify(); void verify_start(); void verify_next_region(HeapRegion* hr); @@ -187,7 +160,6 @@ public: // assert/guarantee-specific message it also prints out the values of // the fields of the associated set. This can be very helpful in // diagnosing failures. - class hrs_ext_msg : public hrs_err_msg { public: hrs_ext_msg(HeapRegionSetBase* set, const char* message) : hrs_err_msg("") { @@ -195,32 +167,6 @@ public: } }; -class HRSPhaseSetter { -public: - HRSPhaseSetter(HRSPhase phase) { - HeapRegionSetBase::set_phase(phase); - } - ~HRSPhaseSetter() { - HeapRegionSetBase::clear_phase(); - } -}; - -// These two macros are provided for convenience, to keep the uses of -// these two asserts a bit more concise. - -#define hrs_assert_mt_safety_ok(_set_) \ - do { \ - assert((_set_)->check_mt_safety(), hrs_ext_msg((_set_), "MT safety")); \ - } while (0) - -#define hrs_assert_region_ok(_set_, _hr_, _expected_) \ - do { \ - assert((_set_)->verify_region((_hr_), (_expected_)), \ - hrs_ext_msg((_set_), "region verification")); \ - } while (0) - -//////////////////// HeapRegionSet //////////////////// - #define hrs_assert_sets_match(_set1_, _set2_) \ do { \ assert(((_set1_)->regions_humongous() == \ @@ -236,63 +182,41 @@ public: // the same interface (namely, the HeapRegionSetBase API). class HeapRegionSet : public HeapRegionSetBase { -protected: - virtual const char* verify_region_extra(HeapRegion* hr) { - if (hr->next() != NULL) { - return "next() should always be NULL as we do not link the regions"; - } - - return HeapRegionSetBase::verify_region_extra(hr); - } - - HeapRegionSet(const char* name) : HeapRegionSetBase(name) { - clear(); - } - public: - // It adds hr to the set. The region should not be a member of - // another set. - inline void add(HeapRegion* hr); + HeapRegionSet(const char* name, bool humongous, HRSMtSafeChecker* mt_safety_checker): + HeapRegionSetBase(name, humongous, false /* empty */, mt_safety_checker) { } - // It removes hr from the set. The region should be a member of - // this set. - inline void remove(HeapRegion* hr); - - // It removes a region from the set. Instead of updating the fields - // of the set to reflect this removal, it accumulates the updates - // in proxy_set. The idea is that proxy_set is thread-local to - // avoid multiple threads updating the fields of the set - // concurrently and having to synchronize. The method - // update_from_proxy() will update the fields of the set from the - // proxy_set. - inline void remove_with_proxy(HeapRegion* hr, HeapRegionSet* proxy_set); - - // After multiple calls to remove_with_proxy() the updates to the - // fields of the set are accumulated in proxy_set. This call - // updates the fields of the set from proxy_set. - void update_from_proxy(HeapRegionSet* proxy_set); + void bulk_remove(const HeapRegionSetCount& removed) { + _count.decrement(removed.length(), removed.capacity()); + } }; -//////////////////// HeapRegionLinkedList //////////////////// - -// A set that links all the regions added to it in a singly-linked +// 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 // such lists in performance critical paths. Typically we should -// add / remove one region at a time or concatenate two lists. All -// those operations are done in constant time. +// 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. -class HeapRegionLinkedListIterator; +class FreeRegionListIterator; -class HeapRegionLinkedList : public HeapRegionSetBase { - friend class HeapRegionLinkedListIterator; +class FreeRegionList : public HeapRegionSetBase { + friend class FreeRegionListIterator; private: HeapRegion* _head; HeapRegion* _tail; - // These are provided for use by the friend classes. - HeapRegion* head() { return _head; } - HeapRegion* tail() { return _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. + HeapRegion* _last; + + static uint _unrealistically_long_length; + + void add_as_head_or_tail(FreeRegionList* from_list, bool as_head); protected: virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg); @@ -300,11 +224,24 @@ protected: // See the comment for HeapRegionSetBase::clear() virtual void clear(); - HeapRegionLinkedList(const char* name) : HeapRegionSetBase(name) { +public: + FreeRegionList(const char* name, HRSMtSafeChecker* mt_safety_checker = NULL): + HeapRegionSetBase(name, false /* humongous */, true /* empty */, mt_safety_checker) { clear(); } -public: + void verify_list(); + + HeapRegion* head() { return _head; } + HeapRegion* tail() { return _tail; } + + static void set_unrealistically_long_length(uint len); + + // Add hr to the list. The region should not be a member of another set. + // Assumes that the list is ordered and will preserve that order. The order + // 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); @@ -320,15 +257,29 @@ public: // 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); + + // 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(HeapRegionLinkedList* from_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(HeapRegionLinkedList* from_list); + void add_as_tail(FreeRegionList* from_list); // It empties the list by removing all regions from it. void remove_all(); @@ -346,15 +297,13 @@ public: virtual void print_on(outputStream* out, bool print_contents = false); }; -//////////////////// HeapRegionLinkedListIterator //////////////////// - // Iterator class that provides a convenient way to iterate over the // regions of a HeapRegionLinkedList instance. -class HeapRegionLinkedListIterator : public StackObj { +class FreeRegionListIterator : public StackObj { private: - HeapRegionLinkedList* _list; - HeapRegion* _curr; + FreeRegionList* _list; + HeapRegion* _curr; public: bool more_available() { @@ -369,13 +318,12 @@ public: // do the "cycle" check. HeapRegion* hr = _curr; - assert(_list->verify_region(hr, _list), "region verification"); + _list->verify_region(hr); _curr = hr->next(); return hr; } - HeapRegionLinkedListIterator(HeapRegionLinkedList* list) - : _curr(NULL), _list(list) { + FreeRegionListIterator(FreeRegionList* list) : _curr(NULL), _list(list) { _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 18c754bdc51..287f1bd96a7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 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 @@ -27,116 +27,110 @@ #include "gc_implementation/g1/heapRegionSet.hpp" -//////////////////// HeapRegionSetBase //////////////////// - -inline void HeapRegionSetBase::update_for_addition(HeapRegion* hr) { - // Assumes the caller has already verified the region. - - _length += 1; - _region_num += hr->region_num(); - _total_used_bytes += hr->used(); -} - -inline void HeapRegionSetBase::add_internal(HeapRegion* hr) { - hrs_assert_region_ok(this, hr, NULL); +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, hrs_ext_msg(this, "should not already be linked")); - update_for_addition(hr); + _count.increment(1u, hr->capacity()); hr->set_containing_set(this); + verify_region(hr); } -inline void HeapRegionSetBase::update_for_removal(HeapRegion* hr) { - // Assumes the caller has already verified the region. - assert(_length > 0, hrs_ext_msg(this, "pre-condition")); - _length -= 1; - - uint region_num_diff = hr->region_num(); - assert(region_num_diff <= _region_num, - hrs_err_msg("[%s] region's region num: %u " - "should be <= region num: %u", - name(), region_num_diff, _region_num)); - _region_num -= region_num_diff; - - size_t used_bytes = hr->used(); - assert(used_bytes <= _total_used_bytes, - hrs_err_msg("[%s] region's used bytes: "SIZE_FORMAT" " - "should be <= used bytes: "SIZE_FORMAT, - name(), used_bytes, _total_used_bytes)); - _total_used_bytes -= used_bytes; -} - -inline void HeapRegionSetBase::remove_internal(HeapRegion* hr) { - hrs_assert_region_ok(this, hr, this); +inline void HeapRegionSetBase::remove(HeapRegion* hr) { + check_mt_safety(); + verify_region(hr); assert(hr->next() == NULL, hrs_ext_msg(this, "should already be unlinked")); hr->set_containing_set(NULL); - update_for_removal(hr); + assert(_count.length() > 0, hrs_ext_msg(this, "pre-condition")); + _count.decrement(1u, hr->capacity()); } -//////////////////// HeapRegionSet //////////////////// - -inline void HeapRegionSet::add(HeapRegion* hr) { - hrs_assert_mt_safety_ok(this); - // add_internal() will verify the region. - add_internal(hr); -} - -inline void HeapRegionSet::remove(HeapRegion* hr) { - hrs_assert_mt_safety_ok(this); - // remove_internal() will verify the region. - remove_internal(hr); -} - -inline void HeapRegionSet::remove_with_proxy(HeapRegion* hr, - HeapRegionSet* proxy_set) { - // No need to fo the MT safety check here given that this method - // does not update the contents of the set but instead accumulates - // the changes in proxy_set which is assumed to be thread-local. - hrs_assert_sets_match(this, proxy_set); - hrs_assert_region_ok(this, hr, this); - - hr->set_containing_set(NULL); - proxy_set->update_for_addition(hr); -} - -//////////////////// HeapRegionLinkedList //////////////////// - -inline void HeapRegionLinkedList::add_as_head(HeapRegion* hr) { - hrs_assert_mt_safety_ok(this); +inline void FreeRegionList::add_ordered(HeapRegion* hr) { + check_mt_safety(); assert((length() == 0 && _head == NULL && _tail == NULL) || (length() > 0 && _head != NULL && _tail != NULL), hrs_ext_msg(this, "invariant")); - // add_internal() will verify the region. - add_internal(hr); + // add() will verify the region and check mt safety. + add(hr); + + // Now link the region + if (_head != NULL) { + HeapRegion* curr; + + if (_last != NULL && _last->hrs_index() < hr->hrs_index()) { + curr = _last; + } else { + curr = _head; + } + + // Find first entry with a Region Index larger than entry to insert. + while (curr != NULL && curr->hrs_index() < hr->hrs_index()) { + curr = curr->next(); + } + + hr->set_next(curr); + + if (curr == NULL) { + // Adding at the end + hr->set_prev(_tail); + _tail->set_next(hr); + _tail = hr; + } else if (curr->prev() == NULL) { + // Adding at the beginning + hr->set_prev(NULL); + _head = hr; + curr->set_prev(hr); + } else { + hr->set_prev(curr->prev()); + hr->prev()->set_next(hr); + curr->set_prev(hr); + } + } else { + // The list was empty + _tail = hr; + _head = 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 HeapRegionLinkedList::add_as_tail(HeapRegion* hr) { - hrs_assert_mt_safety_ok(this); +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_internal() will verify the region. - add_internal(hr); + // 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* HeapRegionLinkedList::remove_head() { - hrs_assert_mt_safety_ok(this); +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")); @@ -146,17 +140,22 @@ inline HeapRegion* HeapRegionLinkedList::remove_head() { _head = hr->next(); if (_head == NULL) { _tail = NULL; + } else { + _head->set_prev(NULL); } hr->set_next(NULL); - // remove_internal() will verify the region. - remove_internal(hr); + if (_last == hr) { + _last = NULL; + } + + // remove() will verify the region and check mt safety. + remove(hr); return hr; } -inline HeapRegion* HeapRegionLinkedList::remove_head_or_null() { - hrs_assert_mt_safety_ok(this); - +inline HeapRegion* FreeRegionList::remove_head_or_null() { + check_mt_safety(); if (!is_empty()) { return remove_head(); } else { @@ -164,4 +163,47 @@ inline HeapRegion* HeapRegionLinkedList::remove_head_or_null() { } } +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(); + if (_tail == NULL) { + _head = NULL; + } else { + _tail->set_next(NULL); + } + hr->set_prev(NULL); + + if (_last == hr) { + _last = NULL; + } + + // remove() will verify the region and check mt safety. + remove(hr); + 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/heapRegionSets.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp deleted file mode 100644 index d2a9665c953..00000000000 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "gc_implementation/g1/heapRegionRemSet.hpp" -#include "gc_implementation/g1/heapRegionSets.hpp" - -// Note on the check_mt_safety() methods below: -// -// Verification of the "master" heap region sets / lists that are -// maintained by G1CollectedHeap is always done during a STW pause and -// by the VM thread at the start / end of the pause. The standard -// verification methods all assert check_mt_safety(). This is -// important as it ensures that verification is done without -// concurrent updates taking place at the same time. It follows, that, -// for the "master" heap region sets / lists, the check_mt_safety() -// method should include the VM thread / STW case. - -//////////////////// FreeRegionList //////////////////// - -const char* FreeRegionList::verify_region_extra(HeapRegion* hr) { - if (hr->is_young()) { - return "the region should not be young"; - } - // The superclass will check that the region is empty and - // not humongous. - return HeapRegionLinkedList::verify_region_extra(hr); -} - -//////////////////// MasterFreeRegionList //////////////////// - -const char* MasterFreeRegionList::verify_region_extra(HeapRegion* hr) { - // We should reset the RSet for parallel iteration before we add it - // to the master free list so that it is ready when the region is - // re-allocated. - if (!hr->rem_set()->verify_ready_for_par_iteration()) { - return "the region's RSet should be ready for parallel iteration"; - } - return FreeRegionList::verify_region_extra(hr); -} - -bool MasterFreeRegionList::check_mt_safety() { - // Master Free List MT safety protocol: - // (a) If we're at a safepoint, operations on the master free list - // should be invoked by either the VM thread (which will serialize - // them) or by the GC workers while holding the - // FreeList_lock. - // (b) If we're not at a safepoint, operations on the master free - // list should be invoked while holding the Heap_lock. - - if (SafepointSynchronize::is_at_safepoint()) { - guarantee(Thread::current()->is_VM_thread() || - FreeList_lock->owned_by_self(), - hrs_ext_msg(this, "master free list MT safety protocol " - "at a safepoint")); - } else { - guarantee(Heap_lock->owned_by_self(), - hrs_ext_msg(this, "master free list MT safety protocol " - "outside a safepoint")); - } - - return FreeRegionList::check_mt_safety(); -} - -//////////////////// SecondaryFreeRegionList //////////////////// - -bool SecondaryFreeRegionList::check_mt_safety() { - // Secondary Free List MT safety protocol: - // Operations on the secondary free list should always be invoked - // while holding the SecondaryFreeList_lock. - - guarantee(SecondaryFreeList_lock->owned_by_self(), - hrs_ext_msg(this, "secondary free list MT safety protocol")); - - return FreeRegionList::check_mt_safety(); -} - -//////////////////// OldRegionSet //////////////////// - -const char* OldRegionSet::verify_region_extra(HeapRegion* hr) { - if (hr->is_young()) { - return "the region should not be young"; - } - // The superclass will check that the region is not empty and not - // humongous. - return HeapRegionSet::verify_region_extra(hr); -} - -//////////////////// MasterOldRegionSet //////////////////// - -bool MasterOldRegionSet::check_mt_safety() { - // Master Old Set MT safety protocol: - // (a) If we're at a safepoint, operations on the master old set - // should be invoked: - // - by the VM thread (which will serialize them), or - // - by the GC workers while holding the FreeList_lock, if we're - // at a safepoint for an evacuation pause (this lock is taken - // anyway when an GC alloc region is retired so that a new one - // is allocated from the free list), or - // - by the GC workers while holding the OldSets_lock, if we're at a - // safepoint for a cleanup pause. - // (b) If we're not at a safepoint, operations on the master old set - // should be invoked while holding the Heap_lock. - - if (SafepointSynchronize::is_at_safepoint()) { - guarantee(Thread::current()->is_VM_thread() || - _phase == HRSPhaseEvacuation && FreeList_lock->owned_by_self() || - _phase == HRSPhaseCleanup && OldSets_lock->owned_by_self(), - hrs_ext_msg(this, "master old set MT safety protocol " - "at a safepoint")); - } else { - guarantee(Heap_lock->owned_by_self(), - hrs_ext_msg(this, "master old set MT safety protocol " - "outside a safepoint")); - } - - return OldRegionSet::check_mt_safety(); -} - -//////////////////// HumongousRegionSet //////////////////// - -const char* HumongousRegionSet::verify_region_extra(HeapRegion* hr) { - if (hr->is_young()) { - return "the region should not be young"; - } - // The superclass will check that the region is not empty and - // humongous. - return HeapRegionSet::verify_region_extra(hr); -} - -//////////////////// MasterHumongousRegionSet //////////////////// - -bool MasterHumongousRegionSet::check_mt_safety() { - // Master Humongous Set MT safety protocol: - // (a) If we're at a safepoint, operations on the master humongous - // set should be invoked by either the VM thread (which will - // serialize them) or by the GC workers while holding the - // OldSets_lock. - // (b) If we're not at a safepoint, operations on the master - // humongous set should be invoked while holding the Heap_lock. - - if (SafepointSynchronize::is_at_safepoint()) { - guarantee(Thread::current()->is_VM_thread() || - OldSets_lock->owned_by_self(), - hrs_ext_msg(this, "master humongous set MT safety protocol " - "at a safepoint")); - } else { - guarantee(Heap_lock->owned_by_self(), - hrs_ext_msg(this, "master humongous set MT safety protocol " - "outside a safepoint")); - } - - return HumongousRegionSet::check_mt_safety(); -} diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp deleted file mode 100644 index 66423266ef3..00000000000 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSETS_HPP -#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSETS_HPP - -#include "gc_implementation/g1/heapRegionSet.inline.hpp" - -//////////////////// FreeRegionList //////////////////// - -class FreeRegionList : public HeapRegionLinkedList { -protected: - virtual const char* verify_region_extra(HeapRegion* hr); - - virtual bool regions_humongous() { return false; } - virtual bool regions_empty() { return true; } - -public: - FreeRegionList(const char* name) : HeapRegionLinkedList(name) { } -}; - -//////////////////// MasterFreeRegionList //////////////////// - -class MasterFreeRegionList : public FreeRegionList { -protected: - virtual const char* verify_region_extra(HeapRegion* hr); - virtual bool check_mt_safety(); - -public: - MasterFreeRegionList(const char* name) : FreeRegionList(name) { } -}; - -//////////////////// SecondaryFreeRegionList //////////////////// - -class SecondaryFreeRegionList : public FreeRegionList { -protected: - virtual bool check_mt_safety(); - -public: - SecondaryFreeRegionList(const char* name) : FreeRegionList(name) { } -}; - -//////////////////// OldRegionSet //////////////////// - -class OldRegionSet : public HeapRegionSet { -protected: - virtual const char* verify_region_extra(HeapRegion* hr); - - virtual bool regions_humongous() { return false; } - virtual bool regions_empty() { return false; } - -public: - OldRegionSet(const char* name) : HeapRegionSet(name) { } -}; - -//////////////////// MasterOldRegionSet //////////////////// - -class MasterOldRegionSet : public OldRegionSet { -private: -protected: - virtual bool check_mt_safety(); - -public: - MasterOldRegionSet(const char* name) : OldRegionSet(name) { } -}; - -//////////////////// HumongousRegionSet //////////////////// - -class HumongousRegionSet : public HeapRegionSet { -protected: - virtual const char* verify_region_extra(HeapRegion* hr); - - virtual bool regions_humongous() { return true; } - virtual bool regions_empty() { return false; } - -public: - HumongousRegionSet(const char* name) : HeapRegionSet(name) { } -}; - -//////////////////// MasterHumongousRegionSet //////////////////// - -class MasterHumongousRegionSet : public HumongousRegionSet { -protected: - virtual bool check_mt_safety(); - -public: - MasterHumongousRegionSet(const char* name) : HumongousRegionSet(name) { } -}; - -#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSETS_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp index ccd51c92ec1..6094837d35a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_SPARSEPRT_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_SPARSEPRT_HPP -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "memory/allocation.hpp" #include "memory/cardTableModRefBS.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 2e4ed2dfb4a..d7820f89abe 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp @@ -57,9 +57,10 @@ nonstatic_field(G1MonitoringSupport, _old_committed, size_t) \ nonstatic_field(G1MonitoringSupport, _old_used, size_t) \ \ - nonstatic_field(HeapRegionSetBase, _length, uint) \ - nonstatic_field(HeapRegionSetBase, _region_num, uint) \ - nonstatic_field(HeapRegionSetBase, _total_used_bytes, size_t) \ + nonstatic_field(HeapRegionSetBase, _count, HeapRegionSetCount) \ + \ + nonstatic_field(HeapRegionSetCount, _length, uint) \ + nonstatic_field(HeapRegionSetCount, _capacity, size_t) \ #define VM_TYPES_G1(declare_type, declare_toplevel_type) \ @@ -71,6 +72,7 @@ declare_type(HeapRegion, ContiguousSpace) \ declare_toplevel_type(HeapRegionSeq) \ declare_toplevel_type(HeapRegionSetBase) \ + declare_toplevel_type(HeapRegionSetCount) \ declare_toplevel_type(G1MonitoringSupport) \ \ declare_toplevel_type(G1CollectedHeap*) \ diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index da0e569e869..9ebdb841dfd 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -665,8 +665,10 @@ void ParallelScavengeHeap::print_heap_change(size_t prev_used) { void ParallelScavengeHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) { const PSHeapSummary& heap_summary = create_ps_heap_summary(); + gc_tracer->report_gc_heap_summary(when, heap_summary); + const MetaspaceSummary& metaspace_summary = create_metaspace_summary(); - gc_tracer->report_gc_heap_summary(when, heap_summary, metaspace_summary); + gc_tracer->report_metaspace_summary(when, metaspace_summary); } ParallelScavengeHeap* ParallelScavengeHeap::heap() { diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp index a708d8ebb72..a5d008ee11c 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp @@ -550,7 +550,8 @@ bool PSScavenge::invoke_no_policy() { if (PrintTenuringDistribution) { gclog_or_tty->cr(); - gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u (max %u)", + gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold " + UINTX_FORMAT " (max threshold " UINTX_FORMAT ")", size_policy->calculated_survivor_size_in_bytes(), _tenuring_threshold, MaxTenuringThreshold); } @@ -829,10 +830,10 @@ GCTaskManager* const PSScavenge::gc_task_manager() { void PSScavenge::initialize() { // Arguments must have been parsed - if (AlwaysTenure) { - _tenuring_threshold = 0; - } else if (NeverTenure) { - _tenuring_threshold = markOopDesc::max_age + 1; + if (AlwaysTenure || NeverTenure) { + assert(MaxTenuringThreshold == 0 || MaxTenuringThreshold == markOopDesc::max_age + 1, + err_msg("MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is ", MaxTenuringThreshold)); + _tenuring_threshold = MaxTenuringThreshold; } else { // We want to smooth out our startup times for the AdaptiveSizePolicy _tenuring_threshold = (UseAdaptiveSizePolicy) ? InitialTenuringThreshold : diff --git a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp b/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp index 311fd7771dd..2fe4de9c30e 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/ageTable.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 @@ -80,28 +80,37 @@ void ageTable::merge_par(ageTable* subTable) { uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) { size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100); - size_t total = 0; - uint age = 1; - assert(sizes[0] == 0, "no objects with age zero should be recorded"); - while (age < table_size) { - total += sizes[age]; - // check if including objects of age 'age' made us pass the desired - // size, if so 'age' is the new threshold - if (total > desired_survivor_size) break; - age++; + uint result; + + if (AlwaysTenure || NeverTenure) { + assert(MaxTenuringThreshold == 0 || MaxTenuringThreshold == markOopDesc::max_age + 1, + err_msg("MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is ", MaxTenuringThreshold)); + result = MaxTenuringThreshold; + } else { + size_t total = 0; + uint age = 1; + assert(sizes[0] == 0, "no objects with age zero should be recorded"); + while (age < table_size) { + total += sizes[age]; + // check if including objects of age 'age' made us pass the desired + // size, if so 'age' is the new threshold + if (total > desired_survivor_size) break; + age++; + } + result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold; } - uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold; if (PrintTenuringDistribution || UsePerfData) { if (PrintTenuringDistribution) { gclog_or_tty->cr(); - gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u (max %u)", + gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold " + UINTX_FORMAT " (max threshold " UINTX_FORMAT ")", desired_survivor_size*oopSize, result, MaxTenuringThreshold); } - total = 0; - age = 1; + size_t total = 0; + uint age = 1; while (age < table_size) { total += sizes[age]; if (sizes[age] > 0) { diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp b/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp index 4e79b8f93d5..7f6dca0fb1f 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCHEAPSUMMARY_HPP #include "memory/allocation.hpp" +#include "memory/metaspaceChunkFreeListSummary.hpp" class VirtualSpaceSummary : public StackObj { HeapWord* _start; @@ -125,18 +126,49 @@ class PSHeapSummary : public GCHeapSummary { }; class MetaspaceSummary : public StackObj { + size_t _capacity_until_GC; MetaspaceSizes _meta_space; MetaspaceSizes _data_space; MetaspaceSizes _class_space; + MetaspaceChunkFreeListSummary _metaspace_chunk_free_list_summary; + MetaspaceChunkFreeListSummary _class_chunk_free_list_summary; public: - MetaspaceSummary() : _meta_space(), _data_space(), _class_space() {} - MetaspaceSummary(const MetaspaceSizes& meta_space, const MetaspaceSizes& data_space, const MetaspaceSizes& class_space) : - _meta_space(meta_space), _data_space(data_space), _class_space(class_space) { } + MetaspaceSummary() : + _capacity_until_GC(0), + _meta_space(), + _data_space(), + _class_space(), + _metaspace_chunk_free_list_summary(), + _class_chunk_free_list_summary() + {} + MetaspaceSummary(size_t capacity_until_GC, + const MetaspaceSizes& meta_space, + const MetaspaceSizes& data_space, + const MetaspaceSizes& class_space, + const MetaspaceChunkFreeListSummary& metaspace_chunk_free_list_summary, + const MetaspaceChunkFreeListSummary& class_chunk_free_list_summary) : + _capacity_until_GC(capacity_until_GC), + _meta_space(meta_space), + _data_space(data_space), + _class_space(class_space), + _metaspace_chunk_free_list_summary(metaspace_chunk_free_list_summary), + _class_chunk_free_list_summary(class_chunk_free_list_summary) + {} + size_t capacity_until_GC() const { return _capacity_until_GC; } const MetaspaceSizes& meta_space() const { return _meta_space; } const MetaspaceSizes& data_space() const { return _data_space; } const MetaspaceSizes& class_space() const { return _class_space; } + + const MetaspaceChunkFreeListSummary& metaspace_chunk_free_list_summary() const { + return _metaspace_chunk_free_list_summary; + } + + const MetaspaceChunkFreeListSummary& class_chunk_free_list_summary() const { + return _class_chunk_free_list_summary; + } + }; #endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCHEAPSUMMARY_HPP diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp index 5e533d341d4..994d468bbc5 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp @@ -139,11 +139,21 @@ void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) { } #endif // INCLUDE_SERVICES -void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const { +void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const { assert_set_gc_id(); send_gc_heap_summary_event(when, heap_summary); - send_meta_space_summary_event(when, meta_space_summary); +} + +void GCTracer::report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& summary) const { + assert_set_gc_id(); + + send_meta_space_summary_event(when, summary); + + send_metaspace_chunk_free_list_summary(when, Metaspace::NonClassType, summary.metaspace_chunk_free_list_summary()); + if (UseCompressedClassPointers) { + send_metaspace_chunk_free_list_summary(when, Metaspace::ClassType, summary.class_chunk_free_list_summary()); + } } void YoungGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp index fda51e8bf52..3b55211a724 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp @@ -30,6 +30,7 @@ #include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/copyFailedInfo.hpp" #include "memory/allocation.hpp" +#include "memory/metaspace.hpp" #include "memory/referenceType.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1YCTypes.hpp" @@ -41,6 +42,7 @@ typedef uint GCId; class EvacuationInfo; class GCHeapSummary; +class MetaspaceChunkFreeListSummary; class MetaspaceSummary; class PSHeapSummary; class ReferenceProcessorStats; @@ -124,7 +126,8 @@ class GCTracer : public ResourceObj { public: void report_gc_start(GCCause::Cause cause, const Ticks& timestamp); void report_gc_end(const Ticks& timestamp, TimePartitions* time_partitions); - void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const; + void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const; + void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; void report_object_count_after_gc(BoolObjectClosure* object_filter) NOT_SERVICES_RETURN; bool has_reported_gc_start() const; @@ -138,6 +141,7 @@ class GCTracer : public ResourceObj { void send_garbage_collection_event() const; void send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary& heap_summary) const; void send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const; + void send_metaspace_chunk_free_list_summary(GCWhen::Type when, Metaspace::MetadataType mdtype, const MetaspaceChunkFreeListSummary& summary) const; void send_reference_stats_event(ReferenceType type, size_t count) const; void send_phase_events(TimePartitions* time_partitions) const; }; diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp b/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp index ecf0731255b..b7d6e8e6b59 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp @@ -64,6 +64,30 @@ void GCTracer::send_reference_stats_event(ReferenceType type, size_t count) cons } } +void GCTracer::send_metaspace_chunk_free_list_summary(GCWhen::Type when, Metaspace::MetadataType mdtype, + const MetaspaceChunkFreeListSummary& summary) const { + EventMetaspaceChunkFreeListSummary e; + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_when(when); + e.set_metadataType(mdtype); + + e.set_specializedChunks(summary.num_specialized_chunks()); + e.set_specializedChunksTotalSize(summary.specialized_chunks_size_in_bytes()); + + e.set_smallChunks(summary.num_small_chunks()); + e.set_smallChunksTotalSize(summary.small_chunks_size_in_bytes()); + + e.set_mediumChunks(summary.num_medium_chunks()); + e.set_mediumChunksTotalSize(summary.medium_chunks_size_in_bytes()); + + e.set_humongousChunks(summary.num_humongous_chunks()); + e.set_humongousChunksTotalSize(summary.humongous_chunks_size_in_bytes()); + + e.commit(); + } +} + void ParallelOldTracer::send_parallel_old_event() const { EventGCParallelOld e(UNTIMED); if (e.should_commit()) { @@ -246,6 +270,7 @@ void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceS if (e.should_commit()) { e.set_gcId(_shared_gc_info.id()); e.set_when((u1) when); + e.set_gcThreshold(meta_space_summary.capacity_until_GC()); e.set_metaspace(to_trace_struct(meta_space_summary.meta_space())); e.set_dataSpace(to_trace_struct(meta_space_summary.data_space())); e.set_classSpace(to_trace_struct(meta_space_summary.class_space())); diff --git a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp index 270d9de71bf..c08e7a6379b 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.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. * 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,10 +30,18 @@ #include "utilities/stack.inline.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS +#include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" #endif // INCLUDE_ALL_GCS inline void MarkSweep::mark_object(oop obj) { +#if INCLUDE_ALL_GCS + if (G1StringDedup::is_enabled()) { + // We must enqueue the object before it is marked + // as we otherwise can't read the object's age. + G1StringDedup::enqueue_from_mark(obj); + } +#endif // some marks may contain information we need to preserve so we store them away // and overwrite the mark. We'll restore it at the end of markSweep. markOop mark = obj->mark(); diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp index 9027b89c375..bdbbae7f412 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp @@ -89,6 +89,15 @@ bool VM_GC_Operation::doit_prologue() { assert(((_gc_cause != GCCause::_no_gc) && (_gc_cause != GCCause::_no_cause_specified)), "Illegal GCCause"); + // To be able to handle a GC the VM initialization needs to be completed. + if (!is_init_completed()) { + vm_exit_during_initialization( + err_msg("GC triggered before VM initialization completed. Try increasing " + "NewSize, current value " UINTX_FORMAT "%s.", + byte_size_in_proper_unit(NewSize), + proper_unit_for_byte_size(NewSize))); + } + acquire_pending_list_lock(); // If the GC count has changed someone beat us to the collection // Get the Heap_lock after the pending_list_lock. diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp index 4efb5651b03..071ca3812d2 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp @@ -97,7 +97,13 @@ MetaspaceSummary CollectedHeap::create_metaspace_summary() { MetaspaceAux::allocated_used_bytes(Metaspace::ClassType), MetaspaceAux::reserved_bytes(Metaspace::ClassType)); - return MetaspaceSummary(meta_space, data_space, class_space); + const MetaspaceChunkFreeListSummary& ms_chunk_free_list_summary = + MetaspaceAux::chunk_free_list_summary(Metaspace::NonClassType); + const MetaspaceChunkFreeListSummary& class_chunk_free_list_summary = + MetaspaceAux::chunk_free_list_summary(Metaspace::ClassType); + + return MetaspaceSummary(MetaspaceGC::capacity_until_GC(), meta_space, data_space, class_space, + ms_chunk_free_list_summary, class_chunk_free_list_summary); } void CollectedHeap::print_heap_before_gc() { @@ -128,8 +134,10 @@ void CollectedHeap::unregister_nmethod(nmethod* nm) { void CollectedHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) { const GCHeapSummary& heap_summary = create_heap_summary(); + gc_tracer->report_gc_heap_summary(when, heap_summary); + const MetaspaceSummary& metaspace_summary = create_metaspace_summary(); - gc_tracer->report_gc_heap_summary(when, heap_summary, metaspace_summary); + gc_tracer->report_metaspace_summary(when, metaspace_summary); } void CollectedHeap::trace_heap_before_gc(GCTracer* gc_tracer) { diff --git a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp index 1892940f216..36867113eff 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp @@ -35,8 +35,6 @@ #include "runtime/timer.hpp" -#ifndef PRODUCT - // Standard closure for BytecodeTracer: prints the current bytecode // and its attributes using bytecode-specific information. @@ -600,4 +598,3 @@ void BytecodePrinter::bytecode_epilog(int bci, outputStream* st) { } } } -#endif // PRODUCT diff --git a/hotspot/src/share/vm/interpreter/bytecodeTracer.hpp b/hotspot/src/share/vm/interpreter/bytecodeTracer.hpp index 5dc78e0ac1a..9e5837139a2 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.hpp @@ -34,8 +34,7 @@ // By specialising the BytecodeClosure, all kinds of bytecode traces can // be done. -#ifndef PRODUCT -// class BytecodeTracer is only used by TraceBytecodes option +// class BytecodeTracer is used by TraceBytecodes option and PrintMethodData class BytecodeClosure; class BytecodeTracer: AllStatic { @@ -60,6 +59,4 @@ class BytecodeClosure { virtual void trace(methodHandle method, address bcp, outputStream* st) = 0; }; -#endif // !PRODUCT - #endif // SHARE_VM_INTERPRETER_BYTECODETRACER_HPP diff --git a/hotspot/src/share/vm/memory/allocation.cpp b/hotspot/src/share/vm/memory/allocation.cpp index 8e382ba85d1..9fece9b4ef4 100644 --- a/hotspot/src/share/vm/memory/allocation.cpp +++ b/hotspot/src/share/vm/memory/allocation.cpp @@ -446,6 +446,7 @@ Arena::Arena(size_t init_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; set_size_in_bytes(init_size); NOT_PRODUCT(Atomic::inc(&_instance_count);) } @@ -454,6 +455,7 @@ Arena::Arena() { _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; set_size_in_bytes(Chunk::init_size); NOT_PRODUCT(Atomic::inc(&_instance_count);) } diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp index 487762201f1..fbfff65dad4 100644 --- a/hotspot/src/share/vm/memory/allocation.hpp +++ b/hotspot/src/share/vm/memory/allocation.hpp @@ -748,6 +748,12 @@ class ArrayAllocator VALUE_OBJ_CLASS_SPEC { bool _use_malloc; size_t _size; bool _free_in_destructor; + + static bool should_use_malloc(size_t size) { + return size < ArrayAllocatorMallocLimit; + } + + static char* allocate_inner(size_t& size, bool& use_malloc); public: ArrayAllocator(bool free_in_destructor = true) : _addr(NULL), _use_malloc(false), _size(0), _free_in_destructor(free_in_destructor) { } @@ -759,6 +765,7 @@ class ArrayAllocator VALUE_OBJ_CLASS_SPEC { } E* allocate(size_t length); + E* reallocate(size_t new_length); void free(); }; diff --git a/hotspot/src/share/vm/memory/allocation.inline.hpp b/hotspot/src/share/vm/memory/allocation.inline.hpp index d8f1940a6d4..806088b9bae 100644 --- a/hotspot/src/share/vm/memory/allocation.inline.hpp +++ b/hotspot/src/share/vm/memory/allocation.inline.hpp @@ -122,35 +122,57 @@ template void CHeapObj::operator delete [](void* p){ } template -E* ArrayAllocator::allocate(size_t length) { - assert(_addr == NULL, "Already in use"); +char* ArrayAllocator::allocate_inner(size_t &size, bool &use_malloc) { + char* addr = NULL; - _size = sizeof(E) * length; - _use_malloc = _size < ArrayAllocatorMallocLimit; - - if (_use_malloc) { - _addr = AllocateHeap(_size, F); - if (_addr == NULL && _size >= (size_t)os::vm_allocation_granularity()) { + if (use_malloc) { + addr = AllocateHeap(size, F); + if (addr == NULL && size >= (size_t)os::vm_allocation_granularity()) { // malloc failed let's try with mmap instead - _use_malloc = false; + use_malloc = false; } else { - return (E*)_addr; + return addr; } } int alignment = os::vm_allocation_granularity(); - _size = align_size_up(_size, alignment); + size = align_size_up(size, alignment); - _addr = os::reserve_memory(_size, NULL, alignment, F); - if (_addr == NULL) { - vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (reserve)"); + addr = os::reserve_memory(size, NULL, alignment, F); + if (addr == NULL) { + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "Allocator (reserve)"); } - os::commit_memory_or_exit(_addr, _size, !ExecMem, "Allocator (commit)"); + os::commit_memory_or_exit(addr, size, !ExecMem, "Allocator (commit)"); + return addr; +} + +template +E* ArrayAllocator::allocate(size_t length) { + assert(_addr == NULL, "Already in use"); + + _size = sizeof(E) * length; + _use_malloc = should_use_malloc(_size); + _addr = allocate_inner(_size, _use_malloc); return (E*)_addr; } +template +E* ArrayAllocator::reallocate(size_t new_length) { + size_t new_size = sizeof(E) * new_length; + bool use_malloc = should_use_malloc(new_size); + char* new_addr = allocate_inner(new_size, use_malloc); + + memcpy(new_addr, _addr, MIN2(new_size, _size)); + + free(); + _size = new_size; + _use_malloc = use_malloc; + _addr = new_addr; + return (E*)new_addr; +} + template void ArrayAllocator::free() { if (_addr != NULL) { diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index 0c93c87992b..166486fa3f0 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.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 @@ -32,8 +32,8 @@ // header: dump of archive instance plus versioning info, datestamp, etc. // [magic # = 0xF00BABA2] // ... padding to align on page-boundary -// read-write space from CompactingPermGenGen -// read-only space from CompactingPermGenGen +// read-write space +// read-only space // misc data (block offset table, string table, symbols, dictionary, etc.) // tag(666) diff --git a/hotspot/src/share/vm/memory/freeList.cpp b/hotspot/src/share/vm/memory/freeList.cpp index 1d521885925..f1d4859a040 100644 --- a/hotspot/src/share/vm/memory/freeList.cpp +++ b/hotspot/src/share/vm/memory/freeList.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 @@ -34,6 +34,7 @@ #if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" +#include "gc_implementation/g1/g1CodeCacheRemSet.hpp" #endif // INCLUDE_ALL_GCS // Free list. A FreeList is used to access a linked list of chunks @@ -332,4 +333,5 @@ template class FreeList; template class FreeList; #if INCLUDE_ALL_GCS template class FreeList; +template class FreeList; #endif // INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/memory/gcLocker.cpp b/hotspot/src/share/vm/memory/gcLocker.cpp index 09fb73bb035..3b208dfff8e 100644 --- a/hotspot/src/share/vm/memory/gcLocker.cpp +++ b/hotspot/src/share/vm/memory/gcLocker.cpp @@ -28,7 +28,6 @@ #include "memory/sharedHeap.hpp" volatile jint GC_locker::_jni_lock_count = 0; -volatile jint GC_locker::_lock_count = 0; volatile bool GC_locker::_needs_gc = false; volatile bool GC_locker::_doing_gc = false; @@ -102,7 +101,7 @@ void GC_locker::jni_lock(JavaThread* thread) { // We check that at least one thread is in a critical region before // blocking because blocked threads are woken up by a thread exiting // a JNI critical region. - while ((needs_gc() && is_jni_active()) || _doing_gc) { + while (is_active_and_needs_gc() || _doing_gc) { JNICritical_lock->wait(); } thread->enter_critical(); @@ -116,27 +115,20 @@ void GC_locker::jni_unlock(JavaThread* thread) { _jni_lock_count--; decrement_debug_jni_lock_count(); thread->exit_critical(); - if (needs_gc() && !is_jni_active()) { + if (needs_gc() && !is_active_internal()) { // We're the last thread out. Cause a GC to occur. - // GC will also check is_active, so this check is not - // strictly needed. It's added here to make it clear that - // the GC will NOT be performed if any other caller - // of GC_locker::lock() still needs GC locked. - if (!is_active_internal()) { - _doing_gc = true; - { - // Must give up the lock while at a safepoint - MutexUnlocker munlock(JNICritical_lock); - if (PrintJNIGCStalls && PrintGCDetails) { - ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 - gclog_or_tty->print_cr("%.3f: Thread \"%s\" is performing GC after exiting critical section, %d locked", - gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); - } - Universe::heap()->collect(GCCause::_gc_locker); + _doing_gc = true; + { + // Must give up the lock while at a safepoint + MutexUnlocker munlock(JNICritical_lock); + if (PrintJNIGCStalls && PrintGCDetails) { + ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 + gclog_or_tty->print_cr("%.3f: Thread \"%s\" is performing GC after exiting critical section, %d locked", + gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); } - _doing_gc = false; + Universe::heap()->collect(GCCause::_gc_locker); } - + _doing_gc = false; _needs_gc = false; JNICritical_lock->notify_all(); } diff --git a/hotspot/src/share/vm/memory/gcLocker.hpp b/hotspot/src/share/vm/memory/gcLocker.hpp index 60bebdf0fa4..f12aa675552 100644 --- a/hotspot/src/share/vm/memory/gcLocker.hpp +++ b/hotspot/src/share/vm/memory/gcLocker.hpp @@ -54,8 +54,6 @@ class GC_locker: public AllStatic { // safepointing and decremented during the slow path of GC_locker // unlocking. static volatile jint _jni_lock_count; // number of jni active instances. - - static volatile jint _lock_count; // number of other active instances static volatile bool _needs_gc; // heap is filling, we need a GC // note: bool is typedef'd as jint static volatile bool _doing_gc; // unlock_critical() is doing a GC @@ -66,12 +64,6 @@ class GC_locker: public AllStatic { static volatile jint _debug_jni_lock_count; #endif - // Accessors - static bool is_jni_active() { - assert(_needs_gc, "only valid when _needs_gc is set"); - return _jni_lock_count > 0; - } - // At a safepoint, visit all threads and count the number of active // critical sections. This is used to ensure that all active // critical sections are exited before a new one is started. @@ -82,7 +74,7 @@ class GC_locker: public AllStatic { static bool is_active_internal() { verify_critical_count(); - return _lock_count > 0 || _jni_lock_count > 0; + return _jni_lock_count > 0; } public: @@ -132,10 +124,6 @@ class GC_locker: public AllStatic { // not a stable predicate. static void stall_until_clear(); - // Non-structured GC locking: currently needed for JNI. Use with care! - static void lock(); - static void unlock(); - // The following two methods are used for JNI critical regions. // If we find that we failed to perform a GC because the GC_locker // was active, arrange for one as soon as possible by allowing diff --git a/hotspot/src/share/vm/memory/gcLocker.inline.hpp b/hotspot/src/share/vm/memory/gcLocker.inline.hpp index 37b4231bbe3..e77d5436b1b 100644 --- a/hotspot/src/share/vm/memory/gcLocker.inline.hpp +++ b/hotspot/src/share/vm/memory/gcLocker.inline.hpp @@ -27,22 +27,6 @@ #include "memory/gcLocker.hpp" -inline void GC_locker::lock() { - // cast away volatile - Atomic::inc(&_lock_count); - CHECK_UNHANDLED_OOPS_ONLY( - if (CheckUnhandledOops) { Thread::current()->_gc_locked_out_count++; }) - assert(Universe::heap() == NULL || - !Universe::heap()->is_gc_active(), "locking failed"); -} - -inline void GC_locker::unlock() { - // cast away volatile - Atomic::dec(&_lock_count); - CHECK_UNHANDLED_OOPS_ONLY( - if (CheckUnhandledOops) { Thread::current()->_gc_locked_out_count--; }) -} - inline void GC_locker::lock_critical(JavaThread* thread) { if (!thread->in_critical()) { if (needs_gc()) { diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index be4ad6945dd..75faabc648e 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -837,12 +837,6 @@ void GenCollectedHeap::oop_iterate(ExtendedOopClosure* cl) { } } -void GenCollectedHeap::oop_iterate(MemRegion mr, ExtendedOopClosure* cl) { - for (int i = 0; i < _n_gens; i++) { - _gens[i]->oop_iterate(mr, cl); - } -} - void GenCollectedHeap::object_iterate(ObjectClosure* cl) { for (int i = 0; i < _n_gens; i++) { _gens[i]->object_iterate(cl); diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.hpp b/hotspot/src/share/vm/memory/genCollectedHeap.hpp index f687a1c97e6..4a62aa4b411 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp @@ -212,7 +212,6 @@ public: // Iteration functions. void oop_iterate(ExtendedOopClosure* cl); - void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); void object_iterate(ObjectClosure* cl); void safe_object_iterate(ObjectClosure* cl); Space* space_containing(const void* addr) const; diff --git a/hotspot/src/share/vm/memory/genOopClosures.hpp b/hotspot/src/share/vm/memory/genOopClosures.hpp index aa9f4366f85..1f24b2b3cab 100644 --- a/hotspot/src/share/vm/memory/genOopClosures.hpp +++ b/hotspot/src/share/vm/memory/genOopClosures.hpp @@ -115,9 +115,6 @@ class ScanClosure: public OopsInKlassOrGenClosure { virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p); inline void do_oop_nv(narrowOop* p); - Prefetch::style prefetch_style() { - return Prefetch::do_write; - } }; // Closure for scanning DefNewGeneration. @@ -137,9 +134,6 @@ class FastScanClosure: public OopsInKlassOrGenClosure { virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p); inline void do_oop_nv(narrowOop* p); - Prefetch::style prefetch_style() { - return Prefetch::do_write; - } }; class KlassScanClosure: public KlassClosure { diff --git a/hotspot/src/share/vm/memory/generation.cpp b/hotspot/src/share/vm/memory/generation.cpp index 5ea44867d6d..11ba05fed8d 100644 --- a/hotspot/src/share/vm/memory/generation.cpp +++ b/hotspot/src/share/vm/memory/generation.cpp @@ -295,22 +295,16 @@ bool Generation::block_is_obj(const HeapWord* p) const { class GenerationOopIterateClosure : public SpaceClosure { public: - ExtendedOopClosure* cl; - MemRegion mr; + ExtendedOopClosure* _cl; virtual void do_space(Space* s) { - s->oop_iterate(mr, cl); + s->oop_iterate(_cl); } - GenerationOopIterateClosure(ExtendedOopClosure* _cl, MemRegion _mr) : - cl(_cl), mr(_mr) {} + GenerationOopIterateClosure(ExtendedOopClosure* cl) : + _cl(cl) {} }; void Generation::oop_iterate(ExtendedOopClosure* cl) { - GenerationOopIterateClosure blk(cl, _reserved); - space_iterate(&blk); -} - -void Generation::oop_iterate(MemRegion mr, ExtendedOopClosure* cl) { - GenerationOopIterateClosure blk(cl, mr); + GenerationOopIterateClosure blk(cl); space_iterate(&blk); } diff --git a/hotspot/src/share/vm/memory/generation.hpp b/hotspot/src/share/vm/memory/generation.hpp index e7cbd2c1226..f44f0245c36 100644 --- a/hotspot/src/share/vm/memory/generation.hpp +++ b/hotspot/src/share/vm/memory/generation.hpp @@ -543,10 +543,6 @@ class Generation: public CHeapObj { // generation, calling "cl.do_oop" on each. virtual void oop_iterate(ExtendedOopClosure* cl); - // Same as above, restricted to the intersection of a memory region and - // the generation. - virtual void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); - // Iterate over all objects in the generation, calling "cl.do_object" on // each. virtual void object_iterate(ObjectClosure* cl); diff --git a/hotspot/src/share/vm/memory/iterator.hpp b/hotspot/src/share/vm/memory/iterator.hpp index 33d10d69ef6..81a845e5056 100644 --- a/hotspot/src/share/vm/memory/iterator.hpp +++ b/hotspot/src/share/vm/memory/iterator.hpp @@ -27,11 +27,8 @@ #include "memory/allocation.hpp" #include "memory/memRegion.hpp" -#include "runtime/prefetch.hpp" #include "utilities/top.hpp" -// The following classes are C++ `closures` for iterating over objects, roots and spaces - class CodeBlob; class nmethod; class ReferenceProcessor; @@ -39,22 +36,11 @@ class DataLayout; class KlassClosure; class ClassLoaderData; -// Closure provides abortability. +// The following classes are C++ `closures` for iterating over objects, roots and spaces -class Closure : public StackObj { - protected: - bool _abort; - void set_abort() { _abort = true; } - public: - Closure() : _abort(false) {} - // A subtype can use this mechanism to indicate to some iterator mapping - // functions that the iteration should cease. - bool abort() { return _abort; } - void clear_abort() { _abort = false; } -}; +class Closure : public StackObj { }; // OopClosure is used for iterating through references to Java objects. - class OopClosure : public Closure { public: virtual void do_oop(oop* o) = 0; @@ -97,11 +83,6 @@ class ExtendedOopClosure : public OopClosure { virtual void do_class_loader_data(ClassLoaderData* cld) { ShouldNotReachHere(); } - // Controls how prefetching is done for invocations of this closure. - Prefetch::style prefetch_style() { // Note that this is non-virtual. - return Prefetch::do_none; - } - // True iff this closure may be safely applied more than once to an oop // location without an intervening "major reset" (like the end of a GC). virtual bool idempotent() { return false; } @@ -177,19 +158,6 @@ public: ObjectToOopClosure(ExtendedOopClosure* cl) : _cl(cl) {} }; -// A version of ObjectClosure with "memory" (see _previous_address below) -class UpwardsObjectClosure: public BoolObjectClosure { - HeapWord* _previous_address; - public: - UpwardsObjectClosure() : _previous_address(NULL) { } - void set_previous(HeapWord* addr) { _previous_address = addr; } - HeapWord* previous() { return _previous_address; } - // A return value of "true" can be used by the caller to decide - // if this object's end should *NOT* be recorded in - // _previous_address above. - virtual bool do_object_bm(oop obj, MemRegion mr) = 0; -}; - // A version of ObjectClosure that is expected to be robust // in the face of possibly uninitialized objects. class ObjectClosureCareful : public ObjectClosure { diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 9c3b48dc8f8..31318cb51d0 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -32,7 +32,9 @@ #include "memory/gcLocker.hpp" #include "memory/metachunk.hpp" #include "memory/metaspace.hpp" +#include "memory/metaspaceGCThresholdUpdater.hpp" #include "memory/metaspaceShared.hpp" +#include "memory/metaspaceTracer.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "runtime/atomic.inline.hpp" @@ -57,6 +59,7 @@ size_t const allocation_from_dictionary_limit = 4 * K; MetaWord* last_allocated = 0; size_t Metaspace::_compressed_class_space_size; +const MetaspaceTracer* Metaspace::_tracer = NULL; // Used in declarations in SpaceManager and ChunkManager enum ChunkIndex { @@ -182,6 +185,48 @@ class ChunkManager : public CHeapObj { // Remove from a list by size. Selects list based on size of chunk. Metachunk* free_chunks_get(size_t chunk_word_size); +#define index_bounds_check(index) \ + assert(index == SpecializedIndex || \ + index == SmallIndex || \ + index == MediumIndex || \ + index == HumongousIndex, err_msg("Bad index: %d", (int) index)) + + size_t num_free_chunks(ChunkIndex index) const { + index_bounds_check(index); + + if (index == HumongousIndex) { + return _humongous_dictionary.total_free_blocks(); + } + + ssize_t count = _free_chunks[index].count(); + return count == -1 ? 0 : (size_t) count; + } + + size_t size_free_chunks_in_bytes(ChunkIndex index) const { + index_bounds_check(index); + + size_t word_size = 0; + if (index == HumongousIndex) { + word_size = _humongous_dictionary.total_size(); + } else { + const size_t size_per_chunk_in_words = _free_chunks[index].size(); + word_size = size_per_chunk_in_words * num_free_chunks(index); + } + + return word_size * BytesPerWord; + } + + MetaspaceChunkFreeListSummary chunk_free_list_summary() const { + return MetaspaceChunkFreeListSummary(num_free_chunks(SpecializedIndex), + num_free_chunks(SmallIndex), + num_free_chunks(MediumIndex), + num_free_chunks(HumongousIndex), + size_free_chunks_in_bytes(SpecializedIndex), + size_free_chunks_in_bytes(SmallIndex), + size_free_chunks_in_bytes(MediumIndex), + size_free_chunks_in_bytes(HumongousIndex)); + } + // Debug support void verify(); void slow_verify() { @@ -1436,19 +1481,21 @@ void MetaspaceGC::compute_new_size() { expand_bytes = align_size_up(expand_bytes, Metaspace::commit_alignment()); // Don't expand unless it's significant if (expand_bytes >= MinMetaspaceExpansion) { - MetaspaceGC::inc_capacity_until_GC(expand_bytes); - } - if (PrintGCDetails && Verbose) { - size_t new_capacity_until_GC = capacity_until_GC; - gclog_or_tty->print_cr(" expanding:" - " minimum_desired_capacity: %6.1fKB" - " expand_bytes: %6.1fKB" - " MinMetaspaceExpansion: %6.1fKB" - " new metaspace HWM: %6.1fKB", - minimum_desired_capacity / (double) K, - expand_bytes / (double) K, - MinMetaspaceExpansion / (double) K, - new_capacity_until_GC / (double) K); + size_t new_capacity_until_GC = MetaspaceGC::inc_capacity_until_GC(expand_bytes); + Metaspace::tracer()->report_gc_threshold(capacity_until_GC, + new_capacity_until_GC, + MetaspaceGCThresholdUpdater::ComputeNewSize); + if (PrintGCDetails && Verbose) { + gclog_or_tty->print_cr(" expanding:" + " minimum_desired_capacity: %6.1fKB" + " expand_bytes: %6.1fKB" + " MinMetaspaceExpansion: %6.1fKB" + " new metaspace HWM: %6.1fKB", + minimum_desired_capacity / (double) K, + expand_bytes / (double) K, + MinMetaspaceExpansion / (double) K, + new_capacity_until_GC / (double) K); + } } return; } @@ -1528,7 +1575,10 @@ void MetaspaceGC::compute_new_size() { // Don't shrink unless it's significant if (shrink_bytes >= MinMetaspaceExpansion && ((capacity_until_GC - shrink_bytes) >= MetaspaceSize)) { - MetaspaceGC::dec_capacity_until_GC(shrink_bytes); + size_t new_capacity_until_GC = MetaspaceGC::dec_capacity_until_GC(shrink_bytes); + Metaspace::tracer()->report_gc_threshold(capacity_until_GC, + new_capacity_until_GC, + MetaspaceGCThresholdUpdater::ComputeNewSize); } } @@ -2629,6 +2679,19 @@ size_t MetaspaceAux::free_chunks_total_bytes() { return free_chunks_total_words() * BytesPerWord; } +bool MetaspaceAux::has_chunk_free_list(Metaspace::MetadataType mdtype) { + return Metaspace::get_chunk_manager(mdtype) != NULL; +} + +MetaspaceChunkFreeListSummary MetaspaceAux::chunk_free_list_summary(Metaspace::MetadataType mdtype) { + if (!has_chunk_free_list(mdtype)) { + return MetaspaceChunkFreeListSummary(); + } + + const ChunkManager* cm = Metaspace::get_chunk_manager(mdtype); + return cm->chunk_free_list_summary(); +} + void MetaspaceAux::print_metaspace_change(size_t prev_metadata_used) { gclog_or_tty->print(", [Metaspace:"); if (PrintGCDetails && Verbose) { @@ -3132,6 +3195,7 @@ void Metaspace::global_initialize() { } MetaspaceGC::initialize(); + _tracer = new MetaspaceTracer(); } Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype, @@ -3220,8 +3284,12 @@ MetaWord* Metaspace::expand_and_allocate(size_t word_size, MetadataType mdtype) assert(delta_bytes > 0, "Must be"); size_t after_inc = MetaspaceGC::inc_capacity_until_GC(delta_bytes); + + // capacity_until_GC might be updated concurrently, must calculate previous value. size_t before_inc = after_inc - delta_bytes; + tracer()->report_gc_threshold(before_inc, after_inc, + MetaspaceGCThresholdUpdater::ExpandAndAllocate); if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT " to " SIZE_FORMAT, before_inc, after_inc); @@ -3275,37 +3343,22 @@ size_t Metaspace::capacity_bytes_slow(MetadataType mdtype) const { } void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { - if (SafepointSynchronize::is_at_safepoint()) { - assert(Thread::current()->is_VM_thread(), "should be the VM thread"); - // Don't take Heap_lock - MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag); - if (word_size < TreeChunk >::min_size()) { - // Dark matter. Too small for dictionary. -#ifdef ASSERT - Copy::fill_to_words((HeapWord*)ptr, word_size, 0xf5f5f5f5); -#endif - return; - } - if (is_class && using_class_space()) { - class_vsm()->deallocate(ptr, word_size); - } else { - vsm()->deallocate(ptr, word_size); - } - } else { - MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag); + assert(!SafepointSynchronize::is_at_safepoint() + || Thread::current()->is_VM_thread(), "should be the VM thread"); - if (word_size < TreeChunk >::min_size()) { - // Dark matter. Too small for dictionary. + MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag); + + if (word_size < TreeChunk >::min_size()) { + // Dark matter. Too small for dictionary. #ifdef ASSERT - Copy::fill_to_words((HeapWord*)ptr, word_size, 0xf5f5f5f5); + Copy::fill_to_words((HeapWord*)ptr, word_size, 0xf5f5f5f5); #endif - return; - } - if (is_class && using_class_space()) { - class_vsm()->deallocate(ptr, word_size); - } else { - vsm()->deallocate(ptr, word_size); - } + return; + } + if (is_class && using_class_space()) { + class_vsm()->deallocate(ptr, word_size); + } else { + vsm()->deallocate(ptr, word_size); } } @@ -3345,6 +3398,8 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, MetaWord* result = loader_data->metaspace_non_null()->allocate(word_size, mdtype); if (result == NULL) { + tracer()->report_metaspace_allocation_failure(loader_data, word_size, type, mdtype); + // Allocation failed. if (is_init_completed()) { // Only start a GC if the bootstrapping has completed. @@ -3356,7 +3411,7 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, } if (result == NULL) { - report_metadata_oome(loader_data, word_size, mdtype, CHECK_NULL); + report_metadata_oome(loader_data, word_size, type, mdtype, CHECK_NULL); } // Zero initialize. @@ -3370,7 +3425,9 @@ size_t Metaspace::class_chunk_size(size_t word_size) { return class_vsm()->calc_chunk_size(word_size); } -void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetadataType mdtype, TRAPS) { +void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetaspaceObj::Type type, MetadataType mdtype, TRAPS) { + tracer()->report_metadata_oom(loader_data, word_size, type, mdtype); + // If result is still null, we are out of memory. if (Verbose && TraceMetadataChunkAllocation) { gclog_or_tty->print_cr("Metaspace allocation failed for size " @@ -3413,6 +3470,16 @@ void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_s } } +const char* Metaspace::metadata_type_name(Metaspace::MetadataType mdtype) { + switch (mdtype) { + case Metaspace::ClassType: return "Class"; + case Metaspace::NonClassType: return "Metadata"; + default: + assert(false, err_msg("Got bad mdtype: %d", (int) mdtype)); + return NULL; + } +} + void Metaspace::record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size) { assert(DumpSharedSpaces, "sanity"); diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index f74cec35546..cd02b4a153e 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -26,6 +26,7 @@ #include "memory/allocation.hpp" #include "memory/memRegion.hpp" +#include "memory/metaspaceChunkFreeListSummary.hpp" #include "runtime/virtualspace.hpp" #include "utilities/exceptions.hpp" @@ -60,6 +61,7 @@ class ChunkManager; class ClassLoaderData; class Metablock; class Metachunk; +class MetaspaceTracer; class MetaWord; class Mutex; class outputStream; @@ -149,6 +151,8 @@ class Metaspace : public CHeapObj { static ChunkManager* _chunk_manager_metadata; static ChunkManager* _chunk_manager_class; + static const MetaspaceTracer* _tracer; + public: static VirtualSpaceList* space_list() { return _space_list; } static VirtualSpaceList* class_space_list() { return _class_space_list; } @@ -164,6 +168,8 @@ class Metaspace : public CHeapObj { return mdtype == ClassType ? chunk_manager_class() : chunk_manager_metadata(); } + static const MetaspaceTracer* tracer() { return _tracer; } + private: // This is used by DumpSharedSpaces only, where only _vsm is used. So we will // maintain a single list for now. @@ -234,7 +240,9 @@ class Metaspace : public CHeapObj { static void purge(); static void report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, - MetadataType mdtype, TRAPS); + MetaspaceObj::Type type, MetadataType mdtype, TRAPS); + + static const char* metadata_type_name(Metaspace::MetadataType mdtype); void print_on(outputStream* st) const; // Debugging support @@ -348,6 +356,9 @@ class MetaspaceAux : AllStatic { return min_chunk_size_words() * BytesPerWord; } + static bool has_chunk_free_list(Metaspace::MetadataType mdtype); + static MetaspaceChunkFreeListSummary chunk_free_list_summary(Metaspace::MetadataType mdtype); + // Print change in used metadata. static void print_metaspace_change(size_t prev_metadata_used); static void print_on(outputStream * out); diff --git a/hotspot/src/share/vm/memory/metaspaceChunkFreeListSummary.hpp b/hotspot/src/share/vm/memory/metaspaceChunkFreeListSummary.hpp new file mode 100644 index 00000000000..bc262f6a19d --- /dev/null +++ b/hotspot/src/share/vm/memory/metaspaceChunkFreeListSummary.hpp @@ -0,0 +1,103 @@ +/* + * 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_MEMORY_METASPACE_CHUNK_FREE_LIST_SUMMARY_HPP +#define SHARE_VM_MEMORY_METASPACE_CHUNK_FREE_LIST_SUMMARY_HPP + +#include "memory/allocation.hpp" + +class MetaspaceChunkFreeListSummary VALUE_OBJ_CLASS_SPEC { + size_t _num_specialized_chunks; + size_t _num_small_chunks; + size_t _num_medium_chunks; + size_t _num_humongous_chunks; + + size_t _specialized_chunks_size_in_bytes; + size_t _small_chunks_size_in_bytes; + size_t _medium_chunks_size_in_bytes; + size_t _humongous_chunks_size_in_bytes; + + public: + MetaspaceChunkFreeListSummary() : + _num_specialized_chunks(0), + _num_small_chunks(0), + _num_medium_chunks(0), + _num_humongous_chunks(0), + _specialized_chunks_size_in_bytes(0), + _small_chunks_size_in_bytes(0), + _medium_chunks_size_in_bytes(0), + _humongous_chunks_size_in_bytes(0) + {} + + MetaspaceChunkFreeListSummary(size_t num_specialized_chunks, + size_t num_small_chunks, + size_t num_medium_chunks, + size_t num_humongous_chunks, + size_t specialized_chunks_size_in_bytes, + size_t small_chunks_size_in_bytes, + size_t medium_chunks_size_in_bytes, + size_t humongous_chunks_size_in_bytes) : + _num_specialized_chunks(num_specialized_chunks), + _num_small_chunks(num_small_chunks), + _num_medium_chunks(num_medium_chunks), + _num_humongous_chunks(num_humongous_chunks), + _specialized_chunks_size_in_bytes(specialized_chunks_size_in_bytes), + _small_chunks_size_in_bytes(small_chunks_size_in_bytes), + _medium_chunks_size_in_bytes(medium_chunks_size_in_bytes), + _humongous_chunks_size_in_bytes(humongous_chunks_size_in_bytes) + {} + + size_t num_specialized_chunks() const { + return _num_specialized_chunks; + } + + size_t num_small_chunks() const { + return _num_small_chunks; + } + + size_t num_medium_chunks() const { + return _num_medium_chunks; + } + + size_t num_humongous_chunks() const { + return _num_humongous_chunks; + } + + size_t specialized_chunks_size_in_bytes() const { + return _specialized_chunks_size_in_bytes; + } + + size_t small_chunks_size_in_bytes() const { + return _small_chunks_size_in_bytes; + } + + size_t medium_chunks_size_in_bytes() const { + return _medium_chunks_size_in_bytes; + } + + size_t humongous_chunks_size_in_bytes() const { + return _humongous_chunks_size_in_bytes; + } +}; + +#endif // SHARE_VM_MEMORY_METASPACE_CHUNK_FREE_LIST_SUMMARY_HPP diff --git a/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp b/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp new file mode 100644 index 00000000000..cbb221dd33b --- /dev/null +++ b/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.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_MEMORY_METASPACE_GC_THRESHOLD_UPDATER_HPP +#define SHARE_VM_MEMORY_METASPACE_GC_THRESHOLD_UPDATER_HPP + +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" + +class MetaspaceGCThresholdUpdater : public AllStatic { + public: + enum Type { + ComputeNewSize, + ExpandAndAllocate, + Last + }; + + static const char* to_string(MetaspaceGCThresholdUpdater::Type updater) { + switch (updater) { + case ComputeNewSize: + return "compute_new_size"; + case ExpandAndAllocate: + return "expand_and_allocate"; + default: + assert(false, err_msg("Got bad updater: %d", (int) updater)); + return NULL; + }; + } +}; + +#endif // SHARE_VM_MEMORY_METASPACE_GC_THRESHOLD_UPDATER_HPP diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 8421b12d7f1..ef4572824f7 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -645,9 +645,6 @@ void MetaspaceShared::preload_and_dump(TRAPS) { TraceTime timer("Dump Shared Spaces", TraceStartupTime); ResourceMark rm; - // Lock out GC - is it necessary? I don't think we care. - No_GC_Verifier no_gc; - // 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) diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.cpp b/hotspot/src/share/vm/memory/metaspaceTracer.cpp new file mode 100644 index 00000000000..2a5cc2825de --- /dev/null +++ b/hotspot/src/share/vm/memory/metaspaceTracer.cpp @@ -0,0 +1,82 @@ +/* + * 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/classLoaderData.hpp" +#include "memory/metaspaceTracer.hpp" +#include "oops/oop.inline.hpp" +#include "trace/tracing.hpp" +#include "trace/traceBackend.hpp" + +void MetaspaceTracer::report_gc_threshold(size_t old_val, + size_t new_val, + MetaspaceGCThresholdUpdater::Type updater) const { + EventMetaspaceGCThreshold event; + if (event.should_commit()) { + event.set_oldValue(old_val); + event.set_newValue(new_val); + event.set_updater((u1)updater); + event.commit(); + } +} + +void MetaspaceTracer::report_metaspace_allocation_failure(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const { + send_allocation_failure_event(cld, word_size, objtype, mdtype); +} + +void MetaspaceTracer::report_metadata_oom(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const { + send_allocation_failure_event(cld, word_size, objtype, mdtype); +} + +template +void MetaspaceTracer::send_allocation_failure_event(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const { + E event; + if (event.should_commit()) { + if (cld->is_anonymous()) { + event.set_classLoader(NULL); + event.set_anonymousClassLoader(true); + } else { + if (cld->is_the_null_class_loader_data()) { + event.set_classLoader((Klass*) NULL); + } else { + event.set_classLoader(cld->class_loader()->klass()); + } + event.set_anonymousClassLoader(false); + } + + event.set_size(word_size * BytesPerWord); + event.set_metadataType((u1) mdtype); + event.set_metaspaceObjectType((u1) objtype); + event.commit(); + } +} diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.hpp b/hotspot/src/share/vm/memory/metaspaceTracer.hpp new file mode 100644 index 00000000000..4ae0138d581 --- /dev/null +++ b/hotspot/src/share/vm/memory/metaspaceTracer.hpp @@ -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. + * + */ + +#ifndef SHARE_VM_MEMORY_METASPACE_TRACER_HPP +#define SHARE_VM_MEMORY_METASPACE_TRACER_HPP + +#include "memory/allocation.hpp" +#include "memory/metaspace.hpp" +#include "memory/metaspaceGCThresholdUpdater.hpp" + +class ClassLoaderData; + +class MetaspaceTracer : public CHeapObj { + template + void send_allocation_failure_event(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const; + public: + void report_gc_threshold(size_t old_val, + size_t new_val, + MetaspaceGCThresholdUpdater::Type updater) const; + void report_metaspace_allocation_failure(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const; + void report_metadata_oom(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const; + +}; + +#endif // SHARE_VM_MEMORY_METASPACE_TRACER_HPP diff --git a/hotspot/src/share/vm/memory/padded.hpp b/hotspot/src/share/vm/memory/padded.hpp index 4c50b39963e..9ddd14f8576 100644 --- a/hotspot/src/share/vm/memory/padded.hpp +++ b/hotspot/src/share/vm/memory/padded.hpp @@ -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 @@ -90,4 +90,23 @@ class PaddedArray { static PaddedEnd* create_unfreeable(uint length); }; +// Helper class to create an array of references to arrays of primitive types +// Both the array of references and the data arrays are aligned to the given +// alignment. The allocated memory is zero-filled. +template +class Padded2DArray { + public: + // Creates an aligned padded 2D array. + // The memory cannot be deleted since the raw memory chunk is not returned. + static T** create_unfreeable(uint rows, uint columns, size_t* allocation_size = NULL); +}; + +// Helper class to create an array of T objects. The array as a whole will +// start at a multiple of alignment and its size will be aligned to alignment. +template +class PaddedPrimitiveArray { + public: + static T* create_unfreeable(size_t length); +}; + #endif // SHARE_VM_MEMORY_PADDED_HPP diff --git a/hotspot/src/share/vm/memory/padded.inline.hpp b/hotspot/src/share/vm/memory/padded.inline.hpp index 1e9994ab647..1e4f8858460 100644 --- a/hotspot/src/share/vm/memory/padded.inline.hpp +++ b/hotspot/src/share/vm/memory/padded.inline.hpp @@ -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 @@ -47,3 +47,42 @@ PaddedEnd* PaddedArray::create_unfreeable(uint length) { return aligned_padded_array; } + +template +T** Padded2DArray::create_unfreeable(uint rows, uint columns, size_t* allocation_size) { + // Calculate and align the size of the first dimension's table. + size_t table_size = align_size_up_(rows * sizeof(T*), alignment); + // The size of the separate rows. + size_t row_size = align_size_up_(columns * sizeof(T), alignment); + // Total size consists of the indirection table plus the rows. + size_t total_size = table_size + rows * row_size + alignment; + + // Allocate a chunk of memory large enough to allow alignment of the chunk. + void* chunk = AllocateHeap(total_size, flags); + // Clear the allocated memory. + memset(chunk, 0, total_size); + // Align the chunk of memory. + T** result = (T**)align_pointer_up(chunk, alignment); + void* data_start = (void*)((uintptr_t)result + table_size); + + // Fill in the row table. + for (size_t i = 0; i < rows; i++) { + result[i] = (T*)((uintptr_t)data_start + i * row_size); + } + + if (allocation_size != NULL) { + *allocation_size = total_size; + } + + return result; +} + +template +T* PaddedPrimitiveArray::create_unfreeable(size_t length) { + // Allocate a chunk of memory large enough to allow for some alignment. + void* chunk = AllocateHeap(length * sizeof(T) + alignment, flags); + + memset(chunk, 0, length * sizeof(T) + alignment); + + return (T*)align_pointer_up(chunk, alignment); +} diff --git a/hotspot/src/share/vm/memory/sharedHeap.hpp b/hotspot/src/share/vm/memory/sharedHeap.hpp index 21d6755d9d3..fef0a3da068 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.hpp +++ b/hotspot/src/share/vm/memory/sharedHeap.hpp @@ -163,9 +163,6 @@ public: // Iteration functions. void oop_iterate(ExtendedOopClosure* cl) = 0; - // Same as above, restricted to a memory region. - virtual void oop_iterate(MemRegion mr, ExtendedOopClosure* cl) = 0; - // Iterate over all spaces in use in the heap, in an undefined order. virtual void space_iterate(SpaceClosure* cl) = 0; diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index 7858a668293..b7b9c00adc1 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -42,9 +42,6 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -void SpaceMemRegionOopsIterClosure::do_oop(oop* p) { SpaceMemRegionOopsIterClosure::do_oop_work(p); } -void SpaceMemRegionOopsIterClosure::do_oop(narrowOop* p) { SpaceMemRegionOopsIterClosure::do_oop_work(p); } - HeapWord* DirtyCardToOopClosure::get_actual_top(HeapWord* top, HeapWord* top_obj) { if (top_obj != NULL) { @@ -305,10 +302,6 @@ void ContiguousSpace::clear(bool mangle_space) { CompactibleSpace::clear(mangle_space); } -bool ContiguousSpace::is_in(const void* p) const { - return _bottom <= p && p < _top; -} - bool ContiguousSpace::is_free_block(const HeapWord* p) const { return p >= _top; } @@ -550,115 +543,11 @@ void Space::oop_iterate(ExtendedOopClosure* blk) { object_iterate(&blk2); } -HeapWord* Space::object_iterate_careful(ObjectClosureCareful* cl) { - guarantee(false, "NYI"); - return bottom(); -} - -HeapWord* Space::object_iterate_careful_m(MemRegion mr, - ObjectClosureCareful* cl) { - guarantee(false, "NYI"); - return bottom(); -} - - -void Space::object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl) { - assert(!mr.is_empty(), "Should be non-empty"); - // We use MemRegion(bottom(), end()) rather than used_region() below - // because the two are not necessarily equal for some kinds of - // spaces, in particular, certain kinds of free list spaces. - // We could use the more complicated but more precise: - // MemRegion(used_region().start(), round_to(used_region().end(), CardSize)) - // but the slight imprecision seems acceptable in the assertion check. - assert(MemRegion(bottom(), end()).contains(mr), - "Should be within used space"); - HeapWord* prev = cl->previous(); // max address from last time - if (prev >= mr.end()) { // nothing to do - return; - } - // This assert will not work when we go from cms space to perm - // space, and use same closure. Easy fix deferred for later. XXX YSR - // assert(prev == NULL || contains(prev), "Should be within space"); - - bool last_was_obj_array = false; - HeapWord *blk_start_addr, *region_start_addr; - if (prev > mr.start()) { - region_start_addr = prev; - blk_start_addr = prev; - // The previous invocation may have pushed "prev" beyond the - // last allocated block yet there may be still be blocks - // in this region due to a particular coalescing policy. - // Relax the assertion so that the case where the unallocated - // block is maintained and "prev" is beyond the unallocated - // block does not cause the assertion to fire. - assert((BlockOffsetArrayUseUnallocatedBlock && - (!is_in(prev))) || - (blk_start_addr == block_start(region_start_addr)), "invariant"); - } else { - region_start_addr = mr.start(); - blk_start_addr = block_start(region_start_addr); - } - HeapWord* region_end_addr = mr.end(); - MemRegion derived_mr(region_start_addr, region_end_addr); - while (blk_start_addr < region_end_addr) { - const size_t size = block_size(blk_start_addr); - if (block_is_obj(blk_start_addr)) { - last_was_obj_array = cl->do_object_bm(oop(blk_start_addr), derived_mr); - } else { - last_was_obj_array = false; - } - blk_start_addr += size; - } - if (!last_was_obj_array) { - assert((bottom() <= blk_start_addr) && (blk_start_addr <= end()), - "Should be within (closed) used space"); - assert(blk_start_addr > prev, "Invariant"); - cl->set_previous(blk_start_addr); // min address for next time - } -} - bool Space::obj_is_alive(const HeapWord* p) const { assert (block_is_obj(p), "The address should point to an object"); return true; } -void ContiguousSpace::object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl) { - assert(!mr.is_empty(), "Should be non-empty"); - assert(used_region().contains(mr), "Should be within used space"); - HeapWord* prev = cl->previous(); // max address from last time - if (prev >= mr.end()) { // nothing to do - return; - } - // See comment above (in more general method above) in case you - // happen to use this method. - assert(prev == NULL || is_in_reserved(prev), "Should be within space"); - - bool last_was_obj_array = false; - HeapWord *obj_start_addr, *region_start_addr; - if (prev > mr.start()) { - region_start_addr = prev; - obj_start_addr = prev; - assert(obj_start_addr == block_start(region_start_addr), "invariant"); - } else { - region_start_addr = mr.start(); - obj_start_addr = block_start(region_start_addr); - } - HeapWord* region_end_addr = mr.end(); - MemRegion derived_mr(region_start_addr, region_end_addr); - while (obj_start_addr < region_end_addr) { - oop obj = oop(obj_start_addr); - const size_t size = obj->size(); - last_was_obj_array = cl->do_object_bm(obj, derived_mr); - obj_start_addr += size; - } - if (!last_was_obj_array) { - assert((bottom() <= obj_start_addr) && (obj_start_addr <= end()), - "Should be within (closed) used space"); - assert(obj_start_addr > prev, "Invariant"); - cl->set_previous(obj_start_addr); // min address for next time - } -} - #if INCLUDE_ALL_GCS #define ContigSpace_PAR_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ \ @@ -686,43 +575,6 @@ void ContiguousSpace::oop_iterate(ExtendedOopClosure* blk) { } } -void ContiguousSpace::oop_iterate(MemRegion mr, ExtendedOopClosure* blk) { - if (is_empty()) { - return; - } - MemRegion cur = MemRegion(bottom(), top()); - mr = mr.intersection(cur); - if (mr.is_empty()) { - return; - } - if (mr.equals(cur)) { - oop_iterate(blk); - return; - } - assert(mr.end() <= top(), "just took an intersection above"); - HeapWord* obj_addr = block_start(mr.start()); - HeapWord* t = mr.end(); - - // Handle first object specially. - oop obj = oop(obj_addr); - SpaceMemRegionOopsIterClosure smr_blk(blk, mr); - obj_addr += obj->oop_iterate(&smr_blk); - while (obj_addr < t) { - oop obj = oop(obj_addr); - assert(obj->is_oop(), "expected an oop"); - obj_addr += obj->size(); - // If "obj_addr" is not greater than top, then the - // entire object "obj" is within the region. - if (obj_addr <= t) { - obj->oop_iterate(blk); - } else { - // "obj" extends beyond end of region - obj->oop_iterate(&smr_blk); - break; - } - }; -} - void ContiguousSpace::object_iterate(ObjectClosure* blk) { if (is_empty()) return; WaterMark bm = bottom_mark(); diff --git a/hotspot/src/share/vm/memory/space.hpp b/hotspot/src/share/vm/memory/space.hpp index 245439f8e3a..2e0ebcb09b4 100644 --- a/hotspot/src/share/vm/memory/space.hpp +++ b/hotspot/src/share/vm/memory/space.hpp @@ -81,31 +81,6 @@ class GenRemSet; class CardTableRS; class DirtyCardToOopClosure; -// An oop closure that is circumscribed by a filtering memory region. -class SpaceMemRegionOopsIterClosure: public ExtendedOopClosure { - private: - ExtendedOopClosure* _cl; - MemRegion _mr; - protected: - template void do_oop_work(T* p) { - if (_mr.contains(p)) { - _cl->do_oop(p); - } - } - public: - SpaceMemRegionOopsIterClosure(ExtendedOopClosure* cl, MemRegion mr): - _cl(cl), _mr(mr) {} - virtual void do_oop(oop* p); - virtual void do_oop(narrowOop* p); - virtual bool do_metadata() { - // _cl is of type ExtendedOopClosure instead of OopClosure, so that we can check this. - assert(!_cl->do_metadata(), "I've checked all call paths, this shouldn't happen."); - return false; - } - virtual void do_klass(Klass* k) { ShouldNotReachHere(); } - virtual void do_class_loader_data(ClassLoaderData* cld) { ShouldNotReachHere(); } -}; - // A Space describes a heap area. Class Space is an abstract // base class. // @@ -145,6 +120,12 @@ class Space: public CHeapObj { void set_saved_mark_word(HeapWord* p) { _saved_mark_word = p; } + // Returns true if this object has been allocated since a + // generation's "save_marks" call. + virtual bool obj_allocated_since_save_marks(const oop obj) const { + return (HeapWord*)obj >= saved_mark_word(); + } + MemRegionClosure* preconsumptionDirtyCardClosure() const { return _preconsumptionDirtyCardClosure; } @@ -152,9 +133,9 @@ class Space: public CHeapObj { _preconsumptionDirtyCardClosure = cl; } - // Returns a subregion of the space containing all the objects in + // Returns a subregion of the space containing only the allocated objects in // the space. - virtual MemRegion used_region() const { return MemRegion(bottom(), end()); } + virtual MemRegion used_region() const = 0; // Returns a region that is guaranteed to contain (at least) all objects // allocated at the time of the last call to "save_marks". If the space @@ -164,7 +145,7 @@ class Space: public CHeapObj { // saved mark. Otherwise, the "obj_allocated_since_save_marks" method of // the space must distinguish between objects in the region allocated before // and after the call to save marks. - virtual MemRegion used_region_at_save_marks() const { + MemRegion used_region_at_save_marks() const { return MemRegion(bottom(), saved_mark_word()); } @@ -197,7 +178,9 @@ class Space: public CHeapObj { // expensive operation. To prevent performance problems // on account of its inadvertent use in product jvm's, // we restrict its use to assertion checks only. - virtual bool is_in(const void* p) const = 0; + bool is_in(const void* p) const { + return used_region().contains(p); + } // Returns true iff the given reserved memory of the space contains the // given address. @@ -221,11 +204,6 @@ class Space: public CHeapObj { // applications of the closure are not included in the iteration. virtual void oop_iterate(ExtendedOopClosure* cl); - // Same as above, restricted to the intersection of a memory region and - // the space. Fields in objects allocated by applications of the closure - // are not included in the iteration. - virtual void oop_iterate(MemRegion mr, ExtendedOopClosure* cl) = 0; - // Iterate over all objects in the space, calling "cl.do_object" on // each. Objects allocated by applications of the closure are not // included in the iteration. @@ -234,24 +212,6 @@ class Space: public CHeapObj { // objects whose internal references point to objects in the space. virtual void safe_object_iterate(ObjectClosure* blk) = 0; - // Iterate over all objects that intersect with mr, calling "cl->do_object" - // on each. There is an exception to this: if this closure has already - // been invoked on an object, it may skip such objects in some cases. This is - // Most likely to happen in an "upwards" (ascending address) iteration of - // MemRegions. - virtual void object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl); - - // Iterate over as many initialized objects in the space as possible, - // calling "cl.do_object_careful" on each. Return NULL if all objects - // in the space (at the start of the iteration) were iterated over. - // Return an address indicating the extent of the iteration in the - // event that the iteration had to return because of finding an - // uninitialized object in the space, or if the closure "cl" - // signaled early termination. - virtual HeapWord* object_iterate_careful(ObjectClosureCareful* cl); - virtual HeapWord* object_iterate_careful_m(MemRegion mr, - ObjectClosureCareful* cl); - // Create and return a new dirty card to oop closure. Can be // overridden to return the appropriate type of closure // depending on the type of space in which the closure will @@ -292,10 +252,6 @@ class Space: public CHeapObj { // Allocation (return NULL if full). Enforces mutual exclusion internally. virtual HeapWord* par_allocate(size_t word_size) = 0; - // Returns true if this object has been allocated since a - // generation's "save_marks" call. - virtual bool obj_allocated_since_save_marks(const oop obj) const = 0; - // Mark-sweep-compact support: all spaces can update pointers to objects // moving as a part of compaction. virtual void adjust_pointers(); @@ -427,7 +383,7 @@ public: // Perform operations on the space needed after a compaction // has been performed. - virtual void reset_after_compaction() {} + virtual void reset_after_compaction() = 0; // Returns the next space (in the current generation) to be compacted in // the global compaction order. Also is used to select the next @@ -492,7 +448,7 @@ protected: HeapWord* _end_of_live; // Minimum size of a free block. - virtual size_t minimum_free_block_size() const = 0; + virtual size_t minimum_free_block_size() const { return 0; } // This the function is invoked when an allocation of an object covering // "start" to "end occurs crosses the threshold; returns the next @@ -808,7 +764,7 @@ class ContiguousSpace: public CompactibleSpace { HeapWord* top() const { return _top; } void set_top(HeapWord* value) { _top = value; } - virtual void set_saved_mark() { _saved_mark_word = top(); } + void set_saved_mark() { _saved_mark_word = top(); } void reset_saved_mark() { _saved_mark_word = bottom(); } WaterMark bottom_mark() { return WaterMark(this, bottom()); } @@ -843,36 +799,30 @@ class ContiguousSpace: public CompactibleSpace { size_t used() const { return byte_size(bottom(), top()); } size_t free() const { return byte_size(top(), end()); } - // Override from space. - bool is_in(const void* p) const; - virtual bool is_free_block(const HeapWord* p) const; // In a contiguous space we have a more obvious bound on what parts // contain objects. MemRegion used_region() const { return MemRegion(bottom(), top()); } - MemRegion used_region_at_save_marks() const { - return MemRegion(bottom(), saved_mark_word()); - } - // Allocation (return NULL if full) virtual HeapWord* allocate(size_t word_size); virtual HeapWord* par_allocate(size_t word_size); - virtual bool obj_allocated_since_save_marks(const oop obj) const { - return (HeapWord*)obj >= saved_mark_word(); - } - // Iteration void oop_iterate(ExtendedOopClosure* cl); - void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); void object_iterate(ObjectClosure* blk); // For contiguous spaces this method will iterate safely over objects // in the space (i.e., between bottom and top) when at a safepoint. void safe_object_iterate(ObjectClosure* blk); - void object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl); - // iterates on objects up to the safe limit + + // Iterate over as many initialized objects in the space as possible, + // calling "cl.do_object_careful" on each. Return NULL if all objects + // in the space (at the start of the iteration) were iterated over. + // Return an address indicating the extent of the iteration in the + // event that the iteration had to return because of finding an + // uninitialized object in the space, or if the closure "cl" + // signaled early termination. HeapWord* object_iterate_careful(ObjectClosureCareful* cl); HeapWord* concurrent_iteration_safe_limit() { assert(_concurrent_iteration_safe_limit <= top(), @@ -903,7 +853,6 @@ class ContiguousSpace: public CompactibleSpace { // set new iteration safe limit set_concurrent_iteration_safe_limit(compaction_top()); } - virtual size_t minimum_free_block_size() const { return 0; } // Override. DirtyCardToOopClosure* new_dcto_cl(ExtendedOopClosure* cl, diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index dc4efcd1c8a..63c7c005d44 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -632,7 +632,6 @@ jint universe_init() { guarantee(sizeof(oop) % sizeof(HeapWord) == 0, "oop size is not not a multiple of HeapWord size"); TraceTime timer("Genesis", TraceStartupTime); - GC_locker::lock(); // do not allow gc during bootstrapping JavaClasses::compute_hard_coded_offsets(); jint status = Universe::initialize_heap(); @@ -1164,8 +1163,6 @@ bool universe_post_init() { MemoryService::add_metaspace_memory_pools(); - GC_locker::unlock(); // allow gc after bootstrapping - MemoryService::set_universe_heap(Universe::_collectedHeap); return true; } diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp index 21df75bdec0..8a8de131420 100644 --- a/hotspot/src/share/vm/oops/constMethod.hpp +++ b/hotspot/src/share/vm/oops/constMethod.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 @@ -27,68 +27,61 @@ #include "oops/oop.hpp" -// An ConstMethod* represents portions of a Java method which -// do not vary. +// An ConstMethod represents portions of a Java method which are not written to after +// the classfile is parsed(*see below). This part of the method can be shared across +// processes in a read-only section with Class Data Sharing (CDS). It's important +// that this class doesn't have virtual functions because the vptr cannot be shared +// with CDS. +// (*)RewriteByteCodes and RewriteFrequentPairs is an exception but turned off in CDS // -// Memory layout (each line represents a word). Note that most -// applications load thousands of methods, so keeping the size of this +// Note that most applications load thousands of methods, so keeping the size of this // structure small has a big impact on footprint. + +// The actual bytecodes are inlined after the end of the ConstMethod struct. // -// |------------------------------------------------------| -// | header | -// | klass | -// |------------------------------------------------------| -// | fingerprint 1 | -// | fingerprint 2 | -// | constants (oop) | -// | stackmap_data (oop) | -// | constMethod_size | -// | interp_kind | flags | code_size | -// | name index | signature index | -// | method_idnum | max_stack | -// | max_locals | size_of_parameters | -// |------------------------------------------------------| -// | | -// | byte codes | -// | | -// |------------------------------------------------------| -// | compressed linenumber table | -// | (see class CompressedLineNumberReadStream) | -// | (note that length is unknown until decompressed) | -// | (access flags bit tells whether table is present) | -// | (indexed from start of ConstMethod*) | -// | (elements not necessarily sorted!) | -// |------------------------------------------------------| -// | localvariable table elements + length (length last) | -// | (length is u2, elements are 6-tuples of u2) | -// | (see class LocalVariableTableElement) | -// | (access flags bit tells whether table is present) | -// | (indexed from end of ConstMethod*) | -// |------------------------------------------------------| -// | exception table + length (length last) | -// | (length is u2, elements are 4-tuples of u2) | -// | (see class ExceptionTableElement) | -// | (access flags bit tells whether table is present) | -// | (indexed from end of ConstMethod*) | -// |------------------------------------------------------| -// | checked exceptions elements + length (length last) | -// | (length is u2, elements are u2) | -// | (see class CheckedExceptionElement) | -// | (access flags bit tells whether table is present) | -// | (indexed from end of ConstMethod*) | -// |------------------------------------------------------| -// | method parameters elements + length (length last) | -// | (length is u2, elements are u2, u4 structures) | -// | (see class MethodParametersElement) | -// | (access flags bit tells whether table is present) | -// | (indexed from end of ConstMethod*) | -// |------------------------------------------------------| -// | generic signature index (u2) | -// | (indexed from start of constMethodOop) | -// |------------------------------------------------------| -// | annotations arrays - method, parameter, type, default| -// | pointer to Array if annotation is present | -// |------------------------------------------------------| +// The line number table is compressed and inlined following the byte codes. It is +// found as the first byte following the byte codes. Note that accessing the line +// number and local variable tables is not performance critical at all. +// +// The checked exceptions table and the local variable table are inlined after the +// line number table, and indexed from the end of the method. We do not compress the +// checked exceptions table since the average length is less than 2, and it is used +// by reflection so access should be fast. We do not bother to compress the local +// variable table either since it is mostly absent. +// +// +// ConstMethod embedded field layout (after declared fields): +// [EMBEDDED byte codes] +// [EMBEDDED compressed linenumber table] +// (see class CompressedLineNumberReadStream) +// (note that length is unknown until decompressed) +// (access flags bit tells whether table is present) +// (indexed from start of ConstMethod) +// (elements not necessarily sorted!) +// [EMBEDDED localvariable table elements + length (length last)] +// (length is u2, elements are 6-tuples of u2) +// (see class LocalVariableTableElement) +// (access flags bit tells whether table is present) +// (indexed from end of ConstMethod*) +// [EMBEDDED exception table + length (length last)] +// (length is u2, elements are 4-tuples of u2) +// (see class ExceptionTableElement) +// (access flags bit tells whether table is present) +// (indexed from end of ConstMethod*) +// [EMBEDDED checked exceptions elements + length (length last)] +// (length is u2, elements are u2) +// (see class CheckedExceptionElement) +// (access flags bit tells whether table is present) +// (indexed from end of ConstMethod*) +// [EMBEDDED method parameters elements + length (length last)] +// (length is u2, elements are u2, u4 structures) +// (see class MethodParametersElement) +// (access flags bit tells whether table is present) +// (indexed from end of ConstMethod*) +// [EMBEDDED generic signature index (u2)] +// (indexed from end of constMethodOop) +// [EMBEDDED annotations arrays - method, parameter, type, default] +// pointer to Array if annotation is present // // IMPORTANT: If anything gets added here, there need to be changes to // ensure that ServicabilityAgent doesn't get broken as a result! diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index 9ed7628985d..f59a6d1d60b 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -180,12 +180,12 @@ int ConstantPool::cp_to_object_index(int cp_index) { return (i < 0) ? _no_index_sentinel : i; } -Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) { +Klass* ConstantPool::klass_at_impl(constantPoolHandle this_cp, int which, TRAPS) { // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*. // It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and // tag is not updated atomicly. - CPSlot entry = this_oop->slot_at(which); + CPSlot entry = this_cp->slot_at(which); if (entry.is_resolved()) { assert(entry.get_klass()->is_klass(), "must be"); // Already resolved - return entry. @@ -204,15 +204,15 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS Symbol* name = NULL; Handle loader; - { MonitorLockerEx ml(this_oop->lock()); + { MonitorLockerEx ml(this_cp->lock()); - if (this_oop->tag_at(which).is_unresolved_klass()) { - if (this_oop->tag_at(which).is_unresolved_klass_in_error()) { + if (this_cp->tag_at(which).is_unresolved_klass()) { + if (this_cp->tag_at(which).is_unresolved_klass_in_error()) { in_error = true; } else { do_resolve = true; - name = this_oop->unresolved_klass_at(which); - loader = Handle(THREAD, this_oop->pool_holder()->class_loader()); + name = this_cp->unresolved_klass_at(which); + loader = Handle(THREAD, this_cp->pool_holder()->class_loader()); } } } // unlocking constantPool @@ -221,26 +221,26 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS // The original attempt to resolve this constant pool entry failed so find the // original error and throw it again (JVMS 5.4.3). if (in_error) { - Symbol* error = SystemDictionary::find_resolution_error(this_oop, which); + Symbol* error = SystemDictionary::find_resolution_error(this_cp, which); guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table"); ResourceMark rm; // exception text will be the class name - const char* className = this_oop->unresolved_klass_at(which)->as_C_string(); + const char* className = this_cp->unresolved_klass_at(which)->as_C_string(); THROW_MSG_0(error, className); } if (do_resolve) { - // this_oop must be unlocked during resolve_or_fail - oop protection_domain = this_oop->pool_holder()->protection_domain(); + // this_cp must be unlocked during resolve_or_fail + oop protection_domain = this_cp->pool_holder()->protection_domain(); Handle h_prot (THREAD, protection_domain); - Klass* k_oop = SystemDictionary::resolve_or_fail(name, loader, h_prot, true, THREAD); + Klass* kk = SystemDictionary::resolve_or_fail(name, loader, h_prot, true, THREAD); KlassHandle k; if (!HAS_PENDING_EXCEPTION) { - k = KlassHandle(THREAD, k_oop); + k = KlassHandle(THREAD, kk); // preserve the resolved klass. - mirror_handle = Handle(THREAD, k_oop->java_mirror()); + mirror_handle = Handle(THREAD, kk->java_mirror()); // Do access check for klasses - verify_constant_pool_resolve(this_oop, k, THREAD); + verify_constant_pool_resolve(this_cp, k, THREAD); } // Failed to resolve class. We must record the errors so that subsequent attempts @@ -251,12 +251,12 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS bool throw_orig_error = false; { - MonitorLockerEx ml(this_oop->lock()); + MonitorLockerEx ml(this_cp->lock()); // some other thread has beaten us and has resolved the class. - if (this_oop->tag_at(which).is_klass()) { + if (this_cp->tag_at(which).is_klass()) { CLEAR_PENDING_EXCEPTION; - entry = this_oop->resolved_klass_at(which); + entry = this_cp->resolved_klass_at(which); return entry.get_klass(); } @@ -267,12 +267,12 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS // and OutOfMemoryError, etc, or if the thread was hit by stop() // Needs clarification to section 5.4.3 of the VM spec (see 6308271) } - else if (!this_oop->tag_at(which).is_unresolved_klass_in_error()) { - SystemDictionary::add_resolution_error(this_oop, which, error); - this_oop->tag_at_put(which, JVM_CONSTANT_UnresolvedClassInError); + else if (!this_cp->tag_at(which).is_unresolved_klass_in_error()) { + SystemDictionary::add_resolution_error(this_cp, which, error); + this_cp->tag_at_put(which, JVM_CONSTANT_UnresolvedClassInError); } else { // some other thread has put the class in error state. - error = SystemDictionary::find_resolution_error(this_oop, which); + error = SystemDictionary::find_resolution_error(this_cp, which); assert(error != NULL, "checking"); throw_orig_error = true; } @@ -281,7 +281,7 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS if (throw_orig_error) { CLEAR_PENDING_EXCEPTION; ResourceMark rm; - const char* className = this_oop->unresolved_klass_at(which)->as_C_string(); + const char* className = this_cp->unresolved_klass_at(which)->as_C_string(); THROW_MSG_0(error, className); } @@ -305,32 +305,32 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS } } } - if (k() != this_oop->pool_holder()) { + if (k() != this_cp->pool_holder()) { // only print something if the classes are different if (source_file != NULL) { tty->print("RESOLVE %s %s %s:%d\n", - this_oop->pool_holder()->external_name(), + this_cp->pool_holder()->external_name(), InstanceKlass::cast(k())->external_name(), source_file, line_number); } else { tty->print("RESOLVE %s %s\n", - this_oop->pool_holder()->external_name(), + this_cp->pool_holder()->external_name(), InstanceKlass::cast(k())->external_name()); } } return k(); } else { - MonitorLockerEx ml(this_oop->lock()); + MonitorLockerEx ml(this_cp->lock()); // Only updated constant pool - if it is resolved. - do_resolve = this_oop->tag_at(which).is_unresolved_klass(); + do_resolve = this_cp->tag_at(which).is_unresolved_klass(); if (do_resolve) { - ClassLoaderData* this_key = this_oop->pool_holder()->class_loader_data(); + ClassLoaderData* this_key = this_cp->pool_holder()->class_loader_data(); this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM - this_oop->klass_at_put(which, k()); + this_cp->klass_at_put(which, k()); } } } - entry = this_oop->resolved_klass_at(which); + entry = this_cp->resolved_klass_at(which); assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point"); return entry.get_klass(); } @@ -340,8 +340,8 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS // by compiler and exception handling. Also used to avoid classloads for // instanceof operations. Returns NULL if the class has not been loaded or // if the verification of constant pool failed -Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) { - CPSlot entry = this_oop->slot_at(which); +Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_cp, int which) { + CPSlot entry = this_cp->slot_at(which); if (entry.is_resolved()) { assert(entry.get_klass()->is_klass(), "must be"); return entry.get_klass(); @@ -349,8 +349,8 @@ Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) assert(entry.is_unresolved(), "must be either symbol or klass"); Thread *thread = Thread::current(); Symbol* name = entry.get_symbol(); - oop loader = this_oop->pool_holder()->class_loader(); - oop protection_domain = this_oop->pool_holder()->protection_domain(); + oop loader = this_cp->pool_holder()->class_loader(); + oop protection_domain = this_cp->pool_holder()->protection_domain(); Handle h_prot (thread, protection_domain); Handle h_loader (thread, loader); Klass* k = SystemDictionary::find(name, h_loader, h_prot, thread); @@ -360,7 +360,7 @@ Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) EXCEPTION_MARK; KlassHandle klass(THREAD, k); // return NULL if verification fails - verify_constant_pool_resolve(this_oop, klass, THREAD); + verify_constant_pool_resolve(this_cp, klass, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return NULL; @@ -373,8 +373,8 @@ Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) } -Klass* ConstantPool::klass_ref_at_if_loaded(constantPoolHandle this_oop, int which) { - return klass_at_if_loaded(this_oop, this_oop->klass_ref_index_at(which)); +Klass* ConstantPool::klass_ref_at_if_loaded(constantPoolHandle this_cp, int which) { + return klass_at_if_loaded(this_cp, this_cp->klass_ref_index_at(which)); } @@ -486,11 +486,11 @@ int ConstantPool::remap_instruction_operand_from_cache(int operand) { } -void ConstantPool::verify_constant_pool_resolve(constantPoolHandle this_oop, KlassHandle k, TRAPS) { +void ConstantPool::verify_constant_pool_resolve(constantPoolHandle this_cp, KlassHandle k, TRAPS) { if (k->oop_is_instance() || k->oop_is_objArray()) { - instanceKlassHandle holder (THREAD, this_oop->pool_holder()); - Klass* elem_oop = k->oop_is_instance() ? k() : ObjArrayKlass::cast(k())->bottom_klass(); - KlassHandle element (THREAD, elem_oop); + instanceKlassHandle holder (THREAD, this_cp->pool_holder()); + Klass* elem = k->oop_is_instance() ? k() : ObjArrayKlass::cast(k())->bottom_klass(); + KlassHandle element (THREAD, elem); // The element type could be a typeArray - we only need the access check if it is // an reference to another class @@ -559,10 +559,10 @@ BasicType ConstantPool::basic_type_for_signature_at(int which) { } -void ConstantPool::resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS) { - for (int index = 1; index < this_oop->length(); index++) { // Index 0 is unused - if (this_oop->tag_at(index).is_string()) { - this_oop->string_at(index, CHECK); +void ConstantPool::resolve_string_constants_impl(constantPoolHandle this_cp, TRAPS) { + for (int index = 1; index < this_cp->length(); index++) { // Index 0 is unused + if (this_cp->tag_at(index).is_string()) { + this_cp->string_at(index, CHECK); } } } @@ -585,11 +585,11 @@ bool ConstantPool::resolve_class_constants(TRAPS) { // If resolution for MethodHandle or MethodType fails, save the exception // in the resolution error table, so that the same exception is thrown again. -void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int which, +void ConstantPool::save_and_throw_exception(constantPoolHandle this_cp, int which, int tag, TRAPS) { ResourceMark rm; Symbol* error = PENDING_EXCEPTION->klass()->name(); - MonitorLockerEx ml(this_oop->lock()); // lock cpool to change tag. + MonitorLockerEx ml(this_cp->lock()); // lock cpool to change tag. int error_tag = (tag == JVM_CONSTANT_MethodHandle) ? JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError; @@ -601,12 +601,12 @@ void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int whi // and OutOfMemoryError, etc, or if the thread was hit by stop() // Needs clarification to section 5.4.3 of the VM spec (see 6308271) - } else if (this_oop->tag_at(which).value() != error_tag) { - SystemDictionary::add_resolution_error(this_oop, which, error); - this_oop->tag_at_put(which, error_tag); + } else if (this_cp->tag_at(which).value() != error_tag) { + SystemDictionary::add_resolution_error(this_cp, which, error); + this_cp->tag_at_put(which, error_tag); } else { // some other thread has put the class in error state. - error = SystemDictionary::find_resolution_error(this_oop, which); + error = SystemDictionary::find_resolution_error(this_cp, which); assert(error != NULL, "checking"); CLEAR_PENDING_EXCEPTION; THROW_MSG(error, ""); @@ -617,7 +617,7 @@ void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int whi // Called to resolve constants in the constant pool and return an oop. // Some constant pool entries cache their resolved oop. This is also // called to create oops from constants to use in arguments for invokedynamic -oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) { +oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index, int cache_index, TRAPS) { oop result_oop = NULL; Handle throw_exception; @@ -625,23 +625,23 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde // It is possible that this constant is one which is cached in the objects. // We'll do a linear search. This should be OK because this usage is rare. assert(index > 0, "valid index"); - cache_index = this_oop->cp_to_object_index(index); + cache_index = this_cp->cp_to_object_index(index); } assert(cache_index == _no_index_sentinel || cache_index >= 0, ""); assert(index == _no_index_sentinel || index >= 0, ""); if (cache_index >= 0) { - result_oop = this_oop->resolved_references()->obj_at(cache_index); + result_oop = this_cp->resolved_references()->obj_at(cache_index); if (result_oop != NULL) { return result_oop; // That was easy... } - index = this_oop->object_to_cp_index(cache_index); + index = this_cp->object_to_cp_index(cache_index); } jvalue prim_value; // temp used only in a few cases below - int tag_value = this_oop->tag_at(index).value(); + int tag_value = this_cp->tag_at(index).value(); switch (tag_value) { @@ -650,7 +650,7 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde case JVM_CONSTANT_Class: { assert(cache_index == _no_index_sentinel, "should not have been set"); - Klass* resolved = klass_at_impl(this_oop, index, CHECK_NULL); + Klass* resolved = klass_at_impl(this_cp, index, CHECK_NULL); // ldc wants the java mirror. result_oop = resolved->java_mirror(); break; @@ -658,17 +658,17 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde case JVM_CONSTANT_String: assert(cache_index != _no_index_sentinel, "should have been set"); - if (this_oop->is_pseudo_string_at(index)) { - result_oop = this_oop->pseudo_string_at(index, cache_index); + if (this_cp->is_pseudo_string_at(index)) { + result_oop = this_cp->pseudo_string_at(index, cache_index); break; } - result_oop = string_at_impl(this_oop, index, cache_index, CHECK_NULL); + result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL); break; case JVM_CONSTANT_MethodHandleInError: case JVM_CONSTANT_MethodTypeInError: { - Symbol* error = SystemDictionary::find_resolution_error(this_oop, index); + Symbol* error = SystemDictionary::find_resolution_error(this_cp, index); guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table"); ResourceMark rm; THROW_MSG_0(error, ""); @@ -677,72 +677,72 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde case JVM_CONSTANT_MethodHandle: { - int ref_kind = this_oop->method_handle_ref_kind_at(index); - int callee_index = this_oop->method_handle_klass_index_at(index); - Symbol* name = this_oop->method_handle_name_ref_at(index); - Symbol* signature = this_oop->method_handle_signature_ref_at(index); + int ref_kind = this_cp->method_handle_ref_kind_at(index); + int callee_index = this_cp->method_handle_klass_index_at(index); + Symbol* name = this_cp->method_handle_name_ref_at(index); + Symbol* signature = this_cp->method_handle_signature_ref_at(index); if (PrintMiscellaneous) tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s", - ref_kind, index, this_oop->method_handle_index_at(index), + ref_kind, index, this_cp->method_handle_index_at(index), callee_index, name->as_C_string(), signature->as_C_string()); KlassHandle callee; - { Klass* k = klass_at_impl(this_oop, callee_index, CHECK_NULL); + { Klass* k = klass_at_impl(this_cp, callee_index, CHECK_NULL); callee = KlassHandle(THREAD, k); } - KlassHandle klass(THREAD, this_oop->pool_holder()); + KlassHandle klass(THREAD, this_cp->pool_holder()); Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, callee, name, signature, THREAD); result_oop = value(); if (HAS_PENDING_EXCEPTION) { - save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL); + save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL); } break; } case JVM_CONSTANT_MethodType: { - Symbol* signature = this_oop->method_type_signature_at(index); + Symbol* signature = this_cp->method_type_signature_at(index); if (PrintMiscellaneous) tty->print_cr("resolve JVM_CONSTANT_MethodType [%d/%d] %s", - index, this_oop->method_type_index_at(index), + index, this_cp->method_type_index_at(index), signature->as_C_string()); - KlassHandle klass(THREAD, this_oop->pool_holder()); + KlassHandle klass(THREAD, this_cp->pool_holder()); Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD); result_oop = value(); if (HAS_PENDING_EXCEPTION) { - save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL); + save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL); } break; } case JVM_CONSTANT_Integer: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.i = this_oop->int_at(index); + prim_value.i = this_cp->int_at(index); result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL); break; case JVM_CONSTANT_Float: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.f = this_oop->float_at(index); + prim_value.f = this_cp->float_at(index); result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL); break; case JVM_CONSTANT_Long: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.j = this_oop->long_at(index); + prim_value.j = this_cp->long_at(index); result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL); break; case JVM_CONSTANT_Double: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.d = this_oop->double_at(index); + prim_value.d = this_cp->double_at(index); result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL); break; default: DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d", - this_oop(), index, cache_index, tag_value) ); + this_cp(), index, cache_index, tag_value) ); assert(false, "unexpected constant tag"); break; } @@ -750,15 +750,15 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde if (cache_index >= 0) { // Cache the oop here also. Handle result_handle(THREAD, result_oop); - MonitorLockerEx ml(this_oop->lock()); // don't know if we really need this - oop result = this_oop->resolved_references()->obj_at(cache_index); + MonitorLockerEx ml(this_cp->lock()); // don't know if we really need this + oop result = this_cp->resolved_references()->obj_at(cache_index); // Benign race condition: resolved_references may already be filled in while we were trying to lock. // The important thing here is that all threads pick up the same result. // It doesn't matter which racing thread wins, as long as only one // result is used by all threads, and all future queries. // That result may be either a resolved constant or a failure exception. if (result == NULL) { - this_oop->resolved_references()->obj_at_put(cache_index, result_handle()); + this_cp->resolved_references()->obj_at_put(cache_index, result_handle()); return result_handle(); } else { // Return the winning thread's result. This can be different than @@ -778,8 +778,8 @@ oop ConstantPool::uncached_string_at(int which, TRAPS) { } -oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oop, int index, TRAPS) { - assert(this_oop->tag_at(index).is_invoke_dynamic(), "Corrupted constant pool"); +oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_cp, int index, TRAPS) { + assert(this_cp->tag_at(index).is_invoke_dynamic(), "Corrupted constant pool"); Handle bsm; int argc; @@ -787,14 +787,14 @@ oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oo // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type], plus optional arguments // The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry. // It is accompanied by the optional arguments. - int bsm_index = this_oop->invoke_dynamic_bootstrap_method_ref_index_at(index); - oop bsm_oop = this_oop->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL); + int bsm_index = this_cp->invoke_dynamic_bootstrap_method_ref_index_at(index); + oop bsm_oop = this_cp->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL); if (!java_lang_invoke_MethodHandle::is_instance(bsm_oop)) { THROW_MSG_NULL(vmSymbols::java_lang_LinkageError(), "BSM not an MethodHandle"); } // Extract the optional static arguments. - argc = this_oop->invoke_dynamic_argument_count_at(index); + argc = this_cp->invoke_dynamic_argument_count_at(index); if (argc == 0) return bsm_oop; bsm = Handle(THREAD, bsm_oop); @@ -808,21 +808,21 @@ oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oo info->obj_at_put(0, bsm()); for (int i = 0; i < argc; i++) { - int arg_index = this_oop->invoke_dynamic_argument_index_at(index, i); - oop arg_oop = this_oop->resolve_possibly_cached_constant_at(arg_index, CHECK_NULL); + int arg_index = this_cp->invoke_dynamic_argument_index_at(index, i); + oop arg_oop = this_cp->resolve_possibly_cached_constant_at(arg_index, CHECK_NULL); info->obj_at_put(1+i, arg_oop); } return info(); } -oop ConstantPool::string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS) { +oop ConstantPool::string_at_impl(constantPoolHandle this_cp, int which, int obj_index, TRAPS) { // If the string has already been interned, this entry will be non-null - oop str = this_oop->resolved_references()->obj_at(obj_index); + oop str = this_cp->resolved_references()->obj_at(obj_index); if (str != NULL) return str; - Symbol* sym = this_oop->unresolved_string_at(which); + Symbol* sym = this_cp->unresolved_string_at(which); str = StringTable::intern(sym, CHECK_(NULL)); - this_oop->string_at_put(which, obj_index, str); + this_cp->string_at_put(which, obj_index, str); assert(java_lang_String::is_instance(str), "must be string"); return str; } diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 497df53d778..169d97f4266 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.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 @@ -48,7 +48,7 @@ # include "bytes_ppc.hpp" #endif -// A constantPool is an array containing class constants as described in the +// A ConstantPool is an array containing class constants as described in the // class file. // // Most of the constant pool entries are written during class parsing, which @@ -81,9 +81,10 @@ class CPSlot VALUE_OBJ_CLASS_SPEC { }; class KlassSizeStats; + class ConstantPool : public Metadata { friend class VMStructs; - friend class BytecodeInterpreter; // Directly extracts an oop in the pool for fast instanceof/checkcast + friend class BytecodeInterpreter; // Directly extracts a klass in the pool for fast instanceof/checkcast friend class Universe; // For null constructor private: Array* _tags; // the tag array describing the constant pool's contents @@ -747,13 +748,13 @@ class ConstantPool : public Metadata { friend class SystemDictionary; // Used by compiler to prevent classloading. - static Method* method_at_if_loaded (constantPoolHandle this_oop, int which); - static bool has_appendix_at_if_loaded (constantPoolHandle this_oop, int which); - static oop appendix_at_if_loaded (constantPoolHandle this_oop, int which); - static bool has_method_type_at_if_loaded (constantPoolHandle this_oop, int which); - static oop method_type_at_if_loaded (constantPoolHandle this_oop, int which); - static Klass* klass_at_if_loaded (constantPoolHandle this_oop, int which); - static Klass* klass_ref_at_if_loaded (constantPoolHandle this_oop, int which); + static Method* method_at_if_loaded (constantPoolHandle this_cp, int which); + static bool has_appendix_at_if_loaded (constantPoolHandle this_cp, int which); + static oop appendix_at_if_loaded (constantPoolHandle this_cp, int which); + static bool has_method_type_at_if_loaded (constantPoolHandle this_cp, int which); + static oop method_type_at_if_loaded (constantPoolHandle this_cp, int which); + static Klass* klass_at_if_loaded (constantPoolHandle this_cp, int which); + static Klass* klass_ref_at_if_loaded (constantPoolHandle this_cp, int which); // Routines currently used for annotations (only called by jvm.cpp) but which might be used in the // future by other Java code. These take constant pool indices rather than @@ -811,19 +812,19 @@ class ConstantPool : public Metadata { } // Performs the LinkResolver checks - static void verify_constant_pool_resolve(constantPoolHandle this_oop, KlassHandle klass, TRAPS); + static void verify_constant_pool_resolve(constantPoolHandle this_cp, KlassHandle klass, TRAPS); // Implementation of methods that needs an exposed 'this' pointer, in order to // handle GC while executing the method - static Klass* klass_at_impl(constantPoolHandle this_oop, int which, TRAPS); - static oop string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS); + static Klass* klass_at_impl(constantPoolHandle this_cp, int which, TRAPS); + static oop string_at_impl(constantPoolHandle this_cp, int which, int obj_index, TRAPS); // Resolve string constants (to prevent allocation during compilation) - static void resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS); + static void resolve_string_constants_impl(constantPoolHandle this_cp, TRAPS); - static oop resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS); - static void save_and_throw_exception(constantPoolHandle this_oop, int which, int tag_value, TRAPS); - static oop resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oop, int index, TRAPS); + static oop resolve_constant_at_impl(constantPoolHandle this_cp, int index, int cache_index, TRAPS); + static void save_and_throw_exception(constantPoolHandle this_cp, int which, int tag_value, TRAPS); + static oop resolve_bootstrap_specifier_at_impl(constantPoolHandle this_cp, int index, TRAPS); public: // Merging ConstantPool* support: diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp index 5e93cd6c803..5e75ad8917e 100644 --- a/hotspot/src/share/vm/oops/cpCache.cpp +++ b/hotspot/src/share/vm/oops/cpCache.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 @@ -328,7 +328,7 @@ void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool, // the f1 method has signature '(Ljl/Object;Ljl/invoke/MethodType;)Ljl/Object;', // not '(Ljava/lang/String;)Ljava/util/List;'. // The fact that String and List are involved is encoded in the MethodType in refs[f2]. - // This allows us to create fewer method oops, while keeping type safety. + // This allows us to create fewer Methods, while keeping type safety. // objArrayHandle resolved_references = cpool->resolved_references(); diff --git a/hotspot/src/share/vm/oops/cpCache.hpp b/hotspot/src/share/vm/oops/cpCache.hpp index 49559be5e2e..1bc7a417938 100644 --- a/hotspot/src/share/vm/oops/cpCache.hpp +++ b/hotspot/src/share/vm/oops/cpCache.hpp @@ -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 @@ -102,8 +102,9 @@ class PSPromotionManager; // _f1 = Method* for non-virtual calls, unused by virtual calls. // for interface calls, which are essentially virtual but need a klass, // contains Klass* for the corresponding interface. -// for invokedynamic, f1 contains a site-specific CallSite object (as an appendix) -// for invokehandle, f1 contains a site-specific MethodType object (as an appendix) +// for invokedynamic and invokehandle, f1 contains the adapter method which +// manages the actual call. The appendix is stored in the ConstantPool +// resolved_references array. // (upcoming metadata changes will move the appendix to a separate array) // _f2 = vtable/itable index (or final Method*) for virtual calls only, // unused by non-virtual. The is_vfinal flag indicates this is a diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 976386978ce..9e6080a8266 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -432,8 +432,8 @@ void InstanceKlass::eager_initialize(Thread *thread) { if (!InstanceKlass::cast(super)->is_initialized()) return; // call body to expose the this pointer - instanceKlassHandle this_oop(thread, this); - eager_initialize_impl(this_oop); + instanceKlassHandle this_k(thread, this); + eager_initialize_impl(this_k); } } @@ -470,16 +470,16 @@ void InstanceKlass::fence_and_clear_init_lock() { assert(!is_not_initialized(), "class must be initialized now"); } -void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) { +void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_k) { EXCEPTION_MARK; - oop init_lock = this_oop->init_lock(); + oop init_lock = this_k->init_lock(); ObjectLocker ol(init_lock, THREAD, init_lock != NULL); // abort if someone beat us to the initialization - if (!this_oop->is_not_initialized()) return; // note: not equivalent to is_initialized() + if (!this_k->is_not_initialized()) return; // note: not equivalent to is_initialized() - ClassState old_state = this_oop->init_state(); - link_class_impl(this_oop, true, THREAD); + ClassState old_state = this_k->init_state(); + link_class_impl(this_k, true, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; // Abort if linking the class throws an exception. @@ -487,16 +487,16 @@ void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) { // Use a test to avoid redundantly resetting the state if there's // no change. Set_init_state() asserts that state changes make // progress, whereas here we might just be spinning in place. - if( old_state != this_oop->_init_state ) - this_oop->set_init_state (old_state); + if( old_state != this_k->_init_state ) + this_k->set_init_state (old_state); } else { // linking successfull, mark class as initialized - this_oop->set_init_state (fully_initialized); - this_oop->fence_and_clear_init_lock(); + this_k->set_init_state (fully_initialized); + this_k->fence_and_clear_init_lock(); // trace if (TraceClassInitialization) { ResourceMark rm(THREAD); - tty->print_cr("[Initialized %s without side effects]", this_oop->external_name()); + tty->print_cr("[Initialized %s without side effects]", this_k->external_name()); } } } @@ -508,8 +508,8 @@ void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) { void InstanceKlass::initialize(TRAPS) { if (this->should_be_initialized()) { HandleMark hm(THREAD); - instanceKlassHandle this_oop(THREAD, this); - initialize_impl(this_oop, CHECK); + instanceKlassHandle this_k(THREAD, this); + initialize_impl(this_k, CHECK); // Note: at this point the class may be initialized // OR it may be in the state of being initialized // in case of recursive initialization! @@ -520,11 +520,11 @@ void InstanceKlass::initialize(TRAPS) { bool InstanceKlass::verify_code( - instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) { + instanceKlassHandle this_k, bool throw_verifyerror, TRAPS) { // 1) Verify the bytecodes Verifier::Mode mode = throw_verifyerror ? Verifier::ThrowException : Verifier::NoException; - return Verifier::verify(this_oop, mode, this_oop->should_verify_class(), CHECK_false); + return Verifier::verify(this_k, mode, this_k->should_verify_class(), CHECK_false); } @@ -540,8 +540,8 @@ void InstanceKlass::link_class(TRAPS) { assert(is_loaded(), "must be loaded"); if (!is_linked()) { HandleMark hm(THREAD); - instanceKlassHandle this_oop(THREAD, this); - link_class_impl(this_oop, true, CHECK); + instanceKlassHandle this_k(THREAD, this); + link_class_impl(this_k, true, CHECK); } } @@ -551,22 +551,22 @@ bool InstanceKlass::link_class_or_fail(TRAPS) { assert(is_loaded(), "must be loaded"); if (!is_linked()) { HandleMark hm(THREAD); - instanceKlassHandle this_oop(THREAD, this); - link_class_impl(this_oop, false, CHECK_false); + instanceKlassHandle this_k(THREAD, this); + link_class_impl(this_k, false, CHECK_false); } return is_linked(); } bool InstanceKlass::link_class_impl( - instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) { + instanceKlassHandle this_k, bool throw_verifyerror, TRAPS) { // check for error state - if (this_oop->is_in_error_state()) { + if (this_k->is_in_error_state()) { ResourceMark rm(THREAD); THROW_MSG_(vmSymbols::java_lang_NoClassDefFoundError(), - this_oop->external_name(), false); + this_k->external_name(), false); } // return if already verified - if (this_oop->is_linked()) { + if (this_k->is_linked()) { return true; } @@ -576,7 +576,7 @@ bool InstanceKlass::link_class_impl( JavaThread* jt = (JavaThread*)THREAD; // link super class before linking this class - instanceKlassHandle super(THREAD, this_oop->super()); + instanceKlassHandle super(THREAD, this_k->super()); if (super.not_null()) { if (super->is_interface()) { // check if super class is an interface ResourceMark rm(THREAD); @@ -584,7 +584,7 @@ bool InstanceKlass::link_class_impl( THREAD_AND_LOCATION, vmSymbols::java_lang_IncompatibleClassChangeError(), "class %s has interface %s as super class", - this_oop->external_name(), + this_k->external_name(), super->external_name() ); return false; @@ -594,7 +594,7 @@ bool InstanceKlass::link_class_impl( } // link all interfaces implemented by this class before linking this class - Array* interfaces = this_oop->local_interfaces(); + Array* interfaces = this_k->local_interfaces(); int num_interfaces = interfaces->length(); for (int index = 0; index < num_interfaces; index++) { HandleMark hm(THREAD); @@ -603,7 +603,7 @@ bool InstanceKlass::link_class_impl( } // in case the class is linked in the process of linking its superclasses - if (this_oop->is_linked()) { + if (this_k->is_linked()) { return true; } @@ -618,14 +618,14 @@ bool InstanceKlass::link_class_impl( // verification & rewriting { - oop init_lock = this_oop->init_lock(); + oop init_lock = this_k->init_lock(); ObjectLocker ol(init_lock, THREAD, init_lock != NULL); // rewritten will have been set if loader constraint error found // on an earlier link attempt // don't verify or rewrite if already rewritten - if (!this_oop->is_linked()) { - if (!this_oop->is_rewritten()) { + if (!this_k->is_linked()) { + if (!this_k->is_rewritten()) { { // Timer includes any side effects of class verification (resolution, // etc), but not recursive entry into verify_code(). @@ -635,7 +635,7 @@ bool InstanceKlass::link_class_impl( jt->get_thread_stat()->perf_recursion_counts_addr(), jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_VERIFY); - bool verify_ok = verify_code(this_oop, throw_verifyerror, THREAD); + bool verify_ok = verify_code(this_k, throw_verifyerror, THREAD); if (!verify_ok) { return false; } @@ -644,39 +644,39 @@ bool InstanceKlass::link_class_impl( // Just in case a side-effect of verify linked this class already // (which can sometimes happen since the verifier loads classes // using custom class loaders, which are free to initialize things) - if (this_oop->is_linked()) { + if (this_k->is_linked()) { return true; } // also sets rewritten - this_oop->rewrite_class(CHECK_false); + this_k->rewrite_class(CHECK_false); } // relocate jsrs and link methods after they are all rewritten - this_oop->link_methods(CHECK_false); + this_k->link_methods(CHECK_false); // Initialize the vtable and interface table after // methods have been rewritten since rewrite may // fabricate new Method*s. // also does loader constraint checking - if (!this_oop()->is_shared()) { + if (!this_k()->is_shared()) { ResourceMark rm(THREAD); - this_oop->vtable()->initialize_vtable(true, CHECK_false); - this_oop->itable()->initialize_itable(true, CHECK_false); + this_k->vtable()->initialize_vtable(true, CHECK_false); + this_k->itable()->initialize_itable(true, CHECK_false); } #ifdef ASSERT else { ResourceMark rm(THREAD); - this_oop->vtable()->verify(tty, true); + this_k->vtable()->verify(tty, true); // In case itable verification is ever added. - // this_oop->itable()->verify(tty, true); + // this_k->itable()->verify(tty, true); } #endif - this_oop->set_init_state(linked); + this_k->set_init_state(linked); if (JvmtiExport::should_post_class_prepare()) { Thread *thread = THREAD; assert(thread->is_Java_thread(), "thread->is_Java_thread()"); - JvmtiExport::post_class_prepare((JavaThread *) thread, this_oop()); + JvmtiExport::post_class_prepare((JavaThread *) thread, this_k()); } } } @@ -689,13 +689,13 @@ bool InstanceKlass::link_class_impl( // verification but before the first method of the class is executed. void InstanceKlass::rewrite_class(TRAPS) { assert(is_loaded(), "must be loaded"); - instanceKlassHandle this_oop(THREAD, this); - if (this_oop->is_rewritten()) { - assert(this_oop()->is_shared(), "rewriting an unshared class?"); + instanceKlassHandle this_k(THREAD, this); + if (this_k->is_rewritten()) { + assert(this_k()->is_shared(), "rewriting an unshared class?"); return; } - Rewriter::rewrite(this_oop, CHECK); - this_oop->set_rewritten(); + Rewriter::rewrite(this_k, CHECK); + this_k->set_rewritten(); } // Now relocate and link method entry points after class is rewritten. @@ -729,19 +729,19 @@ void InstanceKlass::link_methods(TRAPS) { } -void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { +void InstanceKlass::initialize_impl(instanceKlassHandle this_k, TRAPS) { // Make sure klass is linked (verified) before initialization // A class could already be verified, since it has been reflected upon. - this_oop->link_class(CHECK); + this_k->link_class(CHECK); - DTRACE_CLASSINIT_PROBE(required, InstanceKlass::cast(this_oop()), -1); + DTRACE_CLASSINIT_PROBE(required, InstanceKlass::cast(this_k()), -1); bool wait = false; // refer to the JVM book page 47 for description of steps // Step 1 { - oop init_lock = this_oop->init_lock(); + oop init_lock = this_k->init_lock(); ObjectLocker ol(init_lock, THREAD, init_lock != NULL); Thread *self = THREAD; // it's passed the current thread @@ -750,29 +750,29 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { // If we were to use wait() instead of waitInterruptibly() then // we might end up throwing IE from link/symbol resolution sites // that aren't expected to throw. This would wreak havoc. See 6320309. - while(this_oop->is_being_initialized() && !this_oop->is_reentrant_initialization(self)) { + while(this_k->is_being_initialized() && !this_k->is_reentrant_initialization(self)) { wait = true; ol.waitUninterruptibly(CHECK); } // Step 3 - if (this_oop->is_being_initialized() && this_oop->is_reentrant_initialization(self)) { - DTRACE_CLASSINIT_PROBE_WAIT(recursive, InstanceKlass::cast(this_oop()), -1,wait); + if (this_k->is_being_initialized() && this_k->is_reentrant_initialization(self)) { + DTRACE_CLASSINIT_PROBE_WAIT(recursive, InstanceKlass::cast(this_k()), -1,wait); return; } // Step 4 - if (this_oop->is_initialized()) { - DTRACE_CLASSINIT_PROBE_WAIT(concurrent, InstanceKlass::cast(this_oop()), -1,wait); + if (this_k->is_initialized()) { + DTRACE_CLASSINIT_PROBE_WAIT(concurrent, InstanceKlass::cast(this_k()), -1,wait); return; } // Step 5 - if (this_oop->is_in_error_state()) { - DTRACE_CLASSINIT_PROBE_WAIT(erroneous, InstanceKlass::cast(this_oop()), -1,wait); + if (this_k->is_in_error_state()) { + DTRACE_CLASSINIT_PROBE_WAIT(erroneous, InstanceKlass::cast(this_k()), -1,wait); ResourceMark rm(THREAD); const char* desc = "Could not initialize class "; - const char* className = this_oop->external_name(); + const char* className = this_k->external_name(); size_t msglen = strlen(desc) + strlen(className) + 1; char* message = NEW_RESOURCE_ARRAY(char, msglen); if (NULL == message) { @@ -785,13 +785,13 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { } // Step 6 - this_oop->set_init_state(being_initialized); - this_oop->set_init_thread(self); + this_k->set_init_state(being_initialized); + this_k->set_init_thread(self); } // Step 7 - Klass* super_klass = this_oop->super(); - if (super_klass != NULL && !this_oop->is_interface() && super_klass->should_be_initialized()) { + Klass* super_klass = this_k->super(); + if (super_klass != NULL && !this_k->is_interface() && super_klass->should_be_initialized()) { super_klass->initialize(THREAD); if (HAS_PENDING_EXCEPTION) { @@ -799,18 +799,18 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { CLEAR_PENDING_EXCEPTION; { EXCEPTION_MARK; - this_oop->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads + this_k->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, superclass initialization error is thrown below } - DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_oop()), -1,wait); + DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_k()), -1,wait); THROW_OOP(e()); } } - if (this_oop->has_default_methods()) { + if (this_k->has_default_methods()) { // Step 7.5: initialize any interfaces which have default methods - for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) { - Klass* iface = this_oop->local_interfaces()->at(i); + for (int i = 0; i < this_k->local_interfaces()->length(); ++i) { + Klass* iface = this_k->local_interfaces()->at(i); InstanceKlass* ik = InstanceKlass::cast(iface); if (ik->has_default_methods() && ik->should_be_initialized()) { ik->initialize(THREAD); @@ -821,7 +821,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { { EXCEPTION_MARK; // Locks object, set state, and notify all waiting threads - this_oop->set_initialization_state_and_notify( + this_k->set_initialization_state_and_notify( initialization_error, THREAD); // ignore any exception thrown, superclass initialization error is @@ -829,7 +829,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { CLEAR_PENDING_EXCEPTION; } DTRACE_CLASSINIT_PROBE_WAIT( - super__failed, InstanceKlass::cast(this_oop()), -1, wait); + super__failed, InstanceKlass::cast(this_k()), -1, wait); THROW_OOP(e()); } } @@ -840,7 +840,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { { assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl"); JavaThread* jt = (JavaThread*)THREAD; - DTRACE_CLASSINIT_PROBE_WAIT(clinit, InstanceKlass::cast(this_oop()), -1,wait); + DTRACE_CLASSINIT_PROBE_WAIT(clinit, InstanceKlass::cast(this_k()), -1,wait); // Timer includes any side effects of class initialization (resolution, // etc), but not recursive entry into call_class_initializer(). PerfClassTraceTime timer(ClassLoader::perf_class_init_time(), @@ -849,14 +849,14 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { jt->get_thread_stat()->perf_recursion_counts_addr(), jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_CLINIT); - this_oop->call_class_initializer(THREAD); + this_k->call_class_initializer(THREAD); } // Step 9 if (!HAS_PENDING_EXCEPTION) { - this_oop->set_initialization_state_and_notify(fully_initialized, CHECK); + this_k->set_initialization_state_and_notify(fully_initialized, CHECK); { ResourceMark rm(THREAD); - debug_only(this_oop->vtable()->verify(tty, true);) + debug_only(this_k->vtable()->verify(tty, true);) } } else { @@ -868,13 +868,13 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { JvmtiExport::clear_detected_exception((JavaThread*)THREAD); { EXCEPTION_MARK; - this_oop->set_initialization_state_and_notify(initialization_error, THREAD); + this_k->set_initialization_state_and_notify(initialization_error, THREAD); CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below // JVMTI has already reported the pending exception // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError JvmtiExport::clear_detected_exception((JavaThread*)THREAD); } - DTRACE_CLASSINIT_PROBE_WAIT(error, InstanceKlass::cast(this_oop()), -1,wait); + DTRACE_CLASSINIT_PROBE_WAIT(error, InstanceKlass::cast(this_k()), -1,wait); if (e->is_a(SystemDictionary::Error_klass())) { THROW_OOP(e()); } else { @@ -884,7 +884,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { &args); } } - DTRACE_CLASSINIT_PROBE_WAIT(end, InstanceKlass::cast(this_oop()), -1,wait); + DTRACE_CLASSINIT_PROBE_WAIT(end, InstanceKlass::cast(this_k()), -1,wait); } @@ -894,11 +894,11 @@ void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) set_initialization_state_and_notify_impl(kh, state, CHECK); } -void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_oop, ClassState state, TRAPS) { - oop init_lock = this_oop->init_lock(); +void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_k, ClassState state, TRAPS) { + oop init_lock = this_k->init_lock(); ObjectLocker ol(init_lock, THREAD, init_lock != NULL); - this_oop->set_init_state(state); - this_oop->fence_and_clear_init_lock(); + this_k->set_init_state(state); + this_k->fence_and_clear_init_lock(); ol.notify_all(CHECK); } @@ -952,12 +952,11 @@ void InstanceKlass::init_implementor() { void InstanceKlass::process_interfaces(Thread *thread) { // link this class into the implementors list of every interface it implements - Klass* this_as_klass_oop = this; for (int i = local_interfaces()->length() - 1; i >= 0; i--) { assert(local_interfaces()->at(i)->is_klass(), "must be a klass"); InstanceKlass* interf = InstanceKlass::cast(local_interfaces()->at(i)); assert(interf->is_interface(), "expected interface"); - interf->add_implementor(this_as_klass_oop); + interf->add_implementor(this); } } @@ -1083,12 +1082,12 @@ void InstanceKlass::check_valid_for_instantiation(bool throwError, TRAPS) { } Klass* InstanceKlass::array_klass_impl(bool or_null, int n, TRAPS) { - instanceKlassHandle this_oop(THREAD, this); - return array_klass_impl(this_oop, or_null, n, THREAD); + instanceKlassHandle this_k(THREAD, this); + return array_klass_impl(this_k, or_null, n, THREAD); } -Klass* InstanceKlass::array_klass_impl(instanceKlassHandle this_oop, bool or_null, int n, TRAPS) { - if (this_oop->array_klasses() == NULL) { +Klass* InstanceKlass::array_klass_impl(instanceKlassHandle this_k, bool or_null, int n, TRAPS) { + if (this_k->array_klasses() == NULL) { if (or_null) return NULL; ResourceMark rm; @@ -1099,14 +1098,14 @@ Klass* InstanceKlass::array_klass_impl(instanceKlassHandle this_oop, bool or_nul MutexLocker ma(MultiArray_lock, THREAD); // Check if update has already taken place - if (this_oop->array_klasses() == NULL) { - Klass* k = ObjArrayKlass::allocate_objArray_klass(this_oop->class_loader_data(), 1, this_oop, CHECK_NULL); - this_oop->set_array_klasses(k); + if (this_k->array_klasses() == NULL) { + Klass* k = ObjArrayKlass::allocate_objArray_klass(this_k->class_loader_data(), 1, this_k, CHECK_NULL); + this_k->set_array_klasses(k); } } } // _this will always be set at this point - ObjArrayKlass* oak = (ObjArrayKlass*)this_oop->array_klasses(); + ObjArrayKlass* oak = (ObjArrayKlass*)this_k->array_klasses(); if (or_null) { return oak->array_klass_or_null(n); } @@ -1133,20 +1132,20 @@ Method* InstanceKlass::class_initializer() { return NULL; } -void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_oop, TRAPS) { +void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_k, TRAPS) { if (ReplayCompiles && (ReplaySuppressInitializers == 1 || - ReplaySuppressInitializers >= 2 && this_oop->class_loader() != NULL)) { + ReplaySuppressInitializers >= 2 && this_k->class_loader() != NULL)) { // Hide the existence of the initializer for the purpose of replaying the compile return; } - methodHandle h_method(THREAD, this_oop->class_initializer()); - assert(!this_oop->is_initialized(), "we cannot initialize twice"); + methodHandle h_method(THREAD, this_k->class_initializer()); + assert(!this_k->is_initialized(), "we cannot initialize twice"); if (TraceClassInitialization) { tty->print("%d Initializing ", call_class_initializer_impl_counter++); - this_oop->name()->print_value(); - tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", (address)this_oop()); + this_k->name()->print_value(); + tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", (address)this_k()); } if (h_method() != NULL) { JavaCallArguments args; // No arguments @@ -1296,8 +1295,8 @@ void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAP } -void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS) { - for (JavaFieldStream fs(this_oop()); !fs.done(); fs.next()) { +void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_k, void f(fieldDescriptor* fd, TRAPS), TRAPS) { + for (JavaFieldStream fs(this_k()); !fs.done(); fs.next()) { if (fs.access_flags().is_static()) { fieldDescriptor& fd = fs.field_descriptor(); f(&fd, CHECK); @@ -1515,14 +1514,14 @@ Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name, } /* jni_id_for_impl for jfieldIds only */ -JNIid* InstanceKlass::jni_id_for_impl(instanceKlassHandle this_oop, int offset) { +JNIid* InstanceKlass::jni_id_for_impl(instanceKlassHandle this_k, int offset) { MutexLocker ml(JfieldIdCreation_lock); // Retry lookup after we got the lock - JNIid* probe = this_oop->jni_ids() == NULL ? NULL : this_oop->jni_ids()->find(offset); + JNIid* probe = this_k->jni_ids() == NULL ? NULL : this_k->jni_ids()->find(offset); if (probe == NULL) { // Slow case, allocate new static field identifier - probe = new JNIid(this_oop(), offset, this_oop->jni_ids()); - this_oop->set_jni_ids(probe); + probe = new JNIid(this_k(), offset, this_k->jni_ids()); + this_k->set_jni_ids(probe); } return probe; } @@ -3161,8 +3160,8 @@ void InstanceKlass::verify_on(outputStream* st) { } // Verify first subklass - if (subklass_oop() != NULL) { - guarantee(subklass_oop()->is_klass(), "should be klass"); + if (subklass() != NULL) { + guarantee(subklass()->is_klass(), "should be klass"); } // Verify siblings diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index b25c75afc3b..6525c538af9 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -43,35 +43,7 @@ // An InstanceKlass is the VM level representation of a Java class. // It contains all information needed for at class at execution runtime. -// InstanceKlass layout: -// [C++ vtbl pointer ] Klass -// [subtype cache ] Klass -// [instance size ] Klass -// [java mirror ] Klass -// [super ] Klass -// [access_flags ] Klass -// [name ] Klass -// [first subklass ] Klass -// [next sibling ] Klass -// [array klasses ] -// [methods ] -// [local interfaces ] -// [transitive interfaces ] -// [fields ] -// [constants ] -// [class loader ] -// [source file name ] -// [inner classes ] -// [static field size ] -// [nonstatic field size ] -// [static oop fields size ] -// [nonstatic oop maps size ] -// [has finalize method ] -// [deoptimization mark bit ] -// [initialization state ] -// [initializing thread ] -// [Java vtable length ] -// [oop map cache (stack maps) ] +// InstanceKlass embedded field layout (after declared fields): // [EMBEDDED Java vtable ] size in words = vtable_len // [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size // The embedded nonstatic oop-map blocks are short pairs (offset, length) @@ -1031,16 +1003,16 @@ private: // Static methods that are used to implement member methods where an exposed this pointer // is needed due to possible GCs - static bool link_class_impl (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS); - static bool verify_code (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS); - static void initialize_impl (instanceKlassHandle this_oop, TRAPS); - static void eager_initialize_impl (instanceKlassHandle this_oop); - static void set_initialization_state_and_notify_impl (instanceKlassHandle this_oop, ClassState state, TRAPS); - static void call_class_initializer_impl (instanceKlassHandle this_oop, TRAPS); - static Klass* array_klass_impl (instanceKlassHandle this_oop, bool or_null, int n, TRAPS); - static void do_local_static_fields_impl (instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS); + static bool link_class_impl (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS); + static bool verify_code (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS); + static void initialize_impl (instanceKlassHandle this_k, TRAPS); + static void eager_initialize_impl (instanceKlassHandle this_k); + static void set_initialization_state_and_notify_impl (instanceKlassHandle this_k, ClassState state, TRAPS); + static void call_class_initializer_impl (instanceKlassHandle this_k, TRAPS); + static Klass* array_klass_impl (instanceKlassHandle this_k, bool or_null, int n, TRAPS); + static void do_local_static_fields_impl (instanceKlassHandle this_k, void f(fieldDescriptor* fd, TRAPS), TRAPS); /* jni_id_for_impl for jfieldID only */ - static JNIid* jni_id_for_impl (instanceKlassHandle this_oop, int offset); + static JNIid* jni_id_for_impl (instanceKlassHandle this_k, int offset); // Returns the array class for the n'th dimension Klass* array_klass_impl(bool or_null, int n, TRAPS); diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index 0717079e002..ca8a788d477 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -334,19 +334,11 @@ GrowableArray* Klass::compute_secondary_supers(int num_extra_slots) { } -Klass* Klass::subklass() const { - return _subklass == NULL ? NULL : _subklass; -} - InstanceKlass* Klass::superklass() const { assert(super() == NULL || super()->oop_is_instance(), "must be instance klass"); return _super == NULL ? NULL : InstanceKlass::cast(_super); } -Klass* Klass::next_sibling() const { - return _next_sibling == NULL ? NULL : _next_sibling; -} - void Klass::set_subklass(Klass* s) { assert(s != this, "sanity check"); _subklass = s; @@ -365,7 +357,7 @@ void Klass::append_to_sibling_list() { assert((!super->is_interface() // interfaces cannot be supers && (super->superklass() == NULL || !is_interface())), "an interface can only be a subklass of Object"); - Klass* prev_first_subklass = super->subklass_oop(); + Klass* prev_first_subklass = super->subklass(); if (prev_first_subklass != NULL) { // set our sibling to be the superklass' previous first subklass set_next_sibling(prev_first_subklass); @@ -405,7 +397,7 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) { assert(current->is_loader_alive(is_alive), "just checking, this should be live"); // Find and set the first alive subklass - Klass* sub = current->subklass_oop(); + Klass* sub = current->subklass(); while (sub != NULL && !sub->is_loader_alive(is_alive)) { #ifndef PRODUCT if (TraceClassUnloading && WizardMode) { @@ -413,7 +405,7 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) { tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name()); } #endif - sub = sub->next_sibling_oop(); + sub = sub->next_sibling(); } current->set_subklass(sub); if (sub != NULL) { @@ -421,13 +413,13 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) { } // Find and set the first alive sibling - Klass* sibling = current->next_sibling_oop(); + Klass* sibling = current->next_sibling(); while (sibling != NULL && !sibling->is_loader_alive(is_alive)) { if (TraceClassUnloading && WizardMode) { ResourceMark rm; tty->print_cr("[Unlinking class (sibling) %s]", sibling->external_name()); } - sibling = sibling->next_sibling_oop(); + sibling = sibling->next_sibling(); } current->set_next_sibling(sibling); if (sibling != NULL) { diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index fd4701c6e4f..e1a1f817a92 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -56,34 +56,6 @@ // actual type. (See oop.inline.hpp for some of the forwarding code.) // ALL FUNCTIONS IMPLEMENTING THIS DISPATCH ARE PREFIXED WITH "oop_"! -// Klass layout: -// [C++ vtbl ptr ] (contained in Metadata) -// [layout_helper ] -// [super_check_offset ] for fast subtype checks -// [name ] -// [secondary_super_cache] for fast subtype checks -// [secondary_supers ] array of 2ndary supertypes -// [primary_supers 0] -// [primary_supers 1] -// [primary_supers 2] -// ... -// [primary_supers 7] -// [java_mirror ] -// [super ] -// [subklass ] first subclass -// [next_sibling ] link to chain additional subklasses -// [next_link ] -// [class_loader_data] -// [modifier_flags] -// [access_flags ] -// [last_biased_lock_bulk_revocation_time] (64 bits) -// [prototype_header] -// [biased_lock_revocation_count] -// [_modified_oops] -// [_accumulated_modified_oops] -// [trace_id] - - // Forward declarations. template class Array; template class GrowableArray; @@ -257,9 +229,9 @@ class Klass : public Metadata { // Use InstanceKlass::contains_field_offset to classify field offsets. // sub/superklass links + Klass* subklass() const { return _subklass; } + Klass* next_sibling() const { return _next_sibling; } InstanceKlass* superklass() const; - Klass* subklass() const; - Klass* next_sibling() const; void append_to_sibling_list(); // add newly created receiver to superklass' subklass list void set_next_link(Klass* k) { _next_link = k; } @@ -281,8 +253,6 @@ class Klass : public Metadata { bool has_accumulated_modified_oops() { return _accumulated_modified_oops == 1; } protected: // internal accessors - Klass* subklass_oop() const { return _subklass; } - Klass* next_sibling_oop() const { return _next_sibling; } void set_subklass(Klass* s); void set_next_sibling(Klass* s); diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 7c292c3ffe5..cb96fe9c89f 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.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 @@ -273,7 +273,7 @@ int Method::validate_bci_from_bcx(intptr_t bcx) const { } address Method::bcp_from(int bci) const { - assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()), "illegal bci"); + assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()), err_msg("illegal bci: %d", bci)); address bcp = code_base() + bci; assert(is_native() && bcp == code_base() || contains(bcp), "bcp doesn't belong to this method"); return bcp; @@ -329,14 +329,12 @@ bool Method::was_executed_more_than(int n) { } } -#ifndef PRODUCT void Method::print_invocation_count() { if (is_static()) tty->print("static "); if (is_final()) tty->print("final "); if (is_synchronized()) tty->print("synchronized "); if (is_native()) tty->print("native "); - method_holder()->name()->print_symbol_on(tty); - tty->print("."); + tty->print("%s::", method_holder()->external_name()); name()->print_symbol_on(tty); signature()->print_symbol_on(tty); @@ -349,12 +347,12 @@ void Method::print_invocation_count() { tty->print_cr (" interpreter_invocation_count: %8d ", interpreter_invocation_count()); tty->print_cr (" invocation_counter: %8d ", invocation_count()); tty->print_cr (" backedge_counter: %8d ", backedge_count()); +#ifndef PRODUCT if (CountCompiledCalls) { tty->print_cr (" compiled_invocation_count: %8d ", compiled_invocation_count()); } - -} #endif +} // Build a MethodData* object to hold information about this method // collected in the interpreter. @@ -577,12 +575,12 @@ bool Method::is_static_initializer() const { } -objArrayHandle Method::resolved_checked_exceptions_impl(Method* this_oop, TRAPS) { - int length = this_oop->checked_exceptions_length(); +objArrayHandle Method::resolved_checked_exceptions_impl(Method* method, TRAPS) { + int length = method->checked_exceptions_length(); if (length == 0) { // common case return objArrayHandle(THREAD, Universe::the_empty_class_klass_array()); } else { - methodHandle h_this(THREAD, this_oop); + methodHandle h_this(THREAD, method); objArrayOop m_oop = oopFactory::new_objArray(SystemDictionary::Class_klass(), length, CHECK_(objArrayHandle())); objArrayHandle mirrors (THREAD, m_oop); for (int i = 0; i < length; i++) { @@ -1443,10 +1441,6 @@ void Method::print_name(outputStream* st) { #endif // !PRODUCT || INCLUDE_JVMTI -//----------------------------------------------------------------------------------- -// Non-product code - -#ifndef PRODUCT void Method::print_codes_on(outputStream* st) const { print_codes_on(0, code_size(), st); } @@ -1460,7 +1454,6 @@ void Method::print_codes_on(int from, int to, outputStream* st) const { BytecodeTracer::set_closure(BytecodeTracer::std_closure()); while (s.next() >= 0) BytecodeTracer::trace(mh, s.bcp(), st); } -#endif // not PRODUCT // Simple compression of line number tables. We use a regular compressed stream, except that we compress deltas diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 98598dbeeff..3479e2afa6f 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.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 @@ -40,50 +40,15 @@ // A Method represents a Java method. // -// Memory layout (each line represents a word). Note that most applications load thousands of methods, -// so keeping the size of this structure small has a big impact on footprint. +// Note that most applications load thousands of methods, so keeping the size of this +// class small has a big impact on footprint. // -// The actual bytecodes are inlined after the end of the Method struct. +// Note that native_function and signature_handler have to be at fixed offsets +// (required by the interpreter) // -// There are bits in the access_flags telling whether inlined tables are present. -// Note that accessing the line number and local variable tables is not performance critical at all. -// Accessing the checked exceptions table is used by reflection, so we put that last to make access -// to it fast. -// -// The line number table is compressed and inlined following the byte codes. It is found as the first -// byte following the byte codes. The checked exceptions table and the local variable table are inlined -// after the line number table, and indexed from the end of the method. We do not compress the checked -// exceptions table since the average length is less than 2, and do not bother to compress the local -// variable table either since it is mostly absent. -// -// Note that native_function and signature_handler has to be at fixed offsets (required by the interpreter) -// -// |------------------------------------------------------| -// | header | -// | klass | -// |------------------------------------------------------| -// | ConstMethod* (metadata) | -// |------------------------------------------------------| -// | MethodData* (metadata) | -// | MethodCounters | -// |------------------------------------------------------| -// | access_flags | -// | vtable_index | -// |------------------------------------------------------| -// | result_index (C++ interpreter only) | -// |------------------------------------------------------| -// | method_size | intrinsic_id | flags | -// |------------------------------------------------------| -// | code (pointer) | -// | i2i (pointer) | -// | adapter (pointer) | -// | from_compiled_entry (pointer) | -// | from_interpreted_entry (pointer) | -// |------------------------------------------------------| -// | native_function (present only if native) | -// | signature_handler (present only if native) | -// |------------------------------------------------------| - +// Method embedded field layout (after declared fields): +// [EMBEDDED native_function (present only if native) ] +// [EMBEDDED signature_handler (present only if native) ] class CheckedExceptionElement; class LocalVariableTableElement; @@ -429,6 +394,9 @@ class Method : public Metadata { #ifndef PRODUCT int compiled_invocation_count() const { return _compiled_invocation_count; } void set_compiled_invocation_count(int count) { _compiled_invocation_count = count; } +#else + // for PrintMethodData in a product build + int compiled_invocation_count() const { return 0; } #endif // not PRODUCT // Clear (non-shared space) pointers which could not be relevant @@ -497,10 +465,8 @@ class Method : public Metadata { // Interpreter oopmap support void mask_for(int bci, InterpreterOopMap* mask); -#ifndef PRODUCT // operations on invocation counter void print_invocation_count(); -#endif // byte codes void set_code(address code) { return constMethod()->set_code(code); } @@ -509,8 +475,8 @@ class Method : public Metadata { // prints byte codes void print_codes() const { print_codes_on(tty); } - void print_codes_on(outputStream* st) const PRODUCT_RETURN; - void print_codes_on(int from, int to, outputStream* st) const PRODUCT_RETURN; + void print_codes_on(outputStream* st) const; + void print_codes_on(int from, int to, outputStream* st) const; // method parameters bool has_method_parameters() const @@ -661,7 +627,7 @@ class Method : public Metadata { // Static methods that are used to implement member methods where an exposed this pointer // is needed due to possible GCs - static objArrayHandle resolved_checked_exceptions_impl(Method* this_oop, TRAPS); + static objArrayHandle resolved_checked_exceptions_impl(Method* method, TRAPS); // Returns the byte code index from the byte code pointer int bci_from(address bcp) const; diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 0e6e0ec0130..17d80ca5a9f 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" +#include "compiler/compilerOracle.hpp" #include "interpreter/bytecode.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/linkResolver.hpp" @@ -114,7 +115,6 @@ void ProfileData::print_data_on(outputStream* st, const MethodData* md) const { print_data_on(st, print_data_on_helper(md)); } -#ifndef PRODUCT void ProfileData::print_shared(outputStream* st, const char* name, const char* extra) const { st->print("bci: %d", bci()); st->fill_to(tab_width_one); @@ -137,7 +137,6 @@ void ProfileData::print_shared(outputStream* st, const char* name, const char* e void ProfileData::tab(outputStream* st, bool first) const { st->fill_to(first ? tab_width_one : tab_width_two); } -#endif // !PRODUCT // ================================================================== // BitData @@ -146,23 +145,19 @@ void ProfileData::tab(outputStream* st, bool first) const { // whether a checkcast bytecode has seen a null value. -#ifndef PRODUCT void BitData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "BitData", extra); } -#endif // !PRODUCT // ================================================================== // CounterData // // A CounterData corresponds to a simple counter. -#ifndef PRODUCT void CounterData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "CounterData", extra); st->print_cr("count(%u)", count()); } -#endif // !PRODUCT // ================================================================== // JumpData @@ -187,12 +182,10 @@ void JumpData::post_initialize(BytecodeStream* stream, MethodData* mdo) { set_displacement(offset); } -#ifndef PRODUCT void JumpData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "JumpData", extra); st->print_cr("taken(%u) displacement(%d)", taken(), displacement()); } -#endif // !PRODUCT int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_receiver, int max) { // Parameter profiling include the receiver @@ -341,7 +334,6 @@ bool TypeEntriesAtCall::arguments_profiling_enabled() { return MethodData::profile_arguments(); } -#ifndef PRODUCT void TypeEntries::print_klass(outputStream* st, intptr_t k) { if (is_type_none(k)) { st->print("none"); @@ -397,7 +389,6 @@ void VirtualCallTypeData::print_data_on(outputStream* st, const char* extra) con _ret.print_data_on(st); } } -#endif // ================================================================== // ReceiverTypeData @@ -416,7 +407,6 @@ void ReceiverTypeData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { } } -#ifndef PRODUCT void ReceiverTypeData::print_receiver_data_on(outputStream* st) const { uint row; int entries = 0; @@ -446,7 +436,6 @@ void VirtualCallData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "VirtualCallData", extra); print_receiver_data_on(st); } -#endif // !PRODUCT // ================================================================== // RetData @@ -498,7 +487,6 @@ DataLayout* RetData::advance(MethodData *md, int bci) { } #endif // CC_INTERP -#ifndef PRODUCT void RetData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "RetData", extra); uint row; @@ -515,7 +503,6 @@ void RetData::print_data_on(outputStream* st, const char* extra) const { } } } -#endif // !PRODUCT // ================================================================== // BranchData @@ -533,7 +520,6 @@ void BranchData::post_initialize(BytecodeStream* stream, MethodData* mdo) { set_displacement(offset); } -#ifndef PRODUCT void BranchData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "BranchData", extra); st->print_cr("taken(%u) displacement(%d)", @@ -541,7 +527,6 @@ void BranchData::print_data_on(outputStream* st, const char* extra) const { tab(st); st->print_cr("not taken(%u)", not_taken()); } -#endif // ================================================================== // MultiBranchData @@ -607,7 +592,6 @@ void MultiBranchData::post_initialize(BytecodeStream* stream, } } -#ifndef PRODUCT void MultiBranchData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "MultiBranchData", extra); st->print_cr("default_count(%u) displacement(%d)", @@ -619,9 +603,7 @@ void MultiBranchData::print_data_on(outputStream* st, const char* extra) const { count_at(i), displacement_at(i)); } } -#endif -#ifndef PRODUCT void ArgInfoData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "ArgInfoData", extra); int nargs = number_of_args(); @@ -631,8 +613,6 @@ void ArgInfoData::print_data_on(outputStream* st, const char* extra) const { st->cr(); } -#endif - int ParametersTypeData::compute_cell_count(Method* m) { if (!MethodData::profile_parameters_for_method(m)) { return 0; @@ -653,7 +633,6 @@ bool ParametersTypeData::profiling_enabled() { return MethodData::profile_parameters(); } -#ifndef PRODUCT void ParametersTypeData::print_data_on(outputStream* st, const char* extra) const { st->print("parameter types", extra); _parameters.print_data_on(st); @@ -665,7 +644,6 @@ void SpeculativeTrapData::print_data_on(outputStream* st, const char* extra) con method()->print_short_name(st); st->cr(); } -#endif // ================================================================== // MethodData* @@ -800,6 +778,8 @@ bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) { case Bytecodes::_invokeinterface: case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne: + case Bytecodes::_ifnull: + case Bytecodes::_ifnonnull: case Bytecodes::_invokestatic: #ifdef COMPILER2 return UseTypeSpeculation; @@ -1153,6 +1133,21 @@ void MethodData::init() { _highest_osr_comp_level = 0; _would_profile = true; +#if INCLUDE_RTM_OPT + _rtm_state = NoRTM; // No RTM lock eliding by default + if (UseRTMLocking && + !CompilerOracle::has_option_string(_method, "NoRTMLockEliding")) { + if (CompilerOracle::has_option_string(_method, "UseRTMLockEliding") || !UseRTMDeopt) { + // Generate RTM lock eliding code without abort ratio calculation code. + _rtm_state = UseRTM; + } else if (UseRTMDeopt) { + // Generate RTM lock eliding code and include abort ratio calculation + // code if UseRTMDeopt is on. + _rtm_state = ProfileRTM; + } + } +#endif + // Initialize flags and trap history. _nof_decompiles = 0; _nof_overflow_recompiles = 0; @@ -1341,8 +1336,6 @@ ArgInfoData *MethodData::arg_info() { // Printing -#ifndef PRODUCT - void MethodData::print_on(outputStream* st) const { assert(is_methodData(), "should be method data"); st->print("method data for "); @@ -1351,15 +1344,12 @@ void MethodData::print_on(outputStream* st) const { print_data_on(st); } -#endif //PRODUCT - void MethodData::print_value_on(outputStream* st) const { assert(is_methodData(), "should be method data"); st->print("method data for "); method()->print_value_on(st); } -#ifndef PRODUCT void MethodData::print_data_on(outputStream* st) const { ResourceMark rm; ProfileData* data = first_data(); @@ -1400,7 +1390,6 @@ void MethodData::print_data_on(outputStream* st) const { if (dp >= end) return; } } -#endif #if INCLUDE_SERVICES // Size Statistics diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index e0218f9fd47..66a1d1fa719 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -280,12 +280,10 @@ class ProfileData : public ResourceObj { friend class ReturnTypeEntry; friend class TypeStackSlotEntries; private: -#ifndef PRODUCT enum { tab_width_one = 16, tab_width_two = 36 }; -#endif // !PRODUCT // This is a pointer to a section of profiling data. DataLayout* _data; @@ -521,10 +519,8 @@ public: void print_data_on(outputStream* st, const MethodData* md) const; -#ifndef PRODUCT void print_shared(outputStream* st, const char* name, const char* extra) const; void tab(outputStream* st, bool first = false) const; -#endif }; // BitData @@ -583,9 +579,7 @@ public: } #endif // CC_INTERP -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // CounterData @@ -646,9 +640,7 @@ public: } #endif // CC_INTERP -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // JumpData @@ -733,9 +725,7 @@ public: // Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo); -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // Entries in a ProfileData object to record types: it can either be @@ -808,9 +798,7 @@ public: return with_status((intptr_t)k, in); } -#ifndef PRODUCT static void print_klass(outputStream* st, intptr_t k); -#endif // GC support static bool is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p); @@ -919,9 +907,7 @@ public: // GC support void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); -#ifndef PRODUCT void print_data_on(outputStream* st) const; -#endif }; // Type entry used for return from a call. A single cell to record the @@ -964,9 +950,7 @@ public: // GC support void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); -#ifndef PRODUCT void print_data_on(outputStream* st) const; -#endif }; // Entries to collect type information at a call: contains arguments @@ -1144,9 +1128,7 @@ public: } } -#ifndef PRODUCT virtual void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // ReceiverTypeData @@ -1288,10 +1270,8 @@ public: } #endif // CC_INTERP -#ifndef PRODUCT void print_receiver_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // VirtualCallData @@ -1332,9 +1312,7 @@ public: } #endif // CC_INTERP -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // VirtualCallTypeData @@ -1458,9 +1436,7 @@ public: } } -#ifndef PRODUCT virtual void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // RetData @@ -1561,9 +1537,7 @@ public: // Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo); -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // BranchData @@ -1639,9 +1613,7 @@ public: // Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo); -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // ArrayData @@ -1832,9 +1804,7 @@ public: // Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo); -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; class ArgInfoData : public ArrayData { @@ -1859,9 +1829,7 @@ public: array_set_int_at(arg, val); } -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // ParametersTypeData @@ -1920,9 +1888,7 @@ public: _parameters.clean_weak_klass_links(is_alive_closure); } -#ifndef PRODUCT virtual void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif static ByteSize stack_slot_offset(int i) { return cell_offset(stack_slot_local_offset(i)); @@ -1976,9 +1942,7 @@ public: set_intptr_at(method_offset, (intptr_t)m); } -#ifndef PRODUCT virtual void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // MethodData* @@ -2052,7 +2016,7 @@ public: // Whole-method sticky bits and flags enum { - _trap_hist_limit = 18, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 20, // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values @@ -2083,6 +2047,12 @@ private: // Counter values at the time profiling started. int _invocation_counter_start; int _backedge_counter_start; + +#if INCLUDE_RTM_OPT + // State of RTM code generation during compilation of the method + int _rtm_state; +#endif + // Number of loops and blocks is computed when compiling the first // time with C1. It is used to determine if method is trivial. short _num_loops; @@ -2246,6 +2216,22 @@ public: InvocationCounter* invocation_counter() { return &_invocation_counter; } InvocationCounter* backedge_counter() { return &_backedge_counter; } +#if INCLUDE_RTM_OPT + int rtm_state() const { + return _rtm_state; + } + void set_rtm_state(RTMState rstate) { + _rtm_state = (int)rstate; + } + void atomic_set_rtm_state(RTMState rstate) { + Atomic::store((int)rstate, &_rtm_state); + } + + static int rtm_state_offset_in_bytes() { + return offset_of(MethodData, _rtm_state); + } +#endif + void set_would_profile(bool p) { _would_profile = p; } bool would_profile() const { return _would_profile; } @@ -2435,15 +2421,11 @@ public: void set_size(int object_size_in_bytes) { _size = object_size_in_bytes; } // Printing -#ifndef PRODUCT void print_on (outputStream* st) const; -#endif void print_value_on(outputStream* st) const; -#ifndef PRODUCT // printing support for method data void print_data_on(outputStream* st) const; -#endif const char* internal_name() const { return "{method data}"; } diff --git a/hotspot/src/share/vm/opto/addnode.cpp b/hotspot/src/share/vm/opto/addnode.cpp index 045e4f20918..a586eba1322 100644 --- a/hotspot/src/share/vm/opto/addnode.cpp +++ b/hotspot/src/share/vm/opto/addnode.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/machnode.hpp" diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 0db9dab8104..4f45d28666b 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -446,6 +446,9 @@ diagnostic(bool, PrintPreciseBiasedLockingStatistics, false, \ "Print per-lock-site statistics of biased locking in JVM") \ \ + diagnostic(bool, PrintPreciseRTMLockingStatistics, false, \ + "Print per-lock-site statistics of rtm locking in JVM") \ + \ notproduct(bool, PrintEliminateLocks, false, \ "Print out when locks are eliminated") \ \ diff --git a/hotspot/src/share/vm/opto/callGenerator.cpp b/hotspot/src/share/vm/opto/callGenerator.cpp index a655f27b540..2a263639948 100644 --- a/hotspot/src/share/vm/opto/callGenerator.cpp +++ b/hotspot/src/share/vm/opto/callGenerator.cpp @@ -33,8 +33,8 @@ #include "opto/addnode.hpp" #include "opto/callGenerator.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/connode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index 31c004cd8ac..cfe86b1c312 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -27,6 +27,7 @@ #include "compiler/oopMap.hpp" #include "opto/callGenerator.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/escape.hpp" #include "opto/locknode.hpp" #include "opto/machnode.hpp" diff --git a/hotspot/src/share/vm/opto/castnode.cpp b/hotspot/src/share/vm/opto/castnode.cpp new file mode 100644 index 00000000000..b8a35a72df9 --- /dev/null +++ b/hotspot/src/share/vm/opto/castnode.cpp @@ -0,0 +1,294 @@ +/* + * 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 "opto/addnode.hpp" +#include "opto/castnode.hpp" +#include "opto/connode.hpp" +#include "opto/matcher.hpp" +#include "opto/phaseX.hpp" +#include "opto/subnode.hpp" +#include "opto/type.hpp" + +//============================================================================= +// If input is already higher or equal to cast type, then this is an identity. +Node *ConstraintCastNode::Identity( PhaseTransform *phase ) { + return phase->type(in(1))->higher_equal_speculative(_type) ? in(1) : this; +} + +//------------------------------Value------------------------------------------ +// Take 'join' of input and cast-up type +const Type *ConstraintCastNode::Value( PhaseTransform *phase ) const { + if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; + const Type* ft = phase->type(in(1))->filter_speculative(_type); + +#ifdef ASSERT + // Previous versions of this function had some special case logic, + // which is no longer necessary. Make sure of the required effects. + switch (Opcode()) { + case Op_CastII: + { + const Type* t1 = phase->type(in(1)); + if( t1 == Type::TOP ) assert(ft == Type::TOP, "special case #1"); + const Type* rt = t1->join_speculative(_type); + if (rt->empty()) assert(ft == Type::TOP, "special case #2"); + break; + } + case Op_CastPP: + if (phase->type(in(1)) == TypePtr::NULL_PTR && + _type->isa_ptr() && _type->is_ptr()->_ptr == TypePtr::NotNull) + assert(ft == Type::TOP, "special case #3"); + break; + } +#endif //ASSERT + + return ft; +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape){ + return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; +} + +//------------------------------Ideal_DU_postCCP------------------------------- +// Throw away cast after constant propagation +Node *ConstraintCastNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { + const Type *t = ccp->type(in(1)); + ccp->hash_delete(this); + set_type(t); // Turn into ID function + ccp->hash_insert(this); + return this; +} + + +//============================================================================= + +//------------------------------Ideal_DU_postCCP------------------------------- +// If not converting int->oop, throw away cast after constant propagation +Node *CastPPNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { + const Type *t = ccp->type(in(1)); + if (!t->isa_oop_ptr() || ((in(1)->is_DecodeN()) && Matcher::gen_narrow_oop_implicit_null_checks())) { + return NULL; // do not transform raw pointers or narrow oops + } + return ConstraintCastNode::Ideal_DU_postCCP(ccp); +} + + + +//============================================================================= +//------------------------------Identity--------------------------------------- +// If input is already higher or equal to cast type, then this is an identity. +Node *CheckCastPPNode::Identity( PhaseTransform *phase ) { + // Toned down to rescue meeting at a Phi 3 different oops all implementing + // the same interface. CompileTheWorld starting at 502, kd12rc1.zip. + return (phase->type(in(1)) == phase->type(this)) ? in(1) : this; +} + +//------------------------------Value------------------------------------------ +// Take 'join' of input and cast-up type, unless working with an Interface +const Type *CheckCastPPNode::Value( PhaseTransform *phase ) const { + if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; + + const Type *inn = phase->type(in(1)); + if( inn == Type::TOP ) return Type::TOP; // No information yet + + const TypePtr *in_type = inn->isa_ptr(); + const TypePtr *my_type = _type->isa_ptr(); + const Type *result = _type; + if( in_type != NULL && my_type != NULL ) { + TypePtr::PTR in_ptr = in_type->ptr(); + if( in_ptr == TypePtr::Null ) { + result = in_type; + } else if( in_ptr == TypePtr::Constant ) { + // Casting a constant oop to an interface? + // (i.e., a String to a Comparable?) + // Then return the interface. + const TypeOopPtr *jptr = my_type->isa_oopptr(); + assert( jptr, "" ); + result = (jptr->klass()->is_interface() || !in_type->higher_equal(_type)) + ? my_type->cast_to_ptr_type( TypePtr::NotNull ) + : in_type; + } else { + result = my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) ); + } + } + + // This is the code from TypePtr::xmeet() that prevents us from + // having 2 ways to represent the same type. We have to replicate it + // here because we don't go through meet/join. + if (result->remove_speculative() == result->speculative()) { + result = result->remove_speculative(); + } + + // Same as above: because we don't go through meet/join, remove the + // speculative type if we know we won't use it. + return result->cleanup_speculative(); + + // JOIN NOT DONE HERE BECAUSE OF INTERFACE ISSUES. + // FIX THIS (DO THE JOIN) WHEN UNION TYPES APPEAR! + + // + // Remove this code after overnight run indicates no performance + // loss from not performing JOIN at CheckCastPPNode + // + // const TypeInstPtr *in_oop = in->isa_instptr(); + // const TypeInstPtr *my_oop = _type->isa_instptr(); + // // If either input is an 'interface', return destination type + // assert (in_oop == NULL || in_oop->klass() != NULL, ""); + // assert (my_oop == NULL || my_oop->klass() != NULL, ""); + // if( (in_oop && in_oop->klass()->is_interface()) + // ||(my_oop && my_oop->klass()->is_interface()) ) { + // TypePtr::PTR in_ptr = in->isa_ptr() ? in->is_ptr()->_ptr : TypePtr::BotPTR; + // // Preserve cast away nullness for interfaces + // if( in_ptr == TypePtr::NotNull && my_oop && my_oop->_ptr == TypePtr::BotPTR ) { + // return my_oop->cast_to_ptr_type(TypePtr::NotNull); + // } + // return _type; + // } + // + // // Neither the input nor the destination type is an interface, + // + // // history: JOIN used to cause weird corner case bugs + // // return (in == TypeOopPtr::NULL_PTR) ? in : _type; + // // JOIN picks up NotNull in common instance-of/check-cast idioms, both oops. + // // JOIN does not preserve NotNull in other cases, e.g. RawPtr vs InstPtr + // const Type *join = in->join(_type); + // // Check if join preserved NotNull'ness for pointers + // if( join->isa_ptr() && _type->isa_ptr() ) { + // TypePtr::PTR join_ptr = join->is_ptr()->_ptr; + // TypePtr::PTR type_ptr = _type->is_ptr()->_ptr; + // // If there isn't any NotNull'ness to preserve + // // OR if join preserved NotNull'ness then return it + // if( type_ptr == TypePtr::BotPTR || type_ptr == TypePtr::Null || + // join_ptr == TypePtr::NotNull || join_ptr == TypePtr::Constant ) { + // return join; + // } + // // ELSE return same old type as before + // return _type; + // } + // // Not joining two pointers + // return join; +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *CheckCastPPNode::Ideal(PhaseGVN *phase, bool can_reshape){ + return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *CastX2PNode::Value( PhaseTransform *phase ) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + if (t->base() == Type_X && t->singleton()) { + uintptr_t bits = (uintptr_t) t->is_intptr_t()->get_con(); + if (bits == 0) return TypePtr::NULL_PTR; + return TypeRawPtr::make((address) bits); + } + return CastX2PNode::bottom_type(); +} + +//------------------------------Idealize--------------------------------------- +static inline bool fits_in_int(const Type* t, bool but_not_min_int = false) { + if (t == Type::TOP) return false; + const TypeX* tl = t->is_intptr_t(); + jint lo = min_jint; + jint hi = max_jint; + if (but_not_min_int) ++lo; // caller wants to negate the value w/o overflow + return (tl->_lo >= lo) && (tl->_hi <= hi); +} + +static inline Node* addP_of_X2P(PhaseGVN *phase, + Node* base, + Node* dispX, + bool negate = false) { + if (negate) { + dispX = new (phase->C) SubXNode(phase->MakeConX(0), phase->transform(dispX)); + } + return new (phase->C) AddPNode(phase->C->top(), + phase->transform(new (phase->C) CastX2PNode(base)), + phase->transform(dispX)); +} + +Node *CastX2PNode::Ideal(PhaseGVN *phase, bool can_reshape) { + // convert CastX2P(AddX(x, y)) to AddP(CastX2P(x), y) if y fits in an int + int op = in(1)->Opcode(); + Node* x; + Node* y; + switch (op) { + case Op_SubX: + x = in(1)->in(1); + // Avoid ideal transformations ping-pong between this and AddP for raw pointers. + if (phase->find_intptr_t_con(x, -1) == 0) + break; + y = in(1)->in(2); + if (fits_in_int(phase->type(y), true)) { + return addP_of_X2P(phase, x, y, true); + } + break; + case Op_AddX: + x = in(1)->in(1); + y = in(1)->in(2); + if (fits_in_int(phase->type(y))) { + return addP_of_X2P(phase, x, y); + } + if (fits_in_int(phase->type(x))) { + return addP_of_X2P(phase, y, x); + } + break; + } + return NULL; +} + +//------------------------------Identity--------------------------------------- +Node *CastX2PNode::Identity( PhaseTransform *phase ) { + if (in(1)->Opcode() == Op_CastP2X) return in(1)->in(1); + return this; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *CastP2XNode::Value( PhaseTransform *phase ) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + if (t->base() == Type::RawPtr && t->singleton()) { + uintptr_t bits = (uintptr_t) t->is_rawptr()->get_con(); + return TypeX::make(bits); + } + return CastP2XNode::bottom_type(); +} + +Node *CastP2XNode::Ideal(PhaseGVN *phase, bool can_reshape) { + return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; +} + +//------------------------------Identity--------------------------------------- +Node *CastP2XNode::Identity( PhaseTransform *phase ) { + if (in(1)->Opcode() == Op_CastX2P) return in(1)->in(1); + return this; +} diff --git a/hotspot/src/share/vm/opto/castnode.hpp b/hotspot/src/share/vm/opto/castnode.hpp new file mode 100644 index 00000000000..d0f97c9b249 --- /dev/null +++ b/hotspot/src/share/vm/opto/castnode.hpp @@ -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. + * + */ + +#ifndef SHARE_VM_OPTO_CASTNODE_HPP +#define SHARE_VM_OPTO_CASTNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + + +//------------------------------ConstraintCastNode----------------------------- +// cast to a different range +class ConstraintCastNode: public TypeNode { + public: + ConstraintCastNode (Node *n, const Type *t ): TypeNode(t,2) { + init_class_id(Class_ConstraintCast); + init_req(1, n); + } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual int Opcode() const; + virtual uint ideal_reg() const = 0; + virtual Node *Ideal_DU_postCCP( PhaseCCP * ); +}; + +//------------------------------CastIINode------------------------------------- +// cast integer to integer (different range) +class CastIINode: public ConstraintCastNode { + public: + CastIINode (Node *n, const Type *t ): ConstraintCastNode(n,t) {} + virtual int Opcode() const; + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------CastPPNode------------------------------------- +// cast pointer to pointer (different type) +class CastPPNode: public ConstraintCastNode { + public: + CastPPNode (Node *n, const Type *t ): ConstraintCastNode(n, t) {} + virtual int Opcode() const; + virtual uint ideal_reg() const { return Op_RegP; } + virtual Node *Ideal_DU_postCCP( PhaseCCP * ); +}; + +//------------------------------CheckCastPPNode-------------------------------- +// for _checkcast, cast pointer to pointer (different type), without JOIN, +class CheckCastPPNode: public TypeNode { + public: + CheckCastPPNode( Node *c, Node *n, const Type *t ) : TypeNode(t,2) { + init_class_id(Class_CheckCastPP); + init_req(0, c); + init_req(1, n); + } + + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual int Opcode() const; + virtual uint ideal_reg() const { return Op_RegP; } + // No longer remove CheckCast after CCP as it gives me a place to hang + // the proper address type - which is required to compute anti-deps. + //virtual Node *Ideal_DU_postCCP( PhaseCCP * ); +}; + + +//------------------------------CastX2PNode------------------------------------- +// convert a machine-pointer-sized integer to a raw pointer +class CastX2PNode : public Node { + public: + CastX2PNode( Node *n ) : Node(NULL, n) {} + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual Node *Identity( PhaseTransform *phase ); + virtual uint ideal_reg() const { return Op_RegP; } + virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } +}; + +//------------------------------CastP2XNode------------------------------------- +// Used in both 32-bit and 64-bit land. +// Used for card-marks and unsafe pointer math. +class CastP2XNode : public Node { + public: + CastP2XNode( Node *ctrl, Node *n ) : Node(ctrl, n) {} + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual Node *Identity( PhaseTransform *phase ); + virtual uint ideal_reg() const { return Op_RegX; } + virtual const Type *bottom_type() const { return TypeX_X; } + // Return false to keep node from moving away from an associated card mark. + virtual bool depends_only_on_test() const { return false; } +}; + + + +#endif // SHARE_VM_OPTO_CASTNODE_HPP diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp index 25223035f29..02ec25fda2d 100644 --- a/hotspot/src/share/vm/opto/cfgnode.cpp +++ b/hotspot/src/share/vm/opto/cfgnode.cpp @@ -29,8 +29,11 @@ #include "opto/addnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" +#include "opto/movenode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/regmask.hpp" diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index 5a1040aac48..24328546fec 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -37,6 +37,7 @@ #include "opto/indexSet.hpp" #include "opto/machnode.hpp" #include "opto/memnode.hpp" +#include "opto/movenode.hpp" #include "opto/opcodes.hpp" #include "opto/rootnode.hpp" diff --git a/hotspot/src/share/vm/opto/classes.cpp b/hotspot/src/share/vm/opto/classes.cpp index dadc72726e3..a3113922209 100644 --- a/hotspot/src/share/vm/opto/classes.cpp +++ b/hotspot/src/share/vm/opto/classes.cpp @@ -25,17 +25,24 @@ #include "precompiled.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" +#include "opto/countbitsnode.hpp" #include "opto/divnode.hpp" +#include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/memnode.hpp" #include "opto/mathexactnode.hpp" +#include "opto/movenode.hpp" #include "opto/mulnode.hpp" #include "opto/multnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/node.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" #include "opto/subnode.hpp" #include "opto/vectornode.hpp" diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index 3cdc2c58525..54a63db1a98 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -198,6 +198,7 @@ macro(NegF) macro(NeverBranch) macro(Opaque1) macro(Opaque2) +macro(Opaque3) macro(OrI) macro(OrL) macro(OverflowAddI) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 47acd4c5b49..07c20ac4570 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -51,6 +51,7 @@ #include "opto/mathexactnode.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/node.hpp" #include "opto/opcodes.hpp" #include "opto/output.hpp" @@ -694,9 +695,10 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr set_print_inlining(PrintInlining || method()->has_option("PrintInlining") NOT_PRODUCT( || PrintOptoInlining)); set_print_intrinsics(PrintIntrinsics || method()->has_option("PrintIntrinsics")); - if (ProfileTraps) { + if (ProfileTraps RTM_OPT_ONLY( || UseRTMLocking )) { // Make sure the method being compiled gets its own MDO, // so we can at least track the decompile_count(). + // Need MDO to record RTM code generation state. method()->ensure_method_data(); } @@ -907,7 +909,8 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr compiler, env()->comp_level(), has_unsafe_access(), - SharedRuntime::is_wide_vector(max_vector_size()) + SharedRuntime::is_wide_vector(max_vector_size()), + rtm_state() ); if (log() != NULL) // Print code cache state into compiler log @@ -1073,7 +1076,23 @@ void Compile::Init(int aliaslevel) { set_do_scheduling(OptoScheduling); set_do_count_invocations(false); set_do_method_data_update(false); - + set_rtm_state(NoRTM); // No RTM lock eliding by default +#if INCLUDE_RTM_OPT + if (UseRTMLocking && has_method() && (method()->method_data_or_null() != NULL)) { + int rtm_state = method()->method_data()->rtm_state(); + if (method_has_option("NoRTMLockEliding") || ((rtm_state & NoRTM) != 0)) { + // Don't generate RTM lock eliding code. + set_rtm_state(NoRTM); + } else if (method_has_option("UseRTMLockEliding") || ((rtm_state & UseRTM) != 0) || !UseRTMDeopt) { + // Generate RTM lock eliding code without abort ratio calculation code. + set_rtm_state(UseRTM); + } else if (UseRTMDeopt) { + // Generate RTM lock eliding code and include abort ratio calculation + // code if UseRTMDeopt is on. + set_rtm_state(ProfileRTM); + } + } +#endif if (debug_info()->recording_non_safepoints()) { set_node_note_array(new(comp_arena()) GrowableArray (comp_arena(), 8, 0, NULL)); @@ -2581,6 +2600,7 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { break; case Op_Opaque1: // Remove Opaque Nodes before matching case Op_Opaque2: // Remove Opaque Nodes before matching + case Op_Opaque3: n->subsume_by(n->in(1), this); break; case Op_CallStaticJava: diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 3fde797fad1..b9f48c494b9 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -319,9 +319,9 @@ class Compile : public Phase { bool _trace_opto_output; bool _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing #endif - // JSR 292 bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. + RTMState _rtm_state; // State of Restricted Transactional Memory usage // Compilation environment. Arena _comp_arena; // Arena with lifetime equivalent to Compile @@ -591,6 +591,10 @@ class Compile : public Phase { void set_print_inlining(bool z) { _print_inlining = z; } bool print_intrinsics() const { return _print_intrinsics; } void set_print_intrinsics(bool z) { _print_intrinsics = z; } + RTMState rtm_state() const { return _rtm_state; } + void set_rtm_state(RTMState s) { _rtm_state = s; } + bool use_rtm() const { return (_rtm_state & NoRTM) == 0; } + bool profile_rtm() const { return _rtm_state == ProfileRTM; } // check the CompilerOracle for special behaviours for this compile bool method_has_option(const char * option) { return method() != NULL && method()->has_option(option); diff --git a/hotspot/src/share/vm/opto/connode.cpp b/hotspot/src/share/vm/opto/connode.cpp index 0a71bc598e4..8485aba1303 100644 --- a/hotspot/src/share/vm/opto/connode.cpp +++ b/hotspot/src/share/vm/opto/connode.cpp @@ -66,1313 +66,4 @@ ConNode *ConNode::make( Compile* C, const Type *t ) { return NULL; } -//============================================================================= -/* -The major change is for CMoveP and StrComp. They have related but slightly -different problems. They both take in TWO oops which are both null-checked -independently before the using Node. After CCP removes the CastPP's they need -to pick up the guarding test edge - in this case TWO control edges. I tried -various solutions, all have problems: -(1) Do nothing. This leads to a bug where we hoist a Load from a CMoveP or a -StrComp above a guarding null check. I've seen both cases in normal -Xcomp -testing. - -(2) Plug the control edge from 1 of the 2 oops in. Apparent problem here is -to figure out which test post-dominates. The real problem is that it doesn't -matter which one you pick. After you pick up, the dominating-test elider in -IGVN can remove the test and allow you to hoist up to the dominating test on -the chosen oop bypassing the test on the not-chosen oop. Seen in testing. -Oops. - -(3) Leave the CastPP's in. This makes the graph more accurate in some sense; -we get to keep around the knowledge that an oop is not-null after some test. -Alas, the CastPP's interfere with GVN (some values are the regular oop, some -are the CastPP of the oop, all merge at Phi's which cannot collapse, etc). -This cost us 10% on SpecJVM, even when I removed some of the more trivial -cases in the optimizer. Removing more useless Phi's started allowing Loads to -illegally float above null checks. I gave up on this approach. - -(4) Add BOTH control edges to both tests. Alas, too much code knows that -control edges are in slot-zero ONLY. Many quick asserts fail; no way to do -this one. Note that I really want to allow the CMoveP to float and add both -control edges to the dependent Load op - meaning I can select early but I -cannot Load until I pass both tests. - -(5) Do not hoist CMoveP and StrComp. To this end I added the v-call -depends_only_on_test(). No obvious performance loss on Spec, but we are -clearly conservative on CMoveP (also so on StrComp but that's unlikely to -matter ever). - -*/ - - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Move constants to the right. -Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(0) && remove_dead_region(phase, can_reshape) ) return this; - // Don't bother trying to transform a dead node - if( in(0) && in(0)->is_top() ) return NULL; - assert( !phase->eqv(in(Condition), this) && - !phase->eqv(in(IfFalse), this) && - !phase->eqv(in(IfTrue), this), "dead loop in CMoveNode::Ideal" ); - if( phase->type(in(Condition)) == Type::TOP ) - return NULL; // return NULL when Condition is dead - - if( in(IfFalse)->is_Con() && !in(IfTrue)->is_Con() ) { - 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 NULL; -} - -//------------------------------is_cmove_id------------------------------------ -// Helper function to check for CMOVE identity. Shared with PhiNode::Identity -Node *CMoveNode::is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ) { - // Check for Cmp'ing and CMove'ing same values - if( (phase->eqv(cmp->in(1),f) && - phase->eqv(cmp->in(2),t)) || - // Swapped Cmp is OK - (phase->eqv(cmp->in(2),f) && - phase->eqv(cmp->in(1),t)) ) { - // Give up this identity check for floating points because it may choose incorrect - // value around 0.0 and -0.0 - if ( cmp->Opcode()==Op_CmpF || cmp->Opcode()==Op_CmpD ) - return NULL; - // Check for "(t==f)?t:f;" and replace with "f" - if( b->_test._test == BoolTest::eq ) - return f; - // Allow the inverted case as well - // Check for "(t!=f)?t:f;" and replace with "t" - if( b->_test._test == BoolTest::ne ) - return t; - } - return NULL; -} - -//------------------------------Identity--------------------------------------- -// Conditional-move is an identity if both inputs are the same, or the test -// true or false. -Node *CMoveNode::Identity( PhaseTransform *phase ) { - if( phase->eqv(in(IfFalse),in(IfTrue)) ) // C-moving identical inputs? - return in(IfFalse); // Then it doesn't matter - if( phase->type(in(Condition)) == TypeInt::ZERO ) - return in(IfFalse); // Always pick left(false) input - if( phase->type(in(Condition)) == TypeInt::ONE ) - return in(IfTrue); // Always pick right(true) input - - // Check for CMove'ing a constant after comparing against the constant. - // Happens all the time now, since if we compare equality vs a constant in - // the parser, we "know" the variable is constant on one path and we force - // it. Thus code like "if( x==0 ) {/*EMPTY*/}" ends up inserting a - // conditional move: "x = (x==0)?0:x;". Yucko. This fix is slightly more - // general in that we don't need constants. - if( in(Condition)->is_Bool() ) { - BoolNode *b = in(Condition)->as_Bool(); - Node *cmp = b->in(1); - if( cmp->is_Cmp() ) { - Node *id = is_cmove_id( phase, cmp, in(IfTrue), in(IfFalse), b ); - if( id ) return id; - } - } - - return this; -} - -//------------------------------Value------------------------------------------ -// Result is the meet of inputs -const Type *CMoveNode::Value( PhaseTransform *phase ) const { - if( phase->type(in(Condition)) == Type::TOP ) - return Type::TOP; - return phase->type(in(IfFalse))->meet_speculative(phase->type(in(IfTrue))); -} - -//------------------------------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 ) { - switch( t->basic_type() ) { - case T_INT: return new (C) CMoveINode( bol, left, right, t->is_int() ); - case T_FLOAT: return new (C) CMoveFNode( bol, left, right, t ); - case T_DOUBLE: return new (C) CMoveDNode( bol, left, right, t ); - case T_LONG: return new (C) CMoveLNode( bol, left, right, t->is_long() ); - case T_OBJECT: return new (C) CMovePNode( c, bol, left, right, t->is_oopptr() ); - case T_ADDRESS: return new (C) CMovePNode( c, bol, left, right, t->is_ptr() ); - case T_NARROWOOP: return new (C) CMoveNNode( c, bol, left, right, t ); - default: - ShouldNotReachHere(); - return NULL; - } -} - -//============================================================================= -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Check for conversions to boolean -Node *CMoveINode::Ideal(PhaseGVN *phase, bool can_reshape) { - // Try generic ideal's first - Node *x = CMoveNode::Ideal(phase, can_reshape); - if( x ) return x; - - // If zero is on the left (false-case, no-move-case) it must mean another - // constant is on the right (otherwise the shared CMove::Ideal code would - // have moved the constant to the right). This situation is bad for Intel - // and a don't-care for Sparc. It's bad for Intel because the zero has to - // be manifested in a register with a XOR which kills flags, which are live - // on input to the CMoveI, leading to a situation which causes excessive - // spilling on Intel. For Sparc, if the zero in on the left the Sparc will - // zero a register via G0 and conditionally-move the other constant. If the - // zero is on the right, the Sparc will load the first constant with a - // 13-bit set-lo and conditionally move G0. See bug 4677505. - if( phase->type(in(IfFalse)) == TypeInt::ZERO && !(phase->type(in(IfTrue)) == TypeInt::ZERO) ) { - 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 ); - } - } - - // Now check for booleans - int flip = 0; - - // Check for picking from zero/one - if( phase->type(in(IfFalse)) == TypeInt::ZERO && phase->type(in(IfTrue)) == TypeInt::ONE ) { - flip = 1 - flip; - } else if( phase->type(in(IfFalse)) == TypeInt::ONE && phase->type(in(IfTrue)) == TypeInt::ZERO ) { - } else return NULL; - - // Check for eq/ne test - if( !in(1)->is_Bool() ) return NULL; - BoolNode *bol = in(1)->as_Bool(); - if( bol->_test._test == BoolTest::eq ) { - } else if( bol->_test._test == BoolTest::ne ) { - flip = 1-flip; - } else return NULL; - - // Check for vs 0 or 1 - if( !bol->in(1)->is_Cmp() ) return NULL; - const CmpNode *cmp = bol->in(1)->as_Cmp(); - if( phase->type(cmp->in(2)) == TypeInt::ZERO ) { - } else if( phase->type(cmp->in(2)) == TypeInt::ONE ) { - // Allow cmp-vs-1 if the other input is bounded by 0-1 - if( phase->type(cmp->in(1)) != TypeInt::BOOL ) - return NULL; - flip = 1 - flip; - } else return NULL; - - // Convert to a bool (flipped) - // Build int->bool conversion -#ifndef PRODUCT - if( PrintOpto ) tty->print_cr("CMOV to I2B"); -#endif - Node *n = new (phase->C) Conv2BNode( cmp->in(1) ); - if( flip ) - n = new (phase->C) XorINode( phase->transform(n), phase->intcon(1) ); - - return n; -} - -//============================================================================= -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Check for absolute value -Node *CMoveFNode::Ideal(PhaseGVN *phase, bool can_reshape) { - // Try generic ideal's first - Node *x = CMoveNode::Ideal(phase, can_reshape); - if( x ) return x; - - int cmp_zero_idx = 0; // Index of compare input where to look for zero - int phi_x_idx = 0; // Index of phi input where to find naked x - - // Find the Bool - if( !in(1)->is_Bool() ) return NULL; - BoolNode *bol = in(1)->as_Bool(); - // Check bool sense - switch( bol->_test._test ) { - case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break; - case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break; - case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break; - case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break; - default: return NULL; break; - } - - // Find zero input of CmpF; the other input is being abs'd - Node *cmpf = bol->in(1); - if( cmpf->Opcode() != Op_CmpF ) return NULL; - Node *X = NULL; - bool flip = false; - if( phase->type(cmpf->in(cmp_zero_idx)) == TypeF::ZERO ) { - X = cmpf->in(3 - cmp_zero_idx); - } else if (phase->type(cmpf->in(3 - cmp_zero_idx)) == TypeF::ZERO) { - // The test is inverted, we should invert the result... - X = cmpf->in(cmp_zero_idx); - flip = true; - } else { - return NULL; - } - - // If X is found on the appropriate phi input, find the subtract on the other - if( X != in(phi_x_idx) ) return NULL; - int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue; - Node *sub = in(phi_sub_idx); - - // Allow only SubF(0,X) and fail out for all others; NegF is not OK - if( sub->Opcode() != Op_SubF || - sub->in(2) != X || - phase->type(sub->in(1)) != TypeF::ZERO ) return NULL; - - Node *abs = new (phase->C) AbsFNode( X ); - if( flip ) - abs = new (phase->C) SubFNode(sub->in(1), phase->transform(abs)); - - return abs; -} - -//============================================================================= -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Check for absolute value -Node *CMoveDNode::Ideal(PhaseGVN *phase, bool can_reshape) { - // Try generic ideal's first - Node *x = CMoveNode::Ideal(phase, can_reshape); - if( x ) return x; - - int cmp_zero_idx = 0; // Index of compare input where to look for zero - int phi_x_idx = 0; // Index of phi input where to find naked x - - // Find the Bool - if( !in(1)->is_Bool() ) return NULL; - BoolNode *bol = in(1)->as_Bool(); - // Check bool sense - switch( bol->_test._test ) { - case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break; - case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break; - case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break; - case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break; - default: return NULL; break; - } - - // Find zero input of CmpD; the other input is being abs'd - Node *cmpd = bol->in(1); - if( cmpd->Opcode() != Op_CmpD ) return NULL; - Node *X = NULL; - bool flip = false; - if( phase->type(cmpd->in(cmp_zero_idx)) == TypeD::ZERO ) { - X = cmpd->in(3 - cmp_zero_idx); - } else if (phase->type(cmpd->in(3 - cmp_zero_idx)) == TypeD::ZERO) { - // The test is inverted, we should invert the result... - X = cmpd->in(cmp_zero_idx); - flip = true; - } else { - return NULL; - } - - // If X is found on the appropriate phi input, find the subtract on the other - if( X != in(phi_x_idx) ) return NULL; - int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue; - Node *sub = in(phi_sub_idx); - - // Allow only SubD(0,X) and fail out for all others; NegD is not OK - if( sub->Opcode() != Op_SubD || - sub->in(2) != X || - phase->type(sub->in(1)) != TypeD::ZERO ) return NULL; - - Node *abs = new (phase->C) AbsDNode( X ); - if( flip ) - abs = new (phase->C) SubDNode(sub->in(1), phase->transform(abs)); - - return abs; -} - - -//============================================================================= -// If input is already higher or equal to cast type, then this is an identity. -Node *ConstraintCastNode::Identity( PhaseTransform *phase ) { - return phase->type(in(1))->higher_equal_speculative(_type) ? in(1) : this; -} - -//------------------------------Value------------------------------------------ -// Take 'join' of input and cast-up type -const Type *ConstraintCastNode::Value( PhaseTransform *phase ) const { - if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; -const Type* ft = phase->type(in(1))->filter_speculative(_type); - -#ifdef ASSERT - // Previous versions of this function had some special case logic, - // which is no longer necessary. Make sure of the required effects. - switch (Opcode()) { - case Op_CastII: - { - const Type* t1 = phase->type(in(1)); - if( t1 == Type::TOP ) assert(ft == Type::TOP, "special case #1"); - const Type* rt = t1->join_speculative(_type); - if (rt->empty()) assert(ft == Type::TOP, "special case #2"); - break; - } - case Op_CastPP: - if (phase->type(in(1)) == TypePtr::NULL_PTR && - _type->isa_ptr() && _type->is_ptr()->_ptr == TypePtr::NotNull) - assert(ft == Type::TOP, "special case #3"); - break; - } -#endif //ASSERT - - return ft; -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape){ - return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; -} - -//------------------------------Ideal_DU_postCCP------------------------------- -// Throw away cast after constant propagation -Node *ConstraintCastNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - const Type *t = ccp->type(in(1)); - ccp->hash_delete(this); - set_type(t); // Turn into ID function - ccp->hash_insert(this); - return this; -} - - -//============================================================================= - -//------------------------------Ideal_DU_postCCP------------------------------- -// If not converting int->oop, throw away cast after constant propagation -Node *CastPPNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - const Type *t = ccp->type(in(1)); - if (!t->isa_oop_ptr() || ((in(1)->is_DecodeN()) && Matcher::gen_narrow_oop_implicit_null_checks())) { - return NULL; // do not transform raw pointers or narrow oops - } - return ConstraintCastNode::Ideal_DU_postCCP(ccp); -} - - - -//============================================================================= -//------------------------------Identity--------------------------------------- -// If input is already higher or equal to cast type, then this is an identity. -Node *CheckCastPPNode::Identity( PhaseTransform *phase ) { - // Toned down to rescue meeting at a Phi 3 different oops all implementing - // the same interface. CompileTheWorld starting at 502, kd12rc1.zip. - return (phase->type(in(1)) == phase->type(this)) ? in(1) : this; -} - -//------------------------------Value------------------------------------------ -// Take 'join' of input and cast-up type, unless working with an Interface -const Type *CheckCastPPNode::Value( PhaseTransform *phase ) const { - if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; - - const Type *inn = phase->type(in(1)); - if( inn == Type::TOP ) return Type::TOP; // No information yet - - const TypePtr *in_type = inn->isa_ptr(); - const TypePtr *my_type = _type->isa_ptr(); - const Type *result = _type; - if( in_type != NULL && my_type != NULL ) { - TypePtr::PTR in_ptr = in_type->ptr(); - if( in_ptr == TypePtr::Null ) { - result = in_type; - } else if( in_ptr == TypePtr::Constant ) { - // Casting a constant oop to an interface? - // (i.e., a String to a Comparable?) - // Then return the interface. - const TypeOopPtr *jptr = my_type->isa_oopptr(); - assert( jptr, "" ); - result = (jptr->klass()->is_interface() || !in_type->higher_equal(_type)) - ? my_type->cast_to_ptr_type( TypePtr::NotNull ) - : in_type; - } else { - result = my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) ); - } - } - return result; - - // JOIN NOT DONE HERE BECAUSE OF INTERFACE ISSUES. - // FIX THIS (DO THE JOIN) WHEN UNION TYPES APPEAR! - - // - // Remove this code after overnight run indicates no performance - // loss from not performing JOIN at CheckCastPPNode - // - // const TypeInstPtr *in_oop = in->isa_instptr(); - // const TypeInstPtr *my_oop = _type->isa_instptr(); - // // If either input is an 'interface', return destination type - // assert (in_oop == NULL || in_oop->klass() != NULL, ""); - // assert (my_oop == NULL || my_oop->klass() != NULL, ""); - // if( (in_oop && in_oop->klass()->is_interface()) - // ||(my_oop && my_oop->klass()->is_interface()) ) { - // TypePtr::PTR in_ptr = in->isa_ptr() ? in->is_ptr()->_ptr : TypePtr::BotPTR; - // // Preserve cast away nullness for interfaces - // if( in_ptr == TypePtr::NotNull && my_oop && my_oop->_ptr == TypePtr::BotPTR ) { - // return my_oop->cast_to_ptr_type(TypePtr::NotNull); - // } - // return _type; - // } - // - // // Neither the input nor the destination type is an interface, - // - // // history: JOIN used to cause weird corner case bugs - // // return (in == TypeOopPtr::NULL_PTR) ? in : _type; - // // JOIN picks up NotNull in common instance-of/check-cast idioms, both oops. - // // JOIN does not preserve NotNull in other cases, e.g. RawPtr vs InstPtr - // const Type *join = in->join(_type); - // // Check if join preserved NotNull'ness for pointers - // if( join->isa_ptr() && _type->isa_ptr() ) { - // TypePtr::PTR join_ptr = join->is_ptr()->_ptr; - // TypePtr::PTR type_ptr = _type->is_ptr()->_ptr; - // // If there isn't any NotNull'ness to preserve - // // OR if join preserved NotNull'ness then return it - // if( type_ptr == TypePtr::BotPTR || type_ptr == TypePtr::Null || - // join_ptr == TypePtr::NotNull || join_ptr == TypePtr::Constant ) { - // return join; - // } - // // ELSE return same old type as before - // return _type; - // } - // // Not joining two pointers - // return join; -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *CheckCastPPNode::Ideal(PhaseGVN *phase, bool can_reshape){ - return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; -} - - -Node* DecodeNNode::Identity(PhaseTransform* phase) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - - if (in(1)->is_EncodeP()) { - // (DecodeN (EncodeP p)) -> p - return in(1)->in(1); - } - return this; -} - -const Type *DecodeNNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if (t == Type::TOP) return Type::TOP; - if (t == TypeNarrowOop::NULL_PTR) return TypePtr::NULL_PTR; - - assert(t->isa_narrowoop(), "only narrowoop here"); - return t->make_ptr(); -} - -Node* EncodePNode::Identity(PhaseTransform* phase) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - - if (in(1)->is_DecodeN()) { - // (EncodeP (DecodeN p)) -> p - return in(1)->in(1); - } - return this; -} - -const Type *EncodePNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if (t == Type::TOP) return Type::TOP; - if (t == TypePtr::NULL_PTR) return TypeNarrowOop::NULL_PTR; - - assert(t->isa_oop_ptr(), "only oopptr here"); - return t->make_narrowoop(); -} - - -Node *EncodeNarrowPtrNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1)); -} - -Node* DecodeNKlassNode::Identity(PhaseTransform* phase) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - - if (in(1)->is_EncodePKlass()) { - // (DecodeNKlass (EncodePKlass p)) -> p - return in(1)->in(1); - } - return this; -} - -const Type *DecodeNKlassNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if (t == Type::TOP) return Type::TOP; - assert(t != TypeNarrowKlass::NULL_PTR, "null klass?"); - - assert(t->isa_narrowklass(), "only narrow klass ptr here"); - return t->make_ptr(); -} - -Node* EncodePKlassNode::Identity(PhaseTransform* phase) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - - if (in(1)->is_DecodeNKlass()) { - // (EncodePKlass (DecodeNKlass p)) -> p - return in(1)->in(1); - } - return this; -} - -const Type *EncodePKlassNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if (t == Type::TOP) return Type::TOP; - assert (t != TypePtr::NULL_PTR, "null klass?"); - - assert(UseCompressedClassPointers && t->isa_klassptr(), "only klass ptr here"); - return t->make_narrowklass(); -} - - -//============================================================================= -//------------------------------Identity--------------------------------------- -Node *Conv2BNode::Identity( PhaseTransform *phase ) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - if( t == TypeInt::ZERO ) return in(1); - if( t == TypeInt::ONE ) return in(1); - if( t == TypeInt::BOOL ) return in(1); - return this; -} - -//------------------------------Value------------------------------------------ -const Type *Conv2BNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == TypeInt::ZERO ) return TypeInt::ZERO; - if( t == TypePtr::NULL_PTR ) return TypeInt::ZERO; - const TypePtr *tp = t->isa_ptr(); - if( tp != NULL ) { - if( tp->ptr() == TypePtr::AnyNull ) return Type::TOP; - if( tp->ptr() == TypePtr::Constant) return TypeInt::ONE; - if (tp->ptr() == TypePtr::NotNull) return TypeInt::ONE; - return TypeInt::BOOL; - } - if (t->base() != Type::Int) return TypeInt::BOOL; - const TypeInt *ti = t->is_int(); - if( ti->_hi < 0 || ti->_lo > 0 ) return TypeInt::ONE; - return TypeInt::BOOL; -} - - -// The conversions operations are all Alpha sorted. Please keep it that way! -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvD2FNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::DOUBLE ) return Type::FLOAT; - const TypeD *td = t->is_double_constant(); - return TypeF::make( (float)td->getd() ); -} - -//------------------------------Identity--------------------------------------- -// Float's can be converted to doubles with no loss of bits. Hence -// converting a float to a double and back to a float is a NOP. -Node *ConvD2FNode::Identity(PhaseTransform *phase) { - return (in(1)->Opcode() == Op_ConvF2D) ? in(1)->in(1) : this; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvD2INode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::DOUBLE ) return TypeInt::INT; - const TypeD *td = t->is_double_constant(); - return TypeInt::make( SharedRuntime::d2i( td->getd() ) ); -} - -//------------------------------Ideal------------------------------------------ -// If converting to an int type, skip any rounding nodes -Node *ConvD2INode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(1)->Opcode() == Op_RoundDouble ) - set_req(1,in(1)->in(1)); - return NULL; -} - -//------------------------------Identity--------------------------------------- -// Int's can be converted to doubles with no loss of bits. Hence -// converting an integer to a double and back to an integer is a NOP. -Node *ConvD2INode::Identity(PhaseTransform *phase) { - return (in(1)->Opcode() == Op_ConvI2D) ? in(1)->in(1) : this; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvD2LNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::DOUBLE ) return TypeLong::LONG; - const TypeD *td = t->is_double_constant(); - return TypeLong::make( SharedRuntime::d2l( td->getd() ) ); -} - -//------------------------------Identity--------------------------------------- -Node *ConvD2LNode::Identity(PhaseTransform *phase) { - // Remove ConvD2L->ConvL2D->ConvD2L sequences. - if( in(1) ->Opcode() == Op_ConvL2D && - in(1)->in(1)->Opcode() == Op_ConvD2L ) - return in(1)->in(1); - return this; -} - -//------------------------------Ideal------------------------------------------ -// If converting to an int type, skip any rounding nodes -Node *ConvD2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(1)->Opcode() == Op_RoundDouble ) - set_req(1,in(1)->in(1)); - return NULL; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvF2DNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::FLOAT ) return Type::DOUBLE; - const TypeF *tf = t->is_float_constant(); - return TypeD::make( (double)tf->getf() ); -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvF2INode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::FLOAT ) return TypeInt::INT; - const TypeF *tf = t->is_float_constant(); - return TypeInt::make( SharedRuntime::f2i( tf->getf() ) ); -} - -//------------------------------Identity--------------------------------------- -Node *ConvF2INode::Identity(PhaseTransform *phase) { - // Remove ConvF2I->ConvI2F->ConvF2I sequences. - if( in(1) ->Opcode() == Op_ConvI2F && - in(1)->in(1)->Opcode() == Op_ConvF2I ) - return in(1)->in(1); - return this; -} - -//------------------------------Ideal------------------------------------------ -// If converting to an int type, skip any rounding nodes -Node *ConvF2INode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(1)->Opcode() == Op_RoundFloat ) - set_req(1,in(1)->in(1)); - return NULL; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvF2LNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::FLOAT ) return TypeLong::LONG; - const TypeF *tf = t->is_float_constant(); - return TypeLong::make( SharedRuntime::f2l( tf->getf() ) ); -} - -//------------------------------Identity--------------------------------------- -Node *ConvF2LNode::Identity(PhaseTransform *phase) { - // Remove ConvF2L->ConvL2F->ConvF2L sequences. - if( in(1) ->Opcode() == Op_ConvL2F && - in(1)->in(1)->Opcode() == Op_ConvF2L ) - return in(1)->in(1); - return this; -} - -//------------------------------Ideal------------------------------------------ -// If converting to an int type, skip any rounding nodes -Node *ConvF2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(1)->Opcode() == Op_RoundFloat ) - set_req(1,in(1)->in(1)); - return NULL; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvI2DNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeInt *ti = t->is_int(); - if( ti->is_con() ) return TypeD::make( (double)ti->get_con() ); - return bottom_type(); -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvI2FNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeInt *ti = t->is_int(); - if( ti->is_con() ) return TypeF::make( (float)ti->get_con() ); - return bottom_type(); -} - -//------------------------------Identity--------------------------------------- -Node *ConvI2FNode::Identity(PhaseTransform *phase) { - // Remove ConvI2F->ConvF2I->ConvI2F sequences. - if( in(1) ->Opcode() == Op_ConvF2I && - in(1)->in(1)->Opcode() == Op_ConvI2F ) - return in(1)->in(1); - return this; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvI2LNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeInt *ti = t->is_int(); - const Type* tl = TypeLong::make(ti->_lo, ti->_hi, ti->_widen); - // Join my declared type against my incoming type. - tl = tl->filter(_type); - return tl; -} - -#ifdef _LP64 -static inline bool long_ranges_overlap(jlong lo1, jlong hi1, - jlong lo2, jlong hi2) { - // Two ranges overlap iff one range's low point falls in the other range. - return (lo2 <= lo1 && lo1 <= hi2) || (lo1 <= lo2 && lo2 <= hi1); -} -#endif - -//------------------------------Ideal------------------------------------------ -Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { - const TypeLong* this_type = this->type()->is_long(); - Node* this_changed = NULL; - - // If _major_progress, then more loop optimizations follow. Do NOT - // remove this node's type assertion until no more loop ops can happen. - // The progress bit is set in the major loop optimizations THEN comes the - // call to IterGVN and any chance of hitting this code. Cf. Opaque1Node. - if (can_reshape && !phase->C->major_progress()) { - const TypeInt* in_type = phase->type(in(1))->isa_int(); - if (in_type != NULL && this_type != NULL && - (in_type->_lo != this_type->_lo || - in_type->_hi != this_type->_hi)) { - // Although this WORSENS the type, it increases GVN opportunities, - // because I2L nodes with the same input will common up, regardless - // of slightly differing type assertions. Such slight differences - // arise routinely as a result of loop unrolling, so this is a - // post-unrolling graph cleanup. Choose a type which depends only - // on my input. (Exception: Keep a range assertion of >=0 or <0.) - jlong lo1 = this_type->_lo; - jlong hi1 = this_type->_hi; - int w1 = this_type->_widen; - if (lo1 != (jint)lo1 || - hi1 != (jint)hi1 || - lo1 > hi1) { - // Overflow leads to wraparound, wraparound leads to range saturation. - lo1 = min_jint; hi1 = max_jint; - } else if (lo1 >= 0) { - // Keep a range assertion of >=0. - lo1 = 0; hi1 = max_jint; - } else if (hi1 < 0) { - // Keep a range assertion of <0. - lo1 = min_jint; hi1 = -1; - } else { - lo1 = min_jint; hi1 = max_jint; - } - const TypeLong* wtype = TypeLong::make(MAX2((jlong)in_type->_lo, lo1), - MIN2((jlong)in_type->_hi, hi1), - MAX2((int)in_type->_widen, w1)); - if (wtype != type()) { - set_type(wtype); - // Note: this_type still has old type value, for the logic below. - this_changed = this; - } - } - } - -#ifdef _LP64 - // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) , - // but only if x and y have subranges that cannot cause 32-bit overflow, - // under the assumption that x+y is in my own subrange this->type(). - - // This assumption is based on a constraint (i.e., type assertion) - // established in Parse::array_addressing or perhaps elsewhere. - // This constraint has been adjoined to the "natural" type of - // the incoming argument in(0). We know (because of runtime - // checks) - that the result value I2L(x+y) is in the joined range. - // Hence we can restrict the incoming terms (x, y) to values such - // that their sum also lands in that range. - - // This optimization is useful only on 64-bit systems, where we hope - // the addition will end up subsumed in an addressing mode. - // It is necessary to do this when optimizing an unrolled array - // copy loop such as x[i++] = y[i++]. - - // On 32-bit systems, it's better to perform as much 32-bit math as - // possible before the I2L conversion, because 32-bit math is cheaper. - // There's no common reason to "leak" a constant offset through the I2L. - // Addressing arithmetic will not absorb it as part of a 64-bit AddL. - - Node* z = in(1); - int op = z->Opcode(); - if (op == Op_AddI || op == Op_SubI) { - Node* x = z->in(1); - Node* y = z->in(2); - assert (x != z && y != z, "dead loop in ConvI2LNode::Ideal"); - if (phase->type(x) == Type::TOP) return this_changed; - if (phase->type(y) == Type::TOP) return this_changed; - const TypeInt* tx = phase->type(x)->is_int(); - const TypeInt* ty = phase->type(y)->is_int(); - const TypeLong* tz = this_type; - jlong xlo = tx->_lo; - jlong xhi = tx->_hi; - jlong ylo = ty->_lo; - jlong yhi = ty->_hi; - jlong zlo = tz->_lo; - jlong zhi = tz->_hi; - jlong vbit = CONST64(1) << BitsPerInt; - int widen = MAX2(tx->_widen, ty->_widen); - if (op == Op_SubI) { - jlong ylo0 = ylo; - ylo = -yhi; - yhi = -ylo0; - } - // See if x+y can cause positive overflow into z+2**32 - if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo+vbit, zhi+vbit)) { - return this_changed; - } - // See if x+y can cause negative overflow into z-2**32 - if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo-vbit, zhi-vbit)) { - return this_changed; - } - // Now it's always safe to assume x+y does not overflow. - // This is true even if some pairs x,y might cause overflow, as long - // as that overflow value cannot fall into [zlo,zhi]. - - // Confident that the arithmetic is "as if infinite precision", - // we can now use z's range to put constraints on those of x and y. - // The "natural" range of x [xlo,xhi] can perhaps be narrowed to a - // more "restricted" range by intersecting [xlo,xhi] with the - // range obtained by subtracting y's range from the asserted range - // of the I2L conversion. Here's the interval arithmetic algebra: - // x == z-y == [zlo,zhi]-[ylo,yhi] == [zlo,zhi]+[-yhi,-ylo] - // => x in [zlo-yhi, zhi-ylo] - // => x in [zlo-yhi, zhi-ylo] INTERSECT [xlo,xhi] - // => x in [xlo MAX zlo-yhi, xhi MIN zhi-ylo] - jlong rxlo = MAX2(xlo, zlo - yhi); - jlong rxhi = MIN2(xhi, zhi - ylo); - // And similarly, x changing place with y: - jlong rylo = MAX2(ylo, zlo - xhi); - jlong ryhi = MIN2(yhi, zhi - xlo); - if (rxlo > rxhi || rylo > ryhi) { - return this_changed; // x or y is dying; don't mess w/ it - } - if (op == Op_SubI) { - jlong rylo0 = rylo; - rylo = -ryhi; - ryhi = -rylo0; - } - - Node* cx = phase->transform( new (phase->C) ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) ); - Node* cy = phase->transform( new (phase->C) ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) ); - switch (op) { - case Op_AddI: return new (phase->C) AddLNode(cx, cy); - case Op_SubI: return new (phase->C) SubLNode(cx, cy); - default: ShouldNotReachHere(); - } - } -#endif //_LP64 - - return this_changed; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvL2DNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeLong *tl = t->is_long(); - if( tl->is_con() ) return TypeD::make( (double)tl->get_con() ); - return bottom_type(); -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvL2FNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeLong *tl = t->is_long(); - if( tl->is_con() ) return TypeF::make( (float)tl->get_con() ); - return bottom_type(); -} - -//============================================================================= -//----------------------------Identity----------------------------------------- -Node *ConvL2INode::Identity( PhaseTransform *phase ) { - // Convert L2I(I2L(x)) => x - if (in(1)->Opcode() == Op_ConvI2L) return in(1)->in(1); - return this; -} - -//------------------------------Value------------------------------------------ -const Type *ConvL2INode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeLong *tl = t->is_long(); - if (tl->is_con()) - // Easy case. - return TypeInt::make((jint)tl->get_con()); - return bottom_type(); -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Blow off prior masking to int -Node *ConvL2INode::Ideal(PhaseGVN *phase, bool can_reshape) { - Node *andl = in(1); - uint andl_op = andl->Opcode(); - if( andl_op == Op_AndL ) { - // Blow off prior masking to int - if( phase->type(andl->in(2)) == TypeLong::make( 0xFFFFFFFF ) ) { - set_req(1,andl->in(1)); - return this; - } - } - - // Swap with a prior add: convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y)) - // This replaces an 'AddL' with an 'AddI'. - if( andl_op == Op_AddL ) { - // Don't do this for nodes which have more than one user since - // we'll end up computing the long add anyway. - if (andl->outcnt() > 1) return NULL; - - Node* x = andl->in(1); - Node* y = andl->in(2); - assert( x != andl && y != andl, "dead loop in ConvL2INode::Ideal" ); - if (phase->type(x) == Type::TOP) return NULL; - if (phase->type(y) == Type::TOP) return NULL; - Node *add1 = phase->transform(new (phase->C) ConvL2INode(x)); - Node *add2 = phase->transform(new (phase->C) ConvL2INode(y)); - return new (phase->C) AddINode(add1,add2); - } - - // Disable optimization: LoadL->ConvL2I ==> LoadI. - // It causes problems (sizes of Load and Store nodes do not match) - // in objects initialization code and Escape Analysis. - return NULL; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *CastX2PNode::Value( PhaseTransform *phase ) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - if (t->base() == Type_X && t->singleton()) { - uintptr_t bits = (uintptr_t) t->is_intptr_t()->get_con(); - if (bits == 0) return TypePtr::NULL_PTR; - return TypeRawPtr::make((address) bits); - } - return CastX2PNode::bottom_type(); -} - -//------------------------------Idealize--------------------------------------- -static inline bool fits_in_int(const Type* t, bool but_not_min_int = false) { - if (t == Type::TOP) return false; - const TypeX* tl = t->is_intptr_t(); - jint lo = min_jint; - jint hi = max_jint; - if (but_not_min_int) ++lo; // caller wants to negate the value w/o overflow - return (tl->_lo >= lo) && (tl->_hi <= hi); -} - -static inline Node* addP_of_X2P(PhaseGVN *phase, - Node* base, - Node* dispX, - bool negate = false) { - if (negate) { - dispX = new (phase->C) SubXNode(phase->MakeConX(0), phase->transform(dispX)); - } - return new (phase->C) AddPNode(phase->C->top(), - phase->transform(new (phase->C) CastX2PNode(base)), - phase->transform(dispX)); -} - -Node *CastX2PNode::Ideal(PhaseGVN *phase, bool can_reshape) { - // convert CastX2P(AddX(x, y)) to AddP(CastX2P(x), y) if y fits in an int - int op = in(1)->Opcode(); - Node* x; - Node* y; - switch (op) { - case Op_SubX: - x = in(1)->in(1); - // Avoid ideal transformations ping-pong between this and AddP for raw pointers. - if (phase->find_intptr_t_con(x, -1) == 0) - break; - y = in(1)->in(2); - if (fits_in_int(phase->type(y), true)) { - return addP_of_X2P(phase, x, y, true); - } - break; - case Op_AddX: - x = in(1)->in(1); - y = in(1)->in(2); - if (fits_in_int(phase->type(y))) { - return addP_of_X2P(phase, x, y); - } - if (fits_in_int(phase->type(x))) { - return addP_of_X2P(phase, y, x); - } - break; - } - return NULL; -} - -//------------------------------Identity--------------------------------------- -Node *CastX2PNode::Identity( PhaseTransform *phase ) { - if (in(1)->Opcode() == Op_CastP2X) return in(1)->in(1); - return this; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *CastP2XNode::Value( PhaseTransform *phase ) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - if (t->base() == Type::RawPtr && t->singleton()) { - uintptr_t bits = (uintptr_t) t->is_rawptr()->get_con(); - return TypeX::make(bits); - } - return CastP2XNode::bottom_type(); -} - -Node *CastP2XNode::Ideal(PhaseGVN *phase, bool can_reshape) { - return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; -} - -//------------------------------Identity--------------------------------------- -Node *CastP2XNode::Identity( PhaseTransform *phase ) { - if (in(1)->Opcode() == Op_CastX2P) return in(1)->in(1); - return this; -} - - -//============================================================================= -//------------------------------Identity--------------------------------------- -// Remove redundant roundings -Node *RoundFloatNode::Identity( PhaseTransform *phase ) { - assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel"); - // Do not round constants - if (phase->type(in(1))->base() == Type::FloatCon) return in(1); - int op = in(1)->Opcode(); - // Redundant rounding - if( op == Op_RoundFloat ) return in(1); - // Already rounded - if( op == Op_Parm ) return in(1); - if( op == Op_LoadF ) return in(1); - return this; -} - -//------------------------------Value------------------------------------------ -const Type *RoundFloatNode::Value( PhaseTransform *phase ) const { - return phase->type( in(1) ); -} - -//============================================================================= -//------------------------------Identity--------------------------------------- -// Remove redundant roundings. Incoming arguments are already rounded. -Node *RoundDoubleNode::Identity( PhaseTransform *phase ) { - assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel"); - // Do not round constants - if (phase->type(in(1))->base() == Type::DoubleCon) return in(1); - int op = in(1)->Opcode(); - // Redundant rounding - if( op == Op_RoundDouble ) return in(1); - // Already rounded - if( op == Op_Parm ) return in(1); - if( op == Op_LoadD ) return in(1); - if( op == Op_ConvF2D ) return in(1); - if( op == Op_ConvI2D ) return in(1); - return this; -} - -//------------------------------Value------------------------------------------ -const Type *RoundDoubleNode::Value( PhaseTransform *phase ) const { - return phase->type( in(1) ); -} - - -//============================================================================= -// Do not allow value-numbering -uint Opaque1Node::hash() const { return NO_HASH; } -uint Opaque1Node::cmp( const Node &n ) const { - return (&n == this); // Always fail except on self -} - -//------------------------------Identity--------------------------------------- -// If _major_progress, then more loop optimizations follow. Do NOT remove -// the opaque Node until no more loop ops can happen. Note the timing of -// _major_progress; it's set in the major loop optimizations THEN comes the -// call to IterGVN and any chance of hitting this code. Hence there's no -// phase-ordering problem with stripping Opaque1 in IGVN followed by some -// more loop optimizations that require it. -Node *Opaque1Node::Identity( PhaseTransform *phase ) { - return phase->C->major_progress() ? this : in(1); -} - -//============================================================================= -// A node to prevent unwanted optimizations. Allows constant folding. Stops -// value-numbering, most Ideal calls or Identity functions. This Node is -// specifically designed to prevent the pre-increment value of a loop trip -// counter from being live out of the bottom of the loop (hence causing the -// pre- and post-increment values both being live and thus requiring an extra -// temp register and an extra move). If we "accidentally" optimize through -// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus -// it's OK to be slightly sloppy on optimizations here. - -// Do not allow value-numbering -uint Opaque2Node::hash() const { return NO_HASH; } -uint Opaque2Node::cmp( const Node &n ) const { - return (&n == this); // Always fail except on self -} - - -//------------------------------Value------------------------------------------ -const Type *MoveL2DNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeLong *tl = t->is_long(); - if( !tl->is_con() ) return bottom_type(); - JavaValue v; - v.set_jlong(tl->get_con()); - return TypeD::make( v.get_jdouble() ); -} - -//------------------------------Value------------------------------------------ -const Type *MoveI2FNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeInt *ti = t->is_int(); - if( !ti->is_con() ) return bottom_type(); - JavaValue v; - v.set_jint(ti->get_con()); - return TypeF::make( v.get_jfloat() ); -} - -//------------------------------Value------------------------------------------ -const Type *MoveF2INode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::FLOAT ) return TypeInt::INT; - const TypeF *tf = t->is_float_constant(); - JavaValue v; - v.set_jfloat(tf->getf()); - return TypeInt::make( v.get_jint() ); -} - -//------------------------------Value------------------------------------------ -const Type *MoveD2LNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::DOUBLE ) return TypeLong::LONG; - const TypeD *td = t->is_double_constant(); - JavaValue v; - v.set_jdouble(td->getd()); - return TypeLong::make( v.get_jlong() ); -} - -//------------------------------Value------------------------------------------ -const Type* CountLeadingZerosINode::Value(PhaseTransform* phase) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeInt* ti = t->isa_int(); - if (ti && ti->is_con()) { - jint i = ti->get_con(); - // HD, Figure 5-6 - if (i == 0) - return TypeInt::make(BitsPerInt); - int n = 1; - unsigned int x = i; - if (x >> 16 == 0) { n += 16; x <<= 16; } - if (x >> 24 == 0) { n += 8; x <<= 8; } - if (x >> 28 == 0) { n += 4; x <<= 4; } - if (x >> 30 == 0) { n += 2; x <<= 2; } - n -= x >> 31; - return TypeInt::make(n); - } - return TypeInt::INT; -} - -//------------------------------Value------------------------------------------ -const Type* CountLeadingZerosLNode::Value(PhaseTransform* phase) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeLong* tl = t->isa_long(); - if (tl && tl->is_con()) { - jlong l = tl->get_con(); - // HD, Figure 5-6 - if (l == 0) - return TypeInt::make(BitsPerLong); - int n = 1; - unsigned int x = (((julong) l) >> 32); - if (x == 0) { n += 32; x = (int) l; } - if (x >> 16 == 0) { n += 16; x <<= 16; } - if (x >> 24 == 0) { n += 8; x <<= 8; } - if (x >> 28 == 0) { n += 4; x <<= 4; } - if (x >> 30 == 0) { n += 2; x <<= 2; } - n -= x >> 31; - return TypeInt::make(n); - } - return TypeInt::INT; -} - -//------------------------------Value------------------------------------------ -const Type* CountTrailingZerosINode::Value(PhaseTransform* phase) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeInt* ti = t->isa_int(); - if (ti && ti->is_con()) { - jint i = ti->get_con(); - // HD, Figure 5-14 - int y; - if (i == 0) - return TypeInt::make(BitsPerInt); - int n = 31; - y = i << 16; if (y != 0) { n = n - 16; i = y; } - y = i << 8; if (y != 0) { n = n - 8; i = y; } - y = i << 4; if (y != 0) { n = n - 4; i = y; } - y = i << 2; if (y != 0) { n = n - 2; i = y; } - y = i << 1; if (y != 0) { n = n - 1; } - return TypeInt::make(n); - } - return TypeInt::INT; -} - -//------------------------------Value------------------------------------------ -const Type* CountTrailingZerosLNode::Value(PhaseTransform* phase) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeLong* tl = t->isa_long(); - if (tl && tl->is_con()) { - jlong l = tl->get_con(); - // HD, Figure 5-14 - int x, y; - if (l == 0) - return TypeInt::make(BitsPerLong); - int n = 63; - y = (int) l; if (y != 0) { n = n - 32; x = y; } else x = (((julong) l) >> 32); - y = x << 16; if (y != 0) { n = n - 16; x = y; } - y = x << 8; if (y != 0) { n = n - 8; x = y; } - y = x << 4; if (y != 0) { n = n - 4; x = y; } - y = x << 2; if (y != 0) { n = n - 2; x = y; } - y = x << 1; if (y != 0) { n = n - 1; } - return TypeInt::make(n); - } - return TypeInt::INT; -} diff --git a/hotspot/src/share/vm/opto/connode.hpp b/hotspot/src/share/vm/opto/connode.hpp index 03a096b2331..a25e4c128a0 100644 --- a/hotspot/src/share/vm/opto/connode.hpp +++ b/hotspot/src/share/vm/opto/connode.hpp @@ -139,617 +139,16 @@ public: }; -//------------------------------BinaryNode------------------------------------- -// Place holder for the 2 conditional inputs to a CMove. CMove needs 4 -// inputs: the Bool (for the lt/gt/eq/ne bits), the flags (result of some -// compare), and the 2 values to select between. The Matcher requires a -// binary tree so we break it down like this: -// (CMove (Binary bol cmp) (Binary src1 src2)) -class BinaryNode : public Node { -public: - BinaryNode( Node *n1, Node *n2 ) : Node(0,n1,n2) { } - virtual int Opcode() const; - virtual uint ideal_reg() const { return 0; } -}; - -//------------------------------CMoveNode-------------------------------------- -// Conditional move -class CMoveNode : public TypeNode { -public: - enum { Control, // When is it safe to do this cmove? - Condition, // Condition controlling the cmove - IfFalse, // Value if condition is false - IfTrue }; // Value if condition is true - CMoveNode( Node *bol, Node *left, Node *right, const Type *t ) : TypeNode(t,4) - { - init_class_id(Class_CMove); - // all inputs are nullified in Node::Node(int) - // init_req(Control,NULL); - init_req(Condition,bol); - init_req(IfFalse,left); - init_req(IfTrue,right); - } - 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 ); - // Helper function to spot cmove graph shapes - static Node *is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ); -}; - -//------------------------------CMoveDNode------------------------------------- -class CMoveDNode : public CMoveNode { -public: - CMoveDNode( Node *bol, Node *left, Node *right, const Type* t) : CMoveNode(bol,left,right,t){} - virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); -}; - -//------------------------------CMoveFNode------------------------------------- -class CMoveFNode : public CMoveNode { -public: - CMoveFNode( Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) {} - virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); -}; - -//------------------------------CMoveINode------------------------------------- -class CMoveINode : public CMoveNode { -public: - CMoveINode( Node *bol, Node *left, Node *right, const TypeInt *ti ) : CMoveNode(bol,left,right,ti){} - virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); -}; - -//------------------------------CMoveLNode------------------------------------- -class CMoveLNode : public CMoveNode { -public: - CMoveLNode(Node *bol, Node *left, Node *right, const TypeLong *tl ) : CMoveNode(bol,left,right,tl){} - virtual int Opcode() const; -}; - -//------------------------------CMovePNode------------------------------------- -class CMovePNode : public CMoveNode { -public: - CMovePNode( Node *c, Node *bol, Node *left, Node *right, const TypePtr* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); } - virtual int Opcode() const; -}; - -//------------------------------CMoveNNode------------------------------------- -class CMoveNNode : public CMoveNode { -public: - CMoveNNode( Node *c, Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); } - virtual int Opcode() const; -}; - -//------------------------------ConstraintCastNode----------------------------- -// cast to a different range -class ConstraintCastNode: public TypeNode { -public: - ConstraintCastNode (Node *n, const Type *t ): TypeNode(t,2) { - init_class_id(Class_ConstraintCast); - init_req(1, n); - } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual int Opcode() const; - virtual uint ideal_reg() const = 0; - virtual Node *Ideal_DU_postCCP( PhaseCCP * ); -}; - -//------------------------------CastIINode------------------------------------- -// cast integer to integer (different range) -class CastIINode: public ConstraintCastNode { -public: - CastIINode (Node *n, const Type *t ): ConstraintCastNode(n,t) {} - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//------------------------------CastPPNode------------------------------------- -// cast pointer to pointer (different type) -class CastPPNode: public ConstraintCastNode { -public: - CastPPNode (Node *n, const Type *t ): ConstraintCastNode(n, t) {} - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegP; } - virtual Node *Ideal_DU_postCCP( PhaseCCP * ); -}; - -//------------------------------CheckCastPPNode-------------------------------- -// for _checkcast, cast pointer to pointer (different type), without JOIN, -class CheckCastPPNode: public TypeNode { -public: - CheckCastPPNode( Node *c, Node *n, const Type *t ) : TypeNode(t,2) { - init_class_id(Class_CheckCastPP); - init_req(0, c); - init_req(1, n); - } - - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegP; } - // No longer remove CheckCast after CCP as it gives me a place to hang - // the proper address type - which is required to compute anti-deps. - //virtual Node *Ideal_DU_postCCP( PhaseCCP * ); -}; - - -//------------------------------EncodeNarrowPtr-------------------------------- -class EncodeNarrowPtrNode : public TypeNode { - protected: - EncodeNarrowPtrNode(Node* value, const Type* type): - TypeNode(type, 2) { - init_class_id(Class_EncodeNarrowPtr); - init_req(0, NULL); - init_req(1, value); - } - public: - virtual uint ideal_reg() const { return Op_RegN; } - virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); -}; - -//------------------------------EncodeP-------------------------------- -// Encodes an oop pointers into its compressed form -// Takes an extra argument which is the real heap base as a long which -// may be useful for code generation in the backend. -class EncodePNode : public EncodeNarrowPtrNode { - public: - EncodePNode(Node* value, const Type* type): - EncodeNarrowPtrNode(value, type) { - init_class_id(Class_EncodeP); - } - virtual int Opcode() const; - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; -}; - -//------------------------------EncodePKlass-------------------------------- -// Encodes a klass pointer into its compressed form -// Takes an extra argument which is the real heap base as a long which -// may be useful for code generation in the backend. -class EncodePKlassNode : public EncodeNarrowPtrNode { - public: - EncodePKlassNode(Node* value, const Type* type): - EncodeNarrowPtrNode(value, type) { - init_class_id(Class_EncodePKlass); - } - virtual int Opcode() const; - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; -}; - -//------------------------------DecodeNarrowPtr-------------------------------- -class DecodeNarrowPtrNode : public TypeNode { - protected: - DecodeNarrowPtrNode(Node* value, const Type* type): - TypeNode(type, 2) { - init_class_id(Class_DecodeNarrowPtr); - init_req(0, NULL); - init_req(1, value); - } - public: - virtual uint ideal_reg() const { return Op_RegP; } -}; - -//------------------------------DecodeN-------------------------------- -// Converts a narrow oop into a real oop ptr. -// Takes an extra argument which is the real heap base as a long which -// may be useful for code generation in the backend. -class DecodeNNode : public DecodeNarrowPtrNode { - public: - DecodeNNode(Node* value, const Type* type): - DecodeNarrowPtrNode(value, type) { - init_class_id(Class_DecodeN); - } - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); -}; - -//------------------------------DecodeNKlass-------------------------------- -// Converts a narrow klass pointer into a real klass ptr. -// Takes an extra argument which is the real heap base as a long which -// may be useful for code generation in the backend. -class DecodeNKlassNode : public DecodeNarrowPtrNode { - public: - DecodeNKlassNode(Node* value, const Type* type): - DecodeNarrowPtrNode(value, type) { - init_class_id(Class_DecodeNKlass); - } - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); -}; - -//------------------------------Conv2BNode------------------------------------- -// Convert int/pointer to a Boolean. Map zero to zero, all else to 1. -class Conv2BNode : public Node { -public: - Conv2BNode( Node *i ) : Node(0,i) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::BOOL; } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegI; } -}; - -// The conversions operations are all Alpha sorted. Please keep it that way! -//------------------------------ConvD2FNode------------------------------------ -// Convert double to float -class ConvD2FNode : public Node { -public: - ConvD2FNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual uint ideal_reg() const { return Op_RegF; } -}; - -//------------------------------ConvD2INode------------------------------------ -// Convert Double to Integer -class ConvD2INode : public Node { -public: - ConvD2INode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//------------------------------ConvD2LNode------------------------------------ -// Convert Double to Long -class ConvD2LNode : public Node { -public: - ConvD2LNode( Node *dbl ) : Node(0,dbl) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeLong::LONG; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegL; } -}; - -//------------------------------ConvF2DNode------------------------------------ -// Convert Float to a Double. -class ConvF2DNode : public Node { -public: - ConvF2DNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegD; } -}; - -//------------------------------ConvF2INode------------------------------------ -// Convert float to integer -class ConvF2INode : public Node { -public: - ConvF2INode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//------------------------------ConvF2LNode------------------------------------ -// Convert float to long -class ConvF2LNode : public Node { -public: - ConvF2LNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeLong::LONG; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegL; } -}; - -//------------------------------ConvI2DNode------------------------------------ -// Convert Integer to Double -class ConvI2DNode : public Node { -public: - ConvI2DNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegD; } -}; - -//------------------------------ConvI2FNode------------------------------------ -// Convert Integer to Float -class ConvI2FNode : public Node { -public: - ConvI2FNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual uint ideal_reg() const { return Op_RegF; } -}; - -//------------------------------ConvI2LNode------------------------------------ -// Convert integer to long -class ConvI2LNode : public TypeNode { -public: - ConvI2LNode(Node *in1, const TypeLong* t = TypeLong::INT) - : TypeNode(t, 2) - { init_req(1, in1); } - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegL; } -}; - -//------------------------------ConvL2DNode------------------------------------ -// Convert Long to Double -class ConvL2DNode : public Node { -public: - ConvL2DNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegD; } -}; - -//------------------------------ConvL2FNode------------------------------------ -// Convert Long to Float -class ConvL2FNode : public Node { -public: - ConvL2FNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegF; } -}; - -//------------------------------ConvL2INode------------------------------------ -// Convert long to integer -class ConvL2INode : public Node { -public: - ConvL2INode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//------------------------------CastX2PNode------------------------------------- -// convert a machine-pointer-sized integer to a raw pointer -class CastX2PNode : public Node { -public: - CastX2PNode( Node *n ) : Node(NULL, n) {} - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual Node *Identity( PhaseTransform *phase ); - virtual uint ideal_reg() const { return Op_RegP; } - virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } -}; - -//------------------------------CastP2XNode------------------------------------- -// Used in both 32-bit and 64-bit land. -// Used for card-marks and unsafe pointer math. -class CastP2XNode : public Node { -public: - CastP2XNode( Node *ctrl, Node *n ) : Node(ctrl, n) {} - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual Node *Identity( PhaseTransform *phase ); - virtual uint ideal_reg() const { return Op_RegX; } - virtual const Type *bottom_type() const { return TypeX_X; } - // Return false to keep node from moving away from an associated card mark. - virtual bool depends_only_on_test() const { return false; } -}; - //------------------------------ThreadLocalNode-------------------------------- // Ideal Node which returns the base of ThreadLocalStorage. class ThreadLocalNode : public Node { public: - ThreadLocalNode( ) : Node((Node*)Compile::current()->root()) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM;} - virtual uint ideal_reg() const { return Op_RegP; } -}; - -//------------------------------LoadReturnPCNode------------------------------- -class LoadReturnPCNode: public Node { -public: - LoadReturnPCNode(Node *c) : Node(c) { } - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegP; } + ThreadLocalNode( ) : Node((Node*)Compile::current()->root()) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM;} + virtual uint ideal_reg() const { return Op_RegP; } }; -//-----------------------------RoundFloatNode---------------------------------- -class RoundFloatNode: public Node { -public: - RoundFloatNode(Node* c, Node *in1): Node(c, in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual uint ideal_reg() const { return Op_RegF; } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; -}; - - -//-----------------------------RoundDoubleNode--------------------------------- -class RoundDoubleNode: public Node { -public: - RoundDoubleNode(Node* c, Node *in1): Node(c, in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual uint ideal_reg() const { return Op_RegD; } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; -}; - -//------------------------------Opaque1Node------------------------------------ -// A node to prevent unwanted optimizations. Allows constant folding. -// Stops value-numbering, Ideal calls or Identity functions. -class Opaque1Node : public Node { - virtual uint hash() const ; // { return NO_HASH; } - virtual uint cmp( const Node &n ) const; -public: - Opaque1Node( Compile* C, Node *n ) : Node(0,n) { - // Put it on the Macro nodes list to removed during macro nodes expansion. - init_flags(Flag_is_macro); - C->add_macro_node(this); - } - // Special version for the pre-loop to hold the original loop limit - // which is consumed by range check elimination. - Opaque1Node( Compile* C, Node *n, Node* orig_limit ) : Node(0,n,orig_limit) { - // Put it on the Macro nodes list to removed during macro nodes expansion. - init_flags(Flag_is_macro); - C->add_macro_node(this); - } - Node* original_loop_limit() { return req()==3 ? in(2) : NULL; } - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual Node *Identity( PhaseTransform *phase ); -}; - -//------------------------------Opaque2Node------------------------------------ -// A node to prevent unwanted optimizations. Allows constant folding. Stops -// value-numbering, most Ideal calls or Identity functions. This Node is -// specifically designed to prevent the pre-increment value of a loop trip -// counter from being live out of the bottom of the loop (hence causing the -// pre- and post-increment values both being live and thus requiring an extra -// temp register and an extra move). If we "accidentally" optimize through -// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus -// it's OK to be slightly sloppy on optimizations here. -class Opaque2Node : public Node { - virtual uint hash() const ; // { return NO_HASH; } - virtual uint cmp( const Node &n ) const; -public: - Opaque2Node( Compile* C, Node *n ) : Node(0,n) { - // Put it on the Macro nodes list to removed during macro nodes expansion. - init_flags(Flag_is_macro); - C->add_macro_node(this); - } - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } -}; - -//----------------------PartialSubtypeCheckNode-------------------------------- -// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass -// array for an instance of the superklass. Set a hidden internal cache on a -// hit (cache is checked with exposed code in gen_subtype_check()). Return -// not zero for a miss or zero for a hit. -class PartialSubtypeCheckNode : public Node { -public: - PartialSubtypeCheckNode(Node* c, Node* sub, Node* super) : Node(c,sub,super) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } - virtual uint ideal_reg() const { return Op_RegP; } -}; - -// -class MoveI2FNode : public Node { - public: - MoveI2FNode( Node *value ) : Node(0,value) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual uint ideal_reg() const { return Op_RegF; } - virtual const Type* Value( PhaseTransform *phase ) const; -}; - -class MoveL2DNode : public Node { - public: - MoveL2DNode( Node *value ) : Node(0,value) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual uint ideal_reg() const { return Op_RegD; } - virtual const Type* Value( PhaseTransform *phase ) const; -}; - -class MoveF2INode : public Node { - public: - MoveF2INode( Node *value ) : Node(0,value) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual uint ideal_reg() const { return Op_RegI; } - virtual const Type* Value( PhaseTransform *phase ) const; -}; - -class MoveD2LNode : public Node { - public: - MoveD2LNode( Node *value ) : Node(0,value) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeLong::LONG; } - virtual uint ideal_reg() const { return Op_RegL; } - virtual const Type* Value( PhaseTransform *phase ) const; -}; - -//---------- CountBitsNode ----------------------------------------------------- -class CountBitsNode : public Node { -public: - CountBitsNode(Node* in1) : Node(0, in1) {} - const Type* bottom_type() const { return TypeInt::INT; } - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//---------- CountLeadingZerosINode -------------------------------------------- -// Count leading zeros (0-bit count starting from MSB) of an integer. -class CountLeadingZerosINode : public CountBitsNode { -public: - CountLeadingZerosINode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; - virtual const Type* Value(PhaseTransform* phase) const; -}; - -//---------- CountLeadingZerosLNode -------------------------------------------- -// Count leading zeros (0-bit count starting from MSB) of a long. -class CountLeadingZerosLNode : public CountBitsNode { -public: - CountLeadingZerosLNode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; - virtual const Type* Value(PhaseTransform* phase) const; -}; - -//---------- CountTrailingZerosINode ------------------------------------------- -// Count trailing zeros (0-bit count starting from LSB) of an integer. -class CountTrailingZerosINode : public CountBitsNode { -public: - CountTrailingZerosINode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; - virtual const Type* Value(PhaseTransform* phase) const; -}; - -//---------- CountTrailingZerosLNode ------------------------------------------- -// Count trailing zeros (0-bit count starting from LSB) of a long. -class CountTrailingZerosLNode : public CountBitsNode { -public: - CountTrailingZerosLNode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; - virtual const Type* Value(PhaseTransform* phase) const; -}; - -//---------- PopCountINode ----------------------------------------------------- -// Population count (bit count) of an integer. -class PopCountINode : public CountBitsNode { -public: - PopCountINode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; -}; - -//---------- PopCountLNode ----------------------------------------------------- -// Population count (bit count) of a long. -class PopCountLNode : public CountBitsNode { -public: - PopCountLNode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; -}; #endif // SHARE_VM_OPTO_CONNODE_HPP diff --git a/hotspot/src/share/vm/opto/convertnode.cpp b/hotspot/src/share/vm/opto/convertnode.cpp new file mode 100644 index 00000000000..bf09d3fbb90 --- /dev/null +++ b/hotspot/src/share/vm/opto/convertnode.cpp @@ -0,0 +1,512 @@ +/* + * 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 "opto/addnode.hpp" +#include "opto/convertnode.hpp" +#include "opto/matcher.hpp" +#include "opto/phaseX.hpp" +#include "opto/subnode.hpp" + +//============================================================================= +//------------------------------Identity--------------------------------------- +Node *Conv2BNode::Identity( PhaseTransform *phase ) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + if( t == TypeInt::ZERO ) return in(1); + if( t == TypeInt::ONE ) return in(1); + if( t == TypeInt::BOOL ) return in(1); + return this; +} + +//------------------------------Value------------------------------------------ +const Type *Conv2BNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == TypeInt::ZERO ) return TypeInt::ZERO; + if( t == TypePtr::NULL_PTR ) return TypeInt::ZERO; + const TypePtr *tp = t->isa_ptr(); + if( tp != NULL ) { + if( tp->ptr() == TypePtr::AnyNull ) return Type::TOP; + if( tp->ptr() == TypePtr::Constant) return TypeInt::ONE; + if (tp->ptr() == TypePtr::NotNull) return TypeInt::ONE; + return TypeInt::BOOL; + } + if (t->base() != Type::Int) return TypeInt::BOOL; + const TypeInt *ti = t->is_int(); + if( ti->_hi < 0 || ti->_lo > 0 ) return TypeInt::ONE; + return TypeInt::BOOL; +} + + +// The conversions operations are all Alpha sorted. Please keep it that way! +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvD2FNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::DOUBLE ) return Type::FLOAT; + const TypeD *td = t->is_double_constant(); + return TypeF::make( (float)td->getd() ); +} + +//------------------------------Identity--------------------------------------- +// Float's can be converted to doubles with no loss of bits. Hence +// converting a float to a double and back to a float is a NOP. +Node *ConvD2FNode::Identity(PhaseTransform *phase) { + return (in(1)->Opcode() == Op_ConvF2D) ? in(1)->in(1) : this; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvD2INode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::DOUBLE ) return TypeInt::INT; + const TypeD *td = t->is_double_constant(); + return TypeInt::make( SharedRuntime::d2i( td->getd() ) ); +} + +//------------------------------Ideal------------------------------------------ +// If converting to an int type, skip any rounding nodes +Node *ConvD2INode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(1)->Opcode() == Op_RoundDouble ) + set_req(1,in(1)->in(1)); + return NULL; +} + +//------------------------------Identity--------------------------------------- +// Int's can be converted to doubles with no loss of bits. Hence +// converting an integer to a double and back to an integer is a NOP. +Node *ConvD2INode::Identity(PhaseTransform *phase) { + return (in(1)->Opcode() == Op_ConvI2D) ? in(1)->in(1) : this; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvD2LNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::DOUBLE ) return TypeLong::LONG; + const TypeD *td = t->is_double_constant(); + return TypeLong::make( SharedRuntime::d2l( td->getd() ) ); +} + +//------------------------------Identity--------------------------------------- +Node *ConvD2LNode::Identity(PhaseTransform *phase) { + // Remove ConvD2L->ConvL2D->ConvD2L sequences. + if( in(1) ->Opcode() == Op_ConvL2D && + in(1)->in(1)->Opcode() == Op_ConvD2L ) + return in(1)->in(1); + return this; +} + +//------------------------------Ideal------------------------------------------ +// If converting to an int type, skip any rounding nodes +Node *ConvD2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(1)->Opcode() == Op_RoundDouble ) + set_req(1,in(1)->in(1)); + return NULL; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvF2DNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::FLOAT ) return Type::DOUBLE; + const TypeF *tf = t->is_float_constant(); + return TypeD::make( (double)tf->getf() ); +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvF2INode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::FLOAT ) return TypeInt::INT; + const TypeF *tf = t->is_float_constant(); + return TypeInt::make( SharedRuntime::f2i( tf->getf() ) ); +} + +//------------------------------Identity--------------------------------------- +Node *ConvF2INode::Identity(PhaseTransform *phase) { + // Remove ConvF2I->ConvI2F->ConvF2I sequences. + if( in(1) ->Opcode() == Op_ConvI2F && + in(1)->in(1)->Opcode() == Op_ConvF2I ) + return in(1)->in(1); + return this; +} + +//------------------------------Ideal------------------------------------------ +// If converting to an int type, skip any rounding nodes +Node *ConvF2INode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(1)->Opcode() == Op_RoundFloat ) + set_req(1,in(1)->in(1)); + return NULL; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvF2LNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::FLOAT ) return TypeLong::LONG; + const TypeF *tf = t->is_float_constant(); + return TypeLong::make( SharedRuntime::f2l( tf->getf() ) ); +} + +//------------------------------Identity--------------------------------------- +Node *ConvF2LNode::Identity(PhaseTransform *phase) { + // Remove ConvF2L->ConvL2F->ConvF2L sequences. + if( in(1) ->Opcode() == Op_ConvL2F && + in(1)->in(1)->Opcode() == Op_ConvF2L ) + return in(1)->in(1); + return this; +} + +//------------------------------Ideal------------------------------------------ +// If converting to an int type, skip any rounding nodes +Node *ConvF2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(1)->Opcode() == Op_RoundFloat ) + set_req(1,in(1)->in(1)); + return NULL; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvI2DNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeInt *ti = t->is_int(); + if( ti->is_con() ) return TypeD::make( (double)ti->get_con() ); + return bottom_type(); +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvI2FNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeInt *ti = t->is_int(); + if( ti->is_con() ) return TypeF::make( (float)ti->get_con() ); + return bottom_type(); +} + +//------------------------------Identity--------------------------------------- +Node *ConvI2FNode::Identity(PhaseTransform *phase) { + // Remove ConvI2F->ConvF2I->ConvI2F sequences. + if( in(1) ->Opcode() == Op_ConvF2I && + in(1)->in(1)->Opcode() == Op_ConvI2F ) + return in(1)->in(1); + return this; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvI2LNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeInt *ti = t->is_int(); + const Type* tl = TypeLong::make(ti->_lo, ti->_hi, ti->_widen); + // Join my declared type against my incoming type. + tl = tl->filter(_type); + return tl; +} + +#ifdef _LP64 +static inline bool long_ranges_overlap(jlong lo1, jlong hi1, + jlong lo2, jlong hi2) { + // Two ranges overlap iff one range's low point falls in the other range. + return (lo2 <= lo1 && lo1 <= hi2) || (lo1 <= lo2 && lo2 <= hi1); +} +#endif + +//------------------------------Ideal------------------------------------------ +Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { + const TypeLong* this_type = this->type()->is_long(); + Node* this_changed = NULL; + + // If _major_progress, then more loop optimizations follow. Do NOT + // remove this node's type assertion until no more loop ops can happen. + // The progress bit is set in the major loop optimizations THEN comes the + // call to IterGVN and any chance of hitting this code. Cf. Opaque1Node. + if (can_reshape && !phase->C->major_progress()) { + const TypeInt* in_type = phase->type(in(1))->isa_int(); + if (in_type != NULL && this_type != NULL && + (in_type->_lo != this_type->_lo || + in_type->_hi != this_type->_hi)) { + // Although this WORSENS the type, it increases GVN opportunities, + // because I2L nodes with the same input will common up, regardless + // of slightly differing type assertions. Such slight differences + // arise routinely as a result of loop unrolling, so this is a + // post-unrolling graph cleanup. Choose a type which depends only + // on my input. (Exception: Keep a range assertion of >=0 or <0.) + jlong lo1 = this_type->_lo; + jlong hi1 = this_type->_hi; + int w1 = this_type->_widen; + if (lo1 != (jint)lo1 || + hi1 != (jint)hi1 || + lo1 > hi1) { + // Overflow leads to wraparound, wraparound leads to range saturation. + lo1 = min_jint; hi1 = max_jint; + } else if (lo1 >= 0) { + // Keep a range assertion of >=0. + lo1 = 0; hi1 = max_jint; + } else if (hi1 < 0) { + // Keep a range assertion of <0. + lo1 = min_jint; hi1 = -1; + } else { + lo1 = min_jint; hi1 = max_jint; + } + const TypeLong* wtype = TypeLong::make(MAX2((jlong)in_type->_lo, lo1), + MIN2((jlong)in_type->_hi, hi1), + MAX2((int)in_type->_widen, w1)); + if (wtype != type()) { + set_type(wtype); + // Note: this_type still has old type value, for the logic below. + this_changed = this; + } + } + } + +#ifdef _LP64 + // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) , + // but only if x and y have subranges that cannot cause 32-bit overflow, + // under the assumption that x+y is in my own subrange this->type(). + + // This assumption is based on a constraint (i.e., type assertion) + // established in Parse::array_addressing or perhaps elsewhere. + // This constraint has been adjoined to the "natural" type of + // the incoming argument in(0). We know (because of runtime + // checks) - that the result value I2L(x+y) is in the joined range. + // Hence we can restrict the incoming terms (x, y) to values such + // that their sum also lands in that range. + + // This optimization is useful only on 64-bit systems, where we hope + // the addition will end up subsumed in an addressing mode. + // It is necessary to do this when optimizing an unrolled array + // copy loop such as x[i++] = y[i++]. + + // On 32-bit systems, it's better to perform as much 32-bit math as + // possible before the I2L conversion, because 32-bit math is cheaper. + // There's no common reason to "leak" a constant offset through the I2L. + // Addressing arithmetic will not absorb it as part of a 64-bit AddL. + + Node* z = in(1); + int op = z->Opcode(); + if (op == Op_AddI || op == Op_SubI) { + Node* x = z->in(1); + Node* y = z->in(2); + assert (x != z && y != z, "dead loop in ConvI2LNode::Ideal"); + if (phase->type(x) == Type::TOP) return this_changed; + if (phase->type(y) == Type::TOP) return this_changed; + const TypeInt* tx = phase->type(x)->is_int(); + const TypeInt* ty = phase->type(y)->is_int(); + const TypeLong* tz = this_type; + jlong xlo = tx->_lo; + jlong xhi = tx->_hi; + jlong ylo = ty->_lo; + jlong yhi = ty->_hi; + jlong zlo = tz->_lo; + jlong zhi = tz->_hi; + jlong vbit = CONST64(1) << BitsPerInt; + int widen = MAX2(tx->_widen, ty->_widen); + if (op == Op_SubI) { + jlong ylo0 = ylo; + ylo = -yhi; + yhi = -ylo0; + } + // See if x+y can cause positive overflow into z+2**32 + if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo+vbit, zhi+vbit)) { + return this_changed; + } + // See if x+y can cause negative overflow into z-2**32 + if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo-vbit, zhi-vbit)) { + return this_changed; + } + // Now it's always safe to assume x+y does not overflow. + // This is true even if some pairs x,y might cause overflow, as long + // as that overflow value cannot fall into [zlo,zhi]. + + // Confident that the arithmetic is "as if infinite precision", + // we can now use z's range to put constraints on those of x and y. + // The "natural" range of x [xlo,xhi] can perhaps be narrowed to a + // more "restricted" range by intersecting [xlo,xhi] with the + // range obtained by subtracting y's range from the asserted range + // of the I2L conversion. Here's the interval arithmetic algebra: + // x == z-y == [zlo,zhi]-[ylo,yhi] == [zlo,zhi]+[-yhi,-ylo] + // => x in [zlo-yhi, zhi-ylo] + // => x in [zlo-yhi, zhi-ylo] INTERSECT [xlo,xhi] + // => x in [xlo MAX zlo-yhi, xhi MIN zhi-ylo] + jlong rxlo = MAX2(xlo, zlo - yhi); + jlong rxhi = MIN2(xhi, zhi - ylo); + // And similarly, x changing place with y: + jlong rylo = MAX2(ylo, zlo - xhi); + jlong ryhi = MIN2(yhi, zhi - xlo); + if (rxlo > rxhi || rylo > ryhi) { + return this_changed; // x or y is dying; don't mess w/ it + } + if (op == Op_SubI) { + jlong rylo0 = rylo; + rylo = -ryhi; + ryhi = -rylo0; + } + + Node* cx = phase->transform( new (phase->C) ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) ); + Node* cy = phase->transform( new (phase->C) ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) ); + switch (op) { + case Op_AddI: return new (phase->C) AddLNode(cx, cy); + case Op_SubI: return new (phase->C) SubLNode(cx, cy); + default: ShouldNotReachHere(); + } + } +#endif //_LP64 + + return this_changed; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvL2DNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeLong *tl = t->is_long(); + if( tl->is_con() ) return TypeD::make( (double)tl->get_con() ); + return bottom_type(); +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvL2FNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeLong *tl = t->is_long(); + if( tl->is_con() ) return TypeF::make( (float)tl->get_con() ); + return bottom_type(); +} + +//============================================================================= +//----------------------------Identity----------------------------------------- +Node *ConvL2INode::Identity( PhaseTransform *phase ) { + // Convert L2I(I2L(x)) => x + if (in(1)->Opcode() == Op_ConvI2L) return in(1)->in(1); + return this; +} + +//------------------------------Value------------------------------------------ +const Type *ConvL2INode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeLong *tl = t->is_long(); + if (tl->is_con()) + // Easy case. + return TypeInt::make((jint)tl->get_con()); + return bottom_type(); +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Blow off prior masking to int +Node *ConvL2INode::Ideal(PhaseGVN *phase, bool can_reshape) { + Node *andl = in(1); + uint andl_op = andl->Opcode(); + if( andl_op == Op_AndL ) { + // Blow off prior masking to int + if( phase->type(andl->in(2)) == TypeLong::make( 0xFFFFFFFF ) ) { + set_req(1,andl->in(1)); + return this; + } + } + + // Swap with a prior add: convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y)) + // This replaces an 'AddL' with an 'AddI'. + if( andl_op == Op_AddL ) { + // Don't do this for nodes which have more than one user since + // we'll end up computing the long add anyway. + if (andl->outcnt() > 1) return NULL; + + Node* x = andl->in(1); + Node* y = andl->in(2); + assert( x != andl && y != andl, "dead loop in ConvL2INode::Ideal" ); + if (phase->type(x) == Type::TOP) return NULL; + if (phase->type(y) == Type::TOP) return NULL; + Node *add1 = phase->transform(new (phase->C) ConvL2INode(x)); + Node *add2 = phase->transform(new (phase->C) ConvL2INode(y)); + return new (phase->C) AddINode(add1,add2); + } + + // Disable optimization: LoadL->ConvL2I ==> LoadI. + // It causes problems (sizes of Load and Store nodes do not match) + // in objects initialization code and Escape Analysis. + return NULL; +} + + + +//============================================================================= +//------------------------------Identity--------------------------------------- +// Remove redundant roundings +Node *RoundFloatNode::Identity( PhaseTransform *phase ) { + assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel"); + // Do not round constants + if (phase->type(in(1))->base() == Type::FloatCon) return in(1); + int op = in(1)->Opcode(); + // Redundant rounding + if( op == Op_RoundFloat ) return in(1); + // Already rounded + if( op == Op_Parm ) return in(1); + if( op == Op_LoadF ) return in(1); + return this; +} + +//------------------------------Value------------------------------------------ +const Type *RoundFloatNode::Value( PhaseTransform *phase ) const { + return phase->type( in(1) ); +} + +//============================================================================= +//------------------------------Identity--------------------------------------- +// Remove redundant roundings. Incoming arguments are already rounded. +Node *RoundDoubleNode::Identity( PhaseTransform *phase ) { + assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel"); + // Do not round constants + if (phase->type(in(1))->base() == Type::DoubleCon) return in(1); + int op = in(1)->Opcode(); + // Redundant rounding + if( op == Op_RoundDouble ) return in(1); + // Already rounded + if( op == Op_Parm ) return in(1); + if( op == Op_LoadD ) return in(1); + if( op == Op_ConvF2D ) return in(1); + if( op == Op_ConvI2D ) return in(1); + return this; +} + +//------------------------------Value------------------------------------------ +const Type *RoundDoubleNode::Value( PhaseTransform *phase ) const { + return phase->type( in(1) ); +} + + diff --git a/hotspot/src/share/vm/opto/convertnode.hpp b/hotspot/src/share/vm/opto/convertnode.hpp new file mode 100644 index 00000000000..ff19db51e55 --- /dev/null +++ b/hotspot/src/share/vm/opto/convertnode.hpp @@ -0,0 +1,215 @@ +/* + * 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_OPTO_CONVERTNODE_HPP +#define SHARE_VM_OPTO_CONVERTNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + + +//------------------------------Conv2BNode------------------------------------- +// Convert int/pointer to a Boolean. Map zero to zero, all else to 1. +class Conv2BNode : public Node { + public: + Conv2BNode( Node *i ) : Node(0,i) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::BOOL; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegI; } +}; + +// The conversions operations are all Alpha sorted. Please keep it that way! +//------------------------------ConvD2FNode------------------------------------ +// Convert double to float +class ConvD2FNode : public Node { + public: + ConvD2FNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual uint ideal_reg() const { return Op_RegF; } +}; + +//------------------------------ConvD2INode------------------------------------ +// Convert Double to Integer +class ConvD2INode : public Node { + public: + ConvD2INode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------ConvD2LNode------------------------------------ +// Convert Double to Long +class ConvD2LNode : public Node { + public: + ConvD2LNode( Node *dbl ) : Node(0,dbl) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeLong::LONG; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegL; } +}; + +//------------------------------ConvF2DNode------------------------------------ +// Convert Float to a Double. +class ConvF2DNode : public Node { + public: + ConvF2DNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegD; } +}; + +//------------------------------ConvF2INode------------------------------------ +// Convert float to integer +class ConvF2INode : public Node { + public: + ConvF2INode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------ConvF2LNode------------------------------------ +// Convert float to long +class ConvF2LNode : public Node { + public: + ConvF2LNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeLong::LONG; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegL; } +}; + +//------------------------------ConvI2DNode------------------------------------ +// Convert Integer to Double +class ConvI2DNode : public Node { + public: + ConvI2DNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegD; } +}; + +//------------------------------ConvI2FNode------------------------------------ +// Convert Integer to Float +class ConvI2FNode : public Node { + public: + ConvI2FNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual uint ideal_reg() const { return Op_RegF; } +}; + +//------------------------------ConvI2LNode------------------------------------ +// Convert integer to long +class ConvI2LNode : public TypeNode { + public: + ConvI2LNode(Node *in1, const TypeLong* t = TypeLong::INT) + : TypeNode(t, 2) + { init_req(1, in1); } + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegL; } +}; + +//------------------------------ConvL2DNode------------------------------------ +// Convert Long to Double +class ConvL2DNode : public Node { + public: + ConvL2DNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegD; } +}; + +//------------------------------ConvL2FNode------------------------------------ +// Convert Long to Float +class ConvL2FNode : public Node { + public: + ConvL2FNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegF; } +}; + +//------------------------------ConvL2INode------------------------------------ +// Convert long to integer +class ConvL2INode : public Node { + public: + ConvL2INode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//-----------------------------RoundFloatNode---------------------------------- +class RoundFloatNode: public Node { + public: + RoundFloatNode(Node* c, Node *in1): Node(c, in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual uint ideal_reg() const { return Op_RegF; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; +}; + + +//-----------------------------RoundDoubleNode--------------------------------- +class RoundDoubleNode: public Node { + public: + RoundDoubleNode(Node* c, Node *in1): Node(c, in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual uint ideal_reg() const { return Op_RegD; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; +}; + + +#endif // SHARE_VM_OPTO_CONVERTNODE_HPP diff --git a/hotspot/src/share/vm/opto/countbitsnode.cpp b/hotspot/src/share/vm/opto/countbitsnode.cpp new file mode 100644 index 00000000000..152c7699ca7 --- /dev/null +++ b/hotspot/src/share/vm/opto/countbitsnode.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 "opto/countbitsnode.hpp" +#include "opto/opcodes.hpp" +#include "opto/phaseX.hpp" +#include "opto/type.hpp" + +//------------------------------Value------------------------------------------ +const Type* CountLeadingZerosINode::Value(PhaseTransform* phase) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + const TypeInt* ti = t->isa_int(); + if (ti && ti->is_con()) { + jint i = ti->get_con(); + // HD, Figure 5-6 + if (i == 0) + return TypeInt::make(BitsPerInt); + int n = 1; + unsigned int x = i; + if (x >> 16 == 0) { n += 16; x <<= 16; } + if (x >> 24 == 0) { n += 8; x <<= 8; } + if (x >> 28 == 0) { n += 4; x <<= 4; } + if (x >> 30 == 0) { n += 2; x <<= 2; } + n -= x >> 31; + return TypeInt::make(n); + } + return TypeInt::INT; +} + +//------------------------------Value------------------------------------------ +const Type* CountLeadingZerosLNode::Value(PhaseTransform* phase) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + const TypeLong* tl = t->isa_long(); + if (tl && tl->is_con()) { + jlong l = tl->get_con(); + // HD, Figure 5-6 + if (l == 0) + return TypeInt::make(BitsPerLong); + int n = 1; + unsigned int x = (((julong) l) >> 32); + if (x == 0) { n += 32; x = (int) l; } + if (x >> 16 == 0) { n += 16; x <<= 16; } + if (x >> 24 == 0) { n += 8; x <<= 8; } + if (x >> 28 == 0) { n += 4; x <<= 4; } + if (x >> 30 == 0) { n += 2; x <<= 2; } + n -= x >> 31; + return TypeInt::make(n); + } + return TypeInt::INT; +} + +//------------------------------Value------------------------------------------ +const Type* CountTrailingZerosINode::Value(PhaseTransform* phase) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + const TypeInt* ti = t->isa_int(); + if (ti && ti->is_con()) { + jint i = ti->get_con(); + // HD, Figure 5-14 + int y; + if (i == 0) + return TypeInt::make(BitsPerInt); + int n = 31; + y = i << 16; if (y != 0) { n = n - 16; i = y; } + y = i << 8; if (y != 0) { n = n - 8; i = y; } + y = i << 4; if (y != 0) { n = n - 4; i = y; } + y = i << 2; if (y != 0) { n = n - 2; i = y; } + y = i << 1; if (y != 0) { n = n - 1; } + return TypeInt::make(n); + } + return TypeInt::INT; +} + +//------------------------------Value------------------------------------------ +const Type* CountTrailingZerosLNode::Value(PhaseTransform* phase) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + const TypeLong* tl = t->isa_long(); + if (tl && tl->is_con()) { + jlong l = tl->get_con(); + // HD, Figure 5-14 + int x, y; + if (l == 0) + return TypeInt::make(BitsPerLong); + int n = 63; + y = (int) l; if (y != 0) { n = n - 32; x = y; } else x = (((julong) l) >> 32); + y = x << 16; if (y != 0) { n = n - 16; x = y; } + y = x << 8; if (y != 0) { n = n - 8; x = y; } + y = x << 4; if (y != 0) { n = n - 4; x = y; } + y = x << 2; if (y != 0) { n = n - 2; x = y; } + y = x << 1; if (y != 0) { n = n - 1; } + return TypeInt::make(n); + } + return TypeInt::INT; +} diff --git a/hotspot/src/share/vm/opto/countbitsnode.hpp b/hotspot/src/share/vm/opto/countbitsnode.hpp new file mode 100644 index 00000000000..0ead252ee89 --- /dev/null +++ b/hotspot/src/share/vm/opto/countbitsnode.hpp @@ -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. + * + */ + +#ifndef SHARE_VM_OPTO_COUNTBITSNODE_HPP +#define SHARE_VM_OPTO_COUNTBITSNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + +class PhaseTransform; + +//---------- CountBitsNode ----------------------------------------------------- +class CountBitsNode : public Node { + public: + CountBitsNode(Node* in1) : Node(0, in1) {} + const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//---------- CountLeadingZerosINode -------------------------------------------- +// Count leading zeros (0-bit count starting from MSB) of an integer. +class CountLeadingZerosINode : public CountBitsNode { + public: + CountLeadingZerosINode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; + virtual const Type* Value(PhaseTransform* phase) const; +}; + +//---------- CountLeadingZerosLNode -------------------------------------------- +// Count leading zeros (0-bit count starting from MSB) of a long. +class CountLeadingZerosLNode : public CountBitsNode { + public: + CountLeadingZerosLNode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; + virtual const Type* Value(PhaseTransform* phase) const; +}; + +//---------- CountTrailingZerosINode ------------------------------------------- +// Count trailing zeros (0-bit count starting from LSB) of an integer. +class CountTrailingZerosINode : public CountBitsNode { + public: + CountTrailingZerosINode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; + virtual const Type* Value(PhaseTransform* phase) const; +}; + +//---------- CountTrailingZerosLNode ------------------------------------------- +// Count trailing zeros (0-bit count starting from LSB) of a long. +class CountTrailingZerosLNode : public CountBitsNode { + public: + CountTrailingZerosLNode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; + virtual const Type* Value(PhaseTransform* phase) const; +}; + +//---------- PopCountINode ----------------------------------------------------- +// Population count (bit count) of an integer. +class PopCountINode : public CountBitsNode { + public: + PopCountINode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; +}; + +//---------- PopCountLNode ----------------------------------------------------- +// Population count (bit count) of a long. +class PopCountLNode : public CountBitsNode { + public: + PopCountLNode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; +}; + + +#endif // SHARE_VM_OPTO_COUNTBITSNODE_HPP diff --git a/hotspot/src/share/vm/opto/divnode.cpp b/hotspot/src/share/vm/opto/divnode.cpp index 24f4fcb7e9e..f577c8b5125 100644 --- a/hotspot/src/share/vm/opto/divnode.cpp +++ b/hotspot/src/share/vm/opto/divnode.cpp @@ -26,8 +26,10 @@ #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/machnode.hpp" +#include "opto/movenode.hpp" #include "opto/matcher.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index d56f460ea6d..4eb462d9c5e 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -31,6 +31,7 @@ #include "interpreter/linkResolver.hpp" #include "opto/addnode.hpp" #include "opto/callGenerator.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" @@ -249,8 +250,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool } CallGenerator* miss_cg; Deoptimization::DeoptReason reason = morphism == 2 ? - Deoptimization::Reason_bimorphic : - (speculative_receiver_type == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check); + Deoptimization::Reason_bimorphic : Deoptimization::reason_class_check(speculative_receiver_type != NULL); if ((morphism == 1 || (morphism == 2 && next_hit_cg != NULL)) && !too_many_traps(jvms->method(), jvms->bci(), reason) ) { @@ -631,13 +631,7 @@ void Parse::do_call() { } BasicType ct = ctype->basic_type(); if (ct == T_OBJECT || ct == T_ARRAY) { - ciKlass* better_type = method()->return_profiled_type(bci()); - if (UseTypeSpeculation && better_type != NULL) { - // If profiling reports a single type for the return value, - // feed it to the type system so it can propagate it as a - // speculative type - record_profile_for_speculation(stack(sp()-1), better_type); - } + record_profiled_return_for_speculation(); } } diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 028aa2467f2..286216ca7b5 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -33,6 +33,7 @@ #include "opto/compile.hpp" #include "opto/escape.hpp" #include "opto/phaseX.hpp" +#include "opto/movenode.hpp" #include "opto/rootnode.hpp" ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) : diff --git a/hotspot/src/share/vm/opto/generateOptoStub.cpp b/hotspot/src/share/vm/opto/generateOptoStub.cpp index ff501f2bee4..f75110842b9 100644 --- a/hotspot/src/share/vm/opto/generateOptoStub.cpp +++ b/hotspot/src/share/vm/opto/generateOptoStub.cpp @@ -27,7 +27,7 @@ #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" #include "opto/compile.hpp" -#include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/locknode.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index d9fcfb2cb91..3a171e9e7a2 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -30,10 +30,14 @@ #include "memory/barrierSet.hpp" #include "memory/cardTableModRefBS.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" +#include "opto/convertnode.hpp" #include "opto/graphKit.hpp" #include "opto/idealKit.hpp" +#include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/machnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" @@ -612,10 +616,10 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) { // Usual case: Bail to interpreter. // Reserve the right to recompile if we haven't seen anything yet. - assert(!Deoptimization::reason_is_speculate(reason), "unsupported"); + ciMethod* m = Deoptimization::reason_is_speculate(reason) ? C->method() : NULL; Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile; if (treat_throw_as_hot - && (method()->method_data()->trap_recompiled_at(bci(), NULL) + && (method()->method_data()->trap_recompiled_at(bci(), m) || C->too_many_traps(reason))) { // We cannot afford to take more traps here. Suffer in the interpreter. if (C->log() != NULL) @@ -1125,6 +1129,17 @@ Node* GraphKit::ConvI2L(Node* offset) { } return _gvn.transform( new (C) ConvI2LNode(offset)); } + +Node* GraphKit::ConvI2UL(Node* offset) { + juint offset_con = (juint) find_int_con(offset, Type::OffsetBot); + if (offset_con != (juint) Type::OffsetBot) { + return longcon((julong) offset_con); + } + Node* conv = _gvn.transform( new (C) ConvI2LNode(offset)); + Node* mask = _gvn.transform( ConLNode::make(C, (julong) max_juint) ); + return _gvn.transform( new (C) AndLNode(conv, mask) ); +} + Node* GraphKit::ConvL2I(Node* offset) { // short-circuit a common case jlong offset_con = find_long_con(offset, (jlong)Type::OffsetBot); @@ -1170,7 +1185,8 @@ extern int explicit_null_checks_inserted, Node* GraphKit::null_check_common(Node* value, BasicType type, // optional arguments for variations: bool assert_null, - Node* *null_control) { + Node* *null_control, + bool speculative) { assert(!assert_null || null_control == NULL, "not both at once"); if (stopped()) return top(); if (!GenerateCompilerNullChecks && !assert_null && null_control == NULL) { @@ -1280,13 +1296,13 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // Branch to failure if null float ok_prob = PROB_MAX; // a priori estimate: nulls never happen Deoptimization::DeoptReason reason; - if (assert_null) + if (assert_null) { reason = Deoptimization::Reason_null_assert; - else if (type == T_OBJECT) - reason = Deoptimization::Reason_null_check; - else + } else if (type == T_OBJECT) { + reason = Deoptimization::reason_null_check(speculative); + } else { reason = Deoptimization::Reason_div0_check; - + } // %%% Since Reason_unhandled is not recorded on a per-bytecode basis, // ciMethodData::has_trap_at will return a conservative -1 if any // must-be-null assertion has failed. This could cause performance @@ -2109,21 +2125,36 @@ void GraphKit::round_double_arguments(ciMethod* dest_method) { * * @param n node that the type applies to * @param exact_kls type from profiling + * @param maybe_null did profiling see null? * * @return node with improved type */ -Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) { +Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls, bool maybe_null) { const Type* current_type = _gvn.type(n); assert(UseTypeSpeculation, "type speculation must be on"); - const TypeOopPtr* speculative = current_type->speculative(); + const TypePtr* speculative = current_type->speculative(); + // Should the klass from the profile be recorded in the speculative type? if (current_type->would_improve_type(exact_kls, jvms()->depth())) { const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls); const TypeOopPtr* xtype = tklass->as_instance_type(); assert(xtype->klass_is_exact(), "Should be exact"); + // Any reason to believe n is not null (from this profiling or a previous one)? + const TypePtr* ptr = (maybe_null && current_type->speculative_maybe_null()) ? TypePtr::BOTTOM : TypePtr::NOTNULL; // record the new speculative type's depth - speculative = xtype->with_inline_depth(jvms()->depth()); + speculative = xtype->cast_to_ptr_type(ptr->ptr())->is_ptr(); + speculative = speculative->with_inline_depth(jvms()->depth()); + } else if (current_type->would_improve_ptr(maybe_null)) { + // Profiling report that null was never seen so we can change the + // speculative type to non null ptr. + assert(!maybe_null, "nothing to improve"); + if (speculative == NULL) { + speculative = TypePtr::NOTNULL; + } else { + const TypePtr* ptr = TypePtr::NOTNULL; + speculative = speculative->cast_to_ptr_type(ptr->ptr())->is_ptr(); + } } if (speculative != current_type->speculative()) { @@ -2156,7 +2187,15 @@ Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) { return n; } ciKlass* exact_kls = profile_has_unique_klass(); - return record_profile_for_speculation(n, exact_kls); + bool maybe_null = true; + if (java_bc() == Bytecodes::_checkcast || + java_bc() == Bytecodes::_instanceof || + java_bc() == Bytecodes::_aastore) { + ciProfileData* data = method()->method_data()->bci_to_data(bci()); + bool maybe_null = data == NULL ? true : data->as_BitData()->null_seen(); + } + return record_profile_for_speculation(n, exact_kls, maybe_null); + return n; } /** @@ -2176,9 +2215,10 @@ void GraphKit::record_profiled_arguments_for_speculation(ciMethod* dest_method, for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) { const Type *targ = tf->_domain->field_at(j + TypeFunc::Parms); if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) { - ciKlass* better_type = method()->argument_profiled_type(bci(), i); - if (better_type != NULL) { - record_profile_for_speculation(argument(j), better_type); + bool maybe_null = true; + ciKlass* better_type = NULL; + if (method()->argument_profiled_type(bci(), i, better_type, maybe_null)) { + record_profile_for_speculation(argument(j), better_type, maybe_null); } i++; } @@ -2195,15 +2235,34 @@ void GraphKit::record_profiled_parameters_for_speculation() { } for (int i = 0, j = 0; i < method()->arg_size() ; i++) { if (_gvn.type(local(i))->isa_oopptr()) { - ciKlass* better_type = method()->parameter_profiled_type(j); - if (better_type != NULL) { - record_profile_for_speculation(local(i), better_type); + bool maybe_null = true; + ciKlass* better_type = NULL; + if (method()->parameter_profiled_type(j, better_type, maybe_null)) { + record_profile_for_speculation(local(i), better_type, maybe_null); } j++; } } } +/** + * Record profiling data from return value profiling at an invoke with + * the type system so that it can propagate it (speculation) + */ +void GraphKit::record_profiled_return_for_speculation() { + if (!UseTypeSpeculation) { + return; + } + bool maybe_null = true; + ciKlass* better_type = NULL; + if (method()->return_profiled_type(bci(), better_type, maybe_null)) { + // If profiling reports a single type for the return value, + // feed it to the type system so it can propagate it as a + // speculative type + record_profile_for_speculation(stack(sp()-1), better_type, maybe_null); + } +} + void GraphKit::round_double_result(ciMethod* dest_method) { // A non-strict method may return a double value which has an extended // exponent, but this must not be visible in a caller which is 'strict' @@ -2283,10 +2342,12 @@ Node* GraphKit::dstore_rounding(Node* n) { // Null check oop. Set null-path control into Region in slot 3. // Make a cast-not-nullness use the other not-null control. Return cast. Node* GraphKit::null_check_oop(Node* value, Node* *null_control, - bool never_see_null, bool safe_for_replace) { + bool never_see_null, + bool safe_for_replace, + bool speculative) { // Initial NULL check taken path (*null_control) = top(); - Node* cast = null_check_common(value, T_OBJECT, false, null_control); + Node* cast = null_check_common(value, T_OBJECT, false, null_control, speculative); // Generate uncommon_trap: if (never_see_null && (*null_control) != top()) { @@ -2297,7 +2358,8 @@ Node* GraphKit::null_check_oop(Node* value, Node* *null_control, PreserveJVMState pjvms(this); set_control(*null_control); replace_in_map(value, null()); - uncommon_trap(Deoptimization::Reason_null_check, + Deoptimization::DeoptReason reason = Deoptimization::reason_null_check(speculative); + uncommon_trap(reason, Deoptimization::Action_make_not_entrant); (*null_control) = top(); // NULL path is dead } @@ -2721,11 +2783,16 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass, // recompile; the offending check will be recompiled to handle NULLs. // If we see several offending BCIs, then all checks in the // method will be recompiled. -bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) { +bool GraphKit::seems_never_null(Node* obj, ciProfileData* data, bool& speculating) { + speculating = !_gvn.type(obj)->speculative_maybe_null(); + Deoptimization::DeoptReason reason = Deoptimization::reason_null_check(speculating); if (UncommonNullCast // Cutout for this technique && obj != null() // And not the -Xcomp stupid case? - && !too_many_traps(Deoptimization::Reason_null_check) + && !too_many_traps(reason) ) { + if (speculating) { + return true; + } if (data == NULL) // Edge case: no mature data. Be optimistic here. return true; @@ -2735,6 +2802,7 @@ bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) { java_bc() == Bytecodes::_aastore, "MDO must collect null_seen bit here"); return !data->as_BitData()->null_seen(); } + speculating = false; return false; } @@ -2747,7 +2815,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj, bool safe_for_replace) { if (!UseTypeProfile || !TypeProfileCasts) return NULL; - Deoptimization::DeoptReason reason = spec_klass == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check; + Deoptimization::DeoptReason reason = Deoptimization::reason_class_check(spec_klass != NULL); // Make sure we haven't already deoptimized from this tactic. if (too_many_traps(reason)) @@ -2800,7 +2868,7 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj, // type == NULL if profiling tells us this object is always null if (type != NULL) { Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check; - Deoptimization::DeoptReason null_reason = Deoptimization::Reason_null_check; + Deoptimization::DeoptReason null_reason = Deoptimization::Reason_speculate_null_check; if (!too_many_traps(null_reason) && !too_many_traps(class_reason)) { Node* not_null_obj = NULL; @@ -2808,7 +2876,7 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj, // there's no need for a null check if (!not_null) { Node* null_ctl = top(); - not_null_obj = null_check_oop(obj, &null_ctl, true, true); + not_null_obj = null_check_oop(obj, &null_ctl, true, true, true); assert(null_ctl->is_top(), "no null control here"); } else { not_null_obj = obj; @@ -2856,12 +2924,13 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac if (java_bc() == Bytecodes::_instanceof) { // Only for the bytecode data = method()->method_data()->bci_to_data(bci()); } + bool speculative_not_null = false; bool never_see_null = (ProfileDynamicTypes // aggressive use of profile - && seems_never_null(obj, data)); + && seems_never_null(obj, data, speculative_not_null)); // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); - Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace); + Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null); // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a NULL? @@ -2984,12 +3053,13 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, C->set_has_split_ifs(true); // Has chance for split-if optimization // Use null-cast information if it is available + bool speculative_not_null = false; bool never_see_null = ((failure_control == NULL) // regular case only - && seems_never_null(obj, data)); + && seems_never_null(obj, data, speculative_not_null)); // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); - Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace); + Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null); // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a NULL? @@ -3151,10 +3221,14 @@ FastLockNode* GraphKit::shared_lock(Node* obj) { Node* mem = reset_memory(); FastLockNode * flock = _gvn.transform(new (C) FastLockNode(0, obj, box) )->as_FastLock(); - if (PrintPreciseBiasedLockingStatistics) { + if (UseBiasedLocking && PrintPreciseBiasedLockingStatistics) { // Create the counters for this fast lock. flock->create_lock_counter(sync_jvms()); // sync_jvms used to get current bci } + + // Create the rtm counters for this fast lock if needed. + flock->create_rtm_lock_counter(sync_jvms()); // sync_jvms used to get current bci + // Add monitor to debug info for the slow path. If we block inside the // slow path and de-opt, we need the monitor hanging around map()->push_monitor( flock ); diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index fbbf8c9aa86..0d2c6b07a81 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -338,6 +338,7 @@ class GraphKit : public Phase { // Convert between int and long, and size_t. // (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.) Node* ConvI2L(Node* offset); + Node* ConvI2UL(Node* offset); Node* ConvL2I(Node* offset); // Find out the klass of an object. Node* load_object_klass(Node* object); @@ -350,9 +351,11 @@ class GraphKit : public Phase { // Return the value cast to not-null. // Be clever about equivalent dominating null checks. Node* null_check_common(Node* value, BasicType type, - bool assert_null = false, Node* *null_control = NULL); + bool assert_null = false, + Node* *null_control = NULL, + bool speculative = false); Node* null_check(Node* value, BasicType type = T_OBJECT) { - return null_check_common(value, type); + return null_check_common(value, type, false, NULL, !_gvn.type(value)->speculative_maybe_null()); } Node* null_check_receiver() { assert(argument(0)->bottom_type()->isa_ptr(), "must be"); @@ -381,10 +384,12 @@ class GraphKit : public Phase { // If safe_for_replace, then we can replace the value with the cast // in the parsing map (the cast is guaranteed to dominate the map) Node* null_check_oop(Node* value, Node* *null_control, - bool never_see_null = false, bool safe_for_replace = false); + bool never_see_null = false, + bool safe_for_replace = false, + bool speculative = false); // Check the null_seen bit. - bool seems_never_null(Node* obj, ciProfileData* data); + bool seems_never_null(Node* obj, ciProfileData* data, bool& speculating); // Check for unique class for receiver at call ciKlass* profile_has_unique_klass() { @@ -398,10 +403,11 @@ class GraphKit : public Phase { } // record type from profiling with the type system - Node* record_profile_for_speculation(Node* n, ciKlass* exact_kls); - Node* record_profiled_receiver_for_speculation(Node* n); + Node* record_profile_for_speculation(Node* n, ciKlass* exact_kls, bool maybe_null); void record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc); void record_profiled_parameters_for_speculation(); + void record_profiled_return_for_speculation(); + Node* record_profiled_receiver_for_speculation(Node* n); // Use the type profile to narrow an object type. Node* maybe_cast_profiled_receiver(Node* not_null_obj, diff --git a/hotspot/src/share/vm/opto/idealKit.hpp b/hotspot/src/share/vm/opto/idealKit.hpp index 7581570557d..f20d6bfee57 100644 --- a/hotspot/src/share/vm/opto/idealKit.hpp +++ b/hotspot/src/share/vm/opto/idealKit.hpp @@ -27,6 +27,7 @@ #include "opto/addnode.hpp" #include "opto/cfgnode.hpp" +#include "opto/castnode.hpp" #include "opto/connode.hpp" #include "opto/divnode.hpp" #include "opto/graphKit.hpp" diff --git a/hotspot/src/share/vm/opto/ifg.cpp b/hotspot/src/share/vm/opto/ifg.cpp index b84ea45abb7..825a7a25533 100644 --- a/hotspot/src/share/vm/opto/ifg.cpp +++ b/hotspot/src/share/vm/opto/ifg.cpp @@ -31,7 +31,6 @@ #include "opto/cfgnode.hpp" #include "opto/chaitin.hpp" #include "opto/coalesce.hpp" -#include "opto/connode.hpp" #include "opto/indexSet.hpp" #include "opto/machnode.hpp" #include "opto/memnode.hpp" diff --git a/hotspot/src/share/vm/opto/intrinsicnode.cpp b/hotspot/src/share/vm/opto/intrinsicnode.cpp new file mode 100644 index 00000000000..683cad55fed --- /dev/null +++ b/hotspot/src/share/vm/opto/intrinsicnode.cpp @@ -0,0 +1,82 @@ +/* + * 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 "opto/intrinsicnode.hpp" +#include "opto/memnode.hpp" +#include "opto/phaseX.hpp" + +//============================================================================= +// Do not match memory edge. +uint StrIntrinsicNode::match_edge(uint idx) const { + return idx == 2 || idx == 3; +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if (remove_dead_region(phase, can_reshape)) return this; + // Don't bother trying to transform a dead node + if (in(0) && in(0)->is_top()) return NULL; + + if (can_reshape) { + Node* mem = phase->transform(in(MemNode::Memory)); + // If transformed to a MergeMem, get the desired slice + uint alias_idx = phase->C->get_alias_index(adr_type()); + mem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(alias_idx) : mem; + if (mem != in(MemNode::Memory)) { + set_req(MemNode::Memory, mem); + return this; + } + } + return NULL; +} + +//------------------------------Value------------------------------------------ +const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const { + if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; + return bottom_type(); +} + +//============================================================================= +//------------------------------match_edge------------------------------------- +// Do not match memory edge +uint EncodeISOArrayNode::match_edge(uint idx) const { + return idx == 2 || idx == 3; // EncodeISOArray src (Binary dst len) +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *EncodeISOArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { + return remove_dead_region(phase, can_reshape) ? this : NULL; +} + +//------------------------------Value------------------------------------------ +const Type *EncodeISOArrayNode::Value(PhaseTransform *phase) const { + if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; + return bottom_type(); +} + diff --git a/hotspot/src/share/vm/opto/intrinsicnode.hpp b/hotspot/src/share/vm/opto/intrinsicnode.hpp new file mode 100644 index 00000000000..2f19db6474b --- /dev/null +++ b/hotspot/src/share/vm/opto/intrinsicnode.hpp @@ -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. + * + */ + +#ifndef SHARE_VM_OPTO_INTRINSICNODE_HPP +#define SHARE_VM_OPTO_INTRINSICNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + + +//----------------------PartialSubtypeCheckNode-------------------------------- +// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass +// array for an instance of the superklass. Set a hidden internal cache on a +// hit (cache is checked with exposed code in gen_subtype_check()). Return +// not zero for a miss or zero for a hit. +class PartialSubtypeCheckNode : public Node { + public: + PartialSubtypeCheckNode(Node* c, Node* sub, Node* super) : Node(c,sub,super) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } + virtual uint ideal_reg() const { return Op_RegP; } +}; + +//------------------------------StrIntrinsic------------------------------- +// Base class for Ideal nodes used in String instrinsic code. +class StrIntrinsicNode: public Node { + public: + StrIntrinsicNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, Node* s2, Node* c2): + Node(control, char_array_mem, s1, c1, s2, c2) { + } + + StrIntrinsicNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2, Node* c): + Node(control, char_array_mem, s1, s2, c) { + } + + StrIntrinsicNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2): + Node(control, char_array_mem, s1, s2) { + } + + virtual bool depends_only_on_test() const { return false; } + virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } + virtual uint match_edge(uint idx) const; + virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual const Type *Value(PhaseTransform *phase) const; +}; + +//------------------------------StrComp------------------------------------- +class StrCompNode: public StrIntrinsicNode { + public: + StrCompNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, Node* s2, Node* c2): + StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::INT; } +}; + +//------------------------------StrEquals------------------------------------- +class StrEqualsNode: public StrIntrinsicNode { + public: + StrEqualsNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2, Node* c): + StrIntrinsicNode(control, char_array_mem, s1, s2, c) {}; + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::BOOL; } +}; + +//------------------------------StrIndexOf------------------------------------- +class StrIndexOfNode: public StrIntrinsicNode { + public: + StrIndexOfNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, Node* s2, Node* c2): + StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::INT; } +}; + +//------------------------------AryEq--------------------------------------- +class AryEqNode: public StrIntrinsicNode { + public: + AryEqNode(Node* control, Node* char_array_mem, Node* s1, Node* s2): + StrIntrinsicNode(control, char_array_mem, s1, s2) {}; + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::BOOL; } +}; + + +//------------------------------EncodeISOArray-------------------------------- +// encode char[] to byte[] in ISO_8859_1 +class EncodeISOArrayNode: public Node { + public: + EncodeISOArrayNode(Node *control, Node* arymem, Node* s1, Node* s2, Node* c): Node(control, arymem, s1, s2, c) {}; + virtual int Opcode() const; + virtual bool depends_only_on_test() const { return false; } + virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } + virtual uint match_edge(uint idx) const; + virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual const Type *Value(PhaseTransform *phase) const; +}; + +#endif // SHARE_VM_OPTO_INTRINSICNODE_HPP diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index bd2ef020bb2..f2bbfa97caf 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -30,10 +30,16 @@ #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/callGenerator.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" +#include "opto/convertnode.hpp" +#include "opto/countbitsnode.hpp" +#include "opto/intrinsicnode.hpp" #include "opto/idealKit.hpp" #include "opto/mathexactnode.hpp" +#include "opto/movenode.hpp" #include "opto/mulnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/parse.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" @@ -2600,7 +2606,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas case T_ADDRESS: // Cast to an int type. p = _gvn.transform(new (C) CastP2XNode(NULL, p)); - p = ConvX2L(p); + p = ConvX2UL(p); break; default: fatal(err_msg_res("unexpected type %d: %s", type, type2name(type))); @@ -4658,7 +4664,7 @@ bool LibraryCallKit::inline_arraycopy() { ciKlass* src_k = NULL; if (!has_src) { - src_k = src_type->speculative_type(); + src_k = src_type->speculative_type_not_null(); if (src_k != NULL && src_k->is_array_klass()) { could_have_src = true; } @@ -4666,7 +4672,7 @@ bool LibraryCallKit::inline_arraycopy() { ciKlass* dest_k = NULL; if (!has_dest) { - dest_k = dest_type->speculative_type(); + dest_k = dest_type->speculative_type_not_null(); if (dest_k != NULL && dest_k->is_array_klass()) { could_have_dest = true; } @@ -4738,13 +4744,13 @@ bool LibraryCallKit::inline_arraycopy() { ciKlass* src_k = top_src->klass(); ciKlass* dest_k = top_dest->klass(); if (!src_spec) { - src_k = src_type->speculative_type(); + 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(); + dest_k = dest_type->speculative_type_not_null(); if (dest_k != NULL && dest_k->is_array_klass()) { could_have_dest = true; } diff --git a/hotspot/src/share/vm/opto/locknode.cpp b/hotspot/src/share/vm/opto/locknode.cpp index 26c6291686b..426ed9a67d2 100644 --- a/hotspot/src/share/vm/opto/locknode.cpp +++ b/hotspot/src/share/vm/opto/locknode.cpp @@ -136,6 +136,8 @@ bool BoxLockNode::is_simple_lock_region(LockNode** unique_lock, Node* obj) { //-----------------------------hash-------------------------------------------- uint FastLockNode::hash() const { return NO_HASH; } +uint FastLockNode::size_of() const { return sizeof(*this); } + //------------------------------cmp-------------------------------------------- uint FastLockNode::cmp( const Node &n ) const { return (&n == this); // Always fail except on self @@ -159,6 +161,22 @@ void FastLockNode::create_lock_counter(JVMState* state) { _counters = blnc->counters(); } +void FastLockNode::create_rtm_lock_counter(JVMState* state) { +#if INCLUDE_RTM_OPT + Compile* C = Compile::current(); + if (C->profile_rtm() || (PrintPreciseRTMLockingStatistics && C->use_rtm())) { + RTMLockingNamedCounter* rlnc = (RTMLockingNamedCounter*) + OptoRuntime::new_named_counter(state, NamedCounter::RTMLockingCounter); + _rtm_counters = rlnc->counters(); + if (UseRTMForStackLocks) { + rlnc = (RTMLockingNamedCounter*) + OptoRuntime::new_named_counter(state, NamedCounter::RTMLockingCounter); + _stack_rtm_counters = rlnc->counters(); + } + } +#endif +} + //============================================================================= //------------------------------do_monitor_enter------------------------------- void Parse::do_monitor_enter() { diff --git a/hotspot/src/share/vm/opto/locknode.hpp b/hotspot/src/share/vm/opto/locknode.hpp index d8c400c1e61..8bd6f35afd8 100644 --- a/hotspot/src/share/vm/opto/locknode.hpp +++ b/hotspot/src/share/vm/opto/locknode.hpp @@ -92,13 +92,17 @@ public: //------------------------------FastLockNode----------------------------------- class FastLockNode: public CmpNode { private: - BiasedLockingCounters* _counters; + BiasedLockingCounters* _counters; + RTMLockingCounters* _rtm_counters; // RTM lock counters for inflated locks + RTMLockingCounters* _stack_rtm_counters; // RTM lock counters for stack locks public: FastLockNode(Node *ctrl, Node *oop, Node *box) : CmpNode(oop,box) { init_req(0,ctrl); init_class_id(Class_FastLock); _counters = NULL; + _rtm_counters = NULL; + _stack_rtm_counters = NULL; } Node* obj_node() const { return in(1); } Node* box_node() const { return in(2); } @@ -107,13 +111,17 @@ public: // FastLock and FastUnlockNode do not hash, we need one for each correspoding // LockNode/UnLockNode to avoid creating Phi's. virtual uint hash() const ; // { return NO_HASH; } + virtual uint size_of() const; virtual uint cmp( const Node &n ) const ; // Always fail, except on self virtual int Opcode() const; virtual const Type *Value( PhaseTransform *phase ) const { return TypeInt::CC; } const Type *sub(const Type *t1, const Type *t2) const { return TypeInt::CC;} void create_lock_counter(JVMState* s); - BiasedLockingCounters* counters() const { return _counters; } + void create_rtm_lock_counter(JVMState* state); + BiasedLockingCounters* counters() const { return _counters; } + RTMLockingCounters* rtm_counters() const { return _rtm_counters; } + RTMLockingCounters* stack_rtm_counters() const { return _stack_rtm_counters; } }; diff --git a/hotspot/src/share/vm/opto/loopPredicate.cpp b/hotspot/src/share/vm/opto/loopPredicate.cpp index 2fbfba0f48c..0e86e403473 100644 --- a/hotspot/src/share/vm/opto/loopPredicate.cpp +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp @@ -27,8 +27,10 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/loopnode.hpp" #include "opto/mulnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" #include "opto/subnode.hpp" diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 7fa685b03eb..040345b66eb 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -28,9 +28,12 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/loopnode.hpp" #include "opto/mulnode.hpp" +#include "opto/movenode.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" @@ -617,6 +620,15 @@ bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const { case Op_AryEq: { return false; } +#if INCLUDE_RTM_OPT + case Op_FastLock: + case Op_FastUnlock: { + // Don't unroll RTM locking code because it is large. + if (UseRTMLocking) { + return false; + } + } +#endif } // switch } @@ -722,6 +734,15 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const { // String intrinsics are large and have loops. return false; } +#if INCLUDE_RTM_OPT + case Op_FastLock: + case Op_FastUnlock: { + // Don't unroll RTM locking code because it is large. + if (UseRTMLocking) { + return false; + } + } +#endif } // switch } diff --git a/hotspot/src/share/vm/opto/loopUnswitch.cpp b/hotspot/src/share/vm/opto/loopUnswitch.cpp index 047c00e8021..06e17664efe 100644 --- a/hotspot/src/share/vm/opto/loopUnswitch.cpp +++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp @@ -25,7 +25,9 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/loopnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" //================= Loop Unswitching ===================== diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index 719a1fb34f1..401d40e7177 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -30,6 +30,7 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/loopnode.hpp" diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index f9a87bbac57..661a9bc6cfa 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -30,6 +30,8 @@ #include "opto/loopnode.hpp" #include "opto/matcher.hpp" #include "opto/mulnode.hpp" +#include "opto/movenode.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" #include "opto/subnode.hpp" diff --git a/hotspot/src/share/vm/opto/machnode.hpp b/hotspot/src/share/vm/opto/machnode.hpp index 55d7e515882..def4a0df6a8 100644 --- a/hotspot/src/share/vm/opto/machnode.hpp +++ b/hotspot/src/share/vm/opto/machnode.hpp @@ -53,6 +53,7 @@ class MachSpillCopyNode; class Matcher; class PhaseRegAlloc; class RegMask; +class RTMLockingCounters; class State; //---------------------------MachOper------------------------------------------ @@ -714,8 +715,9 @@ public: class MachFastLockNode : public MachNode { virtual uint size_of() const { return sizeof(*this); } // Size is bigger public: - BiasedLockingCounters* _counters; - + BiasedLockingCounters* _counters; + RTMLockingCounters* _rtm_counters; // RTM lock counters for inflated locks + RTMLockingCounters* _stack_rtm_counters; // RTM lock counters for stack locks MachFastLockNode() : MachNode() {} }; diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 912709fdbee..afaa4e858d4 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -27,14 +27,17 @@ #include "libadt/vectset.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/compile.hpp" -#include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/locknode.hpp" #include "opto/loopnode.hpp" #include "opto/macro.hpp" #include "opto/memnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/node.hpp" +#include "opto/opaquenode.hpp" #include "opto/phaseX.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" @@ -2439,6 +2442,7 @@ void PhaseMacroExpand::eliminate_macro_nodes() { } } // Next, attempt to eliminate allocations + _has_locks = false; progress = true; while (progress) { progress = false; @@ -2457,11 +2461,13 @@ void PhaseMacroExpand::eliminate_macro_nodes() { case Node::Class_Lock: case Node::Class_Unlock: assert(!n->as_AbstractLock()->is_eliminated(), "sanity"); + _has_locks = true; break; default: assert(n->Opcode() == Op_LoopLimit || n->Opcode() == Op_Opaque1 || - n->Opcode() == Op_Opaque2, "unknown node type in macro list"); + n->Opcode() == Op_Opaque2 || + n->Opcode() == Op_Opaque3, "unknown node type in macro list"); } assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); progress = progress || success; @@ -2502,6 +2508,30 @@ bool PhaseMacroExpand::expand_macro_nodes() { } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) { _igvn.replace_node(n, n->in(1)); success = true; +#if INCLUDE_RTM_OPT + } else if ((n->Opcode() == Op_Opaque3) && ((Opaque3Node*)n)->rtm_opt()) { + assert(C->profile_rtm(), "should be used only in rtm deoptimization code"); + assert((n->outcnt() == 1) && n->unique_out()->is_Cmp(), ""); + Node* cmp = n->unique_out(); +#ifdef ASSERT + // Validate graph. + assert((cmp->outcnt() == 1) && cmp->unique_out()->is_Bool(), ""); + BoolNode* bol = cmp->unique_out()->as_Bool(); + assert((bol->outcnt() == 1) && bol->unique_out()->is_If() && + (bol->_test._test == BoolTest::ne), ""); + IfNode* ifn = bol->unique_out()->as_If(); + assert((ifn->outcnt() == 2) && + ifn->proj_out(1)->is_uncommon_trap_proj(Deoptimization::Reason_rtm_state_change), ""); +#endif + Node* repl = n->in(1); + if (!_has_locks) { + // Remove RTM state check if there are no locks in the code. + // Replace input to compare the same value. + repl = (cmp->in(1) == n) ? cmp->in(2) : cmp->in(1); + } + _igvn.replace_node(n, repl); + success = true; +#endif } assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); progress = progress || success; diff --git a/hotspot/src/share/vm/opto/macro.hpp b/hotspot/src/share/vm/opto/macro.hpp index 5e2e97c7e3c..0efe988ab17 100644 --- a/hotspot/src/share/vm/opto/macro.hpp +++ b/hotspot/src/share/vm/opto/macro.hpp @@ -76,6 +76,8 @@ private: ProjNode *_memproj_catchall; ProjNode *_resproj; + // Additional data collected during macro expansion + bool _has_locks; void expand_allocate(AllocateNode *alloc); void expand_allocate_array(AllocateArrayNode *alloc); @@ -118,7 +120,7 @@ private: Node* length); public: - PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn) { + PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn), _has_locks(false) { _igvn.set_delay_transform(true); } void eliminate_macro_nodes(); diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index f263a3c5044..0e650639d0c 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -26,10 +26,10 @@ #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" -#include "opto/connode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/matcher.hpp" #include "opto/memnode.hpp" +#include "opto/movenode.hpp" #include "opto/opcodes.hpp" #include "opto/regmask.hpp" #include "opto/rootnode.hpp" diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 3a6d4998b06..6ffd0186d01 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -31,11 +31,13 @@ #include "opto/cfgnode.hpp" #include "opto/compile.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/phaseX.hpp" #include "opto/regmask.hpp" @@ -2903,59 +2905,6 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest, return mem; } -//============================================================================= -// Do not match memory edge. -uint StrIntrinsicNode::match_edge(uint idx) const { - return idx == 2 || idx == 3; -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if (remove_dead_region(phase, can_reshape)) return this; - // Don't bother trying to transform a dead node - if (in(0) && in(0)->is_top()) return NULL; - - if (can_reshape) { - Node* mem = phase->transform(in(MemNode::Memory)); - // If transformed to a MergeMem, get the desired slice - uint alias_idx = phase->C->get_alias_index(adr_type()); - mem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(alias_idx) : mem; - if (mem != in(MemNode::Memory)) { - set_req(MemNode::Memory, mem); - return this; - } - } - return NULL; -} - -//------------------------------Value------------------------------------------ -const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const { - if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; - return bottom_type(); -} - -//============================================================================= -//------------------------------match_edge------------------------------------- -// Do not match memory edge -uint EncodeISOArrayNode::match_edge(uint idx) const { - return idx == 2 || idx == 3; // EncodeISOArray src (Binary dst len) -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *EncodeISOArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { - return remove_dead_region(phase, can_reshape) ? this : NULL; -} - -//------------------------------Value------------------------------------------ -const Type *EncodeISOArrayNode::Value(PhaseTransform *phase) const { - if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; - return bottom_type(); -} - //============================================================================= MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent) : MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)), diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index 9be4b6e9c4b..6808875fdc1 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -866,88 +866,6 @@ public: static bool step_through(Node** np, uint instance_id, PhaseTransform* phase); }; -//------------------------------StrIntrinsic------------------------------- -// Base class for Ideal nodes used in String instrinsic code. -class StrIntrinsicNode: public Node { -public: - StrIntrinsicNode(Node* control, Node* char_array_mem, - Node* s1, Node* c1, Node* s2, Node* c2): - Node(control, char_array_mem, s1, c1, s2, c2) { - } - - StrIntrinsicNode(Node* control, Node* char_array_mem, - Node* s1, Node* s2, Node* c): - Node(control, char_array_mem, s1, s2, c) { - } - - StrIntrinsicNode(Node* control, Node* char_array_mem, - Node* s1, Node* s2): - Node(control, char_array_mem, s1, s2) { - } - - virtual bool depends_only_on_test() const { return false; } - virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual const Type *Value(PhaseTransform *phase) const; -}; - -//------------------------------StrComp------------------------------------- -class StrCompNode: public StrIntrinsicNode { -public: - StrCompNode(Node* control, Node* char_array_mem, - Node* s1, Node* c1, Node* s2, Node* c2): - StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } -}; - -//------------------------------StrEquals------------------------------------- -class StrEqualsNode: public StrIntrinsicNode { -public: - StrEqualsNode(Node* control, Node* char_array_mem, - Node* s1, Node* s2, Node* c): - StrIntrinsicNode(control, char_array_mem, s1, s2, c) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::BOOL; } -}; - -//------------------------------StrIndexOf------------------------------------- -class StrIndexOfNode: public StrIntrinsicNode { -public: - StrIndexOfNode(Node* control, Node* char_array_mem, - Node* s1, Node* c1, Node* s2, Node* c2): - StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } -}; - -//------------------------------AryEq--------------------------------------- -class AryEqNode: public StrIntrinsicNode { -public: - AryEqNode(Node* control, Node* char_array_mem, Node* s1, Node* s2): - StrIntrinsicNode(control, char_array_mem, s1, s2) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::BOOL; } -}; - - -//------------------------------EncodeISOArray-------------------------------- -// encode char[] to byte[] in ISO_8859_1 -class EncodeISOArrayNode: public Node { -public: - EncodeISOArrayNode(Node *control, Node* arymem, Node* s1, Node* s2, Node* c): Node(control, arymem, s1, s2, c) {}; - virtual int Opcode() const; - virtual bool depends_only_on_test() const { return false; } - virtual const Type* bottom_type() const { return TypeInt::INT; } - virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual const Type *Value(PhaseTransform *phase) const; -}; - //------------------------------MemBar----------------------------------------- // There are different flavors of Memory Barriers to match the Java Memory // Model. Monitor-enter and volatile-load act as Aquires: no following ref diff --git a/hotspot/src/share/vm/opto/movenode.cpp b/hotspot/src/share/vm/opto/movenode.cpp new file mode 100644 index 00000000000..bf2a83712c1 --- /dev/null +++ b/hotspot/src/share/vm/opto/movenode.cpp @@ -0,0 +1,398 @@ +/* + * 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 "opto/addnode.hpp" +#include "opto/connode.hpp" +#include "opto/convertnode.hpp" +#include "opto/movenode.hpp" +#include "opto/phaseX.hpp" +#include "opto/subnode.hpp" + +//============================================================================= +/* + The major change is for CMoveP and StrComp. They have related but slightly + different problems. They both take in TWO oops which are both null-checked + independently before the using Node. After CCP removes the CastPP's they need + to pick up the guarding test edge - in this case TWO control edges. I tried + various solutions, all have problems: + + (1) Do nothing. This leads to a bug where we hoist a Load from a CMoveP or a + StrComp above a guarding null check. I've seen both cases in normal -Xcomp + testing. + + (2) Plug the control edge from 1 of the 2 oops in. Apparent problem here is + to figure out which test post-dominates. The real problem is that it doesn't + matter which one you pick. After you pick up, the dominating-test elider in + IGVN can remove the test and allow you to hoist up to the dominating test on + the chosen oop bypassing the test on the not-chosen oop. Seen in testing. + Oops. + + (3) Leave the CastPP's in. This makes the graph more accurate in some sense; + we get to keep around the knowledge that an oop is not-null after some test. + Alas, the CastPP's interfere with GVN (some values are the regular oop, some + are the CastPP of the oop, all merge at Phi's which cannot collapse, etc). + This cost us 10% on SpecJVM, even when I removed some of the more trivial + cases in the optimizer. Removing more useless Phi's started allowing Loads to + illegally float above null checks. I gave up on this approach. + + (4) Add BOTH control edges to both tests. Alas, too much code knows that + control edges are in slot-zero ONLY. Many quick asserts fail; no way to do + this one. Note that I really want to allow the CMoveP to float and add both + control edges to the dependent Load op - meaning I can select early but I + cannot Load until I pass both tests. + + (5) Do not hoist CMoveP and StrComp. To this end I added the v-call + depends_only_on_test(). No obvious performance loss on Spec, but we are + clearly conservative on CMoveP (also so on StrComp but that's unlikely to + matter ever). + + */ + + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Move constants to the right. +Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(0) && remove_dead_region(phase, can_reshape) ) return this; + // Don't bother trying to transform a dead node + if( in(0) && in(0)->is_top() ) return NULL; + assert( !phase->eqv(in(Condition), this) && + !phase->eqv(in(IfFalse), this) && + !phase->eqv(in(IfTrue), this), "dead loop in CMoveNode::Ideal" ); + if( phase->type(in(Condition)) == Type::TOP ) + return NULL; // return NULL when Condition is dead + + if( in(IfFalse)->is_Con() && !in(IfTrue)->is_Con() ) { + 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 NULL; +} + +//------------------------------is_cmove_id------------------------------------ +// Helper function to check for CMOVE identity. Shared with PhiNode::Identity +Node *CMoveNode::is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ) { + // Check for Cmp'ing and CMove'ing same values + if( (phase->eqv(cmp->in(1),f) && + phase->eqv(cmp->in(2),t)) || + // Swapped Cmp is OK + (phase->eqv(cmp->in(2),f) && + phase->eqv(cmp->in(1),t)) ) { + // Give up this identity check for floating points because it may choose incorrect + // value around 0.0 and -0.0 + if ( cmp->Opcode()==Op_CmpF || cmp->Opcode()==Op_CmpD ) + return NULL; + // Check for "(t==f)?t:f;" and replace with "f" + if( b->_test._test == BoolTest::eq ) + return f; + // Allow the inverted case as well + // Check for "(t!=f)?t:f;" and replace with "t" + if( b->_test._test == BoolTest::ne ) + return t; + } + return NULL; +} + +//------------------------------Identity--------------------------------------- +// Conditional-move is an identity if both inputs are the same, or the test +// true or false. +Node *CMoveNode::Identity( PhaseTransform *phase ) { + if( phase->eqv(in(IfFalse),in(IfTrue)) ) // C-moving identical inputs? + return in(IfFalse); // Then it doesn't matter + if( phase->type(in(Condition)) == TypeInt::ZERO ) + return in(IfFalse); // Always pick left(false) input + if( phase->type(in(Condition)) == TypeInt::ONE ) + return in(IfTrue); // Always pick right(true) input + + // Check for CMove'ing a constant after comparing against the constant. + // Happens all the time now, since if we compare equality vs a constant in + // the parser, we "know" the variable is constant on one path and we force + // it. Thus code like "if( x==0 ) {/*EMPTY*/}" ends up inserting a + // conditional move: "x = (x==0)?0:x;". Yucko. This fix is slightly more + // general in that we don't need constants. + if( in(Condition)->is_Bool() ) { + BoolNode *b = in(Condition)->as_Bool(); + Node *cmp = b->in(1); + if( cmp->is_Cmp() ) { + Node *id = is_cmove_id( phase, cmp, in(IfTrue), in(IfFalse), b ); + if( id ) return id; + } + } + + return this; +} + +//------------------------------Value------------------------------------------ +// Result is the meet of inputs +const Type *CMoveNode::Value( PhaseTransform *phase ) const { + if( phase->type(in(Condition)) == Type::TOP ) + return Type::TOP; + return phase->type(in(IfFalse))->meet_speculative(phase->type(in(IfTrue))); +} + +//------------------------------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 ) { + switch( t->basic_type() ) { + case T_INT: return new (C) CMoveINode( bol, left, right, t->is_int() ); + case T_FLOAT: return new (C) CMoveFNode( bol, left, right, t ); + case T_DOUBLE: return new (C) CMoveDNode( bol, left, right, t ); + case T_LONG: return new (C) CMoveLNode( bol, left, right, t->is_long() ); + case T_OBJECT: return new (C) CMovePNode( c, bol, left, right, t->is_oopptr() ); + case T_ADDRESS: return new (C) CMovePNode( c, bol, left, right, t->is_ptr() ); + case T_NARROWOOP: return new (C) CMoveNNode( c, bol, left, right, t ); + default: + ShouldNotReachHere(); + return NULL; + } +} + +//============================================================================= +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Check for conversions to boolean +Node *CMoveINode::Ideal(PhaseGVN *phase, bool can_reshape) { + // Try generic ideal's first + Node *x = CMoveNode::Ideal(phase, can_reshape); + if( x ) return x; + + // If zero is on the left (false-case, no-move-case) it must mean another + // constant is on the right (otherwise the shared CMove::Ideal code would + // have moved the constant to the right). This situation is bad for Intel + // and a don't-care for Sparc. It's bad for Intel because the zero has to + // be manifested in a register with a XOR which kills flags, which are live + // on input to the CMoveI, leading to a situation which causes excessive + // spilling on Intel. For Sparc, if the zero in on the left the Sparc will + // zero a register via G0 and conditionally-move the other constant. If the + // zero is on the right, the Sparc will load the first constant with a + // 13-bit set-lo and conditionally move G0. See bug 4677505. + if( phase->type(in(IfFalse)) == TypeInt::ZERO && !(phase->type(in(IfTrue)) == TypeInt::ZERO) ) { + 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 ); + } + } + + // Now check for booleans + int flip = 0; + + // Check for picking from zero/one + if( phase->type(in(IfFalse)) == TypeInt::ZERO && phase->type(in(IfTrue)) == TypeInt::ONE ) { + flip = 1 - flip; + } else if( phase->type(in(IfFalse)) == TypeInt::ONE && phase->type(in(IfTrue)) == TypeInt::ZERO ) { + } else return NULL; + + // Check for eq/ne test + if( !in(1)->is_Bool() ) return NULL; + BoolNode *bol = in(1)->as_Bool(); + if( bol->_test._test == BoolTest::eq ) { + } else if( bol->_test._test == BoolTest::ne ) { + flip = 1-flip; + } else return NULL; + + // Check for vs 0 or 1 + if( !bol->in(1)->is_Cmp() ) return NULL; + const CmpNode *cmp = bol->in(1)->as_Cmp(); + if( phase->type(cmp->in(2)) == TypeInt::ZERO ) { + } else if( phase->type(cmp->in(2)) == TypeInt::ONE ) { + // Allow cmp-vs-1 if the other input is bounded by 0-1 + if( phase->type(cmp->in(1)) != TypeInt::BOOL ) + return NULL; + flip = 1 - flip; + } else return NULL; + + // Convert to a bool (flipped) + // Build int->bool conversion +#ifndef PRODUCT + if( PrintOpto ) tty->print_cr("CMOV to I2B"); +#endif + Node *n = new (phase->C) Conv2BNode( cmp->in(1) ); + if( flip ) + n = new (phase->C) XorINode( phase->transform(n), phase->intcon(1) ); + + return n; +} + +//============================================================================= +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Check for absolute value +Node *CMoveFNode::Ideal(PhaseGVN *phase, bool can_reshape) { + // Try generic ideal's first + Node *x = CMoveNode::Ideal(phase, can_reshape); + if( x ) return x; + + int cmp_zero_idx = 0; // Index of compare input where to look for zero + int phi_x_idx = 0; // Index of phi input where to find naked x + + // Find the Bool + if( !in(1)->is_Bool() ) return NULL; + BoolNode *bol = in(1)->as_Bool(); + // Check bool sense + switch( bol->_test._test ) { + case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break; + case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break; + case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break; + case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break; + default: return NULL; break; + } + + // Find zero input of CmpF; the other input is being abs'd + Node *cmpf = bol->in(1); + if( cmpf->Opcode() != Op_CmpF ) return NULL; + Node *X = NULL; + bool flip = false; + if( phase->type(cmpf->in(cmp_zero_idx)) == TypeF::ZERO ) { + X = cmpf->in(3 - cmp_zero_idx); + } else if (phase->type(cmpf->in(3 - cmp_zero_idx)) == TypeF::ZERO) { + // The test is inverted, we should invert the result... + X = cmpf->in(cmp_zero_idx); + flip = true; + } else { + return NULL; + } + + // If X is found on the appropriate phi input, find the subtract on the other + if( X != in(phi_x_idx) ) return NULL; + int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue; + Node *sub = in(phi_sub_idx); + + // Allow only SubF(0,X) and fail out for all others; NegF is not OK + if( sub->Opcode() != Op_SubF || + sub->in(2) != X || + phase->type(sub->in(1)) != TypeF::ZERO ) return NULL; + + Node *abs = new (phase->C) AbsFNode( X ); + if( flip ) + abs = new (phase->C) SubFNode(sub->in(1), phase->transform(abs)); + + return abs; +} + +//============================================================================= +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Check for absolute value +Node *CMoveDNode::Ideal(PhaseGVN *phase, bool can_reshape) { + // Try generic ideal's first + Node *x = CMoveNode::Ideal(phase, can_reshape); + if( x ) return x; + + int cmp_zero_idx = 0; // Index of compare input where to look for zero + int phi_x_idx = 0; // Index of phi input where to find naked x + + // Find the Bool + if( !in(1)->is_Bool() ) return NULL; + BoolNode *bol = in(1)->as_Bool(); + // Check bool sense + switch( bol->_test._test ) { + case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break; + case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break; + case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break; + case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break; + default: return NULL; break; + } + + // Find zero input of CmpD; the other input is being abs'd + Node *cmpd = bol->in(1); + if( cmpd->Opcode() != Op_CmpD ) return NULL; + Node *X = NULL; + bool flip = false; + if( phase->type(cmpd->in(cmp_zero_idx)) == TypeD::ZERO ) { + X = cmpd->in(3 - cmp_zero_idx); + } else if (phase->type(cmpd->in(3 - cmp_zero_idx)) == TypeD::ZERO) { + // The test is inverted, we should invert the result... + X = cmpd->in(cmp_zero_idx); + flip = true; + } else { + return NULL; + } + + // If X is found on the appropriate phi input, find the subtract on the other + if( X != in(phi_x_idx) ) return NULL; + int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue; + Node *sub = in(phi_sub_idx); + + // Allow only SubD(0,X) and fail out for all others; NegD is not OK + if( sub->Opcode() != Op_SubD || + sub->in(2) != X || + phase->type(sub->in(1)) != TypeD::ZERO ) return NULL; + + Node *abs = new (phase->C) AbsDNode( X ); + if( flip ) + abs = new (phase->C) SubDNode(sub->in(1), phase->transform(abs)); + + return abs; +} + +//------------------------------Value------------------------------------------ +const Type *MoveL2DNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeLong *tl = t->is_long(); + if( !tl->is_con() ) return bottom_type(); + JavaValue v; + v.set_jlong(tl->get_con()); + return TypeD::make( v.get_jdouble() ); +} + +//------------------------------Value------------------------------------------ +const Type *MoveI2FNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeInt *ti = t->is_int(); + if( !ti->is_con() ) return bottom_type(); + JavaValue v; + v.set_jint(ti->get_con()); + return TypeF::make( v.get_jfloat() ); +} + +//------------------------------Value------------------------------------------ +const Type *MoveF2INode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::FLOAT ) return TypeInt::INT; + const TypeF *tf = t->is_float_constant(); + JavaValue v; + v.set_jfloat(tf->getf()); + return TypeInt::make( v.get_jint() ); +} + +//------------------------------Value------------------------------------------ +const Type *MoveD2LNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::DOUBLE ) return TypeLong::LONG; + const TypeD *td = t->is_double_constant(); + JavaValue v; + v.set_jdouble(td->getd()); + return TypeLong::make( v.get_jlong() ); +} + diff --git a/hotspot/src/share/vm/opto/movenode.hpp b/hotspot/src/share/vm/opto/movenode.hpp new file mode 100644 index 00000000000..8aac944ed92 --- /dev/null +++ b/hotspot/src/share/vm/opto/movenode.hpp @@ -0,0 +1,152 @@ +/* + * 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_OPTO_MOVENODE_HPP +#define SHARE_VM_OPTO_MOVENODE_HPP + +#include "opto/node.hpp" + +//------------------------------CMoveNode-------------------------------------- +// Conditional move +class CMoveNode : public TypeNode { + public: + enum { Control, // When is it safe to do this cmove? + Condition, // Condition controlling the cmove + IfFalse, // Value if condition is false + IfTrue }; // Value if condition is true + CMoveNode( Node *bol, Node *left, Node *right, const Type *t ) : TypeNode(t,4) + { + init_class_id(Class_CMove); + // all inputs are nullified in Node::Node(int) + // init_req(Control,NULL); + init_req(Condition,bol); + init_req(IfFalse,left); + init_req(IfTrue,right); + } + 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 ); + // Helper function to spot cmove graph shapes + static Node *is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ); +}; + +//------------------------------CMoveDNode------------------------------------- +class CMoveDNode : public CMoveNode { + public: + CMoveDNode( Node *bol, Node *left, Node *right, const Type* t) : CMoveNode(bol,left,right,t){} + virtual int Opcode() const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +//------------------------------CMoveFNode------------------------------------- +class CMoveFNode : public CMoveNode { + public: + CMoveFNode( Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) {} + virtual int Opcode() const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +//------------------------------CMoveINode------------------------------------- +class CMoveINode : public CMoveNode { + public: + CMoveINode( Node *bol, Node *left, Node *right, const TypeInt *ti ) : CMoveNode(bol,left,right,ti){} + virtual int Opcode() const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +//------------------------------CMoveLNode------------------------------------- +class CMoveLNode : public CMoveNode { + public: + CMoveLNode(Node *bol, Node *left, Node *right, const TypeLong *tl ) : CMoveNode(bol,left,right,tl){} + virtual int Opcode() const; +}; + +//------------------------------CMovePNode------------------------------------- +class CMovePNode : public CMoveNode { + public: + CMovePNode( Node *c, Node *bol, Node *left, Node *right, const TypePtr* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); } + virtual int Opcode() const; +}; + +//------------------------------CMoveNNode------------------------------------- +class CMoveNNode : public CMoveNode { + public: + CMoveNNode( Node *c, Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); } + virtual int Opcode() const; +}; + +// +class MoveI2FNode : public Node { + public: + MoveI2FNode( Node *value ) : Node(0,value) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual uint ideal_reg() const { return Op_RegF; } + virtual const Type* Value( PhaseTransform *phase ) const; +}; + +class MoveL2DNode : public Node { + public: + MoveL2DNode( Node *value ) : Node(0,value) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual uint ideal_reg() const { return Op_RegD; } + virtual const Type* Value( PhaseTransform *phase ) const; +}; + +class MoveF2INode : public Node { + public: + MoveF2INode( Node *value ) : Node(0,value) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } + virtual const Type* Value( PhaseTransform *phase ) const; +}; + +class MoveD2LNode : public Node { + public: + MoveD2LNode( Node *value ) : Node(0,value) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeLong::LONG; } + virtual uint ideal_reg() const { return Op_RegL; } + virtual const Type* Value( PhaseTransform *phase ) const; +}; + +//------------------------------BinaryNode------------------------------------- +// Place holder for the 2 conditional inputs to a CMove. CMove needs 4 +// inputs: the Bool (for the lt/gt/eq/ne bits), the flags (result of some +// compare), and the 2 values to select between. The Matcher requires a +// binary tree so we break it down like this: +// (CMove (Binary bol cmp) (Binary src1 src2)) +class BinaryNode : public Node { + public: + BinaryNode( Node *n1, Node *n2 ) : Node(0,n1,n2) { } + virtual int Opcode() const; + virtual uint ideal_reg() const { return 0; } +}; + + +#endif // SHARE_VM_OPTO_MOVENODE_HPP + diff --git a/hotspot/src/share/vm/opto/mulnode.cpp b/hotspot/src/share/vm/opto/mulnode.cpp index 4896e98a7f0..861149afca5 100644 --- a/hotspot/src/share/vm/opto/mulnode.cpp +++ b/hotspot/src/share/vm/opto/mulnode.cpp @@ -26,6 +26,7 @@ #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/opto/narrowptrnode.cpp b/hotspot/src/share/vm/opto/narrowptrnode.cpp new file mode 100644 index 00000000000..197d748f407 --- /dev/null +++ b/hotspot/src/share/vm/opto/narrowptrnode.cpp @@ -0,0 +1,113 @@ +/* + * 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 "opto/narrowptrnode.hpp" +#include "opto/phaseX.hpp" + +Node* DecodeNNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_EncodeP()) { + // (DecodeN (EncodeP p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *DecodeNNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + if (t == TypeNarrowOop::NULL_PTR) return TypePtr::NULL_PTR; + + assert(t->isa_narrowoop(), "only narrowoop here"); + return t->make_ptr(); +} + +Node* EncodePNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_DecodeN()) { + // (EncodeP (DecodeN p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *EncodePNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + if (t == TypePtr::NULL_PTR) return TypeNarrowOop::NULL_PTR; + + assert(t->isa_oop_ptr(), "only oopptr here"); + return t->make_narrowoop(); +} + + +Node *EncodeNarrowPtrNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { + return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1)); +} + +Node* DecodeNKlassNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_EncodePKlass()) { + // (DecodeNKlass (EncodePKlass p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *DecodeNKlassNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + assert(t != TypeNarrowKlass::NULL_PTR, "null klass?"); + + assert(t->isa_narrowklass(), "only narrow klass ptr here"); + return t->make_ptr(); +} + +Node* EncodePKlassNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_DecodeNKlass()) { + // (EncodePKlass (DecodeNKlass p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *EncodePKlassNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + assert (t != TypePtr::NULL_PTR, "null klass?"); + + assert(UseCompressedClassPointers && t->isa_klassptr(), "only klass ptr here"); + return t->make_narrowklass(); +} + diff --git a/hotspot/src/share/vm/opto/narrowptrnode.hpp b/hotspot/src/share/vm/opto/narrowptrnode.hpp new file mode 100644 index 00000000000..9b737f59837 --- /dev/null +++ b/hotspot/src/share/vm/opto/narrowptrnode.hpp @@ -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. + * + */ + +#ifndef SHARE_VM_OPTO_NARROWPTRNODE_HPP +#define SHARE_VM_OPTO_NARROWPTRNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + +//------------------------------EncodeNarrowPtr-------------------------------- +class EncodeNarrowPtrNode : public TypeNode { + protected: + EncodeNarrowPtrNode(Node* value, const Type* type): + TypeNode(type, 2) { + init_class_id(Class_EncodeNarrowPtr); + init_req(0, NULL); + init_req(1, value); + } + public: + virtual uint ideal_reg() const { return Op_RegN; } + virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); +}; + +//------------------------------EncodeP-------------------------------- +// Encodes an oop pointers into its compressed form +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class EncodePNode : public EncodeNarrowPtrNode { + public: + EncodePNode(Node* value, const Type* type): + EncodeNarrowPtrNode(value, type) { + init_class_id(Class_EncodeP); + } + virtual int Opcode() const; + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; +}; + +//------------------------------EncodePKlass-------------------------------- +// Encodes a klass pointer into its compressed form +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class EncodePKlassNode : public EncodeNarrowPtrNode { + public: + EncodePKlassNode(Node* value, const Type* type): + EncodeNarrowPtrNode(value, type) { + init_class_id(Class_EncodePKlass); + } + virtual int Opcode() const; + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; +}; + +//------------------------------DecodeNarrowPtr-------------------------------- +class DecodeNarrowPtrNode : public TypeNode { + protected: + DecodeNarrowPtrNode(Node* value, const Type* type): + TypeNode(type, 2) { + init_class_id(Class_DecodeNarrowPtr); + init_req(0, NULL); + init_req(1, value); + } + public: + virtual uint ideal_reg() const { return Op_RegP; } +}; + +//------------------------------DecodeN-------------------------------- +// Converts a narrow oop into a real oop ptr. +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class DecodeNNode : public DecodeNarrowPtrNode { + public: + DecodeNNode(Node* value, const Type* type): + DecodeNarrowPtrNode(value, type) { + init_class_id(Class_DecodeN); + } + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); +}; + +//------------------------------DecodeNKlass-------------------------------- +// Converts a narrow klass pointer into a real klass ptr. +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class DecodeNKlassNode : public DecodeNarrowPtrNode { + public: + DecodeNKlassNode(Node* value, const Type* type): + DecodeNarrowPtrNode(value, type) { + init_class_id(Class_DecodeNKlass); + } + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); +}; + +#endif // SHARE_VM_OPTO_NARROWPTRNODE_HPP + diff --git a/hotspot/src/share/vm/opto/opaquenode.cpp b/hotspot/src/share/vm/opto/opaquenode.cpp new file mode 100644 index 00000000000..b2cd073b131 --- /dev/null +++ b/hotspot/src/share/vm/opto/opaquenode.cpp @@ -0,0 +1,63 @@ +/* + * 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 "opto/opaquenode.hpp" +#include "opto/phaseX.hpp" + +//============================================================================= +// Do not allow value-numbering +uint Opaque1Node::hash() const { return NO_HASH; } +uint Opaque1Node::cmp( const Node &n ) const { + return (&n == this); // Always fail except on self +} + +//------------------------------Identity--------------------------------------- +// If _major_progress, then more loop optimizations follow. Do NOT remove +// the opaque Node until no more loop ops can happen. Note the timing of +// _major_progress; it's set in the major loop optimizations THEN comes the +// call to IterGVN and any chance of hitting this code. Hence there's no +// phase-ordering problem with stripping Opaque1 in IGVN followed by some +// more loop optimizations that require it. +Node *Opaque1Node::Identity( PhaseTransform *phase ) { + return phase->C->major_progress() ? this : in(1); +} + +//============================================================================= +// A node to prevent unwanted optimizations. Allows constant folding. Stops +// value-numbering, most Ideal calls or Identity functions. This Node is +// specifically designed to prevent the pre-increment value of a loop trip +// counter from being live out of the bottom of the loop (hence causing the +// pre- and post-increment values both being live and thus requiring an extra +// temp register and an extra move). If we "accidentally" optimize through +// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus +// it's OK to be slightly sloppy on optimizations here. + +// Do not allow value-numbering +uint Opaque2Node::hash() const { return NO_HASH; } +uint Opaque2Node::cmp( const Node &n ) const { + return (&n == this); // Always fail except on self +} + + diff --git a/hotspot/src/share/vm/opto/opaquenode.hpp b/hotspot/src/share/vm/opto/opaquenode.hpp new file mode 100644 index 00000000000..2f92a4a37aa --- /dev/null +++ b/hotspot/src/share/vm/opto/opaquenode.hpp @@ -0,0 +1,91 @@ +/* + * 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_OPTO_OPAQUENODE_HPP +#define SHARE_VM_OPTO_OPAQUENODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + +//------------------------------Opaque1Node------------------------------------ +// A node to prevent unwanted optimizations. Allows constant folding. +// Stops value-numbering, Ideal calls or Identity functions. +class Opaque1Node : public Node { + virtual uint hash() const ; // { return NO_HASH; } + virtual uint cmp( const Node &n ) const; + public: + Opaque1Node( Compile* C, Node *n ) : Node(0,n) { + // Put it on the Macro nodes list to removed during macro nodes expansion. + init_flags(Flag_is_macro); + C->add_macro_node(this); + } + // Special version for the pre-loop to hold the original loop limit + // which is consumed by range check elimination. + Opaque1Node( Compile* C, Node *n, Node* orig_limit ) : Node(0,n,orig_limit) { + // Put it on the Macro nodes list to removed during macro nodes expansion. + init_flags(Flag_is_macro); + C->add_macro_node(this); + } + Node* original_loop_limit() { return req()==3 ? in(2) : NULL; } + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual Node *Identity( PhaseTransform *phase ); +}; + +//------------------------------Opaque2Node------------------------------------ +// A node to prevent unwanted optimizations. Allows constant folding. Stops +// value-numbering, most Ideal calls or Identity functions. This Node is +// specifically designed to prevent the pre-increment value of a loop trip +// counter from being live out of the bottom of the loop (hence causing the +// pre- and post-increment values both being live and thus requiring an extra +// temp register and an extra move). If we "accidentally" optimize through +// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus +// it's OK to be slightly sloppy on optimizations here. +class Opaque2Node : public Node { + virtual uint hash() const ; // { return NO_HASH; } + virtual uint cmp( const Node &n ) const; + public: + Opaque2Node( Compile* C, Node *n ) : Node(0,n) { + // Put it on the Macro nodes list to removed during macro nodes expansion. + init_flags(Flag_is_macro); + C->add_macro_node(this); + } + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } +}; + +//------------------------------Opaque3Node------------------------------------ +// A node to prevent unwanted optimizations. Will be optimized only during +// macro nodes expansion. +class Opaque3Node : public Opaque2Node { + int _opt; // what optimization it was used for + public: + enum { RTM_OPT }; + Opaque3Node(Compile* C, Node *n, int opt) : Opaque2Node(C, n), _opt(opt) {} + virtual int Opcode() const; + bool rtm_opt() const { return (_opt == RTM_OPT); } +}; + +#endif // SHARE_VM_OPTO_OPAQUENODE_HPP + diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 48117ea14fe..debf13693f2 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -42,18 +42,12 @@ #include "runtime/handles.inline.hpp" #include "utilities/xmlstream.hpp" -extern uint size_exception_handler(); -extern uint size_deopt_handler(); - #ifndef PRODUCT #define DEBUG_ARG(x) , x #else #define DEBUG_ARG(x) #endif -extern int emit_exception_handler(CodeBuffer &cbuf); -extern int emit_deopt_handler(CodeBuffer &cbuf); - // Convert Nodes to instruction bits and pass off to the VM void Compile::Output() { // RootNode goes @@ -394,6 +388,11 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding reloc_size += mach->reloc(); if (mach->is_MachCall()) { + // add size information for trampoline stub + // class CallStubImpl is platform-specific and defined in the *.ad files. + stub_size += CallStubImpl::size_call_trampoline(); + reloc_size += CallStubImpl::reloc_call_trampoline(); + MachCallNode *mcall = mach->as_MachCall(); // This destination address is NOT PC-relative @@ -1133,10 +1132,9 @@ CodeBuffer* Compile::init_buffer(uint* blk_starts) { shorten_branches(blk_starts, code_req, locs_req, stub_req); // nmethod and CodeBuffer count stubs & constants as part of method's code. - int exception_handler_req = size_exception_handler(); - int deopt_handler_req = size_deopt_handler(); - exception_handler_req += MAX_stubs_size; // add marginal slop for handler - deopt_handler_req += MAX_stubs_size; // add marginal slop for handler + // class HandlerImpl is platform-specific and defined in the *.ad files. + int exception_handler_req = HandlerImpl::size_exception_handler() + MAX_stubs_size; // add marginal slop for handler + int deopt_handler_req = HandlerImpl::size_deopt_handler() + MAX_stubs_size; // add marginal slop for handler stub_req += MAX_stubs_size; // ensure per-stub margin code_req += MAX_inst_size; // ensure per-instruction margin @@ -1622,17 +1620,18 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { FillExceptionTables(inct_cnt, call_returns, inct_starts, blk_labels); // Only java methods have exception handlers and deopt handlers + // class HandlerImpl is platform-specific and defined in the *.ad files. if (_method) { // Emit the exception handler code. - _code_offsets.set_value(CodeOffsets::Exceptions, emit_exception_handler(*cb)); + _code_offsets.set_value(CodeOffsets::Exceptions, HandlerImpl::emit_exception_handler(*cb)); // Emit the deopt handler code. - _code_offsets.set_value(CodeOffsets::Deopt, emit_deopt_handler(*cb)); + _code_offsets.set_value(CodeOffsets::Deopt, HandlerImpl::emit_deopt_handler(*cb)); // Emit the MethodHandle deopt handler code (if required). if (has_method_handle_invokes()) { // We can use the same code as for the normal deopt handler, we // just need a different entry point address. - _code_offsets.set_value(CodeOffsets::DeoptMH, emit_deopt_handler(*cb)); + _code_offsets.set_value(CodeOffsets::DeoptMH, HandlerImpl::emit_deopt_handler(*cb)); } } diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index 092e40a7f64..aae634a9563 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -486,6 +486,8 @@ class Parse : public GraphKit { // Helper function to compute array addressing Node* array_addressing(BasicType type, int vals, const Type* *result2=NULL); + void rtm_deopt(); + // Pass current map to exits void return_current(Node* value); diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index db50f98492b..9d7bef8edbd 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -27,9 +27,11 @@ #include "interpreter/linkResolver.hpp" #include "oops/method.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/locknode.hpp" #include "opto/memnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" @@ -567,6 +569,10 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Pars set_map(entry_map); do_method_entry(); } + if (depth() == 1) { + // Add check to deoptimize the nmethod if RTM state was changed + rtm_deopt(); + } // Check for bailouts during method entry. if (failing()) { @@ -2006,6 +2012,42 @@ void Parse::call_register_finalizer() { set_control( _gvn.transform(result_rgn) ); } +// Add check to deoptimize if RTM state is not ProfileRTM +void Parse::rtm_deopt() { +#if INCLUDE_RTM_OPT + if (C->profile_rtm()) { + assert(C->method() != NULL, "only for normal compilations"); + assert(!C->method()->method_data()->is_empty(), "MDO is needed to record RTM state"); + assert(depth() == 1, "generate check only for main compiled method"); + + // Set starting bci for uncommon trap. + set_parse_bci(is_osr_parse() ? osr_bci() : 0); + + // Load the rtm_state from the MethodData. + const TypePtr* adr_type = TypeMetadataPtr::make(C->method()->method_data()); + Node* mdo = makecon(adr_type); + int offset = MethodData::rtm_state_offset_in_bytes(); + Node* adr_node = basic_plus_adr(mdo, mdo, offset); + Node* rtm_state = make_load(control(), adr_node, TypeInt::INT, T_INT, adr_type, MemNode::unordered); + + // Separate Load from Cmp by Opaque. + // In expand_macro_nodes() it will be replaced either + // with this load when there are locks in the code + // or with ProfileRTM (cmp->in(2)) otherwise so that + // the check will fold. + Node* profile_state = makecon(TypeInt::make(ProfileRTM)); + Node* opq = _gvn.transform( new (C) Opaque3Node(C, rtm_state, Opaque3Node::RTM_OPT) ); + Node* chk = _gvn.transform( new (C) CmpINode(opq, profile_state) ); + Node* tst = _gvn.transform( new (C) BoolNode(chk, BoolTest::eq) ); + // Branch to failure if state was changed + { BuildCutout unless(this, tst, PROB_ALWAYS); + uncommon_trap(Deoptimization::Reason_rtm_state_change, + Deoptimization::Action_make_not_entrant); + } + } +#endif +} + //------------------------------return_current--------------------------------- // Append current _map to _exit_return void Parse::return_current(Node* value) { diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index f82d246c381..cce96328b9b 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -30,6 +30,8 @@ #include "interpreter/linkResolver.hpp" #include "memory/universe.inline.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/matcher.hpp" @@ -1288,7 +1290,7 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest, (jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) { TypeNode* ccast = new (C) CheckCastPPNode(control(), obj, tboth); const Type* tcc = ccast->as_Type()->type(); - assert(tcc != obj_type && tcc->higher_equal_speculative(obj_type), "must improve"); + assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve"); // Delay transform() call to allow recovery of pre-cast value // at the control merge. _gvn.set_type_bottom(ccast); @@ -1352,7 +1354,7 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest, if (ccast != NULL) { const Type* tcc = ccast->as_Type()->type(); - assert(tcc != tval && tcc->higher_equal_speculative(tval), "must improve"); + assert(tcc != tval && tcc->higher_equal(tval), "must improve"); // Delay transform() call to allow recovery of pre-cast value // at the control merge. ccast->set_req(0, control()); @@ -1393,7 +1395,7 @@ Node* Parse::optimize_cmp_with_klass(Node* c) { Node* addp = load_klass->in(2); Node* obj = addp->in(AddPNode::Address); const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr(); - if (obj_type->speculative_type() != NULL) { + if (obj_type->speculative_type_not_null() != NULL) { ciKlass* k = obj_type->speculative_type(); inc_sp(2); obj = maybe_cast_profiled_obj(obj, k); @@ -2277,6 +2279,14 @@ void Parse::do_one_bytecode() { maybe_add_safepoint(iter().get_dest()); a = null(); b = pop(); + if (!_gvn.type(b)->speculative_maybe_null() && + !too_many_traps(Deoptimization::Reason_speculate_null_check)) { + inc_sp(1); + Node* null_ctl = top(); + b = null_check_oop(b, &null_ctl, true, true, true); + assert(null_ctl->is_top(), "no null control here"); + dec_sp(1); + } c = _gvn.transform( new (C) CmpPNode(b, a) ); do_ifnull(btest, c); break; diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp index 1f7ea1d3f8b..b76eec74073 100644 --- a/hotspot/src/share/vm/opto/parse3.cpp +++ b/hotspot/src/share/vm/opto/parse3.cpp @@ -28,6 +28,7 @@ #include "memory/universe.inline.hpp" #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/memnode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index fd08b065c5f..61918f4da57 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -27,7 +27,6 @@ #include "opto/block.hpp" #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/connode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" @@ -330,7 +329,7 @@ void NodeHash::check_no_speculative_types() { Node *sentinel_node = sentinel(); for (uint i = 0; i < max; ++i) { Node *n = at(i); - if(n != NULL && n != sentinel_node && n->is_Type()) { + if(n != NULL && n != sentinel_node && n->is_Type() && n->outcnt() > 0) { TypeNode* tn = n->as_Type(); const Type* t = tn->type(); const Type* t_no_spec = t->remove_speculative(); diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 4a18b0a2eae..877090e087a 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -48,7 +48,6 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/connode.hpp" #include "opto/graphKit.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" @@ -1310,6 +1309,14 @@ void OptoRuntime::print_named_counters() { tty->print_cr("%s", c->name()); blc->print_on(tty); } +#if INCLUDE_RTM_OPT + } else if (c->tag() == NamedCounter::RTMLockingCounter) { + RTMLockingCounters* rlc = ((RTMLockingNamedCounter*)c)->counters(); + if (rlc->nonzero()) { + tty->print_cr("%s", c->name()); + rlc->print_on(tty); + } +#endif } c = c->next(); } @@ -1349,6 +1356,8 @@ NamedCounter* OptoRuntime::new_named_counter(JVMState* youngest_jvms, NamedCount NamedCounter* c; if (tag == NamedCounter::BiasedLockingCounter) { c = new BiasedLockingNamedCounter(strdup(st.as_string())); + } else if (tag == NamedCounter::RTMLockingCounter) { + c = new RTMLockingNamedCounter(strdup(st.as_string())); } else { c = new NamedCounter(strdup(st.as_string()), tag); } @@ -1357,6 +1366,7 @@ NamedCounter* OptoRuntime::new_named_counter(JVMState* youngest_jvms, NamedCount // add counters so this is safe. NamedCounter* head; do { + c->set_next(NULL); head = _named_counters; c->set_next(head); } while (Atomic::cmpxchg_ptr(c, &_named_counters, head) != head); diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp index aecb97f6572..9f2a26cecb7 100644 --- a/hotspot/src/share/vm/opto/runtime.hpp +++ b/hotspot/src/share/vm/opto/runtime.hpp @@ -29,6 +29,7 @@ #include "opto/machnode.hpp" #include "opto/type.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/rtmLocking.hpp" #include "runtime/deoptimization.hpp" #include "runtime/vframe.hpp" @@ -61,7 +62,8 @@ public: NoTag, LockCounter, EliminatedLockCounter, - BiasedLockingCounter + BiasedLockingCounter, + RTMLockingCounter }; private: @@ -85,7 +87,7 @@ private: NamedCounter* next() const { return _next; } void set_next(NamedCounter* next) { - assert(_next == NULL, "already set"); + assert(_next == NULL || next == NULL, "already set"); _next = next; } @@ -102,6 +104,18 @@ class BiasedLockingNamedCounter : public NamedCounter { BiasedLockingCounters* counters() { return &_counters; } }; + +class RTMLockingNamedCounter : public NamedCounter { + private: + RTMLockingCounters _counters; + + public: + RTMLockingNamedCounter(const char *n) : + NamedCounter(n, RTMLockingCounter), _counters() {} + + RTMLockingCounters* counters() { return &_counters; } +}; + typedef const TypeFunc*(*TypeFunc_generator)(); class OptoRuntime : public AllStatic { diff --git a/hotspot/src/share/vm/opto/split_if.cpp b/hotspot/src/share/vm/opto/split_if.cpp index 134c8734798..9b99313f2ac 100644 --- a/hotspot/src/share/vm/opto/split_if.cpp +++ b/hotspot/src/share/vm/opto/split_if.cpp @@ -25,8 +25,8 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" #include "opto/callnode.hpp" -#include "opto/connode.hpp" #include "opto/loopnode.hpp" +#include "opto/movenode.hpp" //------------------------------split_thru_region------------------------------ diff --git a/hotspot/src/share/vm/opto/subnode.cpp b/hotspot/src/share/vm/opto/subnode.cpp index 71ffed86691..469d4141e32 100644 --- a/hotspot/src/share/vm/opto/subnode.cpp +++ b/hotspot/src/share/vm/opto/subnode.cpp @@ -28,9 +28,9 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/connode.hpp" #include "opto/loopnode.hpp" #include "opto/matcher.hpp" +#include "opto/movenode.hpp" #include "opto/mulnode.hpp" #include "opto/opcodes.hpp" #include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 9363caa1da4..cd53a971bff 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -27,11 +27,14 @@ #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/matcher.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" #include "opto/opcodes.hpp" +#include "opto/opaquenode.hpp" #include "opto/superword.hpp" #include "opto/vectornode.hpp" diff --git a/hotspot/src/share/vm/opto/superword.hpp b/hotspot/src/share/vm/opto/superword.hpp index 5081586474d..05d079ca2ca 100644 --- a/hotspot/src/share/vm/opto/superword.hpp +++ b/hotspot/src/share/vm/opto/superword.hpp @@ -24,7 +24,6 @@ #ifndef SHARE_VM_OPTO_SUPERWORD_HPP #define SHARE_VM_OPTO_SUPERWORD_HPP -#include "opto/connode.hpp" #include "opto/loopnode.hpp" #include "opto/node.hpp" #include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index d2591735770..0f011e04864 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -350,9 +350,9 @@ void Type::Initialize_shared(Compile* current) { floop[1] = TypeInt::INT; TypeTuple::LOOPBODY = TypeTuple::make( 2, floop ); - TypePtr::NULL_PTR= TypePtr::make( AnyPtr, TypePtr::Null, 0 ); - TypePtr::NOTNULL = TypePtr::make( AnyPtr, TypePtr::NotNull, OffsetBot ); - TypePtr::BOTTOM = TypePtr::make( AnyPtr, TypePtr::BotPTR, OffsetBot ); + TypePtr::NULL_PTR= TypePtr::make(AnyPtr, TypePtr::Null, 0); + TypePtr::NOTNULL = TypePtr::make(AnyPtr, TypePtr::NotNull, OffsetBot); + TypePtr::BOTTOM = TypePtr::make(AnyPtr, TypePtr::BotPTR, OffsetBot); TypeRawPtr::BOTTOM = TypeRawPtr::make( TypePtr::BotPTR ); TypeRawPtr::NOTNULL= TypeRawPtr::make( TypePtr::NotNull ); @@ -372,7 +372,7 @@ void Type::Initialize_shared(Compile* current) { false, 0, oopDesc::mark_offset_in_bytes()); TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), false, 0, oopDesc::klass_offset_in_bytes()); - TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot, NULL); + TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot); TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, OffsetBot); @@ -620,8 +620,8 @@ bool Type::interface_vs_oop(const Type *t) const { return true; } // Now check the speculative parts as well - const TypeOopPtr* this_spec = isa_oopptr() != NULL ? isa_oopptr()->speculative() : NULL; - const TypeOopPtr* t_spec = t->isa_oopptr() != NULL ? t->isa_oopptr()->speculative() : NULL; + const TypePtr* this_spec = isa_ptr() != NULL ? is_ptr()->speculative() : NULL; + const TypePtr* t_spec = t->isa_ptr() != NULL ? t->is_ptr()->speculative() : NULL; if (this_spec != NULL && t_spec != NULL) { if (this_spec->interface_vs_oop_helper(t_spec)) { return true; @@ -1975,6 +1975,25 @@ const Type* TypeAry::remove_speculative() const { return make(_elem->remove_speculative(), _size, _stable); } +/** + * Return same type with cleaned up speculative part of element + */ +const Type* TypeAry::cleanup_speculative() const { + return make(_elem->cleanup_speculative(), _size, _stable); +} + +/** + * Return same type but with a different inline depth (used for speculation) + * + * @param depth depth to meet with + */ +const TypePtr* TypePtr::with_inline_depth(int depth) const { + if (!UseInlineDepthForSpeculativeTypes) { + return this; + } + return make(AnyPtr, _ptr, _offset, _speculative, depth); +} + //----------------------interface_vs_oop--------------------------------------- #ifdef ASSERT bool TypeAry::interface_vs_oop(const Type *t) const { @@ -2179,15 +2198,15 @@ const TypePtr::PTR TypePtr::ptr_meet[TypePtr::lastPTR][TypePtr::lastPTR] = { }; //------------------------------make------------------------------------------- -const TypePtr *TypePtr::make( TYPES t, enum PTR ptr, int offset ) { - return (TypePtr*)(new TypePtr(t,ptr,offset))->hashcons(); +const TypePtr *TypePtr::make(TYPES t, enum PTR ptr, int offset, const TypePtr* speculative, int inline_depth) { + return (TypePtr*)(new TypePtr(t,ptr,offset, speculative, inline_depth))->hashcons(); } //------------------------------cast_to_ptr_type------------------------------- const Type *TypePtr::cast_to_ptr_type(PTR ptr) const { assert(_base == AnyPtr, "subclass must override cast_to_ptr_type"); if( ptr == _ptr ) return this; - return make(_base, ptr, _offset); + return make(_base, ptr, _offset, _speculative, _inline_depth); } //------------------------------get_con---------------------------------------- @@ -2198,7 +2217,29 @@ intptr_t TypePtr::get_con() const { //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypePtr::xmeet( const Type *t ) const { +const Type *TypePtr::xmeet(const Type *t) const { + const Type* res = xmeet_helper(t); + if (res->isa_ptr() == NULL) { + return res; + } + + const TypePtr* res_ptr = res->is_ptr(); + if (res_ptr->speculative() != NULL) { + // type->speculative() == NULL means that speculation is no better + // than type, i.e. type->speculative() == type. So there are 2 + // ways to represent the fact that we have no useful speculative + // data and we should use a single one to be able to test for + // equality between types. Check whether type->speculative() == + // type and set speculative to NULL if it is the case. + if (res_ptr->remove_speculative() == res_ptr->speculative()) { + return res_ptr->remove_speculative(); + } + } + + return res; +} + +const Type *TypePtr::xmeet_helper(const Type *t) const { // Perform a fast test for common case; meeting the same types together. if( this == t ) return this; // Meeting same type-rep? @@ -2221,7 +2262,9 @@ const Type *TypePtr::xmeet( const Type *t ) const { case AnyPtr: { // Meeting to AnyPtrs const TypePtr *tp = t->is_ptr(); - return make( AnyPtr, meet_ptr(tp->ptr()), meet_offset(tp->offset()) ); + const TypePtr* speculative = xmeet_speculative(tp); + int depth = meet_inline_depth(tp->inline_depth()); + return make(AnyPtr, meet_ptr(tp->ptr()), meet_offset(tp->offset()), speculative, depth); } case RawPtr: // For these, flip the call around to cut down case OopPtr: @@ -2260,7 +2303,7 @@ const TypePtr::PTR TypePtr::ptr_dual[TypePtr::lastPTR] = { BotPTR, NotNull, Constant, Null, AnyNull, TopPTR }; const Type *TypePtr::xdual() const { - return new TypePtr( AnyPtr, dual_ptr(), dual_offset() ); + return new TypePtr(AnyPtr, dual_ptr(), dual_offset(), dual_speculative(), dual_inline_depth()); } //------------------------------xadd_offset------------------------------------ @@ -2281,20 +2324,245 @@ int TypePtr::xadd_offset( intptr_t offset ) const { //------------------------------add_offset------------------------------------- const TypePtr *TypePtr::add_offset( intptr_t offset ) const { - return make( AnyPtr, _ptr, xadd_offset(offset) ); + return make(AnyPtr, _ptr, xadd_offset(offset), _speculative, _inline_depth); } //------------------------------eq--------------------------------------------- // Structural equality check for Type representations bool TypePtr::eq( const Type *t ) const { const TypePtr *a = (const TypePtr*)t; - return _ptr == a->ptr() && _offset == a->offset(); + return _ptr == a->ptr() && _offset == a->offset() && eq_speculative(a) && _inline_depth == a->_inline_depth; } //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypePtr::hash(void) const { - return _ptr + _offset; + return _ptr + _offset + hash_speculative() + _inline_depth; +; +} + +/** + * Return same type without a speculative part + */ +const Type* TypePtr::remove_speculative() const { + if (_speculative == NULL) { + return this; + } + assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth"); + return make(AnyPtr, _ptr, _offset, NULL, _inline_depth); +} + +/** + * Return same type but drop speculative part if we know we won't use + * it + */ +const Type* TypePtr::cleanup_speculative() const { + if (speculative() == NULL) { + return this; + } + const Type* no_spec = remove_speculative(); + // If this is NULL_PTR then we don't need the speculative type + // (with_inline_depth in case the current type inline depth is + // InlineDepthTop) + if (no_spec == NULL_PTR->with_inline_depth(inline_depth())) { + return no_spec; + } + if (above_centerline(speculative()->ptr())) { + return no_spec; + } + const TypeOopPtr* spec_oopptr = speculative()->isa_oopptr(); + // If the speculative may be null and is an inexact klass then it + // doesn't help + if (speculative()->maybe_null() && (spec_oopptr == NULL || !spec_oopptr->klass_is_exact())) { + return no_spec; + } + return this; +} + +/** + * dual of the speculative part of the type + */ +const TypePtr* TypePtr::dual_speculative() const { + if (_speculative == NULL) { + return NULL; + } + return _speculative->dual()->is_ptr(); +} + +/** + * meet of the speculative parts of 2 types + * + * @param other type to meet with + */ +const TypePtr* TypePtr::xmeet_speculative(const TypePtr* other) const { + bool this_has_spec = (_speculative != NULL); + bool other_has_spec = (other->speculative() != NULL); + + if (!this_has_spec && !other_has_spec) { + return NULL; + } + + // If we are at a point where control flow meets and one branch has + // a speculative type and the other has not, we meet the speculative + // type of one branch with the actual type of the other. If the + // actual type is exact and the speculative is as well, then the + // result is a speculative type which is exact and we can continue + // speculation further. + const TypePtr* this_spec = _speculative; + const TypePtr* other_spec = other->speculative(); + + if (!this_has_spec) { + this_spec = this; + } + + if (!other_has_spec) { + other_spec = other; + } + + return this_spec->meet(other_spec)->is_ptr(); +} + +/** + * dual of the inline depth for this type (used for speculation) + */ +int TypePtr::dual_inline_depth() const { + return -inline_depth(); +} + +/** + * meet of 2 inline depths (used for speculation) + * + * @param depth depth to meet with + */ +int TypePtr::meet_inline_depth(int depth) const { + return MAX2(inline_depth(), depth); +} + +/** + * Are the speculative parts of 2 types equal? + * + * @param other type to compare this one to + */ +bool TypePtr::eq_speculative(const TypePtr* other) const { + if (_speculative == NULL || other->speculative() == NULL) { + return _speculative == other->speculative(); + } + + if (_speculative->base() != other->speculative()->base()) { + return false; + } + + return _speculative->eq(other->speculative()); +} + +/** + * Hash of the speculative part of the type + */ +int TypePtr::hash_speculative() const { + if (_speculative == NULL) { + return 0; + } + + return _speculative->hash(); +} + +/** + * add offset to the speculative part of the type + * + * @param offset offset to add + */ +const TypePtr* TypePtr::add_offset_speculative(intptr_t offset) const { + if (_speculative == NULL) { + return NULL; + } + return _speculative->add_offset(offset)->is_ptr(); +} + +/** + * return exact klass from the speculative type if there's one + */ +ciKlass* TypePtr::speculative_type() const { + if (_speculative != NULL && _speculative->isa_oopptr()) { + const TypeOopPtr* speculative = _speculative->join(this)->is_oopptr(); + if (speculative->klass_is_exact()) { + return speculative->klass(); + } + } + return NULL; +} + +/** + * return true if speculative type may be null + */ +bool TypePtr::speculative_maybe_null() const { + if (_speculative != NULL) { + const TypePtr* speculative = _speculative->join(this)->is_ptr(); + return speculative->maybe_null(); + } + return true; +} + +/** + * Same as TypePtr::speculative_type() but return the klass only if + * the speculative tells us is not null + */ +ciKlass* TypePtr::speculative_type_not_null() const { + if (speculative_maybe_null()) { + return NULL; + } + return speculative_type(); +} + +/** + * Check whether new profiling would improve speculative type + * + * @param exact_kls class from profiling + * @param inline_depth inlining depth of profile point + * + * @return true if type profile is valuable + */ +bool TypePtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const { + // no profiling? + if (exact_kls == NULL) { + return false; + } + // no speculative type or non exact speculative type? + if (speculative_type() == NULL) { + return true; + } + // If the node already has an exact speculative type keep it, + // unless it was provided by profiling that is at a deeper + // inlining level. Profiling at a higher inlining depth is + // expected to be less accurate. + if (_speculative->inline_depth() == InlineDepthBottom) { + return false; + } + assert(_speculative->inline_depth() != InlineDepthTop, "can't do the comparison"); + return inline_depth < _speculative->inline_depth(); +} + +/** + * Check whether new profiling would improve ptr (= tells us it is non + * null) + * + * @param maybe_null true if profiling tells the ptr may be null + * + * @return true if ptr profile is valuable + */ +bool TypePtr::would_improve_ptr(bool maybe_null) const { + // profiling doesn't tell us anything useful + if (maybe_null) { + return false; + } + // We already know this is not be null + if (!this->maybe_null()) { + return false; + } + // We already know the speculative type cannot be null + if (!speculative_maybe_null()) { + return false; + } + return true; } //------------------------------dump2------------------------------------------ @@ -2309,6 +2577,32 @@ void TypePtr::dump2( Dict &d, uint depth, outputStream *st ) const { if( _offset == OffsetTop ) st->print("+top"); else if( _offset == OffsetBot ) st->print("+bot"); else if( _offset ) st->print("+%d", _offset); + dump_inline_depth(st); + dump_speculative(st); +} + +/** + *dump the speculative part of the type + */ +void TypePtr::dump_speculative(outputStream *st) const { + if (_speculative != NULL) { + st->print(" (speculative="); + _speculative->dump_on(st); + st->print(")"); + } +} + +/** + *dump the inline depth of the type + */ +void TypePtr::dump_inline_depth(outputStream *st) const { + if (_inline_depth != InlineDepthBottom) { + if (_inline_depth == InlineDepthTop) { + st->print(" (inline_depth=InlineDepthTop)"); + } else { + st->print(" (inline_depth=%d)", _inline_depth); + } + } } #endif @@ -2399,7 +2693,7 @@ const Type *TypeRawPtr::xmeet( const Type *t ) const { case TypePtr::Null: if( _ptr == TypePtr::TopPTR ) return t; return TypeRawPtr::BOTTOM; - case TypePtr::NotNull: return TypePtr::make( AnyPtr, meet_ptr(TypePtr::NotNull), tp->meet_offset(0) ); + case TypePtr::NotNull: return TypePtr::make(AnyPtr, meet_ptr(TypePtr::NotNull), tp->meet_offset(0), tp->speculative(), tp->inline_depth()); case TypePtr::AnyNull: if( _ptr == TypePtr::Constant) return this; return make( meet_ptr(TypePtr::AnyNull) ); @@ -2463,16 +2757,15 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const { const TypeOopPtr *TypeOopPtr::BOTTOM; //------------------------------TypeOopPtr------------------------------------- -TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) - : TypePtr(t, ptr, offset), +TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, + int instance_id, const TypePtr* speculative, int inline_depth) + : TypePtr(t, ptr, offset, speculative, inline_depth), _const_oop(o), _klass(k), _klass_is_exact(xk), _is_ptr_to_narrowoop(false), _is_ptr_to_narrowklass(false), _is_ptr_to_boxed_value(false), - _instance_id(instance_id), - _speculative(speculative), - _inline_depth(inline_depth){ + _instance_id(instance_id) { if (Compile::current()->eliminate_boxing() && (t == InstPtr) && (offset > 0) && xk && (k != 0) && k->is_instance_klass()) { _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset); @@ -2538,8 +2831,8 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int o } //------------------------------make------------------------------------------- -const TypeOopPtr *TypeOopPtr::make(PTR ptr, - int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) { +const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset, int instance_id, + const TypePtr* speculative, int inline_depth) { assert(ptr != Constant, "no constant generic pointers"); ciKlass* k = Compile::current()->env()->Object_klass(); bool xk = false; @@ -2582,28 +2875,6 @@ const TypeKlassPtr* TypeOopPtr::as_klass_type() const { return TypeKlassPtr::make(xk? Constant: NotNull, k, 0); } -const Type *TypeOopPtr::xmeet(const Type *t) const { - const Type* res = xmeet_helper(t); - if (res->isa_oopptr() == NULL) { - return res; - } - - const TypeOopPtr* res_oopptr = res->is_oopptr(); - if (res_oopptr->speculative() != NULL) { - // type->speculative() == NULL means that speculation is no better - // than type, i.e. type->speculative() == type. So there are 2 - // ways to represent the fact that we have no useful speculative - // data and we should use a single one to be able to test for - // equality between types. Check whether type->speculative() == - // type and set speculative to NULL if it is the case. - if (res_oopptr->remove_speculative() == res_oopptr->speculative()) { - return res_oopptr->remove_speculative(); - } - } - - return res; -} - //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. const Type *TypeOopPtr::xmeet_helper(const Type *t) const { @@ -2641,19 +2912,20 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const { const TypePtr *tp = t->is_ptr(); int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); + const TypePtr* speculative = xmeet_speculative(tp); + int depth = meet_inline_depth(tp->inline_depth()); switch (tp->ptr()) { case Null: - if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset); + if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); // else fall through: case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = _speculative; - return make(ptr, offset, instance_id, speculative, _inline_depth); + return make(ptr, offset, instance_id, speculative, depth); } case BotPTR: case NotNull: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); default: typerr(t); } } @@ -2661,7 +2933,7 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const { case OopPtr: { // Meeting to other OopPtrs const TypeOopPtr *tp = t->is_oopptr(); int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); return make(meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id, speculative, depth); } @@ -2859,9 +3131,7 @@ const Type *TypeOopPtr::filter_helper(const Type *kills, bool include_speculativ bool TypeOopPtr::eq( const Type *t ) const { const TypeOopPtr *a = (const TypeOopPtr*)t; if (_klass_is_exact != a->_klass_is_exact || - _instance_id != a->_instance_id || - !eq_speculative(a) || - _inline_depth != a->_inline_depth) return false; + _instance_id != a->_instance_id) return false; ciObject* one = const_oop(); ciObject* two = a->const_oop(); if (one == NULL || two == NULL) { @@ -2878,8 +3148,6 @@ int TypeOopPtr::hash(void) const { (const_oop() ? const_oop()->hash() : 0) + _klass_is_exact + _instance_id + - hash_speculative() + - _inline_depth + TypePtr::hash(); } @@ -2903,27 +3171,6 @@ void TypeOopPtr::dump2( Dict &d, uint depth, outputStream *st ) const { dump_inline_depth(st); dump_speculative(st); } - -/** - *dump the speculative part of the type - */ -void TypeOopPtr::dump_speculative(outputStream *st) const { - if (_speculative != NULL) { - st->print(" (speculative="); - _speculative->dump_on(st); - st->print(")"); - } -} - -void TypeOopPtr::dump_inline_depth(outputStream *st) const { - if (_inline_depth != InlineDepthBottom) { - if (_inline_depth == InlineDepthTop) { - st->print(" (inline_depth=InlineDepthTop)"); - } else { - st->print(" (inline_depth=%d)", _inline_depth); - } - } -} #endif //------------------------------singleton-------------------------------------- @@ -2951,50 +3198,31 @@ const Type* TypeOopPtr::remove_speculative() const { return make(_ptr, _offset, _instance_id, NULL, _inline_depth); } +/** + * Return same type but drop speculative part if we know we won't use + * it + */ +const Type* TypeOopPtr::cleanup_speculative() const { + // If the klass is exact and the ptr is not null then there's + // nothing that the speculative type can help us with + if (klass_is_exact() && !maybe_null()) { + return remove_speculative(); + } + return TypePtr::cleanup_speculative(); +} + /** * Return same type but with a different inline depth (used for speculation) * * @param depth depth to meet with */ -const TypeOopPtr* TypeOopPtr::with_inline_depth(int depth) const { +const TypePtr* TypeOopPtr::with_inline_depth(int depth) const { if (!UseInlineDepthForSpeculativeTypes) { return this; } return make(_ptr, _offset, _instance_id, _speculative, depth); } -/** - * Check whether new profiling would improve speculative type - * - * @param exact_kls class from profiling - * @param inline_depth inlining depth of profile point - * - * @return true if type profile is valuable - */ -bool TypeOopPtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const { - // no way to improve an already exact type - if (klass_is_exact()) { - return false; - } - // no profiling? - if (exact_kls == NULL) { - return false; - } - // no speculative type or non exact speculative type? - if (speculative_type() == NULL) { - return true; - } - // If the node already has an exact speculative type keep it, - // unless it was provided by profiling that is at a deeper - // inlining level. Profiling at a higher inlining depth is - // expected to be less accurate. - if (_speculative->inline_depth() == InlineDepthBottom) { - return false; - } - assert(_speculative->inline_depth() != InlineDepthTop, "can't do the comparison"); - return inline_depth < _speculative->inline_depth(); -} - //------------------------------meet_instance_id-------------------------------- int TypeOopPtr::meet_instance_id( int instance_id ) const { // Either is 'TOP' instance? Return the other instance! @@ -3013,102 +3241,19 @@ int TypeOopPtr::dual_instance_id( ) const { } /** - * meet of the speculative parts of 2 types + * Check whether new profiling would improve speculative type * - * @param other type to meet with - */ -const TypeOopPtr* TypeOopPtr::xmeet_speculative(const TypeOopPtr* other) const { - bool this_has_spec = (_speculative != NULL); - bool other_has_spec = (other->speculative() != NULL); - - if (!this_has_spec && !other_has_spec) { - return NULL; - } - - // If we are at a point where control flow meets and one branch has - // a speculative type and the other has not, we meet the speculative - // type of one branch with the actual type of the other. If the - // actual type is exact and the speculative is as well, then the - // result is a speculative type which is exact and we can continue - // speculation further. - const TypeOopPtr* this_spec = _speculative; - const TypeOopPtr* other_spec = other->speculative(); - - if (!this_has_spec) { - this_spec = this; - } - - if (!other_has_spec) { - other_spec = other; - } - - return this_spec->meet_speculative(other_spec)->is_oopptr(); -} - -/** - * dual of the speculative part of the type - */ -const TypeOopPtr* TypeOopPtr::dual_speculative() const { - if (_speculative == NULL) { - return NULL; - } - return _speculative->dual()->is_oopptr(); -} - -/** - * add offset to the speculative part of the type + * @param exact_kls class from profiling + * @param inline_depth inlining depth of profile point * - * @param offset offset to add + * @return true if type profile is valuable */ -const TypeOopPtr* TypeOopPtr::add_offset_speculative(intptr_t offset) const { - if (_speculative == NULL) { - return NULL; - } - return _speculative->add_offset(offset)->is_oopptr(); -} - -/** - * Are the speculative parts of 2 types equal? - * - * @param other type to compare this one to - */ -bool TypeOopPtr::eq_speculative(const TypeOopPtr* other) const { - if (_speculative == NULL || other->speculative() == NULL) { - return _speculative == other->speculative(); - } - - if (_speculative->base() != other->speculative()->base()) { +bool TypeOopPtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const { + // no way to improve an already exact type + if (klass_is_exact()) { return false; } - - return _speculative->eq(other->speculative()); -} - -/** - * Hash of the speculative part of the type - */ -int TypeOopPtr::hash_speculative() const { - if (_speculative == NULL) { - return 0; - } - - return _speculative->hash(); -} - -/** - * dual of the inline depth for this type (used for speculation) - */ -int TypeOopPtr::dual_inline_depth() const { - return -inline_depth(); -} - -/** - * meet of 2 inline depth (used for speculation) - * - * @param depth depth to meet with - */ -int TypeOopPtr::meet_inline_depth(int depth) const { - return MAX2(inline_depth(), depth); + return TypePtr::would_improve_type(exact_kls, inline_depth); } //============================================================================= @@ -3120,8 +3265,10 @@ const TypeInstPtr *TypeInstPtr::MARK; const TypeInstPtr *TypeInstPtr::KLASS; //------------------------------TypeInstPtr------------------------------------- -TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, int instance_id, const TypeOopPtr* speculative, int inline_depth) - : TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth), _name(k->name()) { +TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, + int instance_id, const TypePtr* speculative, int inline_depth) + : TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth), + _name(k->name()) { assert(k != NULL && (k->is_loaded() || o == NULL), "cannot have constants with non-loaded klass"); @@ -3134,7 +3281,7 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr, ciObject* o, int offset, int instance_id, - const TypeOopPtr* speculative, + const TypePtr* speculative, int inline_depth) { assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance"); // Either const_oop() is NULL or else ptr is Constant @@ -3217,7 +3364,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const { int off = meet_offset(tinst->offset()); PTR ptr = meet_ptr(tinst->ptr()); int instance_id = meet_instance_id(tinst->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tinst); + const TypePtr* speculative = xmeet_speculative(tinst); int depth = meet_inline_depth(tinst->inline_depth()); const TypeInstPtr *loaded = is_loaded() ? this : tinst; @@ -3295,7 +3442,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); switch (ptr) { case TopPTR: @@ -3346,7 +3493,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); return make(ptr, klass(), klass_is_exact(), (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth); @@ -3354,7 +3501,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { case NotNull: case BotPTR: { int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth); } @@ -3367,20 +3514,21 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { const TypePtr *tp = t->is_ptr(); int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); + int instance_id = meet_instance_id(InstanceTop); + const TypePtr* speculative = xmeet_speculative(tp); + int depth = meet_inline_depth(tp->inline_depth()); switch (tp->ptr()) { case Null: - if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset); + if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); // else fall through to AnyNull case TopPTR: case AnyNull: { - int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = _speculative; return make(ptr, klass(), klass_is_exact(), - (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, _inline_depth); + (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth); } case NotNull: case BotPTR: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, speculative,depth); default: typerr(t); } } @@ -3407,7 +3555,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { int off = meet_offset( tinst->offset() ); PTR ptr = meet_ptr( tinst->ptr() ); int instance_id = meet_instance_id(tinst->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tinst); + const TypePtr* speculative = xmeet_speculative(tinst); int depth = meet_inline_depth(tinst->inline_depth()); // Check for easy case; klasses are equal (and perhaps not loaded!) @@ -3563,6 +3711,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { // class hierarchy - which means we have to fall to at least NotNull. if( ptr == TopPTR || ptr == AnyNull || ptr == Constant ) ptr = NotNull; + instance_id = InstanceBot; // Now we find the LCA of Java classes @@ -3655,7 +3804,8 @@ void TypeInstPtr::dump2( Dict &d, uint depth, outputStream *st ) const { //------------------------------add_offset------------------------------------- const TypePtr *TypeInstPtr::add_offset(intptr_t offset) const { - return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), _instance_id, add_offset_speculative(offset)); + return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), + _instance_id, add_offset_speculative(offset), _inline_depth); } const Type *TypeInstPtr::remove_speculative() const { @@ -3663,10 +3813,11 @@ const Type *TypeInstPtr::remove_speculative() const { return this; } assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth"); - return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, NULL, _inline_depth); + return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, + _instance_id, NULL, _inline_depth); } -const TypeOopPtr *TypeInstPtr::with_inline_depth(int depth) const { +const TypePtr *TypeInstPtr::with_inline_depth(int depth) const { if (!UseInlineDepthForSpeculativeTypes) { return this; } @@ -3687,7 +3838,8 @@ const TypeAryPtr *TypeAryPtr::FLOATS; const TypeAryPtr *TypeAryPtr::DOUBLES; //------------------------------make------------------------------------------- -const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) { +const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, + int instance_id, const TypePtr* speculative, int inline_depth) { assert(!(k == NULL && ary->_elem->isa_int()), "integral arrays must be pre-equipped with a class"); if (!xk) xk = ary->ary_must_be_exact(); @@ -3697,7 +3849,9 @@ const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool } //------------------------------make------------------------------------------- -const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth, bool is_autobox_cache) { +const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, + int instance_id, const TypePtr* speculative, int inline_depth, + bool is_autobox_cache) { assert(!(k == NULL && ary->_elem->isa_int()), "integral arrays must be pre-equipped with a class"); assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" ); @@ -3807,7 +3961,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const TypeAry* new_ary = TypeAry::make(elem, size(), stable); - return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id); + return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth); } //-----------------------------stable_dimension-------------------------------- @@ -3868,18 +4022,17 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int depth = meet_inline_depth(tp->inline_depth()); + const TypePtr* speculative = xmeet_speculative(tp); switch (tp->ptr()) { case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = xmeet_speculative(tp); return make(ptr, (ptr == Constant ? const_oop() : NULL), _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); } case BotPTR: case NotNull: { int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth); } default: ShouldNotReachHere(); @@ -3891,20 +4044,21 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { const TypePtr *tp = t->is_ptr(); int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); + const TypePtr* speculative = xmeet_speculative(tp); + int depth = meet_inline_depth(tp->inline_depth()); switch (tp->ptr()) { case TopPTR: return this; case BotPTR: case NotNull: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); case Null: - if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset); + if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); // else fall through to AnyNull case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = _speculative; return make(ptr, (ptr == Constant ? const_oop() : NULL), - _ary, _klass, _klass_is_exact, offset, instance_id, speculative, _inline_depth); + _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); } default: ShouldNotReachHere(); } @@ -3920,7 +4074,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { const TypeAry *tary = _ary->meet_speculative(tap->_ary)->is_ary(); PTR ptr = meet_ptr(tap->ptr()); int instance_id = meet_instance_id(tap->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tap); + const TypePtr* speculative = xmeet_speculative(tap); int depth = meet_inline_depth(tap->inline_depth()); ciKlass* lazy_klass = NULL; if (tary->_elem->isa_int()) { @@ -3949,7 +4103,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { // 'this' is exact and super or unrelated: (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); - return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot); + return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth); } bool xk = false; @@ -4001,7 +4155,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); switch (ptr) { case TopPTR: @@ -4125,7 +4279,7 @@ const Type *TypeAryPtr::remove_speculative() const { return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL, _inline_depth); } -const TypeOopPtr *TypeAryPtr::with_inline_depth(int depth) const { +const TypePtr *TypeAryPtr::with_inline_depth(int depth) const { if (!UseInlineDepthForSpeculativeTypes) { return this; } @@ -4250,6 +4404,13 @@ const TypeNarrowOop* TypeNarrowOop::make(const TypePtr* type) { return (const TypeNarrowOop*)(new TypeNarrowOop(type))->hashcons(); } +const Type* TypeNarrowOop::remove_speculative() const { + return make(_ptrtype->remove_speculative()->is_ptr()); +} + +const Type* TypeNarrowOop::cleanup_speculative() const { + return make(_ptrtype->cleanup_speculative()->is_ptr()); +} #ifndef PRODUCT void TypeNarrowOop::dump2( Dict & d, uint depth, outputStream *st ) const { @@ -4376,15 +4537,15 @@ const Type *TypeMetadataPtr::xmeet( const Type *t ) const { PTR ptr = meet_ptr(tp->ptr()); switch (tp->ptr()) { case Null: - if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset); + if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); // else fall through: case TopPTR: case AnyNull: { - return make(ptr, NULL, offset); + return make(ptr, _metadata, offset); } case BotPTR: case NotNull: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); default: typerr(t); } } @@ -4698,12 +4859,12 @@ const Type *TypeKlassPtr::xmeet( const Type *t ) const { case TopPTR: return this; case Null: - if( ptr == Null ) return TypePtr::make( AnyPtr, ptr, offset ); + if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); case AnyNull: return make( ptr, klass(), offset ); case BotPTR: case NotNull: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); default: typerr(t); } } diff --git a/hotspot/src/share/vm/opto/type.hpp b/hotspot/src/share/vm/opto/type.hpp index fb58dc2f584..071c12bf0b6 100644 --- a/hotspot/src/share/vm/opto/type.hpp +++ b/hotspot/src/share/vm/opto/type.hpp @@ -224,7 +224,7 @@ public: } // Variant that keeps the speculative part of the types const Type *meet_speculative(const Type *t) const { - return meet_helper(t, true); + return meet_helper(t, true)->cleanup_speculative(); } // WIDEN: 'widens' for Ints and other range types virtual const Type *widen( const Type *old, const Type* limit ) const { return this; } @@ -247,7 +247,7 @@ public: } // Variant that keeps the speculative part of the types const Type *join_speculative(const Type *t) const { - return join_helper(t, true); + return join_helper(t, true)->cleanup_speculative(); } // Modified version of JOIN adapted to the needs Node::Value. @@ -259,7 +259,7 @@ public: } // Variant that keeps the speculative part of the types const Type *filter_speculative(const Type *kills) const { - return filter_helper(kills, true); + return filter_helper(kills, true)->cleanup_speculative(); } #ifdef ASSERT @@ -414,15 +414,18 @@ public: bool require_constant = false, bool is_autobox_cache = false); - // Speculative type. See TypeInstPtr - virtual const TypeOopPtr* speculative() const { return NULL; } - virtual ciKlass* speculative_type() const { return NULL; } + // Speculative type helper methods. See TypePtr. + virtual const TypePtr* speculative() const { return NULL; } + virtual ciKlass* speculative_type() const { return NULL; } + virtual ciKlass* speculative_type_not_null() const { return NULL; } + virtual bool speculative_maybe_null() const { return true; } + virtual const Type* remove_speculative() const { return this; } + virtual const Type* cleanup_speculative() const { return this; } + virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const { return exact_kls != NULL; } + virtual bool would_improve_ptr(bool maybe_null) const { return !maybe_null; } const Type* maybe_remove_speculative(bool include_speculative) const; - virtual const Type* remove_speculative() const { return this; } - virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const { - return exact_kls != NULL; - } + virtual bool maybe_null() const { return true; } private: // support arrays @@ -679,6 +682,7 @@ public: virtual const Type *xdual() const; // Compute dual right now. bool ary_must_be_exact() const; // true if arrays of such are never generic virtual const Type* remove_speculative() const; + virtual const Type* cleanup_speculative() const; #ifdef ASSERT // One type is interface, the other is oop virtual bool interface_vs_oop(const Type *t) const; @@ -761,13 +765,48 @@ class TypePtr : public Type { public: enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR }; protected: - TypePtr( TYPES t, PTR ptr, int offset ) : Type(t), _ptr(ptr), _offset(offset) {} - virtual bool eq( const Type *t ) const; - virtual int hash() const; // Type specific hashing + TypePtr(TYPES t, PTR ptr, int offset, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom) : + Type(t), _ptr(ptr), _offset(offset), _speculative(speculative), + _inline_depth(inline_depth) {} static const PTR ptr_meet[lastPTR][lastPTR]; static const PTR ptr_dual[lastPTR]; static const char * const ptr_msg[lastPTR]; + enum { + InlineDepthBottom = INT_MAX, + InlineDepthTop = -InlineDepthBottom + }; + + // Extra type information profiling gave us. We propagate it the + // same way the rest of the type info is propagated. If we want to + // use it, then we have to emit a guard: this part of the type is + // not something we know but something we speculate about the type. + const TypePtr* _speculative; + // For speculative types, we record at what inlining depth the + // profiling point that provided the data is. We want to favor + // profile data coming from outer scopes which are likely better for + // the current compilation. + int _inline_depth; + + // utility methods to work on the speculative part of the type + const TypePtr* dual_speculative() const; + const TypePtr* xmeet_speculative(const TypePtr* other) const; + bool eq_speculative(const TypePtr* other) const; + int hash_speculative() const; + const TypePtr* add_offset_speculative(intptr_t offset) const; +#ifndef PRODUCT + void dump_speculative(outputStream *st) const; +#endif + + // utility methods to work on the inline depth of the type + int dual_inline_depth() const; + int meet_inline_depth(int depth) const; +#ifndef PRODUCT + void dump_inline_depth(outputStream *st) const; +#endif + public: const int _offset; // Offset into oop, with TOP & BOT const PTR _ptr; // Pointer equivalence class @@ -775,7 +814,9 @@ public: const int offset() const { return _offset; } const PTR ptr() const { return _ptr; } - static const TypePtr *make( TYPES t, PTR ptr, int offset ); + static const TypePtr *make(TYPES t, PTR ptr, int offset, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom); // Return a 'ptr' version of this type virtual const Type *cast_to_ptr_type(PTR ptr) const; @@ -784,10 +825,13 @@ public: int xadd_offset( intptr_t offset ) const; virtual const TypePtr *add_offset( intptr_t offset ) const; + 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 virtual const Type *xmeet( const Type *t ) const; + virtual const Type *xmeet_helper( const Type *t ) const; int meet_offset( int offset ) const; int dual_offset( ) const; virtual const Type *xdual() const; // Compute dual right now. @@ -802,6 +846,20 @@ public: return ptr_dual[ ptr_meet[ ptr_dual[in_ptr] ] [ dual_ptr() ] ]; } + // Speculative type helper methods. + virtual const TypePtr* speculative() const { return _speculative; } + int inline_depth() const { return _inline_depth; } + virtual ciKlass* speculative_type() const; + virtual ciKlass* speculative_type_not_null() const; + virtual bool speculative_maybe_null() const; + virtual const Type* remove_speculative() const; + virtual const Type* cleanup_speculative() const; + virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const; + virtual bool would_improve_ptr(bool maybe_null) const; + virtual const TypePtr* with_inline_depth(int depth) const; + + virtual bool maybe_null() const { return meet_ptr(Null) == ptr(); } + // Tests for relation to centerline of type lattice: static bool above_centerline(PTR ptr) { return (ptr <= AnyNull); } static bool below_centerline(PTR ptr) { return (ptr >= NotNull); } @@ -850,7 +908,8 @@ public: // Some kind of oop (Java pointer), either klass or instance or array. class TypeOopPtr : public TypePtr { protected: - TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth); + TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, + const TypePtr* speculative, int inline_depth); public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -861,10 +920,6 @@ public: }; protected: - enum { - InlineDepthBottom = INT_MAX, - InlineDepthTop = -InlineDepthBottom - }; // Oop is NULL, unless this is a constant oop. ciObject* _const_oop; // Constant oop // If _klass is NULL, then so is _sig. This is an unloaded klass. @@ -880,38 +935,11 @@ protected: // This is the the node index of the allocation node creating this instance. int _instance_id; - // Extra type information profiling gave us. We propagate it the - // same way the rest of the type info is propagated. If we want to - // use it, then we have to emit a guard: this part of the type is - // not something we know but something we speculate about the type. - const TypeOopPtr* _speculative; - // For speculative types, we record at what inlining depth the - // profiling point that provided the data is. We want to favor - // profile data coming from outer scopes which are likely better for - // the current compilation. - int _inline_depth; - static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact); int dual_instance_id() const; int meet_instance_id(int uid) const; - // utility methods to work on the speculative part of the type - const TypeOopPtr* dual_speculative() const; - const TypeOopPtr* xmeet_speculative(const TypeOopPtr* other) const; - bool eq_speculative(const TypeOopPtr* other) const; - int hash_speculative() const; - const TypeOopPtr* add_offset_speculative(intptr_t offset) const; -#ifndef PRODUCT - void dump_speculative(outputStream *st) const; -#endif - // utility methods to work on the inline depth of the type - int dual_inline_depth() const; - int meet_inline_depth(int depth) const; -#ifndef PRODUCT - void dump_inline_depth(outputStream *st) const; -#endif - // Do not allow interface-vs.-noninterface joins to collapse to top. virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; @@ -941,7 +969,9 @@ public: bool not_null_elements = false); // Make a generic (unclassed) pointer to an oop. - static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom); + static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom); ciObject* const_oop() const { return _const_oop; } virtual ciKlass* klass() const { return _klass; } @@ -955,7 +985,6 @@ public: bool is_known_instance() const { return _instance_id > 0; } int instance_id() const { return _instance_id; } bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; } - virtual const TypeOopPtr* speculative() const { return _speculative; } virtual intptr_t get_con() const; @@ -969,10 +998,13 @@ public: const TypeKlassPtr* as_klass_type() const; virtual const TypePtr *add_offset( intptr_t offset ) const; - // Return same type without a speculative part - virtual const Type* remove_speculative() const; - virtual const Type *xmeet(const Type *t) const; + // Speculative type helper methods. + virtual const Type* remove_speculative() const; + virtual const Type* cleanup_speculative() const; + virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const; + virtual const TypePtr* with_inline_depth(int depth) const; + virtual const Type *xdual() const; // Compute dual right now. // the core of the computation of the meet for TypeOopPtr and for its subclasses virtual const Type *xmeet_helper(const Type *t) const; @@ -982,29 +1014,14 @@ public: #ifndef PRODUCT virtual void dump2( Dict &d, uint depth, outputStream *st ) const; #endif - - // Return the speculative type if any - ciKlass* speculative_type() const { - if (_speculative != NULL) { - const TypeOopPtr* speculative = _speculative->join(this)->is_oopptr(); - if (speculative->klass_is_exact()) { - return speculative->klass(); - } - } - return NULL; - } - int inline_depth() const { - return _inline_depth; - } - virtual const TypeOopPtr* with_inline_depth(int depth) const; - virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const; }; //------------------------------TypeInstPtr------------------------------------ // Class of Java object pointers, pointing either to non-array Java instances // or to a Klass* (including array klasses). class TypeInstPtr : public TypeOopPtr { - TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth); + TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, + const TypePtr* speculative, int inline_depth); virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -1040,7 +1057,10 @@ class TypeInstPtr : public TypeOopPtr { } // Make a pointer to an oop. - static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom); + static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, + int instance_id = InstanceBot, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom); /** Create constant type for a constant boxed value */ const Type* get_const_boxed_value() const; @@ -1057,9 +1077,10 @@ class TypeInstPtr : public TypeOopPtr { virtual const TypeOopPtr *cast_to_instance_id(int instance_id) const; virtual const TypePtr *add_offset( intptr_t offset ) const; - // Return same type without a speculative part + + // Speculative type helper methods. virtual const Type* remove_speculative() const; - virtual const TypeOopPtr* with_inline_depth(int depth) const; + virtual const TypePtr* with_inline_depth(int depth) const; // the core of the computation of the meet of 2 types virtual const Type *xmeet_helper(const Type *t) const; @@ -1081,7 +1102,8 @@ class TypeInstPtr : public TypeOopPtr { // Class of Java array pointers class TypeAryPtr : public TypeOopPtr { TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, - int offset, int instance_id, bool is_autobox_cache, const TypeOopPtr* speculative, int inline_depth) + int offset, int instance_id, bool is_autobox_cache, + const TypePtr* speculative, int inline_depth) : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative, inline_depth), _ary(ary), _is_autobox_cache(is_autobox_cache) @@ -1120,9 +1142,15 @@ public: bool is_autobox_cache() const { return _is_autobox_cache; } - static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom); + static const TypeAryPtr *make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, + int instance_id = InstanceBot, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom); // Constant pointer to array - static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom, bool is_autobox_cache= false); + static const TypeAryPtr *make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, + int instance_id = InstanceBot, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom, bool is_autobox_cache = false); // Return a 'ptr' version of this type virtual const Type *cast_to_ptr_type(PTR ptr) const; @@ -1136,9 +1164,10 @@ public: virtual bool empty(void) const; // TRUE if type is vacuous virtual const TypePtr *add_offset( intptr_t offset ) const; - // Return same type without a speculative part + + // Speculative type helper methods. virtual const Type* remove_speculative() const; - virtual const TypeOopPtr* with_inline_depth(int depth) const; + virtual const TypePtr* with_inline_depth(int depth) const; // the core of the computation of the meet of 2 types virtual const Type *xmeet_helper(const Type *t) const; @@ -1367,9 +1396,8 @@ public: static const TypeNarrowOop *BOTTOM; static const TypeNarrowOop *NULL_PTR; - virtual const Type* remove_speculative() const { - return make(_ptrtype->remove_speculative()->is_ptr()); - } + virtual const Type* remove_speculative() const; + virtual const Type* cleanup_speculative() const; #ifndef PRODUCT virtual void dump2( Dict &d, uint depth, outputStream *st ) const; @@ -1716,6 +1744,7 @@ inline bool Type::is_ptr_to_boxing_obj() const { #define ConvL2X(x) (x) #define ConvX2I(x) ConvL2I(x) #define ConvX2L(x) (x) +#define ConvX2UL(x) (x) #else @@ -1760,6 +1789,7 @@ inline bool Type::is_ptr_to_boxing_obj() const { #define ConvL2X(x) ConvL2I(x) #define ConvX2I(x) (x) #define ConvX2L(x) ConvI2L(x) +#define ConvX2UL(x) ConvI2UL(x) #endif diff --git a/hotspot/src/share/vm/precompiled/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp index 4026c0eb29f..5118a398f13 100644 --- a/hotspot/src/share/vm/precompiled/precompiled.hpp +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp @@ -254,18 +254,24 @@ # include "opto/block.hpp" # include "opto/c2_globals.hpp" # include "opto/callnode.hpp" +# include "opto/castnode.hpp" # include "opto/cfgnode.hpp" # include "opto/compile.hpp" # include "opto/connode.hpp" +# include "opto/convertnode.hpp" +# include "opto/countbitsnode.hpp" # include "opto/idealGraphPrinter.hpp" +# include "opto/intrinsicnode.hpp" # include "opto/loopnode.hpp" # include "opto/machnode.hpp" # include "opto/matcher.hpp" # include "opto/memnode.hpp" +# include "opto/movenode.hpp" # include "opto/mulnode.hpp" # include "opto/multnode.hpp" -# include "opto/node.hpp" +# include "opto/narrowptrnode.hpp" # include "opto/opcodes.hpp" +# include "opto/opaquenode.hpp" # include "opto/optoreg.hpp" # include "opto/phase.hpp" # include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index b778f606998..675ac43ab0f 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -3878,10 +3878,12 @@ void TestMetachunk_test(); void TestVirtualSpaceNode_test(); void TestNewSize_test(); void TestKlass_test(); +void TestBitMap_test(); #if INCLUDE_ALL_GCS void TestOldFreeSpaceCalculation_test(); void TestG1BiasedArray_test(); void TestBufferingOopClosure_test(); +void TestCodeCacheRemSet_test(); #endif void execute_internal_vm_tests() { @@ -3902,6 +3904,7 @@ void execute_internal_vm_tests() { run_unit_test(test_loggc_filename()); run_unit_test(TestNewSize_test()); run_unit_test(TestKlass_test()); + run_unit_test(TestBitMap_test()); #if INCLUDE_VM_STRUCTS run_unit_test(VMStructs::test()); #endif @@ -3910,6 +3913,7 @@ void execute_internal_vm_tests() { run_unit_test(TestG1BiasedArray_test()); run_unit_test(HeapRegionRemSet::test_prt()); run_unit_test(TestBufferingOopClosure_test()); + run_unit_test(TestCodeCacheRemSet_test()); #endif tty->print_cr("All internal VM tests passed"); } @@ -3999,7 +4003,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, v } #ifndef PRODUCT - #ifndef TARGET_OS_FAMILY_windows + #ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f() #endif diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 1c95046c77b..fec483f3011 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -1160,18 +1160,22 @@ static bool is_authorized(Handle context, instanceKlassHandle klass, TRAPS) { // and null permissions - which gives no permissions. oop create_dummy_access_control_context(TRAPS) { InstanceKlass* pd_klass = InstanceKlass::cast(SystemDictionary::ProtectionDomain_klass()); - // new ProtectionDomain(null,null); - oop null_protection_domain = pd_klass->allocate_instance(CHECK_NULL); - Handle null_pd(THREAD, null_protection_domain); + Handle obj = pd_klass->allocate_instance_handle(CHECK_NULL); + // Call constructor ProtectionDomain(null, null); + JavaValue result(T_VOID); + JavaCalls::call_special(&result, obj, KlassHandle(THREAD, pd_klass), + vmSymbols::object_initializer_name(), + vmSymbols::codesource_permissioncollection_signature(), + Handle(), Handle(), CHECK_NULL); // new ProtectionDomain[] {pd}; objArrayOop context = oopFactory::new_objArray(pd_klass, 1, CHECK_NULL); - context->obj_at_put(0, null_pd()); + context->obj_at_put(0, obj()); // new AccessControlContext(new ProtectionDomain[] {pd}) objArrayHandle h_context(THREAD, context); - oop result = java_security_AccessControlContext::create(h_context, false, Handle(), CHECK_NULL); - return result; + oop acc = java_security_AccessControlContext::create(h_context, false, Handle(), CHECK_NULL); + return acc; } JVM_ENTRY(jobject, JVM_DoPrivileged(JNIEnv *env, jclass cls, jobject action, jobject context, jboolean wrapException)) diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp index 597d7a164dc..4e39e767833 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1020,19 +1020,12 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec } if (owning_thread != NULL) { // monitor is owned - if ((address)owning_thread == owner) { - // the owner field is the JavaThread * - assert(mon != NULL, - "must have heavyweight monitor with JavaThread * owner"); - ret.entry_count = mon->recursions() + 1; - } else { - // The owner field is the Lock word on the JavaThread's stack - // so the recursions field is not valid. We have to count the - // number of recursive monitor entries the hard way. We pass - // a handle to survive any GCs along the way. - ResourceMark rm; - ret.entry_count = count_locked_objects(owning_thread, hobj); - } + // The recursions field of a monitor does not reflect recursions + // as lightweight locks before inflating the monitor are not included. + // We have to count the number of recursive monitor entries the hard way. + // We pass a handle to survive any GCs along the way. + ResourceMark rm; + ret.entry_count = count_locked_objects(owning_thread, hobj); } // implied else: entry_count == 0 } diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index 8aacad27e83..8ef2f6ba63b 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -993,7 +993,9 @@ void JvmtiExport::post_class_unload(Klass* klass) { // Before we call the JVMTI agent, we have to set the state in the // thread for which we are proxying. JavaThreadState prev_state = real_thread->thread_state(); - assert(prev_state == _thread_blocked, "JavaThread should be at safepoint"); + assert(((Thread *)real_thread)->is_ConcurrentGC_thread() || + (real_thread->is_Java_thread() && prev_state == _thread_blocked), + "should be ConcurrentGCThread or JavaThread at safepoint"); real_thread->set_thread_state(_thread_in_native); jvmtiExtensionEvent callback = env->ext_callbacks()->ClassUnload; diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index d2d5fadb024..df8a0d2dc2f 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.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 @@ -500,6 +500,54 @@ WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o)) c = *p; WB_END +WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o)) + const char* cpu_features = VM_Version::cpu_features(); + ThreadToNativeFromVM ttn(thread); + jstring features_string = env->NewStringUTF(cpu_features); + + CHECK_JNI_EXCEPTION_(env, NULL); + + return features_string; +WB_END + + +WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr)) + ResourceMark rm(THREAD); + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, NULL); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); + jobjectArray result = NULL; + if (code == NULL) { + return result; + } + int insts_size = code->insts_size(); + + ThreadToNativeFromVM ttn(thread); + jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + result = env->NewObjectArray(2, clazz, NULL); + if (result == NULL) { + return result; + } + + clazz = env->FindClass(vmSymbols::java_lang_Integer()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + jmethodID constructor = env->GetMethodID(clazz, vmSymbols::object_initializer_name()->as_C_string(), vmSymbols::int_void_signature()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + jobject obj = env->NewObject(clazz, constructor, code->comp_level()); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 0, obj); + + jbyteArray insts = env->NewByteArray(insts_size); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetByteArrayRegion(insts, 0, insts_size, (jbyte*) code->insts_begin()); + env->SetObjectArrayElement(result, 1, insts); + + return result; +WB_END + + //Some convenience methods to deal with objects from java int WhiteBox::offset_for_field(const char* field_name, oop object, Symbol* signature_symbol) { @@ -611,6 +659,9 @@ static JNINativeMethod methods[] = { {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable }, {CC"fullGC", CC"()V", (void*)&WB_FullGC }, {CC"readReservedMemory", CC"()V", (void*)&WB_ReadReservedMemory }, + {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, + {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", + (void*)&WB_GetNMethod }, }; #undef CC diff --git a/hotspot/src/share/vm/prims/whitebox.hpp b/hotspot/src/share/vm/prims/whitebox.hpp index a6e27b49055..a9854f3ffea 100644 --- a/hotspot/src/share/vm/prims/whitebox.hpp +++ b/hotspot/src/share/vm/prims/whitebox.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 @@ -40,7 +40,6 @@ do { \ JavaThread* THREAD = JavaThread::thread_from_jni_environment(env); \ if (HAS_PENDING_EXCEPTION) { \ - CLEAR_PENDING_EXCEPTION; \ return(value); \ } \ } while (0) @@ -49,7 +48,6 @@ do { \ JavaThread* THREAD = JavaThread::thread_from_jni_environment(env); \ if (HAS_PENDING_EXCEPTION) { \ - CLEAR_PENDING_EXCEPTION; \ return; \ } \ } while (0) diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 3099df2e8ef..80bab70ef94 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -301,10 +301,12 @@ static ObsoleteFlag obsolete_jvm_flags[] = { { "UseMPSS", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseStringCache", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseOldInlining", JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "SafepointPollOffset", JDK_Version::jdk(9), JDK_Version::jdk(10) }, #ifdef PRODUCT { "DesiredMethodLimit", JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) }, #endif // PRODUCT + { "UseVMInterruptibleIO", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { NULL, JDK_Version(0), JDK_Version(0) } }; @@ -1185,11 +1187,6 @@ void Arguments::set_parnew_gc_flags() { FLAG_SET_DEFAULT(OldPLABSize, (intx)1024); } - // AlwaysTenure flag should make ParNew promote all at first collection. - // See CR 6362902. - if (AlwaysTenure) { - FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0); - } // When using compressed oops, we use local overflow stacks, // rather than using a global overflow list chained through // the klass word of the object's pre-image. @@ -1906,24 +1903,22 @@ static bool verify_serial_gc_flags() { // check if do gclog rotation // +UseGCLogFileRotation is a must, // no gc log rotation when log file not supplied or -// NumberOfGCLogFiles is 0, or GCLogFileSize is 0 +// NumberOfGCLogFiles is 0 void check_gclog_consistency() { if (UseGCLogFileRotation) { - if ((Arguments::gc_log_filename() == NULL) || - (NumberOfGCLogFiles == 0) || - (GCLogFileSize == 0)) { + if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) { jio_fprintf(defaultStream::output_stream(), - "To enable GC log rotation, use -Xloggc: -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles= -XX:GCLogFileSize=[k|K|m|M|g|G]\n" - "where num_of_file > 0 and num_of_size > 0\n" + "To enable GC log rotation, use -Xloggc: -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=\n" + "where num_of_file > 0\n" "GC log rotation is turned off\n"); UseGCLogFileRotation = false; } } - if (UseGCLogFileRotation && GCLogFileSize < 8*K) { - FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K); - jio_fprintf(defaultStream::output_stream(), - "GCLogFileSize changed to minimum 8K\n"); + if (UseGCLogFileRotation && (GCLogFileSize != 0) && (GCLogFileSize < 8*K)) { + FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K); + jio_fprintf(defaultStream::output_stream(), + "GCLogFileSize changed to minimum 8K\n"); } } @@ -2246,6 +2241,8 @@ bool Arguments::check_vm_args_consistency() { "G1ConcRSHotCardLimit"); status = status && verify_interval(G1ConcRSLogCacheSize, 0, 31, "G1ConcRSLogCacheSize"); + status = status && verify_interval(StringDeduplicationAgeThreshold, 1, markOopDesc::max_age, + "StringDeduplicationAgeThreshold"); } if (UseConcMarkSweepGC) { status = status && verify_min_value(CMSOldPLABNumRefills, 1, "CMSOldPLABNumRefills"); @@ -2340,10 +2337,8 @@ bool Arguments::check_vm_args_consistency() { status = status && verify_percentage(YoungGenerationSizeSupplement, "YoungGenerationSizeSupplement"); status = status && verify_percentage(TenuredGenerationSizeSupplement, "TenuredGenerationSizeSupplement"); - // the "age" field in the oop header is 4 bits; do not want to pull in markOop.hpp - // just for that, so hardcode here. - status = status && verify_interval(MaxTenuringThreshold, 0, 15, "MaxTenuringThreshold"); - status = status && verify_interval(InitialTenuringThreshold, 0, MaxTenuringThreshold, "MaxTenuringThreshold"); + status = status && verify_interval(MaxTenuringThreshold, 0, markOopDesc::max_age + 1, "MaxTenuringThreshold"); + status = status && verify_interval(InitialTenuringThreshold, 0, MaxTenuringThreshold, "InitialTenuringThreshold"); status = status && verify_percentage(TargetSurvivorRatio, "TargetSurvivorRatio"); status = status && verify_percentage(MarkSweepDeadRatio, "MarkSweepDeadRatio"); @@ -3069,14 +3064,31 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // but disallow DR and offlining (5008695). FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true); + // Need to keep consistency of MaxTenuringThreshold and AlwaysTenure/NeverTenure; + // and the last option wins. } else if (match_option(option, "-XX:+NeverTenure", &tail)) { - // The last option must always win. - FLAG_SET_CMDLINE(bool, AlwaysTenure, false); FLAG_SET_CMDLINE(bool, NeverTenure, true); + FLAG_SET_CMDLINE(bool, AlwaysTenure, false); + FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1); } else if (match_option(option, "-XX:+AlwaysTenure", &tail)) { - // The last option must always win. FLAG_SET_CMDLINE(bool, NeverTenure, false); FLAG_SET_CMDLINE(bool, AlwaysTenure, true); + FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0); + } else if (match_option(option, "-XX:MaxTenuringThreshold=", &tail)) { + uintx max_tenuring_thresh = 0; + if(!parse_uintx(tail, &max_tenuring_thresh, 0)) { + jio_fprintf(defaultStream::error_stream(), + "Invalid MaxTenuringThreshold: %s\n", option->optionString); + } + FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh); + + if (MaxTenuringThreshold == 0) { + FLAG_SET_CMDLINE(bool, NeverTenure, false); + FLAG_SET_CMDLINE(bool, AlwaysTenure, true); + } else { + FLAG_SET_CMDLINE(bool, NeverTenure, false); + FLAG_SET_CMDLINE(bool, AlwaysTenure, false); + } } else if (match_option(option, "-XX:+CMSPermGenSweepingEnabled", &tail) || match_option(option, "-XX:-CMSPermGenSweepingEnabled", &tail)) { jio_fprintf(defaultStream::error_stream(), @@ -3226,11 +3238,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, return JNI_EINVAL; } FLAG_SET_CMDLINE(uintx, MaxDirectMemorySize, max_direct_memory_size); - } else if (match_option(option, "-XX:+UseVMInterruptibleIO", &tail)) { - // NOTE! In JDK 9, the UseVMInterruptibleIO flag will completely go - // away and will cause VM initialization failures! - warning("-XX:+UseVMInterruptibleIO is obsolete and will be removed in a future release."); - FLAG_SET_CMDLINE(bool, UseVMInterruptibleIO, true); #if !INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:+ManagementServer", &tail)) { jio_fprintf(defaultStream::error_stream(), @@ -3781,9 +3788,6 @@ jint Arguments::apply_ergo() { #endif // CC_INTERP #ifdef COMPILER2 - if (!UseBiasedLocking || EmitSync != 0) { - UseOptoBiasInlining = false; - } if (!EliminateLocks) { EliminateNestedLocks = false; } @@ -3795,10 +3799,6 @@ jint Arguments::apply_ergo() { AlwaysIncrementalInline = false; } #endif - if (IncrementalInline && FLAG_IS_DEFAULT(MaxNodeLimit)) { - // incremental inlining: bump MaxNodeLimit - FLAG_SET_DEFAULT(MaxNodeLimit, (intx)75000); - } if (!UseTypeSpeculation && FLAG_IS_DEFAULT(TypeProfileLevel)) { // nothing to use the profiling, turn if off FLAG_SET_DEFAULT(TypeProfileLevel, 0); @@ -3844,6 +3844,11 @@ jint Arguments::apply_ergo() { UseBiasedLocking = false; } } +#ifdef COMPILER2 + if (!UseBiasedLocking || EmitSync != 0) { + UseOptoBiasInlining = false; + } +#endif return JNI_OK; } diff --git a/hotspot/src/share/vm/runtime/atomic.hpp b/hotspot/src/share/vm/runtime/atomic.hpp index 9ca5fce97e7..5b46b530b51 100644 --- a/hotspot/src/share/vm/runtime/atomic.hpp +++ b/hotspot/src/share/vm/runtime/atomic.hpp @@ -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 @@ -57,6 +57,7 @@ class Atomic : AllStatic { // Atomically add to a location, return updated value inline static jint add (jint add_value, volatile jint* dest); + inline static size_t add (size_t add_value, volatile size_t* dest); inline static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest); inline static void* add_ptr(intptr_t add_value, volatile void* dest); // See comment above about using jlong atomics on 32-bit platforms @@ -65,12 +66,14 @@ class Atomic : AllStatic { // Atomically increment location inline static void inc (volatile jint* dest); static void inc (volatile jshort* dest); + inline static void inc (volatile size_t* dest); inline static void inc_ptr(volatile intptr_t* dest); inline static void inc_ptr(volatile void* dest); // Atomically decrement a location inline static void dec (volatile jint* dest); static void dec (volatile jshort* dest); + inline static void dec (volatile size_t* dest); inline static void dec_ptr(volatile intptr_t* dest); inline static void dec_ptr(volatile void* dest); diff --git a/hotspot/src/share/vm/runtime/atomic.inline.hpp b/hotspot/src/share/vm/runtime/atomic.inline.hpp index 2906719452d..e3983ef6b55 100644 --- a/hotspot/src/share/vm/runtime/atomic.inline.hpp +++ b/hotspot/src/share/vm/runtime/atomic.inline.hpp @@ -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 @@ -70,4 +70,21 @@ # include "atomic_bsd_zero.inline.hpp" #endif +// size_t casts... +#if (SIZE_MAX != UINTPTR_MAX) +#error size_t is not WORD_SIZE, interesting platform, but missing implementation here +#endif + +inline size_t Atomic::add(size_t add_value, volatile size_t* dest) { + return (size_t) add_ptr((intptr_t) add_value, (volatile intptr_t*) dest); +} + +inline void Atomic::inc(volatile size_t* dest) { + inc_ptr((volatile intptr_t*) dest); +} + +inline void Atomic::dec(volatile size_t* dest) { + dec_ptr((volatile intptr_t*) dest); +} + #endif // SHARE_VM_RUNTIME_ATOMIC_INLINE_HPP diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index b1b078f6491..8e3b14c1671 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -1288,7 +1288,8 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra gather_statistics(reason, action, trap_bc); // Ensure that we can record deopt. history: - bool create_if_missing = ProfileTraps; + // Need MDO to record RTM code generation state. + bool create_if_missing = ProfileTraps RTM_OPT_ONLY( || UseRTMLocking ); MethodData* trap_mdo = get_method_data(thread, trap_method, create_if_missing); @@ -1569,6 +1570,17 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra if (tstate1 != tstate0) pdata->set_trap_state(tstate1); } + +#if INCLUDE_RTM_OPT + // Restart collecting RTM locking abort statistic if the method + // is recompiled for a reason other than RTM state change. + // Assume that in new recompiled code the statistic could be different, + // for example, due to different inlining. + if ((reason != Reason_rtm_state_change) && (trap_mdo != NULL) && + UseRTMDeopt && (nm->rtm_state() != ProfileRTM)) { + trap_mdo->atomic_set_rtm_state(ProfileRTM); + } +#endif } if (inc_recompile_count) { @@ -1826,7 +1838,9 @@ const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = { "age", "predicate", "loop_limit_check", - "speculate_class_check" + "speculate_class_check", + "speculate_null_check", + "rtm_state_change" }; const char* Deoptimization::_trap_action_name[Action_LIMIT] = { // Note: Keep this in sync. with enum DeoptAction. diff --git a/hotspot/src/share/vm/runtime/deoptimization.hpp b/hotspot/src/share/vm/runtime/deoptimization.hpp index f2233c9869b..eb8e2cbdede 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.hpp +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp @@ -60,6 +60,8 @@ class Deoptimization : AllStatic { Reason_predicate, // compiler generated predicate failed Reason_loop_limit_check, // compiler generated loop limits check failed Reason_speculate_class_check, // saw unexpected object class from type speculation + Reason_speculate_null_check, // saw unexpected null from type speculation + Reason_rtm_state_change, // rtm state change detected Reason_LIMIT, // Note: Keep this enum in sync. with _trap_reason_name. Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc @@ -314,17 +316,27 @@ class Deoptimization : AllStatic { return Reason_null_check; // recorded per BCI as a null check else if (reason == Reason_speculate_class_check) return Reason_class_check; + else if (reason == Reason_speculate_null_check) + return Reason_null_check; else return Reason_none; } static bool reason_is_speculate(int reason) { - if (reason == Reason_speculate_class_check) { + if (reason == Reason_speculate_class_check || reason == Reason_speculate_null_check) { return true; } return false; } + static DeoptReason reason_null_check(bool speculative) { + return speculative ? Deoptimization::Reason_speculate_null_check : Deoptimization::Reason_null_check; + } + + static DeoptReason reason_class_check(bool speculative) { + return speculative ? Deoptimization::Reason_speculate_class_check : Deoptimization::Reason_class_check; + } + static uint per_method_trap_limit(int reason) { return reason_is_speculate(reason) ? (uint)PerMethodSpecTrapLimit : (uint)PerMethodTrapLimit; } diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index cdd2cf79ac3..1409bd79651 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -531,13 +531,16 @@ jint frame::interpreter_frame_expression_stack_size() const { // Number of elements on the interpreter expression stack // Callers should span by stackElementWords int element_size = Interpreter::stackElementWords; + size_t stack_size = 0; if (frame::interpreter_frame_expression_stack_direction() < 0) { - return (interpreter_frame_expression_stack() - - interpreter_frame_tos_address() + 1)/element_size; + stack_size = (interpreter_frame_expression_stack() - + interpreter_frame_tos_address() + 1)/element_size; } else { - return (interpreter_frame_tos_address() - - interpreter_frame_expression_stack() + 1)/element_size; + stack_size = (interpreter_frame_tos_address() - + interpreter_frame_expression_stack() + 1)/element_size; } + assert( stack_size <= (size_t)max_jint, "stack size too big"); + return ((jint)stack_size); } diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 945e8ea667e..8dcc17edaf2 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2423,9 +2423,9 @@ class CommandLineFlags { "Number of gclog files in rotation " \ "(default: 0, no rotation)") \ \ - product(uintx, GCLogFileSize, 0, \ - "GC log file size (default: 0 bytes, no rotation). " \ - "It requires UseGCLogFileRotation") \ + product(uintx, GCLogFileSize, 8*K, \ + "GC log file size, requires UseGCLogFileRotation. " \ + "Set to 0 to only trigger rotation via jcmd") \ \ /* JVMTI heap profiling */ \ \ @@ -2832,7 +2832,7 @@ class CommandLineFlags { "number of method invocations/branches (expressed as % of " \ "CompileThreshold) before using the method's profile") \ \ - develop(bool, PrintMethodData, false, \ + diagnostic(bool, PrintMethodData, false, \ "Print the results of +ProfileInterpreter at end of run") \ \ develop(bool, VerifyDataPointer, trueInDebug, \ @@ -3840,17 +3840,28 @@ class CommandLineFlags { experimental(uintx, SymbolTableSize, defaultSymbolTableSize, \ "Number of buckets in the JVM internal Symbol table") \ \ + product(bool, UseStringDeduplication, false, \ + "Use string deduplication") \ + \ + product(bool, PrintStringDeduplicationStatistics, false, \ + "Print string deduplication statistics") \ + \ + product(uintx, StringDeduplicationAgeThreshold, 3, \ + "A string must reach this age (or be promoted to an old region) " \ + "to be considered for deduplication") \ + \ + diagnostic(bool, StringDeduplicationResizeALot, false, \ + "Force table resize every time the table is scanned") \ + \ + diagnostic(bool, StringDeduplicationRehashALot, false, \ + "Force table rehash every time the table is scanned") \ + \ develop(bool, TraceDefaultMethods, false, \ "Trace the default method processing steps") \ \ develop(bool, VerifyGenericSignatures, false, \ "Abort VM on erroneous or inconsistent generic signatures") \ \ - product(bool, UseVMInterruptibleIO, false, \ - "(Unstable, Solaris-specific) Thread interrupt before or with " \ - "EINTR for I/O operations results in OS_INTRPT. The default " \ - "value of this flag is true for JDK 6 and earlier") \ - \ diagnostic(bool, WhiteBoxAPI, false, \ "Enable internal testing APIs") \ \ diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 6c2d90daeaa..231f3fe7249 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -98,21 +98,14 @@ #endif -#ifndef PRODUCT - -// Statistics printing (method invocation histogram) - -GrowableArray* collected_invoked_methods; - -void collect_invoked_methods(Method* m) { - if (m->invocation_count() + m->compiled_invocation_count() >= 1 ) { - collected_invoked_methods->push(m); - } -} - - GrowableArray* collected_profiled_methods; +int compare_methods(Method** a, Method** b) { + // %%% there can be 32-bit overflow here + return ((*b)->invocation_count() + (*b)->compiled_invocation_count()) + - ((*a)->invocation_count() + (*a)->compiled_invocation_count()); +} + void collect_profiled_methods(Method* m) { Thread* thread = Thread::current(); // This HandleMark prevents a huge amount of handles from being added @@ -125,14 +118,54 @@ void collect_profiled_methods(Method* m) { } } +void print_method_profiling_data() { + if (ProfileInterpreter COMPILER1_PRESENT(|| C1UpdateMethodData)) { + ResourceMark rm; + HandleMark hm; + collected_profiled_methods = new GrowableArray(1024); + ClassLoaderDataGraph::methods_do(collect_profiled_methods); + collected_profiled_methods->sort(&compare_methods); -int compare_methods(Method** a, Method** b) { - // %%% there can be 32-bit overflow here - return ((*b)->invocation_count() + (*b)->compiled_invocation_count()) - - ((*a)->invocation_count() + (*a)->compiled_invocation_count()); + int count = collected_profiled_methods->length(); + int total_size = 0; + if (count > 0) { + for (int index = 0; index < count; index++) { + Method* m = collected_profiled_methods->at(index); + ttyLocker ttyl; + tty->print_cr("------------------------------------------------------------------------"); + m->print_invocation_count(); + tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes()); + tty->cr(); + // Dump data on parameters if any + if (m->method_data() != NULL && m->method_data()->parameters_type_data() != NULL) { + tty->fill_to(2); + m->method_data()->parameters_type_data()->print_data_on(tty); + } + m->print_codes(); + total_size += m->method_data()->size_in_bytes(); + } + tty->print_cr("------------------------------------------------------------------------"); + tty->print_cr("Total MDO size: %d bytes", total_size); + } + } } +#ifndef PRODUCT + +// Statistics printing (method invocation histogram) + +GrowableArray* collected_invoked_methods; + +void collect_invoked_methods(Method* m) { + if (m->invocation_count() + m->compiled_invocation_count() >= 1 ) { + collected_invoked_methods->push(m); + } +} + + + + void print_method_invocation_histogram() { ResourceMark rm; HandleMark hm; @@ -173,37 +206,6 @@ void print_method_invocation_histogram() { SharedRuntime::print_call_statistics(comp_total); } -void print_method_profiling_data() { - ResourceMark rm; - HandleMark hm; - collected_profiled_methods = new GrowableArray(1024); - SystemDictionary::methods_do(collect_profiled_methods); - collected_profiled_methods->sort(&compare_methods); - - int count = collected_profiled_methods->length(); - int total_size = 0; - if (count > 0) { - for (int index = 0; index < count; index++) { - Method* m = collected_profiled_methods->at(index); - ttyLocker ttyl; - tty->print_cr("------------------------------------------------------------------------"); - //m->print_name(tty); - m->print_invocation_count(); - tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes()); - tty->cr(); - // Dump data on parameters if any - if (m->method_data() != NULL && m->method_data()->parameters_type_data() != NULL) { - tty->fill_to(2); - m->method_data()->parameters_type_data()->print_data_on(tty); - } - m->print_codes(); - total_size += m->method_data()->size_in_bytes(); - } - tty->print_cr("------------------------------------------------------------------------"); - tty->print_cr("Total MDO size: %d bytes", total_size); - } -} - void print_bytecode_count() { if (CountBytecodes || TraceBytecodes || StopInterpreterAt) { tty->print_cr("[BytecodeCounter::counter_value = %d]", BytecodeCounter::counter_value()); @@ -265,7 +267,7 @@ void print_statistics() { os::print_statistics(); } - if (PrintLockStatistics || PrintPreciseBiasedLockingStatistics) { + if (PrintLockStatistics || PrintPreciseBiasedLockingStatistics || PrintPreciseRTMLockingStatistics) { OptoRuntime::print_named_counters(); } @@ -281,9 +283,9 @@ void print_statistics() { if (CountCompiledCalls) { print_method_invocation_histogram(); } - if (ProfileInterpreter COMPILER1_PRESENT(|| C1UpdateMethodData)) { - print_method_profiling_data(); - } + + print_method_profiling_data(); + if (TimeCompiler) { COMPILER2_PRESENT(Compile::print_timers();) } @@ -373,6 +375,10 @@ void print_statistics() { void print_statistics() { + if (PrintMethodData) { + print_method_profiling_data(); + } + if (CITime) { CompileBroker::print_times(); } @@ -387,7 +393,7 @@ void print_statistics() { } #ifdef COMPILER2 - if (PrintPreciseBiasedLockingStatistics) { + if (PrintPreciseBiasedLockingStatistics || PrintPreciseRTMLockingStatistics) { OptoRuntime::print_named_counters(); } #endif diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index 19f98cc2e4f..a798bd8d5b4 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.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 @@ -58,6 +58,8 @@ Mutex* SignatureHandlerLibrary_lock = NULL; Mutex* VtableStubs_lock = NULL; Mutex* SymbolTable_lock = NULL; Mutex* StringTable_lock = NULL; +Monitor* StringDedupQueue_lock = NULL; +Mutex* StringDedupTable_lock = NULL; Mutex* CodeCache_lock = NULL; Mutex* MethodData_lock = NULL; Mutex* RetData_lock = NULL; @@ -196,6 +198,9 @@ void mutex_init() { def(MMUTracker_lock , Mutex , leaf , true ); def(HotCardCache_lock , Mutex , special , true ); def(EvacFailureStack_lock , Mutex , nonleaf , true ); + + def(StringDedupQueue_lock , Monitor, leaf, true ); + def(StringDedupTable_lock , Mutex , leaf, true ); } def(ParGCRareEvent_lock , Mutex , leaf , true ); def(DerivedPointerTableGC_lock , Mutex, leaf, true ); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index d5084aeb476..9ee61bff653 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.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 @@ -66,6 +66,8 @@ extern Mutex* SignatureHandlerLibrary_lock; // a lock on the SignatureHandl extern Mutex* VtableStubs_lock; // a lock on the VtableStubs extern Mutex* SymbolTable_lock; // a lock on the symbol table extern Mutex* StringTable_lock; // a lock on the interned string table +extern Monitor* StringDedupQueue_lock; // a lock on the string deduplication queue +extern Mutex* StringDedupTable_lock; // a lock on the string deduplication table extern Mutex* CodeCache_lock; // a lock on the CodeCache, rank is special, use MutexLockerEx extern Mutex* MethodData_lock; // a lock on installation of method data extern Mutex* RetData_lock; // a lock on installation of RetData inside method data diff --git a/hotspot/src/share/vm/runtime/rtmLocking.hpp b/hotspot/src/share/vm/runtime/rtmLocking.hpp new file mode 100644 index 00000000000..b308b98bf31 --- /dev/null +++ b/hotspot/src/share/vm/runtime/rtmLocking.hpp @@ -0,0 +1,113 @@ +/* + * 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_RUNTIME_RTMLOCKING_HPP +#define SHARE_VM_RUNTIME_RTMLOCKING_HPP + +// Generate RTM (Restricted Transactional Memory) locking code for all inflated +// locks when "UseRTMLocking" option is on with normal locking mechanism as fall back +// handler. +// +// On abort/lock busy the lock will be retried a fixed number of times under RTM +// as specified by "RTMRetryCount" option. The locks which abort too often +// can be auto tuned or manually tuned. +// +// Auto-tuning can be done on an option like UseRTMDeopt and it will need abort +// ratio calculation for each lock. The abort ratio will be calculated after +// "RTMAbortThreshold" number of aborts is reached. The formulas are: +// +// Aborted transactions = abort_count * 100 +// All transactions = total_count * RTMTotalCountIncrRate +// +// Aborted transactions >= All transactions * RTMAbortRatio +// +// If "UseRTMDeopt" is on and the aborts ratio reaches "RTMAbortRatio" +// the method containing the lock will be deoptimized and recompiled with +// all locks as normal locks. If the abort ratio continues to remain low after +// "RTMLockingThreshold" locks are attempted, then the method will be deoptimized +// and recompiled with all locks as RTM locks without abort ratio calculation code. +// The abort ratio calculation can be delayed by specifying flag +// -XX:RTMLockingCalculationDelay in millisecond. +// +// For manual tuning the abort statistics for each lock needs to be provided +// to the user on some JVM option like "PrintPreciseRTMLockingStatistics". +// Based on the abort statistics users can create a .hotspot_compiler file +// or use -XX:CompileCommand=option,class::method,NoRTMLockEliding +// to specify for which methods to disable RTM locking. +// +// When UseRTMForStackLocks option is enabled along with UseRTMLocking option, +// the RTM locking code is generated for stack locks too. +// The retries, auto-tuning support and rtm locking statistics are all +// supported for stack locks just like inflated locks. + +// RTM locking counters +class RTMLockingCounters VALUE_OBJ_CLASS_SPEC { + private: + uintx _total_count; // Total RTM locks count + uintx _abort_count; // Total aborts count + + public: + enum { ABORT_STATUS_LIMIT = 6 }; + // Counters per RTM Abort Status. Incremented with +PrintPreciseRTMLockingStatistics + // RTM uses the EAX register to communicate abort status to software. + // Following an RTM abort the EAX register has the following definition. + // + // EAX register bit position Meaning + // 0 Set if abort caused by XABORT instruction. + // 1 If set, the transaction may succeed on a retry. This bit is always clear if bit 0 is set. + // 2 Set if another logical processor conflicted with a memory address that was part of the transaction that aborted. + // 3 Set if an internal buffer overflowed. + // 4 Set if a debug breakpoint was hit. + // 5 Set if an abort occurred during execution of a nested transaction. + private: + uintx _abortX_count[ABORT_STATUS_LIMIT]; + + public: + static uintx _calculation_flag; + static uintx* rtm_calculation_flag_addr() { return &_calculation_flag; } + + static void init(); + + RTMLockingCounters() : _total_count(0), _abort_count(0) { + for (int i = 0; i < ABORT_STATUS_LIMIT; i++) { + _abortX_count[i] = 0; + } + } + + uintx* total_count_addr() { return &_total_count; } + uintx* abort_count_addr() { return &_abort_count; } + uintx* abortX_count_addr() { return &_abortX_count[0]; } + + static int total_count_offset() { return (int)offset_of(RTMLockingCounters, _total_count); } + static int abort_count_offset() { return (int)offset_of(RTMLockingCounters, _abort_count); } + static int abortX_count_offset() { return (int)offset_of(RTMLockingCounters, _abortX_count[0]); } + + + bool nonzero() { return (_abort_count + _total_count) > 0; } + + void print_on(outputStream* st); + void print() { print_on(tty); } +}; + +#endif // SHARE_VM_RUNTIME_RTMLOCKING_HPP diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp index 5e04b0ba73d..967b1bd3d75 100644 --- a/hotspot/src/share/vm/runtime/safepoint.cpp +++ b/hotspot/src/share/vm/runtime/safepoint.cpp @@ -535,7 +535,7 @@ void SafepointSynchronize::do_cleanup_tasks() { // rotate log files? if (UseGCLogFileRotation) { - gclog_or_tty->rotate_log(); + gclog_or_tty->rotate_log(false); } if (MemTracker::is_on()) { diff --git a/hotspot/src/share/vm/runtime/task.cpp b/hotspot/src/share/vm/runtime/task.cpp index ef57dcd68cc..cc163d38963 100644 --- a/hotspot/src/share/vm/runtime/task.cpp +++ b/hotspot/src/share/vm/runtime/task.cpp @@ -105,7 +105,6 @@ PeriodicTask::PeriodicTask(size_t interval_time) : _counter(0), _interval((int) interval_time) { // Sanity check the interval time assert(_interval >= PeriodicTask::min_interval && - _interval <= PeriodicTask::max_interval && _interval % PeriodicTask::interval_gran == 0, "improper PeriodicTask interval time"); } diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index bd794da4524..8a78ebd7acc 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -107,6 +107,9 @@ #include "opto/c2compiler.hpp" #include "opto/idealGraphPrinter.hpp" #endif +#if INCLUDE_RTM_OPT +#include "runtime/rtmLocking.hpp" +#endif #ifdef DTRACE_ENABLED @@ -211,7 +214,6 @@ Thread::Thread() { debug_only(_allow_allocation_count = 0;) NOT_PRODUCT(_allow_safepoint_count = 0;) NOT_PRODUCT(_skip_gcalot = false;) - CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;) _jvmti_env_iteration_count = 0; set_allocated_bytes(0); _vm_operation_started_count = 0; @@ -3622,6 +3624,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { BiasedLocking::init(); +#if INCLUDE_RTM_OPT + RTMLockingCounters::init(); +#endif + if (JDK_Version::current().post_vm_init_hook_enabled()) { call_postVMInitHook(THREAD); // The Java side of PostVMInitHook.run must deal with all diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index a925646ab04..f97f7952e01 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -249,9 +249,6 @@ class Thread: public ThreadShadow { // Used by SkipGCALot class. NOT_PRODUCT(bool _skip_gcalot;) // Should we elide gc-a-lot? - // Record when GC is locked out via the GC_locker mechanism - CHECK_UNHANDLED_OOPS_ONLY(int _gc_locked_out_count;) - friend class No_Alloc_Verifier; friend class No_Safepoint_Verifier; friend class Pause_No_Safepoint_Verifier; @@ -397,7 +394,6 @@ class Thread: public ThreadShadow { void clear_unhandled_oops() { if (CheckUnhandledOops) unhandled_oops()->clear_unhandled_oops(); } - bool is_gc_locked_out() { return _gc_locked_out_count > 0; } #endif // CHECK_UNHANDLED_OOPS #ifndef PRODUCT diff --git a/hotspot/src/share/vm/runtime/unhandledOops.cpp b/hotspot/src/share/vm/runtime/unhandledOops.cpp index 4cc584e8bc3..cc0002d42c9 100644 --- a/hotspot/src/share/vm/runtime/unhandledOops.cpp +++ b/hotspot/src/share/vm/runtime/unhandledOops.cpp @@ -113,9 +113,7 @@ void UnhandledOops::unregister_unhandled_oop(oop* op) { void UnhandledOops::clear_unhandled_oops() { assert (CheckUnhandledOops, "should only be called with checking option"); - if (_thread->is_gc_locked_out()) { - return; - } + for (int k = 0; k < _oop_list->length(); k++) { UnhandledOopEntry entry = _oop_list->at(k); // If an entry is on the unhandled oop list but isn't on the stack diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 2475de0480a..62ddd43b82d 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -171,15 +171,21 @@ #include "opto/addnode.hpp" #include "opto/block.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/chaitin.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" +#include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" #include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" +#include "opto/movenode.hpp" +#include "opto/narrowptrnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/phaseX.hpp" #include "opto/parse.hpp" #include "opto/regalloc.hpp" diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index a3a58e4d4c3..d0014ef97f5 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -96,6 +96,7 @@ template(JFRCheckpoint) \ template(Exit) \ template(LinuxDllLoad) \ + template(RotateGCLog) \ class VM_Operation: public CHeapObj { public: @@ -399,4 +400,15 @@ class VM_Exit: public VM_Operation { void doit(); }; + +class VM_RotateGCLog: public VM_Operation { + private: + outputStream* _out; + + public: + VM_RotateGCLog(outputStream* st) : _out(st) {} + VMOp_Type type() const { return VMOp_RotateGCLog; } + void doit() { gclog_or_tty->rotate_log(true, _out); } +}; + #endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index daa09f36ff4..74444d6168d 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -55,6 +55,7 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); #endif // INCLUDE_SERVICES DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); // Enhanced JMX Agent Support // These commands won't be exported via the DiagnosticCommandMBean until an @@ -659,3 +660,13 @@ void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) { os::print_dll_info(output()); output()->cr(); } + +void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) { + if (UseGCLogFileRotation) { + VM_RotateGCLog rotateop(output()); + VMThread::execute(&rotateop); + } else { + output()->print_cr("Target VM does not support GC log file rotation."); + } +} + diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index a23af05aa09..7a6d3402809 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -383,4 +383,21 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +class RotateGCLogDCmd : public DCmd { +public: + RotateGCLogDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} + static const char* name() { return "GC.rotate_log"; } + static const char* description() { + return "Force the GC log file to be rotated."; + } + static const char* impact() { return "Low"; } + virtual void execute(DCmdSource source, TRAPS); + static int num_arguments() { return 0; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "control", NULL}; + return p; + } +}; + #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index aae6bc61bb7..1ec04560777 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -152,11 +152,14 @@ void Management::initialize(TRAPS) { // Load and initialize the sun.management.Agent class // invoke startAgent method to start the management server Handle loader = Handle(THREAD, SystemDictionary::java_system_loader()); - Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), + Klass* k = SystemDictionary::resolve_or_null(vmSymbols::sun_management_Agent(), loader, Handle(), - true, - CHECK); + THREAD); + if (k == NULL) { + vm_exit_during_initialization("Management agent initialization failure: " + "class sun.management.Agent not found."); + } instanceKlassHandle ik (THREAD, k); JavaValue result(T_VOID); diff --git a/hotspot/src/share/vm/services/runtimeService.cpp b/hotspot/src/share/vm/services/runtimeService.cpp index 5fdb9705a4d..e2b829c41f5 100644 --- a/hotspot/src/share/vm/services/runtimeService.cpp +++ b/hotspot/src/share/vm/services/runtimeService.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. * 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,9 +38,6 @@ PerfCounter* RuntimeService::_sync_time_ticks = NULL; PerfCounter* RuntimeService::_total_safepoints = NULL; PerfCounter* RuntimeService::_safepoint_time_ticks = NULL; PerfCounter* RuntimeService::_application_time_ticks = NULL; -PerfCounter* RuntimeService::_thread_interrupt_signaled_count = NULL; -PerfCounter* RuntimeService::_interrupted_before_count = NULL; -PerfCounter* RuntimeService::_interrupted_during_count = NULL; void RuntimeService::init() { // Make sure the VM version is initialized @@ -70,26 +67,6 @@ void RuntimeService::init() { PerfDataManager::create_constant(SUN_RT, "jvmVersion", PerfData::U_None, (jlong) Abstract_VM_Version::jvm_version(), CHECK); - // I/O interruption related counters - - // thread signaling via os::interrupt() - - _thread_interrupt_signaled_count = - PerfDataManager::create_counter(SUN_RT, - "threadInterruptSignaled", PerfData::U_Events, CHECK); - - // OS_INTRPT via "check before" in _INTERRUPTIBLE - - _interrupted_before_count = - PerfDataManager::create_counter(SUN_RT, "interruptedBeforeIO", - PerfData::U_Events, CHECK); - - // OS_INTRPT via "check during" in _INTERRUPTIBLE - - _interrupted_during_count = - PerfDataManager::create_counter(SUN_RT, "interruptedDuringIO", - PerfData::U_Events, CHECK); - // The capabilities counter is a binary representation of the VM capabilities in string. // This string respresentation simplifies the implementation of the client side // to parse the value. @@ -181,22 +158,4 @@ jlong RuntimeService::application_time_ms() { Management::ticks_to_ms(_application_time_ticks->get_value()) : -1; } -void RuntimeService::record_interrupted_before_count() { - if (UsePerfData) { - _interrupted_before_count->inc(); - } -} - -void RuntimeService::record_interrupted_during_count() { - if (UsePerfData) { - _interrupted_during_count->inc(); - } -} - -void RuntimeService::record_thread_interrupt_signaled_count() { - if (UsePerfData) { - _thread_interrupt_signaled_count->inc(); - } -} - #endif // INCLUDE_MANAGEMENT diff --git a/hotspot/src/share/vm/services/runtimeService.hpp b/hotspot/src/share/vm/services/runtimeService.hpp index 8de0ebf6ffc..90981ee2ebe 100644 --- a/hotspot/src/share/vm/services/runtimeService.hpp +++ b/hotspot/src/share/vm/services/runtimeService.hpp @@ -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 @@ -34,9 +34,6 @@ private: static PerfCounter* _total_safepoints; static PerfCounter* _safepoint_time_ticks; // Accumulated time at safepoints static PerfCounter* _application_time_ticks; // Accumulated time not at safepoints - static PerfCounter* _thread_interrupt_signaled_count;// os:interrupt thr_kill - static PerfCounter* _interrupted_before_count; // _INTERRUPTIBLE OS_INTRPT - static PerfCounter* _interrupted_during_count; // _INTERRUPTIBLE OS_INTRPT static TimeStamp _safepoint_timer; static TimeStamp _app_timer; @@ -58,10 +55,6 @@ public: static void record_safepoint_end() NOT_MANAGEMENT_RETURN; static void record_application_start() NOT_MANAGEMENT_RETURN; - // interruption events - static void record_interrupted_before_count() NOT_MANAGEMENT_RETURN; - static void record_interrupted_during_count() NOT_MANAGEMENT_RETURN; - static void record_thread_interrupt_signaled_count() NOT_MANAGEMENT_RETURN; }; #endif // SHARE_VM_SERVICES_RUNTIMESERVICE_HPP diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 75efeea115e..cd71b64a2d8 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -193,11 +193,48 @@ Declares a structure type that can be used in other events. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hotspot/src/share/vm/trace/tracetypes.xml b/hotspot/src/share/vm/trace/tracetypes.xml index 9305d2fa75e..eb1c708eadb 100644 --- a/hotspot/src/share/vm/trace/tracetypes.xml +++ b/hotspot/src/share/vm/trace/tracetypes.xml @@ -130,11 +130,26 @@ Now we can use the content + data type in declaring event fields. + + + + + + + + + + + + @@ -324,10 +339,22 @@ Now we can use the content + data type in declaring event fields. + + + + + + + + + diff --git a/hotspot/src/share/vm/utilities/bitMap.cpp b/hotspot/src/share/vm/utilities/bitMap.cpp index b2a2ab7b2d5..024e35e374d 100644 --- a/hotspot/src/share/vm/utilities/bitMap.cpp +++ b/hotspot/src/share/vm/utilities/bitMap.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/copy.hpp" #ifdef TARGET_OS_FAMILY_linux @@ -67,16 +68,14 @@ void BitMap::resize(idx_t size_in_bits, bool in_resource_area) { idx_t new_size_in_words = size_in_words(); if (in_resource_area) { _map = NEW_RESOURCE_ARRAY(bm_word_t, new_size_in_words); + Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map, + MIN2(old_size_in_words, new_size_in_words)); } else { - if (old_map != NULL) { - _map_allocator.free(); - } - _map = _map_allocator.allocate(new_size_in_words); + _map = _map_allocator.reallocate(new_size_in_words); } - Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map, - MIN2(old_size_in_words, new_size_in_words)); + if (new_size_in_words > old_size_in_words) { - clear_range_of_words(old_size_in_words, size_in_words()); + clear_range_of_words(old_size_in_words, new_size_in_words); } } @@ -536,6 +535,83 @@ void BitMap::print_on(outputStream* st) const { tty->cr(); } +class TestBitMap : public AllStatic { + const static BitMap::idx_t BITMAP_SIZE = 1024; + static void fillBitMap(BitMap& map) { + map.set_bit(1); + map.set_bit(3); + map.set_bit(17); + map.set_bit(512); + } + + static void testResize(bool in_resource_area) { + { + BitMap map(0, in_resource_area); + map.resize(BITMAP_SIZE, in_resource_area); + fillBitMap(map); + + BitMap map2(BITMAP_SIZE, in_resource_area); + fillBitMap(map2); + assert(map.is_same(map2), "could be"); + } + + { + BitMap map(128, in_resource_area); + map.resize(BITMAP_SIZE, in_resource_area); + fillBitMap(map); + + BitMap map2(BITMAP_SIZE, in_resource_area); + fillBitMap(map2); + assert(map.is_same(map2), "could be"); + } + + { + BitMap map(BITMAP_SIZE, in_resource_area); + map.resize(BITMAP_SIZE, in_resource_area); + fillBitMap(map); + + BitMap map2(BITMAP_SIZE, in_resource_area); + fillBitMap(map2); + assert(map.is_same(map2), "could be"); + } + } + + static void testResizeResource() { + ResourceMark rm; + testResize(true); + } + + static void testResizeNonResource() { + const uintx bitmap_bytes = BITMAP_SIZE / BitsPerByte; + + // Test the default behavior + testResize(false); + + { + // Make sure that AllocatorMallocLimit is larger than our allocation request + // forcing it to call standard malloc() + UIntFlagSetting 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); + testResize(false); + } + } + + public: + static void test() { + testResizeResource(); + testResizeNonResource(); + } + +}; + +void TestBitMap_test() { + TestBitMap::test(); +} #endif diff --git a/hotspot/src/share/vm/utilities/debug.hpp b/hotspot/src/share/vm/utilities/debug.hpp index ccadc077219..310080dbb0e 100644 --- a/hotspot/src/share/vm/utilities/debug.hpp +++ b/hotspot/src/share/vm/utilities/debug.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 @@ -243,7 +243,6 @@ template <> struct StaticAssert {}; // out of shared space reporting enum SharedSpaceType { - SharedPermGen, SharedReadOnly, SharedReadWrite, SharedMiscData diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index e56d4b0d59e..df2a8a30253 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -373,6 +373,21 @@ const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlass // Machine dependent stuff +#if defined(X86) && defined(COMPILER2) && !defined(JAVASE_EMBEDDED) +// Include Restricted Transactional Memory lock eliding optimization +#define INCLUDE_RTM_OPT 1 +#define RTM_OPT_ONLY(code) code +#else +#define INCLUDE_RTM_OPT 0 +#define RTM_OPT_ONLY(code) +#endif +// States of Restricted Transactional Memory usage. +enum RTMState { + NoRTM = 0x2, // Don't use RTM + UseRTM = 0x1, // Use RTM + ProfileRTM = 0x0 // Use RTM with abort ratio calculation +}; + #ifdef TARGET_ARCH_x86 # include "globalDefinitions_x86.hpp" #endif diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index 90b3559e48c..e09dfccf123 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -662,13 +662,13 @@ void gcLogFileStream::write(const char* s, size_t len) { // write to gc log file at safepoint. If in future, changes made for mutator threads or // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log // must be synchronized. -void gcLogFileStream::rotate_log() { +void gcLogFileStream::rotate_log(bool force, outputStream* out) { char time_msg[FILENAMEBUFLEN]; char time_str[EXTRACHARLEN]; char current_file_name[FILENAMEBUFLEN]; char renamed_file_name[FILENAMEBUFLEN]; - if (_bytes_written < (jlong)GCLogFileSize) { + if (!should_rotate(force)) { return; } @@ -685,6 +685,11 @@ void gcLogFileStream::rotate_log() { jio_snprintf(time_msg, sizeof(time_msg), "File %s rotated at %s\n", _file_name, os::local_time_string((char *)time_str, sizeof(time_str))); write(time_msg, strlen(time_msg)); + + if (out != NULL) { + out->print(time_msg); + } + dump_loggc_header(); return; } @@ -706,12 +711,18 @@ void gcLogFileStream::rotate_log() { _file_name, _cur_file_num); jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); - jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the" - " maximum size. Saved as %s\n", - os::local_time_string((char *)time_str, sizeof(time_str)), - renamed_file_name); + + const char* msg = force ? "GC log rotation request has been received." + : "GC log file has reached the maximum size."; + jio_snprintf(time_msg, sizeof(time_msg), "%s %s Saved as %s\n", + os::local_time_string((char *)time_str, sizeof(time_str)), + msg, renamed_file_name); write(time_msg, strlen(time_msg)); + if (out != NULL) { + out->print(time_msg); + } + fclose(_file); _file = NULL; @@ -752,6 +763,11 @@ void gcLogFileStream::rotate_log() { os::local_time_string((char *)time_str, sizeof(time_str)), current_file_name); write(time_msg, strlen(time_msg)); + + if (out != NULL) { + out->print(time_msg); + } + dump_loggc_header(); // remove the existing file if (access(current_file_name, F_OK) == 0) { diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp index 20e6f30bf37..92440ee0a64 100644 --- a/hotspot/src/share/vm/utilities/ostream.hpp +++ b/hotspot/src/share/vm/utilities/ostream.hpp @@ -115,7 +115,7 @@ class outputStream : public ResourceObj { // flushing virtual void flush() {} virtual void write(const char* str, size_t len) = 0; - virtual void rotate_log() {} // GC log rotation + virtual void rotate_log(bool force, outputStream* out = NULL) {} // GC log rotation virtual ~outputStream() {} // close properly on deletion void dec_cr() { dec(); cr(); } @@ -240,8 +240,14 @@ class gcLogFileStream : public fileStream { gcLogFileStream(const char* file_name); ~gcLogFileStream(); virtual void write(const char* c, size_t len); - virtual void rotate_log(); + virtual void rotate_log(bool force, outputStream* out = NULL); void dump_loggc_header(); + + /* If "force" sets true, force log file rotation from outside JVM */ + bool should_rotate(bool force) { + return force || + ((GCLogFileSize != 0) && ((uintx)_bytes_written >= GCLogFileSize)); + } }; #ifndef PRODUCT diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index 676d859686d..b0a4f605ad8 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -129,6 +129,8 @@ needs_compact3 = \ gc/g1/TestHumongousAllocInitialMark.java \ gc/arguments/TestG1HeapRegionSize.java \ gc/metaspace/TestMetaspaceMemoryPool.java \ + gc/arguments/TestDynMinHeapFreeRatio.java \ + gc/arguments/TestDynMaxHeapFreeRatio.java \ runtime/InternalApi/ThreadCpuTimesDeadlock.java \ serviceability/threads/TestFalseDeadLock.java \ compiler/tiered/NonTieredLevelsTest.java \ diff --git a/hotspot/test/compiler/6792161/Test6792161.java b/hotspot/test/compiler/6792161/Test6792161.java index ac3843c1b72..309c5bbf3be 100644 --- a/hotspot/test/compiler/6792161/Test6792161.java +++ b/hotspot/test/compiler/6792161/Test6792161.java @@ -27,7 +27,7 @@ * @bug 6792161 * @summary assert("No dead instructions after post-alloc") * - * @run main/othervm/timeout=300 -Xcomp -XX:MaxInlineSize=120 Test6792161 + * @run main/othervm/timeout=600 -Xcomp -XX:MaxInlineSize=120 Test6792161 */ import java.lang.reflect.Constructor; diff --git a/hotspot/test/compiler/arguments/BMICommandLineOptionTestBase.java b/hotspot/test/compiler/arguments/BMICommandLineOptionTestBase.java new file mode 100644 index 00000000000..6d4fa400dda --- /dev/null +++ b/hotspot/test/compiler/arguments/BMICommandLineOptionTestBase.java @@ -0,0 +1,68 @@ +/* + * 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 com.oracle.java.testlibrary.cli.*; + +/** + * Base class for all X86 bit manipulation related command line options. + */ +public abstract class BMICommandLineOptionTestBase + extends CPUSpecificCommandLineOptionTest { + + public static final String LZCNT_WARNING = + "lzcnt instruction is not available on this CPU"; + public static final String TZCNT_WARNING = + "tzcnt instruction is not available on this CPU"; + public static final String BMI1_WARNING = + "BMI1 instructions are not available on this CPU"; + + protected final String optionName; + protected final String warningMessage; + protected final String errorMessage; + + /** + * Construct new test on {@code optionName} option. + * + * @param optionName Name of the option to be tested + * without -XX:[+-] prefix. + * @param warningMessage Message that can occur in VM output + * if CPU on test box does not support + * features required by the option. + * @param supportedCPUFeatures CPU features requires by the option, + * that should be supported on test box. + * @param unsupportedCPUFeatures CPU features requires by the option, + * that should not be supported on test box. + */ + public BMICommandLineOptionTestBase(String optionName, + String warningMessage, + String supportedCPUFeatures[], + String unsupportedCPUFeatures[]) { + super(".*", supportedCPUFeatures, unsupportedCPUFeatures); + this.optionName = optionName; + this.warningMessage = warningMessage; + this.errorMessage = CommandLineOptionTest. + UNRECOGNIZED_OPTION_ERROR_FORMAT.format(optionName); + } + +} + diff --git a/hotspot/test/compiler/arguments/BMISupportedCPUTest.java b/hotspot/test/compiler/arguments/BMISupportedCPUTest.java new file mode 100644 index 00000000000..c0af31fd766 --- /dev/null +++ b/hotspot/test/compiler/arguments/BMISupportedCPUTest.java @@ -0,0 +1,72 @@ +/* + * 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 com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +/** + * Test on bit manipulation related command line options, + * that should be executed on CPU that supports all required + * features. + */ +public class BMISupportedCPUTest extends BMICommandLineOptionTestBase { + + /** + * Construct new test on {@code optionName} option. + * + * @param optionName Name of the option to be tested + * without -XX:[+-] prefix. + * @param warningMessage Message that can occur in VM output + * if CPU on test box does not support + * features required by the option. + * @param cpuFeatures CPU features requires by the option. + */ + public BMISupportedCPUTest(String optionName, + String warningMessage, + String... cpuFeatures) { + super(optionName, warningMessage, cpuFeatures, null); + } + + @Override + public void runTestCases() throws Throwable { + // verify that VM will succesfully start up whithout warnings + CommandLineOptionTest. + verifyJVMStartup("-XX:+" + optionName, + null, new String[] { warningMessage }, + ExitCode.OK); + + // verify that VM will succesfully start up whithout warnings + CommandLineOptionTest. + verifyJVMStartup("-XX:-" + optionName, + null, new String[] { warningMessage }, + ExitCode.OK); + + // verify that on appropriate CPU option in on by default + CommandLineOptionTest.verifyOptionValue(optionName, "true"); + + // verify that option could be explicitly turned off + CommandLineOptionTest.verifyOptionValue(optionName, "false", + "-XX:-" + optionName); + } +} + diff --git a/hotspot/test/compiler/arguments/BMIUnsupportedCPUTest.java b/hotspot/test/compiler/arguments/BMIUnsupportedCPUTest.java new file mode 100644 index 00000000000..7a78c74e579 --- /dev/null +++ b/hotspot/test/compiler/arguments/BMIUnsupportedCPUTest.java @@ -0,0 +1,114 @@ +/* + * 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 com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +/** + * Test on bit manipulation related command line options, + * that should be executed on CPU that does not support + * required features. + */ +public class BMIUnsupportedCPUTest extends BMICommandLineOptionTestBase { + + /** + * Construct new test on {@code optionName} option. + * + * @param optionName Name of the option to be tested + * without -XX:[+-] prefix. + * @param warningMessage Message that can occur in VM output + * if CPU on test box does not support + * features required by the option. + * @param cpuFeatures CPU features requires by the option. + */ + public BMIUnsupportedCPUTest(String optionName, + String warningMessage, + String... cpuFeatures) { + super(optionName, warningMessage, null, cpuFeatures); + } + + @Override + public void runTestCases() throws Throwable { + if (Platform.isX86() || Platform.isX64()) { + unsupportedX86CPUTestCases(); + } else { + unsupportedNonX86CPUTestCases(); + } + } + + /** + * Run test cases common for all bit manipulation related VM options + * targeted to X86 CPU that does not support required features. + * + * @throws Throwable if test failed. + */ + public void unsupportedX86CPUTestCases() throws Throwable { + + // verify that VM will succesfully start up, but output will + // contain a warning + CommandLineOptionTest. + verifyJVMStartup("-XX:+" + optionName, + new String[] { warningMessage }, + new String[] { errorMessage }, + ExitCode.OK); + + // verify that VM will succesfully startup without any warnings + CommandLineOptionTest. + verifyJVMStartup("-XX:-" + optionName, + null, + new String[] { warningMessage, errorMessage }, + ExitCode.OK); + + // verify that on unsupported CPUs option is off by default + CommandLineOptionTest.verifyOptionValue(optionName, "false"); + + // verify that on unsupported CPUs option will be off even if + // it was explicitly turned on by uset + CommandLineOptionTest.verifyOptionValue(optionName, "false", + "-XX:+" + optionName); + + } + + /** + * Run test cases common for all bit manipulation related VM options + * targeted to non-X86 CPU that does not support required features. + * + * @throws Throwable if test failed. + */ + public void unsupportedNonX86CPUTestCases() throws Throwable { + + // verify that VM known nothing about tested option + CommandLineOptionTest. + verifyJVMStartup("-XX:+" + optionName, + new String[] { errorMessage }, + null, + ExitCode.FAIL); + + CommandLineOptionTest. + verifyJVMStartup("-XX:-" + optionName, + new String[] { errorMessage }, + null, + ExitCode.FAIL); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java new file mode 100644 index 00000000000..559c3a6a643 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java @@ -0,0 +1,51 @@ +/* + * 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 8031321 + * @summary Verify processing of UseBMI1Instructions option on CPU with + * BMI1 feature support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseBMI1InstructionsOnSupportedCPU + * BMISupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestUseBMI1InstructionsOnSupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; + +public class TestUseBMI1InstructionsOnSupportedCPU + extends BMISupportedCPUTest { + + public TestUseBMI1InstructionsOnSupportedCPU() { + super("UseBMI1Instructions", BMI1_WARNING, "bmi1"); + } + + public static void main(String args[]) throws Throwable { + new TestUseBMI1InstructionsOnSupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java new file mode 100644 index 00000000000..3df8d659cf0 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java @@ -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. + */ + +/** + * @test + * @bug 8031321 + * @summary Verify processing of UseBMI1Instructions option on CPU without + * BMI1 feature support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseBMI1InstructionsOnUnsupportedCPU + * BMIUnsupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestUseBMI1InstructionsOnUnsupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +public class TestUseBMI1InstructionsOnUnsupportedCPU + extends BMIUnsupportedCPUTest { + + public TestUseBMI1InstructionsOnUnsupportedCPU() { + super("UseBMI1Instructions", BMI1_WARNING, "bmi1"); + } + + public static void main(String args[]) throws Throwable { + new TestUseBMI1InstructionsOnUnsupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java new file mode 100644 index 00000000000..c8437748341 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java @@ -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. + */ + +/** + * @test + * @bug 8031321 + * @summary Verify processing of UseCountLeadingZerosInstruction option + * on CPU with LZCNT support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseCountLeadingZerosInstructionOnSupportedCPU + * BMISupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * TestUseCountLeadingZerosInstructionOnSupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; + +public class TestUseCountLeadingZerosInstructionOnSupportedCPU + extends BMISupportedCPUTest { + + public TestUseCountLeadingZerosInstructionOnSupportedCPU() { + super("UseCountLeadingZerosInstruction", LZCNT_WARNING, "lzcnt"); + } + + public static void main(String args[]) throws Throwable { + new TestUseCountLeadingZerosInstructionOnSupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java new file mode 100644 index 00000000000..e2ffba28a43 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java @@ -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. + */ + +/** + * @test + * @bug 8031321 + * @summary Verify processing of UseCountLeadingZerosInstruction option + * on CPU without LZCNT support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseCountLeadingZerosInstructionOnUnsupportedCPU + * BMIUnsupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * TestUseCountLeadingZerosInstructionOnUnsupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; + +public class TestUseCountLeadingZerosInstructionOnUnsupportedCPU + extends BMIUnsupportedCPUTest { + + public TestUseCountLeadingZerosInstructionOnUnsupportedCPU() { + super("UseCountLeadingZerosInstruction", LZCNT_WARNING, "lzcnt"); + } + + public static void main(String args[]) throws Throwable { + new TestUseCountLeadingZerosInstructionOnUnsupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java new file mode 100644 index 00000000000..995d450e365 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java @@ -0,0 +1,72 @@ +/* + * 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 8031321 + * @summary Verify processing of UseCountTrailingZerosInstruction option + * on CPU with TZCNT (BMI1 feature) support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseCountTrailingZerosInstructionOnSupportedCPU + * BMISupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * TestUseCountTrailingZerosInstructionOnSupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +public class TestUseCountTrailingZerosInstructionOnSupportedCPU + extends BMISupportedCPUTest { + + public TestUseCountTrailingZerosInstructionOnSupportedCPU() { + super("UseCountTrailingZerosInstruction", TZCNT_WARNING, "bmi1"); + } + + @Override + public void runTestCases() throws Throwable { + + super.runTestCases(); + + // verify that option will be disabled if all BMI1 instuctions + // are explicitly disabled + CommandLineOptionTest. + verifyOptionValue("UseCountTrailingZerosInstruction", "false", + "-XX:-UseBMI1Instructions"); + + // verify that option could be turned on even if other BMI1 + // instructions were turned off + CommandLineOptionTest. + verifyOptionValue("UseCountTrailingZerosInstruction", "true", + "-XX:-UseBMI1Instructions", + "-XX:+UseCountTrailingZerosInstruction"); + } + + public static void main(String args[]) throws Throwable { + new TestUseCountTrailingZerosInstructionOnSupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java new file mode 100644 index 00000000000..86853aab0c5 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java @@ -0,0 +1,70 @@ +/* + * 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 8031321 + * @summary Verify processing of UseCountTrailingZerosInstruction option + * on CPU without TZCNT instuction (BMI1 feature) support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseCountTrailingZerosInstructionOnUnsupportedCPU + * BMIUnsupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * TestUseCountTrailingZerosInstructionOnUnsupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +public class TestUseCountTrailingZerosInstructionOnUnsupportedCPU + extends BMIUnsupportedCPUTest { + + public TestUseCountTrailingZerosInstructionOnUnsupportedCPU() { + super("UseCountTrailingZerosInstruction", TZCNT_WARNING, "bmi1"); + } + + @Override + public void unsupportedX86CPUTestCases() throws Throwable { + + super.unsupportedX86CPUTestCases(); + + // verify that option will not be turned on during + // UseBMI1Instuctions processing + CommandLineOptionTest. + verifyOptionValue("UseCountTrailingZerosInstruction", "false", + "-XX:+UseBMI1Instructions"); + + CommandLineOptionTest. + verifyOptionValue("UseCountTrailingZerosInstruction", "false", + "-XX:+UseCountTrailingZerosInstruction", + "-XX:+UseBMI1Instructions"); + } + + public static void main(String args[]) throws Throwable { + new TestUseCountTrailingZerosInstructionOnUnsupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/ciReplay/common.sh b/hotspot/test/compiler/ciReplay/common.sh index 608f68e551a..f992ff39fc2 100644 --- a/hotspot/test/compiler/ciReplay/common.sh +++ b/hotspot/test/compiler/ciReplay/common.sh @@ -218,7 +218,7 @@ generate_replay() { -XX:VMThreadStackSize=512 \ -XX:CompilerThreadStackSize=512 \ -XX:ParallelGCThreads=1 \ - -XX:CICompilerCount=1 \ + -XX:CICompilerCount=2 \ -Xcomp \ -XX:CICrashAt=1 \ -XX:+CreateMinidumpOnCrash \ diff --git a/hotspot/test/compiler/codegen/C1NullCheckOfNullStore.java b/hotspot/test/compiler/codegen/C1NullCheckOfNullStore.java new file mode 100644 index 00000000000..0bec2c1ab42 --- /dev/null +++ b/hotspot/test/compiler/codegen/C1NullCheckOfNullStore.java @@ -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. + */ + +/* + * @test + * @bug 8039043 + * @summary Null check is placed in a wrong place when storing a null to an object field on x64 with compressed oops off + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CompileCommand=compileonly,C1NullCheckOfNullStore::test -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-UseCompressedOops C1NullCheckOfNullStore + * + */ + +public class C1NullCheckOfNullStore { + private static class Foo { + Object bar; + } + static private void test(Foo x) { + x.bar = null; + } + static public void main(String args[]) { + Foo x = new Foo(); + for (int i = 0; i < 10000; i++) { + test(x); + } + boolean gotNPE = false; + try { + for (int i = 0; i < 10000; i++) { + test(null); + } + } + catch(NullPointerException e) { + gotNPE = true; + } + if (!gotNPE) { + throw new Error("Expecting a NullPointerException"); + } + } +} diff --git a/hotspot/test/compiler/intrinsics/bmi/BMITestRunner.java b/hotspot/test/compiler/intrinsics/bmi/BMITestRunner.java new file mode 100644 index 00000000000..ea7fd821f33 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/BMITestRunner.java @@ -0,0 +1,442 @@ +/* + * 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.util.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; + +import com.oracle.java.testlibrary.*; + +/** + * Test runner that invokes all methods implemented by particular Expr + * with random arguments in two different JVM processes and compares output. + * JVMs being started in different modes - one in int and other in comp + * with C2 and disabled tiered compilation. + */ +public class BMITestRunner { + + enum VMMode { + COMP, INT; + }; + + public static int DEFAULT_ITERATIONS_COUNT = 4000; + + /** + * Execute all methods implemented by expr in int and comp modes + * and compare output. + * Test pass only of output obtained with different VM modes is equal. + * To control behaviour of test following options could be passed: + *

    + *
  • -iterations=<N> each operation implemented by + * expr will be executed N times. Default value + * is 4000.
  • + *
  • -seed=<SEED> arguments for expr's methods + * obtained via RNG initiated with seed SEED. By default + * some random seed will be used.
  • + *
+ * + * @param expr operation that should be tested + * @param testOpts options to control test behaviour + * @param additionalVMOpts additional options for VM + * + * @throws Throwable if test failed. + */ + public static void runTests(Class expr, + String testOpts[], + String... additionalVMOpts) + throws Throwable { + + int seed = new Random().nextInt(); + int iterations = DEFAULT_ITERATIONS_COUNT; + + for (String testOption : testOpts) { + if (testOption.startsWith("-iterations=")) { + iterations = Integer.valueOf(testOption. + replace("-iterations=", "")); + } else if (testOption.startsWith("-seed=")) { + seed = Integer.valueOf(testOption.replace("-seed=", "")); + } + } + + System.out.println("Running test with seed: " + seed); + + OutputAnalyzer intOutput = runTest(expr, VMMode.INT, + additionalVMOpts, + seed, iterations); + OutputAnalyzer compOutput = runTest(expr, VMMode.COMP, + additionalVMOpts, + seed, iterations); + + dumpOutput(intOutput, "int"); + dumpOutput(compOutput, "comp"); + + Asserts.assertStringsEqual(intOutput.getStdout(), + compOutput.getStdout(), + "Results obtained in -Xint and " + + "-Xcomp should be the same."); + } + + /** + * Execute tests on methods implemented by expr in new VM + * started in testVMMode mode. + * + * @param expr operation that should be tested + * @param testVMMode VM mode for test + * @param additionalVMOpts additional options for VM + * @param seed for RNG used it tests + * @param iterations that will be used to invoke expr's methods. + * + * @return OutputAnalyzer for executed test. + * @throws Throwable when something goes wrong. + */ + public static OutputAnalyzer runTest(Class expr, + VMMode testVMMode, + String additionalVMOpts[], + int seed, int iterations) + throws Throwable { + + List vmOpts = new LinkedList(); + + Collections.addAll(vmOpts, additionalVMOpts); + + //setup mode-specific options + switch (testVMMode) { + case INT: + Collections.addAll(vmOpts, new String[] { "-Xint" }); + break; + case COMP: + Collections.addAll(vmOpts, new String[] { + "-Xcomp", + "-XX:-TieredCompilation", + String.format("-XX:CompileCommand=compileonly,%s::*", + expr.getName()) + }); + break; + } + + Collections.addAll(vmOpts, new String[] { + "-XX:+DisplayVMOutputToStderr", + Executor.class.getName(), + expr.getName(), + new Integer(seed).toString(), + new Integer(iterations).toString() + }); + + OutputAnalyzer outputAnalyzer = ProcessTools. + executeTestJvm(vmOpts.toArray(new String[vmOpts.size()])); + + outputAnalyzer.shouldHaveExitValue(0); + + return outputAnalyzer; + } + + /** + * Dump stdout and stderr of test process to prefix.test.out + * and prefix.test.err respectively. + * + * @param outputAnalyzer OutputAnalyzer whom output should be dumped + * @param prefix Prefix that will be used in file names. + * @throws IOException if unable to dump output to file. + */ + protected static void dumpOutput(OutputAnalyzer outputAnalyzer, + String prefix) + throws IOException { + Files.write(Paths.get(prefix + ".test.out"), + outputAnalyzer.getStdout().getBytes()); + + Files.write(Paths.get(prefix + ".test.err"), + outputAnalyzer.getStderr().getBytes()); + } + + + /** + * Executor that invoke all methods implemented by particular + * Expr instance. + */ + public static class Executor { + + /** + * Usage: BMITestRunner$Executor + */ + public static void main(String args[]) throws Exception { + @SuppressWarnings("unchecked") + Class exprClass = + (Class)Class.forName(args[0]); + Expr expr = exprClass.getConstructor().newInstance(); + Random rng = new Random(Integer.valueOf(args[1])); + int iterations = Integer.valueOf(args[2]); + runTests(expr, iterations, rng); + } + + + public static int[] getIntBitShifts() { + //SIZE+1 shift is for zero. + int data[] = new int[Integer.SIZE+1]; + for (int s = 0; s < data.length; s++) { + data[s] = 1< 0X%x", + value, expr.intExpr(value)); + } + + for (int i = 0; i < iterations; i++) { + int value = rng.nextInt(); + log("UnaryIntReg(0X%x) -> 0X%x", + value, expr.intExpr(value)); + } + } + + public static void runUnaryIntMemTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isUnaryArgumentSupported() + && expr.isIntExprSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int value : getIntBitShifts()) { + log("UnaryIntMem(0X%x) -> 0X%x", + value, expr.intExpr(new Expr.MemI(value))); + } + + for (int i = 0; i < iterations; i++) { + int value = rng.nextInt(); + log("UnaryIntMem(0X%x) -> 0X%x", + value, expr.intExpr(new Expr.MemI(value))); + } + } + + public static void runUnaryLongRegTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isUnaryArgumentSupported() + && expr.isLongExprSupported())) { + return; + } + + for (long value : getLongBitShifts()) { + log("UnaryLongReg(0X%x) -> 0X%x", + value, expr.longExpr(value)); + } + + for (int i = 0; i < iterations; i++) { + long value = rng.nextLong(); + log("UnaryLongReg(0X%x) -> 0X%x", + value, expr.longExpr(value)); + } + } + + public static void runUnaryLongMemTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isUnaryArgumentSupported() + && expr.isLongExprSupported() + && expr.isMemExprSupported())) { + return; + } + + for (long value : getLongBitShifts()) { + log("UnaryLongMem(0X%x) -> 0X%x", + value, expr.longExpr(new Expr.MemL(value))); + } + + for (int i = 0; i < iterations; i++) { + long value = rng.nextLong(); + log("UnaryLongMem(0X%x) -> 0X%x", + value, expr.longExpr(new Expr.MemL(value))); + } + } + + public static void runBinaryRegRegIntTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isIntExprSupported() + && expr.isBinaryArgumentSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + int aValue = rng.nextInt(); + int bValue = rng.nextInt(); + log("BinaryIntRegReg(0X%x, 0X%x) -> 0X%x", + aValue, bValue, expr.intExpr(aValue, bValue)); + } + } + + public static void runBinaryRegMemIntTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isIntExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + int aValue = rng.nextInt(); + int bValue = rng.nextInt(); + log("BinaryIntRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.intExpr(aValue, new Expr.MemI(bValue))); + } + } + + public static void runBinaryMemRegIntTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isIntExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + int aValue = rng.nextInt(); + int bValue = rng.nextInt(); + log("BinaryIntMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.intExpr(new Expr.MemI(aValue), bValue)); + } + } + + public static void runBinaryMemMemIntTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isIntExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + int aValue = rng.nextInt(); + int bValue = rng.nextInt(); + log("BinaryIntMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.intExpr(new Expr.MemI(aValue), + new Expr.MemI(bValue))); + } + } + + public static void runBinaryRegRegLongTest(Expr expr, + int iterations, + Random rng) { + if (!(expr.isLongExprSupported() + && expr.isBinaryArgumentSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + long aValue = rng.nextLong(); + long bValue = rng.nextLong(); + log("BinaryLongRegReg(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.longExpr(aValue, bValue)); + } + } + + public static void runBinaryRegMemLongTest(Expr expr, + int iterations, + Random rng) { + if (!(expr.isLongExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + long aValue = rng.nextLong(); + long bValue = rng.nextLong(); + log("BinaryLongRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.longExpr(aValue, new Expr.MemL(bValue))); + } + } + + public static void runBinaryMemRegLongTest(Expr expr, + int iterations, + Random rng) { + if (!(expr.isLongExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + long aValue = rng.nextLong(); + long bValue = rng.nextLong(); + log("BinaryLongMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.longExpr(new Expr.MemL(aValue), bValue)); + } + } + + public static void runBinaryMemMemLongTest(Expr expr, + int iterations, + Random rng) { + if (!(expr.isLongExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + long aValue = rng.nextLong(); + long bValue = rng.nextLong(); + log("BinaryLongMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.longExpr(new Expr.MemL(aValue), + new Expr.MemL(bValue))); + } + } + } +} diff --git a/hotspot/test/compiler/intrinsics/bmi/Expr.java b/hotspot/test/compiler/intrinsics/bmi/Expr.java new file mode 100644 index 00000000000..2d4a84a0193 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/Expr.java @@ -0,0 +1,178 @@ +/* + * 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. + * + */ + +/** + * Expression that should be replaced by particular instrinsic + * or intruction during compilation. + */ + +public abstract class Expr { + + public static class MemI { + public MemI(int i) { + this.value = i; + } + + public int value; + } + + public static class MemL { + public MemL(long l) { + this.value = l; + } + + public long value; + } + + public boolean isUnaryArgumentSupported() { + return false; + } + + public boolean isIntExprSupported() { + return false; + } + + public boolean isBinaryArgumentSupported() { + return false; + } + + public boolean isLongExprSupported() { + return false; + } + + public boolean isMemExprSupported() { + return false; + } + + public int intExpr(int reg) { + throw new UnsupportedOperationException(); + } + + public int intExpr(MemI mem) { + throw new UnsupportedOperationException(); + } + + public int intExpr(int a, int b) { + throw new UnsupportedOperationException(); + } + + public int intExpr(int a, MemI b) { + throw new UnsupportedOperationException(); + } + + public int intExpr(MemI a, int b) { + throw new UnsupportedOperationException(); + } + + public int intExpr(MemI a, MemI b) { + throw new UnsupportedOperationException(); + } + + public long longExpr(long reg) { + throw new UnsupportedOperationException(); + } + + public long longExpr(MemL mem) { + throw new UnsupportedOperationException(); + } + + public long longExpr(long a, long b) { + throw new UnsupportedOperationException(); + } + + public long longExpr(long a, MemL b) { + throw new UnsupportedOperationException(); + } + + public long longExpr(MemL a, long b) { + throw new UnsupportedOperationException(); + } + + public long longExpr(MemL a, MemL b) { + throw new UnsupportedOperationException(); + } + + public static class BMIExpr extends Expr { + + public boolean isMemExprSupported() { + return true; + } + } + + public static class BMIBinaryExpr extends BMIExpr { + + public boolean isBinaryArgumentSupported() { + return true; + } + + } + + public static class BMIUnaryExpr extends BMIExpr { + public boolean isUnaryArgumentSupported() { + return true; + } + } + + public static class BMIBinaryIntExpr extends BMIBinaryExpr { + public boolean isIntExprSupported() { + return true; + } + } + + public static class BMIBinaryLongExpr extends BMIBinaryExpr { + public boolean isLongExprSupported() { + return true; + } + } + + public static class BMIUnaryIntExpr extends BMIUnaryExpr { + public boolean isIntExprSupported() { + return true; + } + } + + public static class BMIUnaryLongExpr extends BMIUnaryExpr { + public boolean isLongExprSupported() { + return true; + } + } + + public static class BitCountingExpr extends Expr { + public boolean isUnaryArgumentSupported() { + return true; + } + } + + public static class BitCountingIntExpr extends BitCountingExpr { + public boolean isIntExprSupported() { + return true; + } + } + + public static class BitCountingLongExpr extends BitCountingExpr { + public boolean isLongExprSupported() { + return true; + } + } +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java b/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java new file mode 100644 index 00000000000..e8cfaa23f0f --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java @@ -0,0 +1,91 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of ANDN instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestAndnI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestAndnI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestAndnI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. "+ + "Test skipped."); + return; + } + + BMITestRunner.runTests(AndnIExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(AndnICommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class AndnIExpr extends Expr.BMIBinaryIntExpr { + + public int intExpr(int src1, int src2) { + return ~src1 & src2; + } + + public int intExpr(int src1, Expr.MemI src2) { + return ~src1 & src2.value; + } + + public int intExpr(Expr.MemI src1, int src2) { + return ~src1.value & src2; + } + + public int intExpr(Expr.MemI src1, Expr.MemI src2) { + return ~src1.value & src2.value; + } + } + + public static class AndnICommutativeExpr extends Expr.BMIBinaryIntExpr { + + public int intExpr(int src1, int src2) { + return src1 & ~src2; + } + + public int intExpr(int src1, Expr.MemI src2) { + return src1 & ~src2.value; + } + + public int intExpr(Expr.MemI src1, int src2) { + return src1.value & ~src2; + } + + public int intExpr(Expr.MemI src1, Expr.MemI src2) { + return src1.value & ~src2.value; + } + } +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java b/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java new file mode 100644 index 00000000000..0dca7aa399a --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java @@ -0,0 +1,95 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of ANDN instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestAndnL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestAndnL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestAndnL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(AndnLExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(AndnLCommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class AndnLExpr extends Expr.BMIBinaryLongExpr { + + public long longExpr(long src1, long src2) { + return ~src1 & src2; + } + + public long longExpr(long src1, Expr.MemL src2) { + return ~src1 & src2.value; + } + + public long longExpr(Expr.MemL src1, long src2) { + return ~src1.value & src2; + } + + public long longExpr(Expr.MemL src1, Expr.MemL src2) { + return ~src1.value & src2.value; + } + + + } + + public static class AndnLCommutativeExpr extends Expr.BMIBinaryLongExpr { + + public long longExpr(long src1, long src2) { + return src1 & ~src2; + } + + public long longExpr(long src1, Expr.MemL src2) { + return src1 & ~src2.value; + } + + public long longExpr(Expr.MemL src1, long src2) { + return src1.value & ~src2; + } + + public long longExpr(Expr.MemL src1, Expr.MemL src2) { + return src1.value & ~src2.value; + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java new file mode 100644 index 00000000000..9f998bc05d5 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java @@ -0,0 +1,78 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSI instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsiI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsiI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsiI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsiIExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsiICommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsiIExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return -src & src; + } + + public int intExpr(Expr.MemI src) { + return -src.value & src.value; + } + + } + + public static class BlsiICommutativeExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return src & -src; + } + + public int intExpr(Expr.MemI src) { + return src.value & -src.value; + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java new file mode 100644 index 00000000000..b7a36c65a26 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java @@ -0,0 +1,78 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSI instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsiL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsiL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsiL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsiLExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsiLCommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsiLExpr extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return -src & src; + } + + public long longExpr(Expr.MemL src) { + return -src.value & src.value; + } + + } + + public static class BlsiLCommutativeExpr extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return src & -src; + } + + public long longExpr(Expr.MemL src) { + return src.value & -src.value; + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java new file mode 100644 index 00000000000..a06b429ec03 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java @@ -0,0 +1,78 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSMSK instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsmskI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsmskI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsmskI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsmskIExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsmskICommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsmskIExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return (src - 1) ^ src; + } + + public int intExpr(Expr.MemI src) { + return (src.value - 1) ^ src.value; + } + + } + + public static class BlsmskICommutativeExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return src ^ (src - 1); + } + + public int intExpr(Expr.MemI src) { + return src.value ^ (src.value - 1); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java new file mode 100644 index 00000000000..794c4c8f9a9 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java @@ -0,0 +1,80 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSMSK instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsmskL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsmskL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsmskL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsmskLExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsmskLCommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsmskLExpr + extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return (src - 1) ^ src; + } + + public long longExpr(Expr.MemL src) { + return (src.value - 1) ^ src.value; + } + + } + + public static class BlsmskLCommutativeExpr + extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return src ^ (src - 1); + } + + public long longExpr(Expr.MemL src) { + return src.value ^ (src.value - 1); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java new file mode 100644 index 00000000000..73ea886023f --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java @@ -0,0 +1,78 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSR instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsrI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsrI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsrI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsrIExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsrICommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsrIExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return (src - 1) & src; + } + + public int intExpr(Expr.MemI src) { + return (src.value - 1) & src.value; + } + + } + + public static class BlsrICommutativeExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return src & (src - 1); + } + + public int intExpr(Expr.MemI src) { + return src.value & (src.value - 1); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java new file mode 100644 index 00000000000..861f160806b --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java @@ -0,0 +1,78 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSR instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsrL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsrL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsrL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsrLExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsrLCommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsrLExpr extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return (src - 1) & src; + } + + public long longExpr(Expr.MemL src) { + return (src.value - 1) & src.value; + } + + } + + public static class BlsrLCommutativeExpr extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return src & (src - 1); + } + + public long longExpr(Expr.MemL src) { + return src.value & (src.value - 1); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java b/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java new file mode 100644 index 00000000000..a3720dc51e3 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java @@ -0,0 +1,60 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of intrinsic + * @library /testlibrary /testlibrary/whitebox + * @build TestLzcntI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestLzcntI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestLzcntI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("lzcnt")) { + System.out.println("CPU does not support lzcnt feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(LzcntIExpr.class, args, + "-XX:+UseCountLeadingZerosInstruction"); + } + + public static class LzcntIExpr extends Expr.BitCountingIntExpr { + + public int intExpr(int src) { + return Integer.numberOfLeadingZeros(src); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java b/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java new file mode 100644 index 00000000000..a3d788725a7 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java @@ -0,0 +1,60 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of intrinsic + * @library /testlibrary /testlibrary/whitebox + * @build TestLzcntL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestLzcntL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestLzcntL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("lzcnt")) { + System.out.println("CPU does not support lzcnt feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(LzcntLExpr.class, args, + "-XX:+UseCountLeadingZerosInstruction"); + } + + public static class LzcntLExpr extends Expr.BitCountingLongExpr { + + public long longExpr(long src) { + return Long.numberOfLeadingZeros(src); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java b/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java new file mode 100644 index 00000000000..d74c82a9a9e --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java @@ -0,0 +1,60 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of intrinsic + * @library /testlibrary /testlibrary/whitebox + * @build TestTzcntI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestTzcntI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestTzcntI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(TzcntIExpr.class, args, + "-XX:+UseCountTrailingZerosInstruction"); + } + + public static class TzcntIExpr extends Expr.BitCountingIntExpr { + + public int intExpr(int src) { + return Integer.numberOfTrailingZeros(src); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java b/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java new file mode 100644 index 00000000000..0c1841991d9 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java @@ -0,0 +1,60 @@ +/* + * 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of intrinsic + * @library /testlibrary /testlibrary/whitebox + * @build TestTzcntL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestTzcntL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestTzcntL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(TzcntLExpr.class, args, + "-XX:+UseCountTrailingZerosInstruction"); + } + + public static class TzcntLExpr extends Expr.BitCountingLongExpr { + + public long longExpr(long src) { + return Long.numberOfTrailingZeros(src); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/unsafe/UnsafeGetAddressTest.java b/hotspot/test/compiler/intrinsics/unsafe/UnsafeGetAddressTest.java new file mode 100644 index 00000000000..9e5772a944d --- /dev/null +++ b/hotspot/test/compiler/intrinsics/unsafe/UnsafeGetAddressTest.java @@ -0,0 +1,68 @@ +/* + * 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 6653795 + * @summary C2 intrinsic for Unsafe.getAddress performs pointer sign extension on 32-bit systems + * @run main UnsafeGetAddressTest + * + */ + +import sun.misc.Unsafe; +import java.lang.reflect.*; + +public class UnsafeGetAddressTest { + private static Unsafe unsafe; + + public static void main(String[] args) throws Exception { + Class c = UnsafeGetAddressTest.class.getClassLoader().loadClass("sun.misc.Unsafe"); + Field f = c.getDeclaredField("theUnsafe"); + f.setAccessible(true); + unsafe = (Unsafe)f.get(c); + + long address = unsafe.allocateMemory(unsafe.addressSize()); + unsafe.putAddress(address, 0x0000000080000000L); + // from sun.misc.Unsafe.getAddress' documentation: + // "If the native pointer is less than 64 bits wide, it is + // extended as an unsigned number to a Java long." + result = unsafe.getAddress(address); + System.out.printf("1: was 0x%x, expected 0x%x\n", result, + 0x0000000080000000L); + for (int i = 0; i < 1000000; i++) { + result = unsafe.getAddress(address); + } + + // The code has got compiled, check the result now + System.out.printf("2: was 0x%x, expected 0x%x\n", result, + 0x0000000080000000L); + if (result != 0x0000000080000000L) { + System.out.println("Test Failed"); + System.exit(97); + } else { + System.out.println("Test Passed"); + } + } + static volatile long result; +} + diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java index c199c2a6a67..5f353998061 100644 --- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java @@ -24,6 +24,7 @@ import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.VMOption; import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; import sun.management.ManagementFactoryHelper; import java.lang.reflect.Constructor; @@ -278,7 +279,8 @@ public abstract class CompilerWhiteBoxTest { } protected final int getCompLevel() { - return WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()); + NMethod nm = NMethod.get(method, testCase.isOsr()); + return nm == null ? COMP_LEVEL_NONE : nm.comp_level; } protected final boolean isCompilable() { diff --git a/hotspot/test/compiler/whitebox/GetNMethodTest.java b/hotspot/test/compiler/whitebox/GetNMethodTest.java new file mode 100644 index 00000000000..bb95f01b991 --- /dev/null +++ b/hotspot/test/compiler/whitebox/GetNMethodTest.java @@ -0,0 +1,71 @@ +/* + * 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.code.NMethod; + +/* + * @test GetNMethodTest + * @bug 8038240 + * @library /testlibrary /testlibrary/whitebox + * @build GetNMethodTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @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 + */ +public class GetNMethodTest extends CompilerWhiteBoxTest { + public static void main(String[] args) throws Exception { + CompilerWhiteBoxTest.main(GetNMethodTest::new, args); + } + + private GetNMethodTest(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + @Override + protected void test() throws Exception { + checkNotCompiled(); + + compile(); + checkCompiled(); + NMethod nmethod = NMethod.get(method, testCase.isOsr()); + if (IS_VERBOSE) { + System.out.println("nmethod = " + nmethod); + } + if (nmethod == null) { + throw new RuntimeException("nmethod of compiled method is null"); + } + if (nmethod.insts.length == 0) { + throw new RuntimeException("compiled method's instructions is empty"); + } + deoptimize(); + checkNotCompiled(); + nmethod = NMethod.get(method, testCase.isOsr()); + if (nmethod != null) { + throw new RuntimeException("nmethod of non-compiled method isn't null"); + } + } +} diff --git a/hotspot/test/gc/TestGCLogRotationViaJcmd.java b/hotspot/test/gc/TestGCLogRotationViaJcmd.java new file mode 100644 index 00000000000..fd71d368b88 --- /dev/null +++ b/hotspot/test/gc/TestGCLogRotationViaJcmd.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 TestGCLogRotationViaJcmd.java + * @bug 7090324 + * @summary test for gc log rotation via jcmd + * @library /testlibrary + * @run main/othervm -Xloggc:test.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 TestGCLogRotationViaJcmd + * + */ +import com.oracle.java.testlibrary.*; +import java.io.File; +import java.io.FilenameFilter; + +public class TestGCLogRotationViaJcmd { + + static final File currentDirectory = new File("."); + static final String LOG_FILE_NAME = "test.log"; + static final int NUM_LOGS = 3; + + static FilenameFilter logFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.startsWith(LOG_FILE_NAME); + } + }; + + public static void main(String[] args) throws Exception { + // Grab the pid from the current java process + String pid = Integer.toString(ProcessTools.getProcessId()); + + // Create a JDKToolLauncher + JDKToolLauncher jcmd = JDKToolLauncher.create("jcmd") + .addToolArg(pid) + .addToolArg("GC.rotate_log"); + + for (int times = 1; times < NUM_LOGS; times++) { + // Run jcmd GC.rotate_log + ProcessBuilder pb = new ProcessBuilder(jcmd.getCommand()); + + // Make sure we didn't crash + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } + + // GC log check + File[] logs = currentDirectory.listFiles(logFilter); + if (logs.length != NUM_LOGS) { + throw new Error("There are only " + logs.length + + " logs instead " + NUM_LOGS); + } + + } + +} + diff --git a/hotspot/test/gc/arguments/FlagsValue.java b/hotspot/test/gc/arguments/FlagsValue.java new file mode 100644 index 00000000000..1dbd4a3cbbf --- /dev/null +++ b/hotspot/test/gc/arguments/FlagsValue.java @@ -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. +*/ + +import java.util.regex.*; + +public class FlagsValue { + public static boolean getFlagBoolValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?= (true|false)").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + return m.group(1).equals("true"); + } + + public static long getFlagLongValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + String match = m.group(); + return Long.parseLong(match.substring(match.lastIndexOf(" ") + 1, match.length())); + } +} \ No newline at end of file diff --git a/hotspot/test/gc/arguments/TestDynMaxHeapFreeRatio.java b/hotspot/test/gc/arguments/TestDynMaxHeapFreeRatio.java new file mode 100644 index 00000000000..6d36106c43b --- /dev/null +++ b/hotspot/test/gc/arguments/TestDynMaxHeapFreeRatio.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 TestDynMaxHeapFreeRatio + * @bug 8028391 + * @summary Verify that MaxHeapFreeRatio flag is manageable + * @library /testlibrary + * @run main TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:-UseAdaptiveSizePolicy TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=51 -XX:MaxHeapFreeRatio=52 TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=75 -XX:MaxHeapFreeRatio=100 TestDynMaxHeapFreeRatio + */ +import com.oracle.java.testlibrary.TestDynamicVMOption; +import com.oracle.java.testlibrary.DynamicVMOptionChecker; + +public class TestDynMaxHeapFreeRatio extends TestDynamicVMOption { + + public static final String MinFreeRatioFlagName = "MinHeapFreeRatio"; + public static final String MaxFreeRatioFlagName = "MaxHeapFreeRatio"; + + public TestDynMaxHeapFreeRatio() { + super(MaxFreeRatioFlagName); + } + + public void test() { + + int minHeapFreeValue = DynamicVMOptionChecker.getIntValue(MinFreeRatioFlagName); + System.out.println(MinFreeRatioFlagName + " = " + minHeapFreeValue); + + testPercentageValues(); + + checkInvalidValue(Integer.toString(minHeapFreeValue - 1)); + checkValidValue(Integer.toString(minHeapFreeValue)); + checkValidValue("100"); + } + + public static void main(String args[]) throws Exception { + new TestDynMaxHeapFreeRatio().test(); + } + +} diff --git a/hotspot/test/gc/arguments/TestDynMinHeapFreeRatio.java b/hotspot/test/gc/arguments/TestDynMinHeapFreeRatio.java new file mode 100644 index 00000000000..13132f04d38 --- /dev/null +++ b/hotspot/test/gc/arguments/TestDynMinHeapFreeRatio.java @@ -0,0 +1,62 @@ +/* + * 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 TestDynMinHeapFreeRatio + * @bug 8028391 + * @summary Verify that MinHeapFreeRatio flag is manageable + * @library /testlibrary + * @run main TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:-UseAdaptiveSizePolicy TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=51 -XX:MaxHeapFreeRatio=52 TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=75 -XX:MaxHeapFreeRatio=100 TestDynMinHeapFreeRatio + */ +import com.oracle.java.testlibrary.TestDynamicVMOption; +import com.oracle.java.testlibrary.DynamicVMOptionChecker; + +public class TestDynMinHeapFreeRatio extends TestDynamicVMOption { + + public static final String MinFreeRatioFlagName = "MinHeapFreeRatio"; + public static final String MaxFreeRatioFlagName = "MaxHeapFreeRatio"; + + public TestDynMinHeapFreeRatio() { + super(MinFreeRatioFlagName); + } + + public void test() { + int maxHeapFreeValue = DynamicVMOptionChecker.getIntValue(MaxFreeRatioFlagName); + System.out.println(MaxFreeRatioFlagName + " = " + maxHeapFreeValue); + + testPercentageValues(); + + checkInvalidValue(Integer.toString(maxHeapFreeValue + 1)); + checkValidValue(Integer.toString(maxHeapFreeValue)); + checkValidValue("0"); + } + + public static void main(String args[]) throws Exception { + new TestDynMinHeapFreeRatio().test(); + } +} diff --git a/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java b/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java index 2c97ccd8fff..130ff744d08 100644 --- a/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java +++ b/hotspot/test/gc/arguments/TestInitialTenuringThreshold.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 @@ -63,13 +63,13 @@ public class TestInitialTenuringThreshold { // successful tests runWithThresholds(0, 10, false); runWithThresholds(5, 5, false); + runWithThresholds(8, 16, false); // failing tests runWithThresholds(10, 0, true); runWithThresholds(9, 8, true); runWithThresholds(-1, 8, true); runWithThresholds(8, -1, true); - runWithThresholds(8, 16, true); runWithThresholds(16, 8, true); + runWithThresholds(8, 17, true); } -} - +} \ No newline at end of file diff --git a/hotspot/test/gc/arguments/TestObjectTenuringFlags.java b/hotspot/test/gc/arguments/TestObjectTenuringFlags.java new file mode 100644 index 00000000000..64ddeb46744 --- /dev/null +++ b/hotspot/test/gc/arguments/TestObjectTenuringFlags.java @@ -0,0 +1,215 @@ +/* +* 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 TestObjectTenuringFlags + * @key gc + * @bug 6521376 + * @summary Tests argument processing for NeverTenure, AlwaysTenure, + * and MaxTenuringThreshold + * @library /testlibrary + * @build TestObjectTenuringFlags FlagsValue + * @run main/othervm TestObjectTenuringFlags + */ + +import com.oracle.java.testlibrary.*; + +import java.util.*; + +public class TestObjectTenuringFlags { + public static void main(String args[]) throws Exception { + // default case + runTenuringFlagsConsistencyTest( + new String[]{}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 15)); + + // valid cases + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+NeverTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, true /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+AlwaysTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=0"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=5"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 5, 5)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=10"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 10)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=15"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 15)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=16"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=0"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 0, 15)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=5"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 5, 15)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=10"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 10, 15)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=15"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 15, 15)); + + // "Last option wins" cases + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+AlwaysTenure", "-XX:+NeverTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, true /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+NeverTenure", "-XX:+AlwaysTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=16", "-XX:+AlwaysTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+AlwaysTenure", "-XX:MaxTenuringThreshold=16"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=0", "-XX:+NeverTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, true /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+NeverTenure", "-XX:MaxTenuringThreshold=0"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + // Illegal cases + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=17"}, + true /* shouldFail */, + new ExpectedTenuringFlags()); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=16"}, + true /* shouldFail */, + new ExpectedTenuringFlags()); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=17"}, + true /* shouldFail */, + new ExpectedTenuringFlags()); + } + + private static void runTenuringFlagsConsistencyTest(String[] tenuringFlags, + boolean shouldFail, + ExpectedTenuringFlags expectedFlags) throws Exception { + List vmOpts = new ArrayList<>(); + if (tenuringFlags.length > 0) { + Collections.addAll(vmOpts, tenuringFlags); + } + Collections.addAll(vmOpts, "-XX:+PrintFlagsFinal", "-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + if (shouldFail) { + output.shouldHaveExitValue(1); + } else { + output.shouldHaveExitValue(0); + String stdout = output.getStdout(); + checkTenuringFlagsConsistency(stdout, expectedFlags); + } + } + + private static void checkTenuringFlagsConsistency(String output, ExpectedTenuringFlags expectedFlags) { + if (expectedFlags.alwaysTenure != FlagsValue.getFlagBoolValue("AlwaysTenure", output)) { + throw new RuntimeException( + "Actual flag AlwaysTenure " + FlagsValue.getFlagBoolValue("AlwaysTenure", output) + + " is not equal to expected flag AlwaysTenure " + expectedFlags.alwaysTenure); + } + + if (expectedFlags.neverTenure != FlagsValue.getFlagBoolValue("NeverTenure", output)) { + throw new RuntimeException( + "Actual flag NeverTenure " + FlagsValue.getFlagBoolValue("NeverTenure", output) + + " is not equal to expected flag NeverTenure " + expectedFlags.neverTenure); + } + + if (expectedFlags.initialTenuringThreshold != FlagsValue.getFlagLongValue("InitialTenuringThreshold", output)) { + throw new RuntimeException( + "Actual flag InitialTenuringThreshold " + FlagsValue.getFlagLongValue("InitialTenuringThreshold", output) + + " is not equal to expected flag InitialTenuringThreshold " + expectedFlags.initialTenuringThreshold); + } + + if (expectedFlags.maxTenuringThreshold != FlagsValue.getFlagLongValue("MaxTenuringThreshold", output)) { + throw new RuntimeException( + "Actual flag MaxTenuringThreshold " + FlagsValue.getFlagLongValue("MaxTenuringThreshold", output) + + " is not equal to expected flag MaxTenuringThreshold " + expectedFlags.maxTenuringThreshold); + } + } +} + +class ExpectedTenuringFlags { + public boolean alwaysTenure; + public boolean neverTenure; + public long initialTenuringThreshold; + public long maxTenuringThreshold; + + public ExpectedTenuringFlags(boolean alwaysTenure, + boolean neverTenure, + long initialTenuringThreshold, + long maxTenuringThreshold) { + this.alwaysTenure = alwaysTenure; + this.neverTenure = neverTenure; + this.initialTenuringThreshold = initialTenuringThreshold; + this.maxTenuringThreshold = maxTenuringThreshold; + } + public ExpectedTenuringFlags() {} +} diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java new file mode 100644 index 00000000000..06ce2ca6d2d --- /dev/null +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -0,0 +1,152 @@ +/* + * 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 TestPrintGCDetails + * @bug 8035406 8027295 8035398 + * @summary Ensure that the PrintGCDetails output for a minor GC with G1 + * includes the expected necessary messages. + * @key gc + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class TestGCLogMessages { + public static void main(String[] args) throws Exception { + testNormalLogs(); + testWithToSpaceExhaustionLogs(); + } + + private static void testNormalLogs() throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + GCTest.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldNotContain("[Redirty Cards"); + output.shouldNotContain("[Code Root Purge"); + output.shouldNotContain("[String Dedup Fixup"); + output.shouldNotContain("[Young Free CSet"); + output.shouldNotContain("[Non-Young Free CSet"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:+UseStringDeduplication", + "-Xmx10M", + "-XX:+PrintGCDetails", + GCTest.class.getName()); + + output = new OutputAnalyzer(pb.start()); + + output.shouldContain("[Redirty Cards"); + output.shouldContain("[Code Root Purge"); + output.shouldContain("[String Dedup Fixup"); + output.shouldNotContain("[Young Free CSet"); + output.shouldNotContain("[Non-Young Free CSet"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:+UseStringDeduplication", + "-Xmx10M", + "-XX:+PrintGCDetails", + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1LogLevel=finest", + GCTest.class.getName()); + + output = new OutputAnalyzer(pb.start()); + + output.shouldContain("[Redirty Cards"); + output.shouldContain("[Code Root Purge"); + output.shouldContain("[String Dedup Fixup"); + output.shouldContain("[Young Free CSet"); + output.shouldContain("[Non-Young Free CSet"); + + // also check evacuation failure messages once + output.shouldNotContain("[Evacuation Failure"); + output.shouldNotContain("[Recalculate Used"); + output.shouldNotContain("[Remove Self Forwards"); + output.shouldNotContain("[Restore RemSet"); + output.shouldHaveExitValue(0); + } + + private static void testWithToSpaceExhaustionLogs() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + "-Xmn5M", + "-XX:+PrintGCDetails", + GCTestWithToSpaceExhaustion.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[Evacuation Failure"); + output.shouldNotContain("[Recalculate Used"); + output.shouldNotContain("[Remove Self Forwards"); + output.shouldNotContain("[Restore RemSet"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + "-Xmn5M", + "-XX:+PrintGCDetails", + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1LogLevel=finest", + GCTestWithToSpaceExhaustion.class.getName()); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("[Evacuation Failure"); + output.shouldContain("[Recalculate Used"); + output.shouldContain("[Remove Self Forwards"); + output.shouldContain("[Restore RemSet"); + output.shouldHaveExitValue(0); + } + + static class GCTest { + private static byte[] garbage; + public static void main(String [] args) { + System.out.println("Creating garbage"); + // create 128MB of garbage. This should result in at least one GC + for (int i = 0; i < 1024; i++) { + garbage = new byte[128 * 1024]; + } + System.out.println("Done"); + } + } + + static class GCTestWithToSpaceExhaustion { + private static byte[] garbage; + private static byte[] largeObject; + public static void main(String [] args) { + largeObject = new byte[5*1024*1024]; + System.out.println("Creating garbage"); + // create 128MB of garbage. This should result in at least one GC, + // some of them with to-space exhaustion. + for (int i = 0; i < 1024; i++) { + garbage = new byte[128 * 1024]; + } + System.out.println("Done"); + } + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationAgeThreshold.java b/hotspot/test/gc/g1/TestStringDeduplicationAgeThreshold.java new file mode 100644 index 00000000000..8bdac8d07f6 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationAgeThreshold.java @@ -0,0 +1,36 @@ +/* + * 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 TestStringDeduplicationAgeThreshold + * @summary Test string deduplication age threshold + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationAgeThreshold { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testAgeThreshold(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationFullGC.java b/hotspot/test/gc/g1/TestStringDeduplicationFullGC.java new file mode 100644 index 00000000000..0e47db75c4c --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationFullGC.java @@ -0,0 +1,36 @@ +/* + * 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 TestStringDeduplicationFullGC + * @summary Test string deduplication during full GC + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationFullGC { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testFullGC(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationInterned.java b/hotspot/test/gc/g1/TestStringDeduplicationInterned.java new file mode 100644 index 00000000000..680fa860ea8 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationInterned.java @@ -0,0 +1,36 @@ +/* + * 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 TestStringDeduplicationInterned + * @summary Test string deduplication of interned strings + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationInterned { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testInterned(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java b/hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java new file mode 100644 index 00000000000..ba3428986e2 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java @@ -0,0 +1,36 @@ +/* + * 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 TestStringDeduplicationMemoryUsage + * @summary Test string deduplication memory usage + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationMemoryUsage { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testMemoryUsage(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationPrintOptions.java b/hotspot/test/gc/g1/TestStringDeduplicationPrintOptions.java new file mode 100644 index 00000000000..58279644490 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationPrintOptions.java @@ -0,0 +1,36 @@ +/* + * 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 TestStringDeduplicationPrintOptions + * @summary Test string deduplication print options + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationPrintOptions { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testPrintOptions(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationTableRehash.java b/hotspot/test/gc/g1/TestStringDeduplicationTableRehash.java new file mode 100644 index 00000000000..9b5d09215dd --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationTableRehash.java @@ -0,0 +1,36 @@ +/* + * 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 TestStringDeduplicationTableRehash + * @summary Test string deduplication table rehash + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationTableRehash { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testTableRehash(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationTableResize.java b/hotspot/test/gc/g1/TestStringDeduplicationTableResize.java new file mode 100644 index 00000000000..803c63bbb20 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationTableResize.java @@ -0,0 +1,36 @@ +/* + * 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 TestStringDeduplicationTableResize + * @summary Test string deduplication table resize + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationTableResize { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testTableResize(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationTools.java b/hotspot/test/gc/g1/TestStringDeduplicationTools.java new file mode 100644 index 00000000000..1c1f480189a --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationTools.java @@ -0,0 +1,512 @@ +/* + * 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. + */ + +/* + * Common code for string deduplication tests + */ + +import java.lang.management.*; +import java.lang.reflect.*; +import java.security.*; +import java.util.*; +import com.oracle.java.testlibrary.*; +import sun.misc.*; + +class TestStringDeduplicationTools { + private static final String YoungGC = "YoungGC"; + private static final String FullGC = "FullGC"; + + private static final int Xmn = 50; // MB + private static final int Xms = 100; // MB + private static final int Xmx = 100; // MB + private static final int MB = 1024 * 1024; + private static final int StringLength = 50; + + private static Field valueField; + private static Unsafe unsafe; + private static byte[] dummy; + + static { + try { + Field field = Unsafe.class.getDeclaredField("theUnsafe"); + field.setAccessible(true); + unsafe = (Unsafe)field.get(null); + + valueField = String.class.getDeclaredField("value"); + valueField.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static Object getValue(String string) { + try { + return valueField.get(string); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void doFullGc(int numberOfTimes) { + for (int i = 0; i < numberOfTimes; i++) { + System.out.println("Begin: Full GC " + (i + 1) + "/" + numberOfTimes); + System.gc(); + System.out.println("End: Full GC " + (i + 1) + "/" + numberOfTimes); + } + } + + private static void doYoungGc(int numberOfTimes) { + // Provoke at least numberOfTimes young GCs + final int objectSize = 128; + final int maxObjectInYoung = (Xmn * MB) / objectSize; + for (int i = 0; i < numberOfTimes; i++) { + System.out.println("Begin: Young GC " + (i + 1) + "/" + numberOfTimes); + for (int j = 0; j < maxObjectInYoung + 1; j++) { + dummy = new byte[objectSize]; + } + System.out.println("End: Young GC " + (i + 1) + "/" + numberOfTimes); + } + } + + private static void forceDeduplication(int ageThreshold, String gcType) { + // Force deduplication to happen by either causing a FullGC or a YoungGC. + // We do several collections to also provoke a situation where the the + // deduplication thread needs to yield while processing the queue. This + // also tests that the references in the deduplication queue are adjusted + // accordingly. + if (gcType.equals(FullGC)) { + doFullGc(3); + } else { + doYoungGc(ageThreshold + 3); + } + } + + private static String generateString(int id) { + StringBuilder builder = new StringBuilder(StringLength); + + builder.append("DeduplicationTestString:" + id + ":"); + + while (builder.length() < StringLength) { + builder.append('X'); + } + + return builder.toString(); + } + + private static ArrayList createStrings(int total, int unique) { + System.out.println("Creating strings: total=" + total + ", unique=" + unique); + if (total % unique != 0) { + throw new RuntimeException("Total must be divisible by unique"); + } + + ArrayList list = new ArrayList(total); + for (int j = 0; j < total / unique; j++) { + for (int i = 0; i < unique; i++) { + list.add(generateString(i)); + } + } + + return list; + } + + private static void verifyStrings(ArrayList list, int uniqueExpected) { + for (;;) { + // Check number of deduplicated strings + ArrayList unique = new ArrayList(uniqueExpected); + for (String string: list) { + Object value = getValue(string); + boolean uniqueValue = true; + for (Object obj: unique) { + if (obj == value) { + uniqueValue = false; + break; + } + } + + if (uniqueValue) { + unique.add(value); + } + } + + System.out.println("Verifying strings: total=" + list.size() + + ", uniqueFound=" + unique.size() + + ", uniqueExpected=" + uniqueExpected); + + if (unique.size() == uniqueExpected) { + System.out.println("Deduplication completed"); + break; + } else { + System.out.println("Deduplication not completed, waiting..."); + + // Give the deduplication thread time to complete + try { + Thread.sleep(1000); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + + private static OutputAnalyzer runTest(String... extraArgs) throws Exception { + String[] defaultArgs = new String[] { + "-Xmn" + Xmn + "m", + "-Xms" + Xms + "m", + "-Xmx" + Xmx + "m", + "-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+VerifyAfterGC" // Always verify after GC + }; + + ArrayList args = new ArrayList(); + args.addAll(Arrays.asList(defaultArgs)); + args.addAll(Arrays.asList(extraArgs)); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + System.err.println(output.getStderr()); + System.out.println(output.getStdout()); + return output; + } + + private static class DeduplicationTest { + public static void main(String[] args) { + System.out.println("Begin: DeduplicationTest"); + + final int numberOfStrings = Integer.parseUnsignedInt(args[0]); + final int numberOfUniqueStrings = Integer.parseUnsignedInt(args[1]); + final int ageThreshold = Integer.parseUnsignedInt(args[2]); + final String gcType = args[3]; + + ArrayList list = createStrings(numberOfStrings, numberOfUniqueStrings); + forceDeduplication(ageThreshold, gcType); + verifyStrings(list, numberOfUniqueStrings); + + System.out.println("End: DeduplicationTest"); + } + + public static OutputAnalyzer run(int numberOfStrings, int ageThreshold, String gcType, String... extraArgs) throws Exception { + String[] defaultArgs = new String[] { + "-XX:+UseStringDeduplication", + "-XX:StringDeduplicationAgeThreshold=" + ageThreshold, + DeduplicationTest.class.getName(), + "" + numberOfStrings, + "" + numberOfStrings / 2, + "" + ageThreshold, + gcType + }; + + ArrayList args = new ArrayList(); + args.addAll(Arrays.asList(extraArgs)); + args.addAll(Arrays.asList(defaultArgs)); + + return runTest(args.toArray(new String[args.size()])); + } + } + + private static class InternedTest { + public static void main(String[] args) { + // This test verifies that interned strings are always + // deduplicated when being interned, and never after + // being interned. + + System.out.println("Begin: InternedTest"); + + final int ageThreshold = Integer.parseUnsignedInt(args[0]); + final String baseString = "DeduplicationTestString:" + InternedTest.class.getName(); + + // Create duplicate of baseString + StringBuilder sb1 = new StringBuilder(baseString); + String dupString1 = sb1.toString(); + if (getValue(dupString1) == getValue(baseString)) { + throw new RuntimeException("Values should not match"); + } + + // Force baseString to be inspected for deduplication + // and be inserted into the deduplication hashtable. + forceDeduplication(ageThreshold, FullGC); + + // Wait for deduplication to occur + while (getValue(dupString1) != getValue(baseString)) { + System.out.println("Waiting..."); + try { + Thread.sleep(100); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // Create a new duplicate of baseString + StringBuilder sb2 = new StringBuilder(baseString); + String dupString2 = sb2.toString(); + if (getValue(dupString2) == getValue(baseString)) { + throw new RuntimeException("Values should not match"); + } + + // Intern the new duplicate + Object beforeInternedValue = getValue(dupString2); + String internedString = dupString2.intern(); + if (internedString != dupString2) { + throw new RuntimeException("String should match"); + } + if (getValue(internedString) != getValue(baseString)) { + throw new RuntimeException("Values should match"); + } + + // Check original value of interned string, to make sure + // deduplication happened on the interned string and not + // on the base string + if (beforeInternedValue == getValue(baseString)) { + throw new RuntimeException("Values should not match"); + } + + System.out.println("End: InternedTest"); + } + + public static OutputAnalyzer run() throws Exception { + return runTest("-XX:+PrintGC", + "-XX:+PrintGCDetails", + "-XX:+UseStringDeduplication", + "-XX:+PrintStringDeduplicationStatistics", + "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold, + InternedTest.class.getName(), + "" + DefaultAgeThreshold); + } + } + + private static class MemoryUsageTest { + public static void main(String[] args) { + System.out.println("Begin: MemoryUsageTest"); + + final boolean useStringDeduplication = Boolean.parseBoolean(args[0]); + final int numberOfStrings = LargeNumberOfStrings; + final int numberOfUniqueStrings = 1; + + ArrayList list = createStrings(numberOfStrings, numberOfUniqueStrings); + forceDeduplication(DefaultAgeThreshold, FullGC); + + if (useStringDeduplication) { + verifyStrings(list, numberOfUniqueStrings); + } + + System.gc(); + System.out.println("Heap Memory Usage: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()); + + System.out.println("End: MemoryUsageTest"); + } + + public static OutputAnalyzer run(boolean useStringDeduplication) throws Exception { + String[] extraArgs = new String[0]; + + if (useStringDeduplication) { + extraArgs = new String[] { + "-XX:+UseStringDeduplication", + "-XX:+PrintStringDeduplicationStatistics", + "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold + }; + } + + String[] defaultArgs = new String[] { + "-XX:+PrintGC", + "-XX:+PrintGCDetails", + MemoryUsageTest.class.getName(), + "" + useStringDeduplication + }; + + ArrayList args = new ArrayList(); + args.addAll(Arrays.asList(extraArgs)); + args.addAll(Arrays.asList(defaultArgs)); + + return runTest(args.toArray(new String[args.size()])); + } + } + + /* + * Tests + */ + + private static final int LargeNumberOfStrings = 10000; + private static final int SmallNumberOfStrings = 10; + + private static final int MaxAgeThreshold = 15; + private static final int DefaultAgeThreshold = 3; + private static final int MinAgeThreshold = 1; + + private static final int TooLowAgeThreshold = MinAgeThreshold - 1; + private static final int TooHighAgeThreshold = MaxAgeThreshold + 1; + + public static void testYoungGC() throws Exception { + // Do young GC to age strings to provoke deduplication + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, + DefaultAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics"); + output.shouldNotContain("Full GC"); + output.shouldContain("GC pause (G1 Evacuation Pause) (young)"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldHaveExitValue(0); + } + + public static void testFullGC() throws Exception { + // Do full GC to age strings to provoke deduplication + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, + DefaultAgeThreshold, + FullGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics"); + output.shouldNotContain("GC pause (G1 Evacuation Pause) (young)"); + output.shouldContain("Full GC"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldHaveExitValue(0); + } + + public static void testTableResize() throws Exception { + // Test with StringDeduplicationResizeALot + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, + DefaultAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics", + "-XX:+StringDeduplicationResizeALot"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldNotContain("Resize Count: 0"); + output.shouldHaveExitValue(0); + } + + public static void testTableRehash() throws Exception { + // Test with StringDeduplicationRehashALot + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, + DefaultAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics", + "-XX:+StringDeduplicationRehashALot"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldNotContain("Rehash Count: 0"); + output.shouldNotContain("Hash Seed: 0x0"); + output.shouldHaveExitValue(0); + } + + public static void testAgeThreshold() throws Exception { + OutputAnalyzer output; + + // Test with max age theshold + output = DeduplicationTest.run(SmallNumberOfStrings, + MaxAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldHaveExitValue(0); + + // Test with min age theshold + output = DeduplicationTest.run(SmallNumberOfStrings, + MinAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldHaveExitValue(0); + + // Test with too low age threshold + output = DeduplicationTest.run(SmallNumberOfStrings, + TooLowAgeThreshold, + YoungGC); + output.shouldContain("StringDeduplicationAgeThreshold of " + TooLowAgeThreshold + + " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold); + output.shouldHaveExitValue(1); + + // Test with too high age threshold + output = DeduplicationTest.run(SmallNumberOfStrings, + TooHighAgeThreshold, + YoungGC); + output.shouldContain("StringDeduplicationAgeThreshold of " + TooHighAgeThreshold + + " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold); + output.shouldHaveExitValue(1); + } + + public static void testPrintOptions() throws Exception { + OutputAnalyzer output; + + // Test without PrintGC and without PrintStringDeduplicationStatistics + output = DeduplicationTest.run(SmallNumberOfStrings, + DefaultAgeThreshold, + YoungGC); + output.shouldNotContain("GC concurrent-string-deduplication"); + output.shouldNotContain("Deduplicated:"); + output.shouldHaveExitValue(0); + + // Test with PrintGC but without PrintStringDeduplicationStatistics + output = DeduplicationTest.run(SmallNumberOfStrings, + DefaultAgeThreshold, + YoungGC, + "-XX:+PrintGC"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldNotContain("Deduplicated:"); + output.shouldHaveExitValue(0); + } + + public static void testInterned() throws Exception { + // Test that interned strings are deduplicated before being interned + OutputAnalyzer output = InternedTest.run(); + output.shouldHaveExitValue(0); + } + + public static void testMemoryUsage() throws Exception { + // Test that memory usage is reduced after deduplication + OutputAnalyzer output; + final String usagePattern = "Heap Memory Usage: (\\d+)"; + + // Run without deduplication + output = MemoryUsageTest.run(false); + output.shouldHaveExitValue(0); + final long memoryUsageWithoutDedup = Long.parseLong(output.firstMatch(usagePattern, 1)); + + // Run with deduplication + output = MemoryUsageTest.run(true); + output.shouldHaveExitValue(0); + final long memoryUsageWithDedup = Long.parseLong(output.firstMatch(usagePattern, 1)); + + // Calculate expected memory usage with deduplication enabled. This calculation does + // not take alignment and padding into account, so it's a conservative estimate. + final long sizeOfChar = 2; // bytes + final long bytesSaved = (LargeNumberOfStrings - 1) * (StringLength * sizeOfChar + unsafe.ARRAY_CHAR_BASE_OFFSET); + final long memoryUsageWithDedupExpected = memoryUsageWithoutDedup - bytesSaved; + + System.out.println("Memory usage summary:"); + System.out.println(" memoryUsageWithoutDedup: " + memoryUsageWithoutDedup); + System.out.println(" memoryUsageWithDedup: " + memoryUsageWithDedup); + System.out.println(" memoryUsageWithDedupExpected: " + memoryUsageWithDedupExpected); + + if (memoryUsageWithDedup > memoryUsageWithDedupExpected) { + throw new Exception("Unexpected memory usage, memoryUsageWithDedup should less or equal to memoryUsageWithDedupExpected"); + } + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationYoungGC.java b/hotspot/test/gc/g1/TestStringDeduplicationYoungGC.java new file mode 100644 index 00000000000..c856d019205 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationYoungGC.java @@ -0,0 +1,36 @@ +/* + * 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 TestStringDeduplicationYoungGC + * @summary Test string deduplication during young GC + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationYoungGC { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testYoungGC(); + } +} diff --git a/hotspot/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java b/hotspot/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java index 8152a9eb1ca..489ae411669 100644 --- a/hotspot/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java +++ b/hotspot/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java @@ -26,7 +26,7 @@ * @bug 8004924 * @summary Checks that jmap -heap contains the flag CompressedClassSpaceSize * @library /testlibrary - * @run main/othervm -XX:CompressedClassSpaceSize=50m CompressedClassSpaceSizeInJmapHeap + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:CompressedClassSpaceSize=50m CompressedClassSpaceSizeInJmapHeap */ import com.oracle.java.testlibrary.*; @@ -37,6 +37,11 @@ import java.util.List; public class CompressedClassSpaceSizeInJmapHeap { public static void main(String[] args) throws Exception { + if (!Platform.is64bit()) { + // Compressed Class Space is only available on 64-bit JVMs + return; + } + String pid = Integer.toString(ProcessTools.getProcessId()); JDKToolLauncher jmap = JDKToolLauncher.create("jmap") diff --git a/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java b/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java index 480905f5dca..73f0c804312 100644 --- a/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java +++ b/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.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 @@ -22,7 +22,6 @@ */ /* - * @ignore 8026154 * @test * @bug 8005933 * @summary Test that -Xshare:auto uses CDS when explicitly specified with -server. @@ -50,21 +49,15 @@ public class XShareAuto { pb = ProcessTools.createJavaProcessBuilder( "-server", "-Xshare:auto", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-version"); + "-XX:SharedArchiveFile=./sample.jsa", "-XX:+PrintSharedSpaces", "-version"); output = new OutputAnalyzer(pb.start()); try { output.shouldContain("sharing"); - output.shouldHaveExitValue(0); } catch (RuntimeException e) { - // If this failed then check that it would also be unable - // to share even if -Xshare:on is specified. If so, then - // return a success status. - pb = ProcessTools.createJavaProcessBuilder( - "-server", "-Xshare:on", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("Unable to use shared archive"); - output.shouldHaveExitValue(1); + // if sharing failed due to ASLR or similar reasons, + // check whether sharing was attempted at all (UseSharedSpaces) + output.shouldContain("UseSharedSpaces:"); } + output.shouldHaveExitValue(0); } } diff --git a/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java b/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java index 7b58a841315..9ef37434937 100644 --- a/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java +++ b/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java @@ -26,10 +26,7 @@ * @key nmt jcmd * @summary Verify that jcmd correctly reports that NMT is not enabled * @library /testlibrary - * First run without enabling NMT - * @run main/othervm JcmdWithNMTDisabled - * Then run with explicitly disabling NMT, should not be any difference - * @run main/othervm -XX:NativeMemoryTracking=off JcmdWithNMTDisabled + * @run main JcmdWithNMTDisabled 1 */ import com.oracle.java.testlibrary.*; @@ -39,6 +36,27 @@ public class JcmdWithNMTDisabled { static String pid; public static void main(String args[]) throws Exception { + + // This test explicitly needs to be run with the exact command lines below, not passing on + // arguments from the parent VM is a conscious choice to avoid NMT being turned on. + if (args.length > 0) { + ProcessBuilder pb; + OutputAnalyzer output; + String testjdkPath = System.getProperty("test.jdk"); + + // First run without enabling NMT + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "JcmdWithNMTDisabled"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + // Then run with explicitly disabling NMT, should not be any difference + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "-XX:NativeMemoryTracking=off", "JcmdWithNMTDisabled"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + return; + } + // Grab my own PID pid = Integer.toString(ProcessTools.getProcessId()); diff --git a/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java b/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java index 55eb104b050..9ecb1dae390 100644 --- a/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java +++ b/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.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 @@ -22,7 +22,6 @@ */ /* - * @ignore 8025642 * @test CdsDifferentObjectAlignment * @summary Testing CDS (class data sharing) using varying object alignment. * Using different object alignment for each dump/load pair. @@ -84,7 +83,11 @@ public class CdsDifferentObjectAlignment { createAlignment, loadAlignment); - output.shouldContain(expectedErrorMsg); + try { + output.shouldContain(expectedErrorMsg); + } catch (RuntimeException e) { + output.shouldContain("Unable to use shared archive"); + } output.shouldHaveExitValue(1); } } diff --git a/hotspot/test/runtime/SharedArchiveFile/CdsWriteError.java b/hotspot/test/runtime/SharedArchiveFile/CdsWriteError.java index 05e469452ec..162f3ad4722 100644 --- a/hotspot/test/runtime/SharedArchiveFile/CdsWriteError.java +++ b/hotspot/test/runtime/SharedArchiveFile/CdsWriteError.java @@ -22,7 +22,6 @@ */ /* - * @ignore 8032222 * @test CdsWriteError * @summary Test how VM handles situation when it is impossible to write the * CDS archive. VM is expected to exit gracefully and display the @@ -46,6 +45,12 @@ public class CdsWriteError { return; } + // This test has been unstable for Mac OSx (see JDK-8032222) + if (Platform.isOSX()) { + System.out.println("This test is skipped on Mac"); + return; + } + String folderName = "tmp"; String fileName = folderName + File.separator + "empty.jsa"; diff --git a/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java b/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java index 5883fab7ecc..52cae81cc4f 100644 --- a/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java +++ b/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java @@ -22,7 +22,6 @@ */ /* - * @ignore 8032224 * @test DefaultUseWithClient * @summary Test default behavior of sharing with -client * @library /testlibrary @@ -57,10 +56,17 @@ public class DefaultUseWithClient { "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./" + fileName, "-client", + "-XX:+PrintSharedSpaces", "-version"); output = new OutputAnalyzer(pb.start()); - output.shouldContain("sharing"); + try { + output.shouldContain("sharing"); + } catch (RuntimeException e) { + // if sharing failed due to ASLR or similar reasons, + // check whether sharing was attempted at all (UseSharedSpaces) + output.shouldContain("UseSharedSpaces:"); + } output.shouldHaveExitValue(0); } } diff --git a/hotspot/test/serviceability/jvmti/8036666/GetObjectLockCount.java b/hotspot/test/serviceability/jvmti/8036666/GetObjectLockCount.java new file mode 100644 index 00000000000..47e4104bd3d --- /dev/null +++ b/hotspot/test/serviceability/jvmti/8036666/GetObjectLockCount.java @@ -0,0 +1,284 @@ +/* + * Copyright 2014 SAP AG. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.Bootstrap; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.Location; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.StackFrame; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.Connector.Argument; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.connect.LaunchingConnector; +import com.sun.jdi.connect.VMStartException; +import com.sun.jdi.event.BreakpointEvent; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventQueue; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.VMDeathEvent; +import com.sun.jdi.event.VMDisconnectEvent; +import com.sun.jdi.event.VMStartEvent; +import com.sun.jdi.request.BreakpointRequest; +import com.sun.jdi.request.ClassPrepareRequest; +import com.sun.jdi.request.EventRequestManager; + + +/* + * @test GetObjectLockCount.java + * @bug 8036666 + * @key regression + * @summary verify jvm returns correct lock recursion count + * @run compile -g RecursiveObjectLock.java + * @run main/othervm GetObjectLockCount + * @author axel.siebenborn@sap.com + */ + +public class GetObjectLockCount { + + public static final String CLASS_NAME = "RecursiveObjectLock"; + public static final String METHOD_NAME = "breakpoint1"; + public static final String ARGUMENTS = ""; + + + /** + * Find a com.sun.jdi.CommandLineLaunch connector + */ + static LaunchingConnector findLaunchingConnector() { + List connectors = Bootstrap.virtualMachineManager().allConnectors(); + Iterator iter = connectors.iterator(); + while (iter.hasNext()) { + Connector connector = iter.next(); + if (connector.name().equals("com.sun.jdi.CommandLineLaunch")) { + return (LaunchingConnector)connector; + } + } + throw new Error("No launching connector"); + } + + static VirtualMachine launchTarget(String mainArgs) { + LaunchingConnector connector = findLaunchingConnector(); + Map arguments = connectorArguments(connector, mainArgs); + try { + return (VirtualMachine) 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()); + } + } + /** + * Return the launching connector's arguments. + */ + static 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); + + Connector.Argument optionsArg = (Connector.Argument)arguments.get("options"); + if (optionsArg == null) { + throw new Error("Bad launching connector"); + } + optionsArg.setValue(ARGUMENTS); + return arguments; + } + + private static void addClassWatch(VirtualMachine vm) { + EventRequestManager erm = vm.eventRequestManager(); + ClassPrepareRequest classPrepareRequest = erm + .createClassPrepareRequest(); + classPrepareRequest.addClassFilter(CLASS_NAME); + classPrepareRequest.setEnabled(true); + } + + private static void addBreakpoint(VirtualMachine vm, ReferenceType refType) { + Location breakpointLocation = null; + List locs; + try { + locs = refType.allLineLocations(); + for (Location loc: locs) { + if (loc.method().name().equals(METHOD_NAME)) { + breakpointLocation = loc; + break; + } + } + } catch (AbsentInformationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (breakpointLocation != null) { + EventRequestManager evtReqMgr = vm.eventRequestManager(); + BreakpointRequest bReq = evtReqMgr.createBreakpointRequest(breakpointLocation); + bReq.setSuspendPolicy(BreakpointRequest.SUSPEND_ALL); + bReq.enable(); + } + } + + /** + * @param args + * @throws InterruptedException + */ + public static void main(String[] args) throws InterruptedException { + + VirtualMachine vm = launchTarget(CLASS_NAME); + + // process events + EventQueue eventQueue = vm.eventQueue(); + // resume the vm + boolean launched = false; + + while (!launched) { + EventSet eventSet = eventQueue.remove(); + for (Event event : eventSet) { + if (event instanceof VMStartEvent) { + System.out.println("Vm launched"); + // set watch field on already loaded classes + List referenceTypes = vm.classesByName(CLASS_NAME); + for (ReferenceType refType : referenceTypes) { + System.out.println("Found Class"); + addBreakpoint(vm, refType); + } + + // watch for loaded classes + addClassWatch(vm); + vm.resume(); + launched = true; + } + } + } + + Process process = vm.process(); + + // Copy target's output and error to our output and error. + Thread outThread = new StreamRedirectThread("out reader", process.getInputStream()); + Thread errThread = new StreamRedirectThread("error reader", process.getErrorStream()); + + int recursionCount = -1; + + errThread.start(); + outThread.start(); + boolean connected = true; + while (connected) { + EventSet eventSet = eventQueue.remove(); + for (Event event : eventSet) { + if (event instanceof VMDeathEvent || event instanceof VMDisconnectEvent) { + // exit + connected = false; + } + else if (event instanceof ClassPrepareEvent) { + // watch field on loaded class + System.out.println("ClassPrepareEvent"); + ClassPrepareEvent classPrepEvent = (ClassPrepareEvent) event; + ReferenceType refType = classPrepEvent.referenceType(); + addBreakpoint(vm, refType); + } else if (event instanceof BreakpointEvent) { + recursionCount = getLockRecursions(vm); + System.out.println("resume..."); + } + } + eventSet.resume(); + } + // Shutdown begins when event thread terminates + try { + errThread.join(); // Make sure output is forwarded + outThread.join(); + } catch (InterruptedException e) { + // we don't interrupt + e.printStackTrace(); + } + if (recursionCount != 3) { + throw new AssertionError("recursions: expected 3, but was " + recursionCount); + } + } + + public static int getLockRecursions(VirtualMachine vm) { + List threads = vm.allThreads(); + for (ThreadReference thread : threads) { + if (thread.name().equals("main")) { + + System.out.println("Found main thread."); + try{ + StackFrame frame = thread.frame(3); + return frame.thisObject().entryCount(); + } catch (Exception e) { + e.printStackTrace(); + } + } + System.out.println("Main thread not found!"); + } + return -1; + } +} + +class StreamRedirectThread extends Thread { + + private final BufferedReader in; + + private static final int BUFFER_SIZE = 2048; + + /** + * Set up for copy. + * @param name Name of the thread + * @param in Stream to copy from + */ + StreamRedirectThread(String name, InputStream in) { + super(name); + this.in = new BufferedReader(new InputStreamReader(in)); + } + + /** + * Copy. + */ + public void run() { + try { + String line; + while ((line = in.readLine ()) != null) { + System.out.println("testvm: " + line); + } + System.out.flush(); + } catch(IOException exc) { + System.err.println("Child I/O Transfer - " + exc); + exc.printStackTrace(); + } + } +} diff --git a/hotspot/test/serviceability/jvmti/8036666/RecursiveObjectLock.java b/hotspot/test/serviceability/jvmti/8036666/RecursiveObjectLock.java new file mode 100644 index 00000000000..d1a35edd6c3 --- /dev/null +++ b/hotspot/test/serviceability/jvmti/8036666/RecursiveObjectLock.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 SAP AG. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class RecursiveObjectLock { + + public void testMethod() { + synchronized (this) { + nestedLock1(); + } + } + + public void nestedLock1() { + synchronized (this) { + nestedLock2(); + } + } + + public void nestedLock2() { + synchronized (this) { + callWait(); + } + } + + public void callWait(){ + try { + this.wait(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + breakpoint1(); + } + + public static void breakpoint1() { + // purpose: hold a breakpoint + } + + public static void main(String[] args) { + RecursiveObjectLock ro = new RecursiveObjectLock(); + ro.testMethod(); + System.out.println("ready"); + } + +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java index e92e26dd4b5..176e883546b 100644 --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java @@ -378,6 +378,64 @@ public class Asserts { } } + /** + * Asserts that two strings are equal. + * + * If strings are not equals, then exception message + * will contain {@code msg} followed by list of mismatched lines. + * + * @param str1 First string to compare. + * @param str2 Second string to compare. + * @param msg A description of the assumption. + * @throws RuntimeException if strings are not equal. + */ + public static void assertStringsEqual(String str1, String str2, + String msg) { + String lineSeparator = System.getProperty("line.separator"); + String str1Lines[] = str1.split(lineSeparator); + String str2Lines[] = str2.split(lineSeparator); + + int minLength = Math.min(str1Lines.length, str2Lines.length); + String longestStringLines[] = ((str1Lines.length == minLength) ? + str2Lines : str1Lines); + + boolean stringsAreDifferent = false; + + StringBuilder messageBuilder = new StringBuilder(msg); + + messageBuilder.append("\n"); + + for (int line = 0; line < minLength; line++) { + if (!str1Lines[line].equals(str2Lines[line])) { + messageBuilder.append(String. + format("[line %d] '%s' differs " + + "from '%s'\n", + line, + str1Lines[line], + str2Lines[line])); + stringsAreDifferent = true; + } + } + + if (minLength < longestStringLines.length) { + String stringName = ((longestStringLines == str1Lines) ? + "first" : "second"); + messageBuilder.append(String.format("Only %s string contains " + + "following lines:\n", + stringName)); + stringsAreDifferent = true; + for(int line = minLength; line < longestStringLines.length; line++) { + messageBuilder.append(String. + format("[line %d] '%s'", line, + longestStringLines[line])); + } + } + + if (stringsAreDifferent) { + error(messageBuilder.toString()); + } + } + private static > int compare(T lhs, T rhs, String msg) { assertNotNull(lhs, msg); assertNotNull(rhs, msg); diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/DynamicVMOptionChecker.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/DynamicVMOptionChecker.java new file mode 100644 index 00000000000..baa717d46aa --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/DynamicVMOptionChecker.java @@ -0,0 +1,121 @@ +/* + * 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 com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import java.lang.management.ManagementFactory; + +/** + * Simple class to check writeability, invalid and valid values for VMOption + */ +public class DynamicVMOptionChecker { + + /** + * Reads VM option from PlatformMXBean and parse it to integer value + * + * @param name of option + * @return parsed value + */ + public static int getIntValue(String name) { + + VMOption option = ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + getVMOption(name); + + return Integer.parseInt(option.getValue()); + } + + /** + * Sets VM option value + * + * @param name of option + * @param value to set + */ + public static void setIntValue(String name, int value) { + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class).setVMOption(name, Integer.toString(value)); + } + + /** + * Checks that VM option is dynamically writable + * + * @param name + * @throws RuntimeException if option if not writable + * @return always true + */ + public static boolean checkIsWritable(String name) { + VMOption option = ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + getVMOption(name); + + if (!option.isWriteable()) { + throw new RuntimeException(name + " is not writable"); + } + + return true; + } + + /** + * Checks that value cannot be set + * + * @param name of flag + * @param value string representation of value to set + * @throws RuntimeException on error - when expected exception hasn't been thrown + */ + public static void checkInvalidValue(String name, String value) { + // should throw + try { + ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + setVMOption(name, value); + + } catch (IllegalArgumentException e) { + return; + } + + throw new RuntimeException("Expected IllegalArgumentException was not thrown, " + name + "= " + value); + } + + /** + * Checks that value can be set + * + * @param name of flag to set + * @param value string representation of value to set + * @throws RuntimeException on error - when value in VM is not equal to origin + */ + public static void checkValidValue(String name, String value) { + ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + setVMOption(name, value); + + VMOption option = ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + getVMOption(name); + + if (!option.getValue().equals(value)) { + throw new RuntimeException("Actual value of " + name + " \"" + option.getValue() + + "\" not equal origin \"" + value + "\""); + } + } + +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ExitCode.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ExitCode.java new file mode 100644 index 00000000000..2db3be2d26d --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ExitCode.java @@ -0,0 +1,40 @@ +/* + * 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; + +/** + * Exit code values that could be returned by the JVM. + */ +public enum ExitCode { + OK(0), + FAIL(1), + CRASH(134); + + public final int value; + + ExitCode(int value) { + this.value = value; + } +} + diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/TestDynamicVMOption.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/TestDynamicVMOption.java new file mode 100644 index 00000000000..2c164596924 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/TestDynamicVMOption.java @@ -0,0 +1,104 @@ +/* + * 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; + +/** + * Simple class to check writeability, invalid and valid values for concrete VMOption + */ +public class TestDynamicVMOption { + + private final String name; + private final int value; + + /** + * Constructor + * + * @param name of VM option to test + */ + public TestDynamicVMOption(String name) { + this.name = name; + this.value = DynamicVMOptionChecker.getIntValue(name); + System.out.println(this.name + " = " + this.value); + } + + /** + * Checks that this value can accept valid percentage values and cannot accept invalid percentage values + * + * @throws RuntimeException + */ + public void testPercentageValues() { + checkInvalidValue(Integer.toString(Integer.MIN_VALUE)); + checkInvalidValue(Integer.toString(Integer.MAX_VALUE)); + checkInvalidValue("-10"); + checkInvalidValue("190"); + } + + /** + * Reads VM option from PlatformMXBean and parse it to integer value + * + * @return value + */ + public int getIntValue() { + return DynamicVMOptionChecker.getIntValue(this.name); + } + + /** + * Sets VM option value + * + * @param value to set + */ + public void setIntValue(int value) { + DynamicVMOptionChecker.setIntValue(this.name, value); + } + + /** + * Checks that this VM option is dynamically writable + * + * @throws RuntimeException if option if not writable + * @return true + */ + public boolean checkIsWritable() throws RuntimeException { + return DynamicVMOptionChecker.checkIsWritable(this.name); + } + + /** + * Checks that value for this VM option cannot be set + * + * @param value to check + * @throws RuntimeException on error - when expected exception hasn't been thrown + */ + public void checkInvalidValue(String value) { + DynamicVMOptionChecker.checkInvalidValue(this.name, value); + } + + /** + * Checks that value for this VM option can be set + * + * @param value to check + * @throws RuntimeException on error - when value in VM is not equal to origin + */ + public void checkValidValue(String value) { + DynamicVMOptionChecker.checkValidValue(this.name, value); + } + +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java index a0031e706ec..03fd773e0a3 100644 --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.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 @@ -107,6 +107,40 @@ public final class Utils { return opts.toArray(new String[0]); } + /** + * Returns the default JTReg arguments for a jvm running a test without + * options that matches regular expresions in {@code filters}. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts. + * @param filters Regular expressions used to filter out options. + * @return An array of options, or an empty array if no opptions. + */ + public static String[] getFilteredTestJavaOpts(String... filters) { + String options[] = getTestJavaOpts(); + + if (filters.length == 0) { + return options; + } + + List filteredOptions = new ArrayList(options.length); + Pattern patterns[] = new Pattern[filters.length]; + for (int i = 0; i < filters.length; i++) { + patterns[i] = Pattern.compile(filters[i]); + } + + for (String option : options) { + boolean matched = false; + for (int i = 0; i < patterns.length && !matched; i++) { + Matcher matcher = patterns[i].matcher(option); + matched = matcher.find(); + } + if (!matched) { + filteredOptions.add(option); + } + } + + return filteredOptions.toArray(new String[filteredOptions.size()]); + } + /** * Combines given arguments with default JTReg arguments for a jvm running a test. * This is the combination of JTReg arguments test.vm.opts and test.java.opts diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CPUSpecificCommandLineOptionTest.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CPUSpecificCommandLineOptionTest.java new file mode 100644 index 00000000000..a300e038d29 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CPUSpecificCommandLineOptionTest.java @@ -0,0 +1,110 @@ +/* + * 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.cli; + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; + +/** + * Base class for command line options tests that + * requires specific CPU arch or specific CPU features. + */ +public abstract class CPUSpecificCommandLineOptionTest + extends CommandLineOptionTest { + + private String cpuArchPattern; + private String supportedCPUFeatures[]; + private String unsupportedCPUFeatures[]; + + /** + * Create new CPU specific test instance that does not + * require any CPU features. + * + * @param cpuArchPattern Regular expression that should + * match os.arch. + */ + public CPUSpecificCommandLineOptionTest(String cpuArchPattern) { + this(cpuArchPattern, null, null); + } + + /** + * Create new CPU specific test instance that does not + * require from CPU support of {@code supportedCPUFeatures} features + * and no support of {@code unsupportedCPUFeatures}. + * + * @param cpuArchPattern Regular expression that should + * match os.arch. + * @param supportedCPUFeatures Array with names of features that + * should be supported by CPU. If null, + * then no features have to be supported. + * @param unsupportedCPUFeatures Array with names of features that + * should not be supported by CPU. + * If null, then CPU may support any + * features. + */ + public CPUSpecificCommandLineOptionTest(String cpuArchPattern, + String supportedCPUFeatures[], + String unsupportedCPUFeatures[]) { + this.cpuArchPattern = cpuArchPattern; + this.supportedCPUFeatures = supportedCPUFeatures; + this.unsupportedCPUFeatures = unsupportedCPUFeatures; + } + + /** + * Check that CPU on test box has appropriate architecture, support all + * required features and does not support all features that should not be + * supported. + * + * @return true if CPU on test box fulfill all requirements. + */ + @Override + public boolean checkPreconditions() { + if (!Platform.getOsArch().matches(cpuArchPattern)) { + System.out.println("CPU arch does not match " + cpuArchPattern); + return false; + } + + if (supportedCPUFeatures != null) { + for (String feature : supportedCPUFeatures) { + if (!CPUInfo.hasFeature(feature)) { + System.out.println("CPU does not support " + feature + + " feature"); + return false; + } + } + } + + if (unsupportedCPUFeatures != null) { + for (String feature : unsupportedCPUFeatures) { + if (CPUInfo.hasFeature(feature)) { + System.out.println("CPU support " + feature + " feature"); + return false; + } + } + } + + return true; + } +} + diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CommandLineOptionTest.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CommandLineOptionTest.java new file mode 100644 index 00000000000..d4d4e7c743a --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CommandLineOptionTest.java @@ -0,0 +1,173 @@ +/* + * 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.cli; + +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + +import com.oracle.java.testlibrary.*; + +/** + * Base class for command line option tests. + */ +public abstract class CommandLineOptionTest { + + public static final String UNRECOGNIZED_OPTION_ERROR_FORMAT = + "Unrecognized VM option '[+-]?%s'"; + + public static final String printFlagsFinalFormat = "%s\\s*:?=\\s*%s"; + + /** + * Verify that JVM startup behaviour matches our expectations. + * + * @param option The option that should be passed to JVM + * @param excpectedMessages Array of patterns that should occur + * in JVM output. If null then + * JVM output could be empty. + * @param unexpectedMessages Array of patterns that should not + * occur in JVM output. If null then + * JVM output could be empty. + * @param exitCode expected exit code. + * @throws Throwable if verification fails or some other issues occur. + */ + public static void verifyJVMStartup(String option, + String expectedMessages[], + String unexpectedMessages[], + ExitCode exitCode) + throws Throwable { + + OutputAnalyzer outputAnalyzer = + ProcessTools.executeTestJvm(option, "-version"); + + outputAnalyzer.shouldHaveExitValue(exitCode.value); + + if (expectedMessages != null) { + for (String expectedMessage : expectedMessages) { + outputAnalyzer.shouldMatch(expectedMessage); + } + } + + if (unexpectedMessages != null) { + for (String unexpectedMessage : unexpectedMessages) { + outputAnalyzer.shouldNotMatch(unexpectedMessage); + } + } + } + + /** + * Verify that value of specified JVM option is the same as + * expected value. + * This method filter out option with {@code optionName} + * name from test java options. + * + * @param optionName Name of tested option. + * @param expectedValue Expected value of tested option. + * @param additionalVMOpts Additonal options that should be + * passed to JVM. + * @throws Throwable if verification fails or some other issues occur. + */ + public static void verifyOptionValue(String optionName, + String expectedValue, + String... additionalVMOpts) + throws Throwable { + verifyOptionValue(optionName, expectedValue, true, additionalVMOpts); + } + + /** + * Verify that value of specified JVM option is the same as + * expected value. + * This method filter out option with {@code optionName} + * name from test java options. + * + * @param optionName Name of tested option. + * @param expectedValue Expected value of tested option. + * @param addTestVmOptions If true, then test VM options + * will be used. + * @param additionalVMOpts Additonal options that should be + * passed to JVM. + * @throws Throwable if verification fails or some other issues occur. + */ + public static void verifyOptionValue(String optionName, + String expectedValue, + boolean addTestVmOptions, + String... additionalVMOpts) + throws Throwable { + + List vmOpts = new ArrayList(); + + if (addTestVmOptions) { + Collections.addAll(vmOpts, + Utils.getFilteredTestJavaOpts(optionName)); + } + Collections.addAll(vmOpts, additionalVMOpts); + Collections.addAll(vmOpts, new String[] { + "-XX:+PrintFlagsFinal", + "-version" + }); + + ProcessBuilder processBuilder = + ProcessTools. + createJavaProcessBuilder(vmOpts. + toArray(new String[vmOpts.size()])); + + OutputAnalyzer outputAnalyzer = + new OutputAnalyzer(processBuilder.start()); + + outputAnalyzer.shouldHaveExitValue(0); + outputAnalyzer.shouldMatch(String. + format(printFlagsFinalFormat, + optionName, + expectedValue)); + } + + + /** + * Run command line option test. + * + * @throws Throwable if test failed. + */ + public final void test() throws Throwable { + if (checkPreconditions()) { + runTestCases(); + } + } + + /** + * Check that all preconditions for test execution are met. + * + * @return true if test could be executed. + */ + public boolean checkPreconditions() { + return true; + } + + /** + * Run test cases. + * + * @throws Throwable if test failed. + */ + public abstract void runTestCases() throws Throwable; +} + diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java index da1244ce093..e35260c6d2f 100644 --- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.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 @@ -135,6 +135,7 @@ public class WhiteBox { public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci); public native void clearMethodState(Executable method); public native int getMethodEntryBci(Executable method); + public native Object[] getNMethod(Executable method, boolean isOsr); // Intered strings public native boolean isInStringTable(String str); @@ -150,4 +151,7 @@ public class WhiteBox { public native void runMemoryUnitTests(); public native void readFromNoaccessArea(); + // CPU features + public native String getCPUFeatures(); + } diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java new file mode 100644 index 00000000000..4bdb49d0b3e --- /dev/null +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java @@ -0,0 +1,51 @@ +/* + * 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 sun.hotspot.code; + +import java.lang.reflect.Executable; +import sun.hotspot.WhiteBox; + +public class NMethod { + private static final WhiteBox wb = WhiteBox.getWhiteBox(); + public static NMethod get(Executable method, boolean isOsr) { + Object[] obj = wb.getNMethod(method, isOsr); + return obj == null ? null : new NMethod(obj); + } + private NMethod(Object[] obj) { + assert obj.length == 2; + comp_level = (Integer) obj[0]; + insts = (byte[]) obj[1]; + } + public byte[] insts; + public int comp_level; + + @Override + public String toString() { + return "NMethod{" + + "insts=" + insts + + ", comp_level=" + comp_level + + '}'; + } +} diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/cpuinfo/CPUInfo.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/cpuinfo/CPUInfo.java new file mode 100644 index 00000000000..8532573a94c --- /dev/null +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/cpuinfo/CPUInfo.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. + * + */ + +package sun.hotspot.cpuinfo; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import sun.hotspot.WhiteBox; + +/** + * Information about CPU on test box. + * + * CPUInfo uses WhiteBox to gather information, + * so WhiteBox class should be added to bootclasspath + * and option -XX:+WhiteBoxAPI should expclicetly + * specified on command line. + */ +public class CPUInfo { + + private static final List features; + private static final String additionalCPUInfo; + + static { + WhiteBox wb = WhiteBox.getWhiteBox(); + + Pattern additionalCPUInfoRE = + Pattern.compile("([^(]*\\([^)]*\\)[^,]*),\\s*"); + + String cpuFeaturesString = wb.getCPUFeatures(); + Matcher matcher = additionalCPUInfoRE.matcher(cpuFeaturesString); + if (matcher.find()) { + additionalCPUInfo = matcher.group(1); + } else { + additionalCPUInfo = ""; + } + String splittedFeatures[] = matcher.replaceAll("").split("(, )| "); + + features = Collections.unmodifiableList(Arrays. + asList(splittedFeatures)); + } + + /** + * Get additional information about CPU. + * For example, on X86 in will be family/model/stepping + * and number of cores. + * + * @return additional CPU info + */ + public static String getAdditionalCPUInfo() { + return additionalCPUInfo; + } + + /** + * Get all known features supported by CPU. + * + * @return unmodifiable list with names of all known features + * supported by CPU. + */ + public static List getFeatures() { + return features; + } + + /** + * Check if some feature is supported by CPU. + * + * @param feature Name of feature to be tested. + * @return true if tested feature is supported by CPU. + */ + public static boolean hasFeature(String feature) { + return features.contains(feature.toLowerCase()); + } +} diff --git a/jaxp/.hgtags b/jaxp/.hgtags index ee71c38a814..e7dc2ecc96a 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -249,3 +249,4 @@ fb92ed0399424193f444489ad49a16748816dc12 jdk9-b03 2846d8fc31490897817a122a668af4f44fc913d0 jdk9-b04 b92a20e303d24c74078888cd7084b14d7626d48f jdk9-b05 46e4951b2a267e98341613a3b796f2c7554eb831 jdk9-b06 +389f4094fd603c17e215997b0b40171179629007 jdk9-b07 diff --git a/jaxp/src/com/sun/org/apache/xerces/internal/dom/DOMStringListImpl.java b/jaxp/src/com/sun/org/apache/xerces/internal/dom/DOMStringListImpl.java index c5ce5ec2615..835a66fe1c4 100644 --- a/jaxp/src/com/sun/org/apache/xerces/internal/dom/DOMStringListImpl.java +++ b/jaxp/src/com/sun/org/apache/xerces/internal/dom/DOMStringListImpl.java @@ -3,11 +3,12 @@ * 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 * @@ -20,6 +21,7 @@ package com.sun.org.apache.xerces.internal.dom; +import java.util.ArrayList; import java.util.Vector; import org.w3c.dom.DOMStringList; @@ -35,47 +37,54 @@ import org.w3c.dom.DOMStringList; */ public class DOMStringListImpl implements DOMStringList { - //A collection of DOMString values - private Vector fStrings; + // A collection of DOMString values + private final ArrayList fStrings; /** * Construct an empty list of DOMStringListImpl */ public DOMStringListImpl() { - fStrings = new Vector(); + fStrings = new ArrayList(); } /** - * Construct an empty list of DOMStringListImpl + * Construct a DOMStringListImpl from an ArrayList */ - public DOMStringListImpl(Vector params) { + public DOMStringListImpl(ArrayList params) { fStrings = params; } - /** - * @see org.w3c.dom.DOMStringList#item(int) - */ - public String item(int index) { - try { - return (String) fStrings.elementAt(index); - } catch (ArrayIndexOutOfBoundsException e) { - return null; - } - } + /** + * Construct a DOMStringListImpl from a Vector + */ + public DOMStringListImpl(Vector params) { + fStrings = new ArrayList(params); + } - /** - * @see org.w3c.dom.DOMStringList#getLength() - */ - public int getLength() { - return fStrings.size(); + /** + * @see org.w3c.dom.DOMStringList#item(int) + */ + public String item(int index) { + final int length = getLength(); + if (index >= 0 && index < length) { + return (String) fStrings.get(index); } + return null; + } - /** - * @see org.w3c.dom.DOMStringList#contains(String) - */ - public boolean contains(String param) { - return fStrings.contains(param) ; - } + /** + * @see org.w3c.dom.DOMStringList#getLength() + */ + public int getLength() { + return fStrings.size(); + } + + /** + * @see org.w3c.dom.DOMStringList#contains(String) + */ + public boolean contains(String param) { + return fStrings.contains(param); + } /** * DOM Internal: diff --git a/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java index 09a82608c14..988fd6f9c60 100644 --- a/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java +++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java @@ -1,13 +1,14 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 * @@ -52,7 +53,7 @@ import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Stack; -import javax.xml.XMLConstants; +import java.util.StringTokenizer; /** @@ -1810,7 +1811,7 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { userDir = userDir.replace(separator, '/'); int len = userDir.length(), ch; - StringBuffer buffer = new StringBuffer(len*3); + StringBuilder buffer = new StringBuilder(len*3); // change C:/blah to /C:/blah if (len >= 2 && userDir.charAt(1) == ':') { ch = Character.toUpperCase(userDir.charAt(0)); @@ -1880,6 +1881,61 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { return gUserDirURI; } + public static OutputStream createOutputStream(String uri) throws IOException { + // URI was specified. Handle relative URIs. + final String expanded = XMLEntityManager.expandSystemId(uri, null, true); + final URL url = new URL(expanded != null ? expanded : uri); + OutputStream out = null; + String protocol = url.getProtocol(); + String host = url.getHost(); + // Use FileOutputStream if this URI is for a local file. + if (protocol.equals("file") + && (host == null || host.length() == 0 || host.equals("localhost"))) { + File file = new File(getPathWithoutEscapes(url.getPath())); + if (!file.exists()) { + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + parent.mkdirs(); + } + } + out = new FileOutputStream(file); + } + // Try to write to some other kind of URI. Some protocols + // won't support this, though HTTP should work. + else { + URLConnection urlCon = url.openConnection(); + urlCon.setDoInput(false); + urlCon.setDoOutput(true); + urlCon.setUseCaches(false); // Enable tunneling. + if (urlCon instanceof HttpURLConnection) { + // The DOM L3 REC says if we are writing to an HTTP URI + // it is to be done with an HTTP PUT. + HttpURLConnection httpCon = (HttpURLConnection) urlCon; + httpCon.setRequestMethod("PUT"); + } + out = urlCon.getOutputStream(); + } + return out; + } + + private static String getPathWithoutEscapes(String origPath) { + if (origPath != null && origPath.length() != 0 && origPath.indexOf('%') != -1) { + // Locate the escape characters + StringTokenizer tokenizer = new StringTokenizer(origPath, "%"); + StringBuilder result = new StringBuilder(origPath.length()); + int size = tokenizer.countTokens(); + result.append(tokenizer.nextToken()); + for(int i = 1; i < size; ++i) { + String token = tokenizer.nextToken(); + // Decode the 2 digit hexadecimal number following % in '%nn' + result.append((char)Integer.valueOf(token.substring(0, 2), 16).intValue()); + result.append(token.substring(2)); + } + return result.toString(); + } + return origPath; + } + /** * Absolutizes a URI using the current value * of the "user.dir" property as the base URI. If diff --git a/jaxp/src/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java b/jaxp/src/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java index 3a7ac70385b..192be06a35c 100644 --- a/jaxp/src/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java +++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2002,2004,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 * @@ -351,7 +352,7 @@ final class RangeToken extends Token implements java.io.Serializable { // src2: o----o // src2: o----o // src2: o------------o - if (src2begin <= src2begin && src1end <= src2end) { + if (src2begin <= src1begin && src1end <= src2end) { // src1: o--------o // src2: o------------o // res: o--------o @@ -384,6 +385,7 @@ final class RangeToken extends Token implements java.io.Serializable { result[wp++] = src2begin; result[wp++] = src2end; this.ranges[src1] = src2end+1; + src2 += 2; } } else if (src2end < src1begin) { // Not overlapped @@ -399,10 +401,6 @@ final class RangeToken extends Token implements java.io.Serializable { +"]"); } } - while (src1 < this.ranges.length) { - result[wp++] = this.ranges[src1++]; - result[wp++] = this.ranges[src1++]; - } this.ranges = new int[wp]; System.arraycopy(result, 0, this.ranges, 0, wp); // this.ranges is sorted and compacted. @@ -464,8 +462,8 @@ final class RangeToken extends Token implements java.io.Serializable { if (ch > 0xffff) lowers.addRange(ch, ch); else { - char uch = Character.toUpperCase((char)ch); - lowers.addRange(uch, uch); + char lch = Character.toLowerCase((char)ch); + lowers.addRange(lch, lch); } } } @@ -479,8 +477,10 @@ final class RangeToken extends Token implements java.io.Serializable { void dumpRanges() { System.err.print("RANGE: "); - if (this.ranges == null) + if (this.ranges == null) { System.err.println(" NULL"); + return; + } for (int i = 0; i < this.ranges.length; i += 2) { System.err.print("["+this.ranges[i]+","+this.ranges[i+1]+"] "); } @@ -552,10 +552,10 @@ final class RangeToken extends Token implements java.io.Serializable { else if (this == Token.token_spaces) ret = "\\s"; else { - StringBuffer sb = new StringBuffer(); - sb.append("["); + StringBuilder sb = new StringBuilder(); + sb.append('['); for (int i = 0; i < this.ranges.length; i += 2) { - if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(","); + if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(','); if (this.ranges[i] == this.ranges[i+1]) { sb.append(escapeCharInCharClass(this.ranges[i])); } else { @@ -564,7 +564,7 @@ final class RangeToken extends Token implements java.io.Serializable { sb.append(escapeCharInCharClass(this.ranges[i+1])); } } - sb.append("]"); + sb.append(']'); ret = sb.toString(); } } else { @@ -578,7 +578,7 @@ final class RangeToken extends Token implements java.io.Serializable { StringBuffer sb = new StringBuffer(); sb.append("[^"); for (int i = 0; i < this.ranges.length; i += 2) { - if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(","); + if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(','); if (this.ranges[i] == this.ranges[i+1]) { sb.append(escapeCharInCharClass(this.ranges[i])); } else { @@ -587,7 +587,7 @@ final class RangeToken extends Token implements java.io.Serializable { sb.append(escapeCharInCharClass(this.ranges[i+1])); } } - sb.append("]"); + sb.append(']'); ret = sb.toString(); } } diff --git a/jaxp/src/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java b/jaxp/src/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java index 9bbdaec2fe9..3150b10d860 100644 --- a/jaxp/src/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java +++ b/jaxp/src/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2002,2004,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 * @@ -18,7 +19,6 @@ * limitations under the License. */ - // Sep 14, 2000: // Fixed comments to preserve whitespaces and add a line break // when indenting. Reported by Gervase Markham @@ -57,17 +57,13 @@ import com.sun.org.apache.xerces.internal.dom.DOMErrorImpl; import com.sun.org.apache.xerces.internal.dom.DOMLocatorImpl; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; import com.sun.org.apache.xerces.internal.util.XMLChar; -import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.DocumentType; -import org.w3c.dom.DOMError; -import org.w3c.dom.DOMErrorHandler; import org.w3c.dom.Element; -import org.w3c.dom.Entity; -import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import org.w3c.dom.Notation; import org.w3c.dom.ls.LSException; import org.w3c.dom.ls.LSSerializerFilter; import org.w3c.dom.traversal.NodeFilter; @@ -126,7 +122,7 @@ import org.xml.sax.ext.LexicalHandler; * @author Elena Litani, IBM * @author Sunitha Reddy, Sun Microsystems * @see Serializer - * @see LSSerializer + * @see org.w3c.dom.ls.LSSerializer */ public abstract class BaseMarkupSerializer implements ContentHandler, DocumentHandler, LexicalHandler, @@ -337,6 +333,9 @@ public abstract class BaseMarkupSerializer return true; } + protected void cleanup() { + fCurrentNode = null; + } protected void prepare() throws IOException @@ -409,6 +408,7 @@ public abstract class BaseMarkupSerializer reset(); prepare(); serializeNode( elem ); + cleanup(); _printer.flush(); if ( _printer.getException() != null ) throw _printer.getException(); @@ -438,7 +438,7 @@ public abstract class BaseMarkupSerializer * writer and output format. Throws an exception only if * an I/O exception occured while serializing. * - * @param elem The element to serialize + * @param frag The document fragment to serialize * @throws IOException An I/O exception occured while * serializing */ @@ -448,6 +448,7 @@ public abstract class BaseMarkupSerializer reset(); prepare(); serializeNode( frag ); + cleanup(); _printer.flush(); if ( _printer.getException() != null ) throw _printer.getException(); @@ -470,6 +471,7 @@ public abstract class BaseMarkupSerializer prepare(); serializeNode( doc ); serializePreRoot(); + cleanup(); _printer.flush(); if ( _printer.getException() != null ) throw _printer.getException(); @@ -530,22 +532,22 @@ public abstract class BaseMarkupSerializer if (!XMLChar.isValid(ch)) { // check if it is surrogate if (++index < end) { - surrogates(ch, chars[index]); + surrogates(ch, chars[index],true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; - } else { - if ( ( ch >= ' ' && _encodingInfo.isPrintable((char)ch) && ch != 0xF7 ) || - ch == '\n' || ch == '\r' || ch == '\t' ) { - _printer.printText((char)ch); - } else { - // The character is not printable -- split CDATA section - _printer.printText("]]>&#x"); - _printer.printText(Integer.toHexString(ch)); - _printer.printText(";= ' ' && _encodingInfo.isPrintable(ch) && ch != 0x7F ) || + ch == '\n' || ch == '\r' || ch == '\t' ) { + _printer.printText(ch); + } + else { + // The character is not printable -- split CDATA section + _printer.printText("]]>&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";empty and afterElement set to false. * * @return The current element state - * @throws IOException An I/O exception occured while + * @throws IOException An I/O exception occurred while * serializing */ protected ElementState content() @@ -1415,7 +1411,6 @@ public abstract class BaseMarkupSerializer * whether the text is printed as CDATA or unescaped. * * @param text The text to print - * @param unescaped True is should print unescaped * @throws IOException An I/O exception occured while * serializing */ @@ -1430,9 +1425,6 @@ public abstract class BaseMarkupSerializer // state) or whether we are inside a CDATA section or entity. if ( state.inCData || state.doCData ) { - int index; - int saveIndent; - // Print a CDATA section. The text is not escaped, but ']]>' // appearing in the code must be identified and dealt with. // The contents of a text node is considered space preserving. @@ -1440,7 +1432,7 @@ public abstract class BaseMarkupSerializer _printer.printText("= ' ' && _encodingInfo.isPrintable((char)ch) && ch != 0xF7 ) || - ch == '\n' || ch == '\r' || ch == '\t' ) { - _printer.printText((char)ch); - } else { + } + if ( ( ch >= ' ' && _encodingInfo.isPrintable(ch) && ch != 0x7F ) || + ch == '\n' || ch == '\r' || ch == '\t' ) { + _printer.printText(ch); + } + else { - // The character is not printable -- split CDATA section - _printer.printText("]]>&#x"); - _printer.printText(Integer.toHexString(ch)); - _printer.printText(";&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";&#x"); _printer.printText(Integer.toHexString(supplemental)); _printer.printText("; 0 ) { - ch = chars[ start ]; + char ch = chars[ start ]; ++start; - if ( ch == '\n' || ch == '\r' || unescaped ) + if ( ch == '\n' || ch == '\r' || unescaped ) { _printer.printText( ch ); - else + } + else { printEscaped( ch ); + } } } else { // Not preserving spaces: print one part at a time, and @@ -1664,14 +1656,17 @@ public abstract class BaseMarkupSerializer // by printing mechanism. Line terminator is treated // no different than other text part. while ( length-- > 0 ) { - ch = chars[ start ]; + char ch = chars[ start ]; ++start; - if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) + if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) { _printer.printSpace(); - else if ( unescaped ) + } + else if ( unescaped ) { _printer.printText( ch ); - else + } + else { printEscaped( ch ); + } } } } @@ -1703,12 +1698,15 @@ public abstract class BaseMarkupSerializer // no different than other text part. for ( index = 0 ; index < text.length() ; ++index ) { ch = text.charAt( index ); - if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) + if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) { _printer.printSpace(); - else if ( unescaped ) + } + else if ( unescaped ) { _printer.printText( ch ); - else + } + else { printEscaped( ch ); + } } } } @@ -1751,7 +1749,7 @@ public abstract class BaseMarkupSerializer _printer.printText( '&' ); _printer.printText( charRef ); _printer.printText( ';' ); - } else if ( ( ch >= ' ' && _encodingInfo.isPrintable((char)ch) && ch != 0xF7 ) || + } else if ( ( ch >= ' ' && _encodingInfo.isPrintable((char)ch) && ch != 0x7F ) || ch == '\n' || ch == '\r' || ch == '\t' ) { // Non printables are below ASCII space but not tab or line // terminator, ASCII delete, or above a certain Unicode threshold. @@ -1872,14 +1870,13 @@ public abstract class BaseMarkupSerializer { if ( _elementStateCount > 0 ) { /*Corrected by David Blondeau (blondeau@intalio.com)*/ - _prefixes = null; - //_prefixes = _elementStates[ _elementStateCount ].prefixes; + _prefixes = null; + //_prefixes = _elementStates[ _elementStateCount ].prefixes; -- _elementStateCount; return _elementStates[ _elementStateCount ]; - } else { - String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "Internal", null); - throw new IllegalStateException(msg); } + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "Internal", null); + throw new IllegalStateException(msg); } @@ -1890,11 +1887,14 @@ public abstract class BaseMarkupSerializer * * @return True if in the state of the document */ - protected boolean isDocumentState() - { + protected boolean isDocumentState() { return _elementStateCount == 0; } + /** Clears document state. **/ + final void clearDocumentState() { + _elementStateCount = 0; + } /** * Returns the namespace prefix for the specified URI. @@ -1913,15 +1913,14 @@ public abstract class BaseMarkupSerializer if ( prefix != null ) return prefix; } - if ( _elementStateCount == 0 ) + if ( _elementStateCount == 0 ) { return null; - else { - for ( int i = _elementStateCount ; i > 0 ; --i ) { - if ( _elementStates[ i ].prefixes != null ) { - prefix = (String) _elementStates[ i ].prefixes.get( namespaceURI ); - if ( prefix != null ) - return prefix; - } + } + for ( int i = _elementStateCount ; i > 0 ; --i ) { + if ( _elementStates[ i ].prefixes != null ) { + prefix = (String) _elementStates[ i ].prefixes.get( namespaceURI ); + if ( prefix != null ) + return prefix; } } return null; diff --git a/jaxp/src/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java b/jaxp/src/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java index fdced040897..c9b36c5b07a 100644 --- a/jaxp/src/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java +++ b/jaxp/src/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java @@ -3,11 +3,12 @@ * 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 * @@ -17,21 +18,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.sun.org.apache.xml.internal.serialize; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.lang.reflect.Method; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.util.StringTokenizer; -import java.util.Vector; +import java.util.ArrayList; import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl; import com.sun.org.apache.xerces.internal.dom.DOMErrorImpl; @@ -39,10 +34,6 @@ import com.sun.org.apache.xerces.internal.dom.DOMLocatorImpl; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; import com.sun.org.apache.xerces.internal.dom.DOMNormalizer; import com.sun.org.apache.xerces.internal.dom.DOMStringListImpl; -import org.w3c.dom.DOMConfiguration; -import org.w3c.dom.DOMError; -import org.w3c.dom.DOMErrorHandler; -import org.w3c.dom.DOMStringList; import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.impl.XMLEntityManager; import com.sun.org.apache.xerces.internal.util.DOMUtil; @@ -52,26 +43,30 @@ import com.sun.org.apache.xerces.internal.util.XML11Char; import com.sun.org.apache.xerces.internal.util.XMLChar; import org.w3c.dom.Attr; import org.w3c.dom.Comment; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; import org.w3c.dom.ls.LSException; import org.w3c.dom.ls.LSOutput; import org.w3c.dom.ls.LSSerializer; import org.w3c.dom.ls.LSSerializerFilter; - /** - * EXPERIMENTAL: Implemenatation of DOM Level 3 org.w3c.ls.LSSerializer by delegating serialization - * calls to XMLSerializer. - * LSSerializer provides an API for serializing (writing) a DOM document out in an - * XML document. The XML data is written to an output stream. - * During serialization of XML data, namespace fixup is done when possible as - * defined in DOM Level 3 Core, Appendix B. + * EXPERIMENTAL: Implemenatation of DOM Level 3 org.w3c.ls.LSSerializer by + * delegating serialization calls to XMLSerializer. LSSerializer + * provides an API for serializing (writing) a DOM document out in an XML + * document. The XML data is written to an output stream. During serialization + * of XML data, namespace fixup is done when possible as defined in DOM Level 3 + * Core, Appendix B. * * @author Elena Litani, IBM * @author Gopal Sharma, Sun Microsystems @@ -84,7 +79,6 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { // TODO: When DOM Level 3 goes to REC replace method calls using // reflection for: getXmlEncoding, getInputEncoding and getXmlEncoding // with regular static calls on the Document object. - // data // serializer private XMLSerializer serializer; @@ -95,35 +89,36 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { //Recognized parameters private DOMStringList fRecognizedParameters; - /** REVISIT: Currently we handle 3 different configurations, would be nice just have one configuration - * that has different recognized parameters depending if it is used in Core/LS. + /** + * REVISIT: Currently we handle 3 different configurations, would be nice + * just have one configuration that has different recognized parameters + * depending if it is used in Core/LS. */ protected short features = 0; - protected final static short NAMESPACES = 0x1<<0; - protected final static short WELLFORMED = 0x1<<1; - protected final static short ENTITIES = 0x1<<2; - protected final static short CDATA = 0x1<<3; - protected final static short SPLITCDATA = 0x1<<4; - protected final static short COMMENTS = 0x1<<5; - protected final static short DISCARDDEFAULT = 0x1<<6; - protected final static short INFOSET = 0x1<<7; - protected final static short XMLDECL = 0x1<<8; - protected final static short NSDECL = 0x1<<9; - protected final static short DOM_ELEMENT_CONTENT_WHITESPACE = 0x1<<10; - protected final static short FORMAT_PRETTY_PRINT = 0x1<<11; + protected final static short NAMESPACES = 0x1 << 0; + protected final static short WELLFORMED = 0x1 << 1; + protected final static short ENTITIES = 0x1 << 2; + protected final static short CDATA = 0x1 << 3; + protected final static short SPLITCDATA = 0x1 << 4; + protected final static short COMMENTS = 0x1 << 5; + protected final static short DISCARDDEFAULT = 0x1 << 6; + protected final static short INFOSET = 0x1 << 7; + protected final static short XMLDECL = 0x1 << 8; + protected final static short NSDECL = 0x1 << 9; + protected final static short DOM_ELEMENT_CONTENT_WHITESPACE = 0x1 << 10; + protected final static short PRETTY_PRINT = 0x1 << 11; // well-formness checking private DOMErrorHandler fErrorHandler = null; private final DOMErrorImpl fError = new DOMErrorImpl(); private final DOMLocatorImpl fLocator = new DOMLocatorImpl(); - private static final RuntimeException abort = new RuntimeException(); /** - * Constructs a new LSSerializer. - * The constructor turns on the namespace support in XMLSerializer and - * initializes the following fields: fNSBinder, fLocalNSBinder, fSymbolTable, - * fEmptySymbol, fXmlSymbol, fXmlnsSymbol, fNamespaceCounter, fFeatures. + * Constructs a new LSSerializer. The constructor turns on the namespace + * support in XMLSerializer and initializes the following + * fields: fNSBinder, fLocalNSBinder, fSymbolTable, fEmptySymbol, + * fXmlSymbol, fXmlnsSymbol, fNamespaceCounter, fFeatures. */ public DOMSerializerImpl() { // set default features @@ -142,24 +137,21 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { initSerializer(serializer); } - - // // LSSerializer methods // - - public DOMConfiguration getDomConfig(){ + public DOMConfiguration getDomConfig() { return this; } - /** DOM L3-EXPERIMENTAL: - * Setter for boolean and object parameters + /** + * DOM L3-EXPERIMENTAL: Setter for boolean and object parameters */ public void setParameter(String name, Object value) throws DOMException { if (value instanceof Boolean) { boolean state = ((Boolean) value).booleanValue(); - if (name.equalsIgnoreCase(Constants.DOM_INFOSET)){ - if (state){ + if (name.equalsIgnoreCase(Constants.DOM_INFOSET)) { + if (state) { features &= ~ENTITIES; features &= ~CDATA; features |= NAMESPACES; @@ -169,54 +161,50 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { } // false does not have any effect } else if (name.equalsIgnoreCase(Constants.DOM_XMLDECL)) { - features = - (short) (state ? features | XMLDECL : features & ~XMLDECL); + features + = (short) (state ? features | XMLDECL : features & ~XMLDECL); } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) { - features = - (short) (state + features + = (short) (state ? features | NAMESPACES : features & ~NAMESPACES); serializer.fNamespaces = state; } else if (name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA)) { - features = - (short) (state + features + = (short) (state ? features | SPLITCDATA : features & ~SPLITCDATA); } else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)) { - features = - (short) (state + features + = (short) (state ? features | DISCARDDEFAULT : features & ~DISCARDDEFAULT); } else if (name.equalsIgnoreCase(Constants.DOM_WELLFORMED)) { - features = - (short) (state + features + = (short) (state ? features | WELLFORMED : features & ~WELLFORMED); - } else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)){ - features = - (short) (state + } else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)) { + features + = (short) (state ? features | ENTITIES : features & ~ENTITIES); - } - else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)){ - features = - (short) (state + } else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) { + features + = (short) (state ? features | CDATA : features & ~CDATA); - } - else if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)){ - features = - (short) (state - ? features | COMMENTS - : features & ~COMMENTS); - } - else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)){ - features = - (short) (state - ? features | FORMAT_PRETTY_PRINT - : features & ~FORMAT_PRETTY_PRINT); - } - else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) + } else if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)) { + features + = (short) (state + ? features | COMMENTS + : features & ~COMMENTS); + } else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) { + features + = (short) (state + ? features | PRETTY_PRINT + : features & ~PRETTY_PRINT); + } else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) || name.equalsIgnoreCase(Constants.DOM_VALIDATE) || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) @@ -224,85 +212,81 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { // || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)) { // true is not supported if (state) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_SUPPORTED", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } - }else if ( - name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { - //namespace-declaration has effect only if namespaces is true - features = - (short) (state - ? features | NSDECL - : features & ~NSDECL); - serializer.fNamespacePrefixes = state; + } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { + //namespace-declaration has effect only if namespaces is true + features + = (short) (state + ? features | NSDECL + : features & ~NSDECL); + serializer.fNamespacePrefixes = state; } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) || name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { // false is not supported if (!state) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_SUPPORTED", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } } else { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_FOUND", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) { if (value == null || value instanceof DOMErrorHandler) { - fErrorHandler = (DOMErrorHandler)value; + fErrorHandler = (DOMErrorHandler) value; } else { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "TYPE_MISMATCH_ERR", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "TYPE_MISMATCH_ERR", + new Object[]{name}); throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg); } - } else if ( - name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) + } else if (name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) || name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION) || name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE) || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS) && value != null) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_SUPPORTED", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } else { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_FOUND", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[]{name}); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } } - /** DOM L3-EXPERIMENTAL: - * Check if parameter can be set + /** + * DOM L3-EXPERIMENTAL: Check if parameter can be set */ public boolean canSetParameter(String name, Object state) { - if (state == null) { return true; } if (state instanceof Boolean) { boolean value = ((Boolean) state).booleanValue(); - if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES) || name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA) || name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT) @@ -312,8 +296,8 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { || name.equalsIgnoreCase(Constants.DOM_ENTITIES) || name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS) || name.equalsIgnoreCase(Constants.DOM_COMMENTS) - || name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS) - || name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) { + || name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT) + || name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { // both values supported return true; } else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) @@ -329,8 +313,8 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { // false is not supported return value; } - } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER) && - state == null || state instanceof DOMErrorHandler) { + } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER) + && state == null || state instanceof DOMErrorHandler) { return true; } @@ -338,60 +322,57 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { } /** - * DOM Level 3 Core CR - Experimental. + * DOM Level 3 Core CR - Experimental. * - * The list of the parameters supported by this - * DOMConfiguration object and for which at least one value - * can be set by the application. Note that this list can also contain - * parameter names defined outside this specification. + * The list of the parameters supported by this + * DOMConfiguration object and for which at least one value can + * be set by the application. Note that this list can also contain parameter + * names defined outside this specification. */ public DOMStringList getParameterNames() { - if (fRecognizedParameters == null){ - Vector parameters = new Vector(); + if (fRecognizedParameters == null) { + ArrayList parameters = new ArrayList(); - //Add DOM recognized parameters - //REVISIT: Would have been nice to have a list of - //recognized parameters. - parameters.add(Constants.DOM_NAMESPACES); - parameters.add(Constants.DOM_SPLIT_CDATA); - parameters.add(Constants.DOM_DISCARD_DEFAULT_CONTENT); - parameters.add(Constants.DOM_XMLDECL); - parameters.add(Constants.DOM_CANONICAL_FORM); - parameters.add(Constants.DOM_VALIDATE_IF_SCHEMA); - parameters.add(Constants.DOM_VALIDATE); - parameters.add(Constants.DOM_CHECK_CHAR_NORMALIZATION); - parameters.add(Constants.DOM_DATATYPE_NORMALIZATION); - parameters.add(Constants.DOM_FORMAT_PRETTY_PRINT); - //parameters.add(Constants.DOM_NORMALIZE_CHARACTERS); - parameters.add(Constants.DOM_WELLFORMED); - parameters.add(Constants.DOM_INFOSET); - parameters.add(Constants.DOM_NAMESPACE_DECLARATIONS); - parameters.add(Constants.DOM_ELEMENT_CONTENT_WHITESPACE); - parameters.add(Constants.DOM_ENTITIES); - parameters.add(Constants.DOM_CDATA_SECTIONS); - parameters.add(Constants.DOM_COMMENTS); - parameters.add(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS); - parameters.add(Constants.DOM_ERROR_HANDLER); - //parameters.add(Constants.DOM_SCHEMA_LOCATION); - //parameters.add(Constants.DOM_SCHEMA_TYPE); - - //Add recognized xerces features and properties - - fRecognizedParameters = new DOMStringListImpl(parameters); + //Add DOM recognized parameters + //REVISIT: Would have been nice to have a list of + //recognized parameters. + parameters.add(Constants.DOM_NAMESPACES); + parameters.add(Constants.DOM_SPLIT_CDATA); + parameters.add(Constants.DOM_DISCARD_DEFAULT_CONTENT); + parameters.add(Constants.DOM_XMLDECL); + parameters.add(Constants.DOM_CANONICAL_FORM); + parameters.add(Constants.DOM_VALIDATE_IF_SCHEMA); + parameters.add(Constants.DOM_VALIDATE); + parameters.add(Constants.DOM_CHECK_CHAR_NORMALIZATION); + parameters.add(Constants.DOM_DATATYPE_NORMALIZATION); + parameters.add(Constants.DOM_FORMAT_PRETTY_PRINT); + //parameters.add(Constants.DOM_NORMALIZE_CHARACTERS); + parameters.add(Constants.DOM_WELLFORMED); + parameters.add(Constants.DOM_INFOSET); + parameters.add(Constants.DOM_NAMESPACE_DECLARATIONS); + parameters.add(Constants.DOM_ELEMENT_CONTENT_WHITESPACE); + parameters.add(Constants.DOM_ENTITIES); + parameters.add(Constants.DOM_CDATA_SECTIONS); + parameters.add(Constants.DOM_COMMENTS); + parameters.add(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS); + parameters.add(Constants.DOM_ERROR_HANDLER); + //parameters.add(Constants.DOM_SCHEMA_LOCATION); + //parameters.add(Constants.DOM_SCHEMA_TYPE); + //Add recognized xerces features and properties + fRecognizedParameters = new DOMStringListImpl(parameters); } return fRecognizedParameters; } - /** DOM L3-EXPERIMENTAL: - * Getter for boolean and object parameters + /** + * DOM L3-EXPERIMENTAL: Getter for boolean and object parameters */ public Object getParameter(String name) throws DOMException { - - if(name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)){ - return null; + if (name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)) { + return null; } else if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)) { return ((features & COMMENTS) != 0) ? Boolean.TRUE : Boolean.FALSE; } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) { @@ -408,23 +389,23 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { return (features & WELLFORMED) != 0 ? Boolean.TRUE : Boolean.FALSE; } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { return (features & NSDECL) != 0 ? Boolean.TRUE : Boolean.FALSE; - } else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) { - return (features & FORMAT_PRETTY_PRINT) != 0 ? Boolean.TRUE : Boolean.FALSE; - } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) || - name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { + } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) + || name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { return Boolean.TRUE; - }else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)){ - return ((features & DISCARDDEFAULT)!=0)?Boolean.TRUE:Boolean.FALSE; - }else if (name.equalsIgnoreCase(Constants.DOM_INFOSET)){ - if ((features & ENTITIES) == 0 && - (features & CDATA) == 0 && - (features & NAMESPACES) != 0 && - (features & NSDECL) != 0 && - (features & WELLFORMED) != 0 && - (features & COMMENTS) != 0) { - return Boolean.TRUE; - } - return Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)) { + return ((features & DISCARDDEFAULT) != 0) ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) { + return ((features & PRETTY_PRINT) != 0) ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_INFOSET)) { + if ((features & ENTITIES) == 0 + && (features & CDATA) == 0 + && (features & NAMESPACES) != 0 + && (features & NSDECL) != 0 + && (features & WELLFORMED) != 0 + && (features & COMMENTS) != 0) { + return Boolean.TRUE; + } + return Boolean.FALSE; } else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) @@ -434,64 +415,48 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { return Boolean.FALSE; } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) { return fErrorHandler; - } else if ( - name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) + } else if (name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) || name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION) || name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE)) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_SUPPORTED", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } else { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_FOUND", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[]{name}); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } } - /** - * DOM L3 EXPERIMENTAL: - * Serialize the specified node as described above in the description of - * LSSerializer. The result of serializing the node is - * returned as a string. Writing a Document or Entity node produces a - * serialized form that is well formed XML. Writing other node types - * produces a fragment of text in a form that is not fully defined by + * DOM L3 EXPERIMENTAL: Serialize the specified node as described above in + * the description of LSSerializer. The result of serializing + * the node is returned as a string. Writing a Document or Entity node + * produces a serialized form that is well formed XML. Writing other node + * types produces a fragment of text in a form that is not fully defined by * this document, but that should be useful to a human for debugging or * diagnostic purposes. - * @param wnode The node to be written. - * @return Returns the serialized data - * @exception DOMException - * DOMSTRING_SIZE_ERR: The resulting string is too long to fit in a - * DOMString. - * @exception LSException - * SERIALIZE_ERR: Unable to serialize the node. DOM applications should - * attach a DOMErrorHandler using the parameter - * "error-handler" to get details on error. + * + * @param wnode The node to be written. + * @return Returns the serialized data + * @exception DOMException DOMSTRING_SIZE_ERR: The resulting string is too + * long to fit in a DOMString. + * @exception LSException SERIALIZE_ERR: Unable to serialize the node. DOM + * applications should attach a DOMErrorHandler using the + * parameter "error-handler" to get details on error. */ public String writeToString(Node wnode) throws DOMException, LSException { // determine which serializer to use: - Document doc = (wnode.getNodeType() == Node.DOCUMENT_NODE)?(Document)wnode:wnode.getOwnerDocument(); - Method getVersion = null; XMLSerializer ser = null; - String ver = null; - // this should run under JDK 1.1.8... - try { - getVersion = doc.getClass().getMethod("getXmlVersion", new Class[]{}); - if(getVersion != null ) { - ver = (String)getVersion.invoke(doc, (Object[]) null); - } - } catch (Exception e) { - // no way to test the version... - // ignore the exception - } - if(ver != null && ver.equals("1.1")) { - if(xml11Serializer == null) { + String ver = _getXmlVersion(wnode); + if (ver != null && ver.equals("1.1")) { + if (xml11Serializer == null) { xml11Serializer = new XML11Serializer(); initSerializer(xml11Serializer); } @@ -508,25 +473,21 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser._format.setEncoding("UTF-16"); ser.setOutputCharStream(destination); if (wnode.getNodeType() == Node.DOCUMENT_NODE) { - ser.serialize((Document)wnode); - } - else if (wnode.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { - ser.serialize((DocumentFragment)wnode); - } - else if (wnode.getNodeType() == Node.ELEMENT_NODE) { - ser.serialize((Element)wnode); - } - else if (wnode.getNodeType() == Node.TEXT_NODE || - wnode.getNodeType() == Node.COMMENT_NODE || - wnode.getNodeType() == Node.ENTITY_REFERENCE_NODE || - wnode.getNodeType() == Node.CDATA_SECTION_NODE || - wnode.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE ) { + ser.serialize((Document) wnode); + } else if (wnode.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { + ser.serialize((DocumentFragment) wnode); + } else if (wnode.getNodeType() == Node.ELEMENT_NODE) { + ser.serialize((Element) wnode); + } else if (wnode.getNodeType() == Node.TEXT_NODE + || wnode.getNodeType() == Node.COMMENT_NODE + || wnode.getNodeType() == Node.ENTITY_REFERENCE_NODE + || wnode.getNodeType() == Node.CDATA_SECTION_NODE + || wnode.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { ser.serialize(wnode); - } - else { + } else { String msg = DOMMessageFormatter.formatMessage( - DOMMessageFormatter.SERIALIZER_DOMAIN, - "unable-to-serialize-node", null); + DOMMessageFormatter.SERIALIZER_DOMAIN, + "unable-to-serialize-node", null); if (ser.fDOMErrorHandler != null) { DOMErrorImpl error = new DOMErrorImpl(); error.fType = "unable-to-serialize-node"; @@ -540,45 +501,42 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { // Rethrow LSException. throw lse; } catch (RuntimeException e) { - if (e == DOMNormalizer.abort){ + if (e == DOMNormalizer.abort) { // stopped at user request return null; } - throw (LSException) new LSException(LSException.SERIALIZE_ERR, e.toString()).initCause(e); + throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); } catch (IOException ioe) { // REVISIT: A generic IOException doesn't provide enough information // to determine that the serialized document is too large to fit // into a string. This could have thrown for some other reason. -- mrglavas String msg = DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "STRING_TOO_LONG", - new Object[] { ioe.getMessage()}); - throw (DOMException) new DOMException(DOMException.DOMSTRING_SIZE_ERR, msg).initCause(ioe); + DOMMessageFormatter.DOM_DOMAIN, + "STRING_TOO_LONG", + new Object[]{ioe.getMessage()}); + throw new DOMException(DOMException.DOMSTRING_SIZE_ERR, msg); + } finally { + ser.clearDocumentState(); } - return destination.toString(); } /** - * DOM L3 EXPERIMENTAL: - * The end-of-line sequence of characters to be used in the XML being - * written out. The only permitted values are these: + * DOM L3 EXPERIMENTAL: The end-of-line sequence of characters to be used in + * the XML being written out. The only permitted values are these: *
*
null
*
- * Use a default end-of-line sequence. DOM implementations should choose - * the default to match the usual convention for text files in the - * environment being used. Implementations must choose a default - * sequence that matches one of those allowed by 2.11 "End-of-Line - * Handling".
+ * Use a default end-of-line sequence. DOM implementations should choose the + * default to match the usual convention for text files in the environment + * being used. Implementations must choose a default sequence that matches + * one of those allowed by 2.11 "End-of-Line Handling". *
CR
*
The carriage-return character (#xD).
*
CR-LF
- *
The - * carriage-return and line-feed characters (#xD #xA).
+ *
The carriage-return and line-feed characters (#xD #xA).
*
LF
- *
The line-feed - * character (#xA).
+ *
The line-feed character (#xA).
*
*
The default value for this attribute is null. */ @@ -586,27 +544,22 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { serializer._format.setLineSeparator(newLine); } - /** - * DOM L3 EXPERIMENTAL: - * The end-of-line sequence of characters to be used in the XML being - * written out. The only permitted values are these: + * DOM L3 EXPERIMENTAL: The end-of-line sequence of characters to be used in + * the XML being written out. The only permitted values are these: *
*
null
*
- * Use a default end-of-line sequence. DOM implementations should choose - * the default to match the usual convention for text files in the - * environment being used. Implementations must choose a default - * sequence that matches one of those allowed by 2.11 "End-of-Line - * Handling".
+ * Use a default end-of-line sequence. DOM implementations should choose the + * default to match the usual convention for text files in the environment + * being used. Implementations must choose a default sequence that matches + * one of those allowed by 2.11 "End-of-Line Handling". *
CR
*
The carriage-return character (#xD).
*
CR-LF
- *
The - * carriage-return and line-feed characters (#xD #xA).
+ *
The carriage-return and line-feed characters (#xD #xA).
*
LF
- *
The line-feed - * character (#xA).
+ *
The line-feed character (#xA).
*
*
The default value for this attribute is null. */ @@ -614,23 +567,23 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { return serializer._format.getLineSeparator(); } - /** - * When the application provides a filter, the serializer will call out - * to the filter before serializing each Node. Attribute nodes are never - * passed to the filter. The filter implementation can choose to remove - * the node from the stream or to terminate the serialization early. + * When the application provides a filter, the serializer will call out to + * the filter before serializing each Node. Attribute nodes are never passed + * to the filter. The filter implementation can choose to remove the node + * from the stream or to terminate the serialization early. */ - public LSSerializerFilter getFilter(){ + public LSSerializerFilter getFilter() { return serializer.fDOMFilter; } + /** - * When the application provides a filter, the serializer will call out - * to the filter before serializing each Node. Attribute nodes are never - * passed to the filter. The filter implementation can choose to remove - * the node from the stream or to terminate the serialization early. + * When the application provides a filter, the serializer will call out to + * the filter before serializing each Node. Attribute nodes are never passed + * to the filter. The filter implementation can choose to remove the node + * from the stream or to terminate the serialization early. */ - public void setFilter(LSSerializerFilter filter){ + public void setFilter(LSSerializerFilter filter) { serializer.fDOMFilter = filter; } @@ -654,56 +607,44 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { }//copysettings /** - * Serialize the specified node as described above in the general - * description of the LSSerializer interface. The output - * is written to the supplied LSOutput. - *
When writing to a LSOutput, the encoding is found by - * looking at the encoding information that is reachable through the - * LSOutput and the item to be written (or its owner - * document) in this order: - *
    - *
  1. LSOutput.encoding, - *
  2. - *
  3. - * Document.actualEncoding, - *
  4. - *
  5. - * Document.xmlEncoding. - *
  6. - *
- *
If no encoding is reachable through the above properties, a - * default encoding of "UTF-8" will be used. - *
If the specified encoding is not supported an - * "unsupported-encoding" error is raised. - *
If no output is specified in the LSOutput, a - * "no-output-specified" error is raised. - * @param node The node to serialize. - * @param destination The destination for the serialized DOM. - * @return Returns true if node was - * successfully serialized and false in case the node - * couldn't be serialized. - */ - public boolean write(Node node, LSOutput destination) throws LSException{ + * Serialize the specified node as described above in the general + * description of the LSSerializer interface. The output is + * written to the supplied LSOutput. + *
When writing to a LSOutput, the encoding is found by + * looking at the encoding information that is reachable through the + * LSOutput and the item to be written (or its owner document) + * in this order: + *
    + *
  1. LSOutput.encoding, + *
  2. + *
  3. + * Document.actualEncoding, + *
  4. + *
  5. + * Document.xmlEncoding. + *
  6. + *
+ *
If no encoding is reachable through the above properties, a default + * encoding of "UTF-8" will be used. + *
If the specified encoding is not supported an "unsupported-encoding" + * error is raised. + *
If no output is specified in the LSOutput, a + * "no-output-specified" error is raised. + * + * @param node The node to serialize. + * @param destination The destination for the serialized DOM. + * @return Returns true if node was successfully + * serialized and false in case the node couldn't be + * serialized. + */ + public boolean write(Node node, LSOutput destination) throws LSException { - if (node == null) + if (node == null) { return false; - - Method getVersion = null; - XMLSerializer ser = null; - String ver = null; - Document fDocument =(node.getNodeType() == Node.DOCUMENT_NODE) - ? (Document) node - : node.getOwnerDocument(); - // this should run under JDK 1.1.8... - try { - getVersion = fDocument.getClass().getMethod("getXmlVersion", new Class[] {}); - if (getVersion != null) { - ver = (String) getVersion.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - //no way to test the version... - //ignore the exception } + + XMLSerializer ser = null; + String ver = _getXmlVersion(node); //determine which serializer to use: if (ver != null && ver.equals("1.1")) { if (xml11Serializer == null) { @@ -719,25 +660,9 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { String encoding = null; if ((encoding = destination.getEncoding()) == null) { - try { - Method getEncoding = - fDocument.getClass().getMethod("getInputEncoding", new Class[] {}); - if (getEncoding != null) { - encoding = (String) getEncoding.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // ignore the exception - } + encoding = _getInputEncoding(node); if (encoding == null) { - try { - Method getEncoding = - fDocument.getClass().getMethod("getXmlEncoding", new Class[] {}); - if (getEncoding != null) { - encoding = (String) getEncoding.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // ignore the exception - } + encoding = _getXmlEncoding(node); if (encoding == null) { encoding = "UTF-8"; } @@ -748,13 +673,13 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser._format.setEncoding(encoding); OutputStream outputStream = destination.getByteStream(); Writer writer = destination.getCharacterStream(); - String uri = destination.getSystemId(); + String uri = destination.getSystemId(); if (writer == null) { if (outputStream == null) { if (uri == null) { String msg = DOMMessageFormatter.formatMessage( - DOMMessageFormatter.SERIALIZER_DOMAIN, - "no-output-specified", null); + DOMMessageFormatter.SERIALIZER_DOMAIN, + "no-output-specified", null); if (ser.fDOMErrorHandler != null) { DOMErrorImpl error = new DOMErrorImpl(); error.fType = "no-output-specified"; @@ -763,81 +688,52 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser.fDOMErrorHandler.handleError(error); } throw new LSException(LSException.SERIALIZE_ERR, msg); + } else { + ser.setOutputByteStream(XMLEntityManager.createOutputStream(uri)); } - else { - // URI was specified. Handle relative URIs. - String expanded = XMLEntityManager.expandSystemId(uri, null, true); - URL url = new URL(expanded != null ? expanded : uri); - OutputStream out = null; - String protocol = url.getProtocol(); - String host = url.getHost(); - // Use FileOutputStream if this URI is for a local file. - if (protocol.equals("file") - && (host == null || host.length() == 0 || host.equals("localhost"))) { - out = new FileOutputStream(getPathWithoutEscapes(url.getFile())); - } - // Try to write to some other kind of URI. Some protocols - // won't support this, though HTTP should work. - else { - URLConnection urlCon = url.openConnection(); - urlCon.setDoInput(false); - urlCon.setDoOutput(true); - urlCon.setUseCaches(false); // Enable tunneling. - if (urlCon instanceof HttpURLConnection) { - // The DOM L3 LS CR says if we are writing to an HTTP URI - // it is to be done with an HTTP PUT. - HttpURLConnection httpCon = (HttpURLConnection) urlCon; - httpCon.setRequestMethod("PUT"); - } - out = urlCon.getOutputStream(); - } - ser.setOutputByteStream(out); - } - } - else { + } else { // byte stream was specified ser.setOutputByteStream(outputStream); } - } - else { + } else { // character stream is specified ser.setOutputCharStream(writer); } - if (node.getNodeType() == Node.DOCUMENT_NODE) + if (node.getNodeType() == Node.DOCUMENT_NODE) { ser.serialize((Document) node); - else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) + } else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { ser.serialize((DocumentFragment) node); - else if (node.getNodeType() == Node.ELEMENT_NODE) + } else if (node.getNodeType() == Node.ELEMENT_NODE) { ser.serialize((Element) node); - else if (node.getNodeType() == Node.TEXT_NODE || - node.getNodeType() == Node.COMMENT_NODE || - node.getNodeType() == Node.ENTITY_REFERENCE_NODE || - node.getNodeType() == Node.CDATA_SECTION_NODE || - node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE ) { + } else if (node.getNodeType() == Node.TEXT_NODE + || node.getNodeType() == Node.COMMENT_NODE + || node.getNodeType() == Node.ENTITY_REFERENCE_NODE + || node.getNodeType() == Node.CDATA_SECTION_NODE + || node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { ser.serialize(node); - } - else + } else { return false; - } catch( UnsupportedEncodingException ue) { + } + } catch (UnsupportedEncodingException ue) { if (ser.fDOMErrorHandler != null) { DOMErrorImpl error = new DOMErrorImpl(); error.fException = ue; - error.fType = "unsupported-encoding"; + error.fType = "unsupported-encoding"; error.fMessage = ue.getMessage(); - error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; ser.fDOMErrorHandler.handleError(error); - } + } throw new LSException(LSException.SERIALIZE_ERR, - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.SERIALIZER_DOMAIN, - "unsupported-encoding", null)); - //return false; + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "unsupported-encoding", null)); + //return false; } catch (LSException lse) { // Rethrow LSException. throw lse; } catch (RuntimeException e) { - if (e == DOMNormalizer.abort){ + if (e == DOMNormalizer.abort) { // stopped at user request return false; } @@ -851,62 +747,48 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser.fDOMErrorHandler.handleError(error); } - e.printStackTrace(); throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); + } finally { + ser.clearDocumentState(); } return true; } //write /** - * Serialize the specified node as described above in the general - * description of the LSSerializer interface. The output - * is written to the supplied URI. - *
When writing to a URI, the encoding is found by looking at the - * encoding information that is reachable through the item to be written - * (or its owner document) in this order: - *
    - *
  1. - * Document.inputEncoding, - *
  2. - *
  3. - * Document.xmlEncoding. - *
  4. - *
- *
If no encoding is reachable through the above properties, a - * default encoding of "UTF-8" will be used. - *
If the specified encoding is not supported an - * "unsupported-encoding" error is raised. - * @param node The node to serialize. - * @param URI The URI to write to. - * @return Returns true if node was - * successfully serialized and false in case the node - * couldn't be serialized. - */ - public boolean writeToURI(Node node, String URI) throws LSException{ - if (node == null){ + * Serialize the specified node as described above in the general + * description of the LSSerializer interface. The output is + * written to the supplied URI. + *
When writing to a URI, the encoding is found by looking at the + * encoding information that is reachable through the item to be written (or + * its owner document) in this order: + *
    + *
  1. + * Document.inputEncoding, + *
  2. + *
  3. + * Document.xmlEncoding. + *
  4. + *
+ *
If no encoding is reachable through the above properties, a default + * encoding of "UTF-8" will be used. + *
If the specified encoding is not supported an "unsupported-encoding" + * error is raised. + * + * @param node The node to serialize. + * @param URI The URI to write to. + * @return Returns true if node was successfully + * serialized and false in case the node couldn't be + * serialized. + */ + public boolean writeToURI(Node node, String URI) throws LSException { + if (node == null) { return false; } - Method getXmlVersion = null; XMLSerializer ser = null; - String ver = null; - String encoding = null; + String ver = _getXmlVersion(node); - Document fDocument =(node.getNodeType() == Node.DOCUMENT_NODE) - ? (Document) node - : node.getOwnerDocument(); - // this should run under JDK 1.1.8... - try { - getXmlVersion = - fDocument.getClass().getMethod("getXmlVersion", new Class[] {}); - if (getXmlVersion != null) { - ver = (String) getXmlVersion.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // no way to test the version... - // ignore the exception - } if (ver != null && ver.equals("1.1")) { if (xml11Serializer == null) { xml11Serializer = new XML11Serializer(); @@ -919,25 +801,9 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser = serializer; } - try { - Method getEncoding = - fDocument.getClass().getMethod("getInputEncoding", new Class[] {}); - if (getEncoding != null) { - encoding = (String) getEncoding.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // ignore the exception - } + String encoding = _getInputEncoding(node); if (encoding == null) { - try { - Method getEncoding = - fDocument.getClass().getMethod("getXmlEncoding", new Class[] {}); - if (getEncoding != null) { - encoding = (String) getEncoding.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // ignore the exception - } + encoding = _getXmlEncoding(node); if (encoding == null) { encoding = "UTF-8"; } @@ -946,55 +812,28 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { try { prepareForSerialization(ser, node); ser._format.setEncoding(encoding); + ser.setOutputByteStream(XMLEntityManager.createOutputStream(URI)); - // URI was specified. Handle relative URIs. - String expanded = XMLEntityManager.expandSystemId(URI, null, true); - URL url = new URL(expanded != null ? expanded : URI); - OutputStream out = null; - String protocol = url.getProtocol(); - String host = url.getHost(); - // Use FileOutputStream if this URI is for a local file. - if (protocol.equals("file") - && (host == null || host.length() == 0 || host.equals("localhost"))) { - out = new FileOutputStream(getPathWithoutEscapes(url.getFile())); - } - // Try to write to some other kind of URI. Some protocols - // won't support this, though HTTP should work. - else { - URLConnection urlCon = url.openConnection(); - urlCon.setDoInput(false); - urlCon.setDoOutput(true); - urlCon.setUseCaches(false); // Enable tunneling. - if (urlCon instanceof HttpURLConnection) { - // The DOM L3 LS CR says if we are writing to an HTTP URI - // it is to be done with an HTTP PUT. - HttpURLConnection httpCon = (HttpURLConnection) urlCon; - httpCon.setRequestMethod("PUT"); - } - out = urlCon.getOutputStream(); - } - ser.setOutputByteStream(out); - - if (node.getNodeType() == Node.DOCUMENT_NODE) + if (node.getNodeType() == Node.DOCUMENT_NODE) { ser.serialize((Document) node); - else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) + } else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { ser.serialize((DocumentFragment) node); - else if (node.getNodeType() == Node.ELEMENT_NODE) + } else if (node.getNodeType() == Node.ELEMENT_NODE) { ser.serialize((Element) node); - else if (node.getNodeType() == Node.TEXT_NODE || - node.getNodeType() == Node.COMMENT_NODE || - node.getNodeType() == Node.ENTITY_REFERENCE_NODE || - node.getNodeType() == Node.CDATA_SECTION_NODE || - node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE ) { + } else if (node.getNodeType() == Node.TEXT_NODE + || node.getNodeType() == Node.COMMENT_NODE + || node.getNodeType() == Node.ENTITY_REFERENCE_NODE + || node.getNodeType() == Node.CDATA_SECTION_NODE + || node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { ser.serialize(node); - } - else + } else { return false; + } } catch (LSException lse) { // Rethrow LSException. throw lse; } catch (RuntimeException e) { - if (e == DOMNormalizer.abort){ + if (e == DOMNormalizer.abort) { // stopped at user request return false; } @@ -1008,24 +847,24 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser.fDOMErrorHandler.handleError(error); } throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); + } finally { + ser.clearDocumentState(); } return true; } //writeURI - // // Private methods // - private void prepareForSerialization(XMLSerializer ser, Node node) { ser.reset(); ser.features = features; ser.fDOMErrorHandler = fErrorHandler; ser.fNamespaces = (features & NAMESPACES) != 0; ser.fNamespacePrefixes = (features & NSDECL) != 0; - ser._format.setOmitComments((features & COMMENTS)==0); + ser._format.setIndenting((features & PRETTY_PRINT) != 0); + ser._format.setOmitComments((features & COMMENTS) == 0); ser._format.setOmitXMLDeclaration((features & XMLDECL) == 0); - ser._format.setIndenting((features & FORMAT_PRETTY_PRINT) != 0); if ((features & WELLFORMED) != 0) { // REVISIT: this is inefficient implementation of well-formness. Instead, we should check @@ -1034,13 +873,13 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { root = node; Method versionChanged; boolean verifyNames = true; - Document document =(node.getNodeType() == Node.DOCUMENT_NODE) + Document document = (node.getNodeType() == Node.DOCUMENT_NODE) ? (Document) node : node.getOwnerDocument(); try { - versionChanged = document.getClass().getMethod("isXMLVersionChanged()", new Class[] {}); + versionChanged = document.getClass().getMethod("isXMLVersionChanged()", new Class[]{}); if (versionChanged != null) { - verifyNames = ((Boolean)versionChanged.invoke(document, (Object[]) null)).booleanValue(); + verifyNames = ((Boolean) versionChanged.invoke(document, (Object[]) null)).booleanValue(); } } catch (Exception e) { //no way to test the version... @@ -1053,59 +892,53 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { next = node.getFirstChild(); // No child nodes, so walk tree while (next == null) { - // Move to sibling if possible. - next = node.getNextSibling(); - if (next == null) { - node = node.getParentNode(); - if (root == node){ - next = null; - break; - } - next = node.getNextSibling(); - } + // Move to sibling if possible. + next = node.getNextSibling(); + if (next == null) { + node = node.getParentNode(); + if (root == node) { + next = null; + break; + } + next = node.getNextSibling(); + } } node = next; } - } - else { + } else { verify(node, verifyNames, false); } } } - - private void verify (Node node, boolean verifyNames, boolean xml11Version){ + private void verify(Node node, boolean verifyNames, boolean xml11Version) { int type = node.getNodeType(); fLocator.fRelatedNode = node; boolean wellformed; switch (type) { - case Node.DOCUMENT_NODE:{ + case Node.DOCUMENT_NODE: { break; } - case Node.DOCUMENT_TYPE_NODE:{ + case Node.DOCUMENT_TYPE_NODE: { break; } - case Node.ELEMENT_NODE:{ - if (verifyNames){ - if((features & NAMESPACES) != 0){ - wellformed = CoreDocumentImpl.isValidQName(node.getPrefix() , node.getLocalName(), xml11Version) ; + case Node.ELEMENT_NODE: { + if (verifyNames) { + if ((features & NAMESPACES) != 0) { + wellformed = CoreDocumentImpl.isValidQName(node.getPrefix(), node.getLocalName(), xml11Version); + } else { + wellformed = CoreDocumentImpl.isXMLName(node.getNodeName(), xml11Version); } - else{ - wellformed = CoreDocumentImpl.isXMLName(node.getNodeName() , xml11Version); - } - if (!wellformed){ - if (!wellformed){ - if (fErrorHandler != null) { - String msg = DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "wf-invalid-character-in-node-name", - new Object[]{"Element", node.getNodeName()}); - DOMNormalizer.reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, - "wf-invalid-character-in-node-name"); - } - - } + if (!wellformed) { + if (fErrorHandler != null) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Element", node.getNodeName()}); + DOMNormalizer.reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, + "wf-invalid-character-in-node-name"); + } } } @@ -1114,17 +947,17 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { for (int i = 0; i < attributes.getLength(); ++i) { Attr attr = (Attr) attributes.item(i); fLocator.fRelatedNode = attr; - DOMNormalizer.isAttrValueWF( fErrorHandler, fError, fLocator, - attributes, attr, attr.getValue(), xml11Version); + DOMNormalizer.isAttrValueWF(fErrorHandler, fError, fLocator, + attributes, attr, attr.getValue(), xml11Version); if (verifyNames) { - wellformed = CoreDocumentImpl.isXMLName( attr.getNodeName(), xml11Version); + wellformed = CoreDocumentImpl.isXMLName(attr.getNodeName(), xml11Version); if (!wellformed) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "wf-invalid-character-in-node-name", - new Object[] { "Attr", node.getNodeName()}); - DOMNormalizer.reportDOMError( fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Attr", node.getNodeName()}); + DOMNormalizer.reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, "wf-invalid-character-in-node-name"); } } @@ -1135,78 +968,156 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { break; } - case Node.COMMENT_NODE: { - // only verify well-formness if comments included in the tree - if ((features & COMMENTS) != 0) - DOMNormalizer.isCommentWF(fErrorHandler, fError, fLocator, ((Comment)node).getData(), xml11Version); - break; - } - case Node.ENTITY_REFERENCE_NODE: { - // only if entity is preserved in the tree - if (verifyNames && (features & ENTITIES) != 0){ - CoreDocumentImpl.isXMLName(node.getNodeName() , xml11Version); - } - break; - - } - case Node.CDATA_SECTION_NODE: { - // verify content - DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); - // the ]]> string will be checked during serialization - break; - } - case Node.TEXT_NODE:{ - DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); - break; - } - case Node.PROCESSING_INSTRUCTION_NODE:{ - ProcessingInstruction pinode = (ProcessingInstruction)node ; - String target = pinode.getTarget(); - if (verifyNames) { - if (xml11Version) { - wellformed = XML11Char.isXML11ValidName(target); - } else { - wellformed = XMLChar.isValidName(target); - } - - if (!wellformed) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "wf-invalid-character-in-node-name", - new Object[] { "Element", node.getNodeName()}); - DOMNormalizer.reportDOMError( - fErrorHandler, - fError, - fLocator, - msg, - DOMError.SEVERITY_FATAL_ERROR, - "wf-invalid-character-in-node-name"); + case Node.COMMENT_NODE: { + // only verify well-formness if comments included in the tree + if ((features & COMMENTS) != 0) { + DOMNormalizer.isCommentWF(fErrorHandler, fError, fLocator, ((Comment) node).getData(), xml11Version); } + break; } - DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, pinode.getData(), xml11Version); - break; - } - } + case Node.ENTITY_REFERENCE_NODE: { + // only if entity is preserved in the tree + if (verifyNames && (features & ENTITIES) != 0) { + CoreDocumentImpl.isXMLName(node.getNodeName(), xml11Version); + } + break; + } + case Node.CDATA_SECTION_NODE: { + // verify content + DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); + // the ]]> string will be checked during serialization + break; + } + case Node.TEXT_NODE: { + DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE: { + ProcessingInstruction pinode = (ProcessingInstruction) node; + String target = pinode.getTarget(); + if (verifyNames) { + if (xml11Version) { + wellformed = XML11Char.isXML11ValidName(target); + } else { + wellformed = XMLChar.isValidName(target); + } + + if (!wellformed) { + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Element", node.getNodeName()}); + DOMNormalizer.reportDOMError( + fErrorHandler, + fError, + fLocator, + msg, + DOMError.SEVERITY_FATAL_ERROR, + "wf-invalid-character-in-node-name"); + } + } + DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, pinode.getData(), xml11Version); + break; + } + } + fLocator.fRelatedNode = null; } - private String getPathWithoutEscapes(String origPath) { - if (origPath != null && origPath.length() != 0 && origPath.indexOf('%') != -1) { - // Locate the escape characters - StringTokenizer tokenizer = new StringTokenizer(origPath, "%"); - StringBuffer result = new StringBuffer(origPath.length()); - int size = tokenizer.countTokens(); - result.append(tokenizer.nextToken()); - for(int i = 1; i < size; ++i) { - String token = tokenizer.nextToken(); - // Decode the 2 digit hexadecimal number following % in '%nn' - result.append((char)Integer.valueOf(token.substring(0, 2), 16).intValue()); - result.append(token.substring(2)); + private String _getXmlVersion(Node node) { + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) + ? (Document) node : node.getOwnerDocument(); + if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) { + try { + return (String) DocumentMethods.fgDocumentGetXmlVersionMethod.invoke(doc, (Object[]) null); + } // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } // Ignore all other exceptions and errors + catch (Throwable t) { } - return result.toString(); } - return origPath; + return null; } -}//DOMSerializerImpl + private String _getInputEncoding(Node node) { + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) + ? (Document) node : node.getOwnerDocument(); + if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) { + try { + return (String) DocumentMethods.fgDocumentGetInputEncodingMethod.invoke(doc, (Object[]) null); + } // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } // Ignore all other exceptions and errors + catch (Throwable t) { + } + } + return null; + } + + private String _getXmlEncoding(Node node) { + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) + ? (Document) node : node.getOwnerDocument(); + if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) { + try { + return (String) DocumentMethods.fgDocumentGetXmlEncodingMethod.invoke(doc, (Object[]) null); + } // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } // Ignore all other exceptions and errors + catch (Throwable t) { + } + } + return null; + } + + /** + * Holder of DOM Level 3 methods from org.w3c.dom.Document. + */ + static class DocumentMethods { + + // Method: org.w3c.dom.Document.getXmlVersion() + private static java.lang.reflect.Method fgDocumentGetXmlVersionMethod = null; + + // Method: org.w3c.dom.Document.getInputEncoding() + private static java.lang.reflect.Method fgDocumentGetInputEncodingMethod = null; + + // Method: org.w3c.dom.Document.getXmlEncoding() + private static java.lang.reflect.Method fgDocumentGetXmlEncodingMethod = null; + + // Flag indicating whether or not Document methods are available. + private static boolean fgDocumentMethodsAvailable = false; + + private DocumentMethods() { + } + + // Attempt to get methods for org.w3c.dom.Document on class initialization. + static { + try { + fgDocumentGetXmlVersionMethod = Document.class.getMethod("getXmlVersion", new Class[]{}); + fgDocumentGetInputEncodingMethod = Document.class.getMethod("getInputEncoding", new Class[]{}); + fgDocumentGetXmlEncodingMethod = Document.class.getMethod("getXmlEncoding", new Class[]{}); + fgDocumentMethodsAvailable = true; + } // ClassNotFoundException, NoSuchMethodException or SecurityException + // Whatever the case, we cannot retrieve the methods. + catch (Exception exc) { + fgDocumentGetXmlVersionMethod = null; + fgDocumentGetInputEncodingMethod = null; + fgDocumentGetXmlEncodingMethod = null; + fgDocumentMethodsAvailable = false; + } + } + } + +} //DOMSerializerImpl diff --git a/jaxp/src/com/sun/org/apache/xml/internal/serialize/XML11Serializer.java b/jaxp/src/com/sun/org/apache/xml/internal/serialize/XML11Serializer.java index e1728cd7624..ced3ef5c4d5 100644 --- a/jaxp/src/com/sun/org/apache/xml/internal/serialize/XML11Serializer.java +++ b/jaxp/src/com/sun/org/apache/xml/internal/serialize/XML11Serializer.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2002,2004,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 * @@ -18,8 +19,6 @@ * limitations under the License. */ - - // Sep 14, 2000: // Fixed problem with namespace handling. Contributed by // David Blondeau @@ -33,22 +32,20 @@ // Aug 21, 2000: // Added ability to omit DOCTYPE declaration. - package com.sun.org.apache.xml.internal.serialize; - import java.io.IOException; import java.io.OutputStream; import java.io.Writer; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; -import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.util.NamespaceSupport; import com.sun.org.apache.xerces.internal.util.SymbolTable; import com.sun.org.apache.xerces.internal.util.XML11Char; import com.sun.org.apache.xerces.internal.util.XMLChar; -import org.xml.sax.SAXException; import org.w3c.dom.DOMError; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; /** * Implements an XML serializer supporting both DOM and SAX pretty @@ -62,9 +59,9 @@ import org.w3c.dom.DOMError; * The serializer supports both DOM and SAX. SAX serializing is done by firing * SAX events and using the serializer as a document handler. DOM serializing is done * by calling {@link #serialize(Document)} or by using DOM Level 3 - * {@link org.w3c.dom.ls.DOMSerializer} and - * serializing with {@link org.w3c.dom.ls.DOMSerializer#write}, - * {@link org.w3c.dom.ls.DOMSerializer#writeToString}. + * {@link org.w3c.dom.ls.LSSerializer} and + * serializing with {@link org.w3c.dom.ls.LSSerializer#write}, + * {@link org.w3c.dom.ls.LSSerializer#writeToString}. *

* If an I/O exception occurs while serializing, the serializer * will not throw an exception directly, but only throw it @@ -122,10 +119,6 @@ extends XMLSerializer { */ protected boolean fNamespaces = false; - - private boolean fPreserveSpace; - - /** * Constructs a new serializer. The serializer cannot be used without * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} @@ -217,26 +210,27 @@ extends XMLSerializer { if (!XML11Char.isXML11Valid(ch)) { // check if it is surrogate if (++index < end) { - surrogates(ch, chars[index]); + surrogates(ch, chars[index], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; - } else { - if ( _encodingInfo.isPrintable((char)ch) && XML11Char.isXML11ValidLiteral(ch)) { - _printer.printText((char)ch); - } else { - // The character is not printable -- split CDATA section - _printer.printText("]]>&#x"); - _printer.printText(Integer.toHexString(ch)); - _printer.printText(";&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";= ' ' && _encodingInfo.isPrintable((char) ch))) { - _printer.printText((char) ch); - } else { - printHex(ch); - } + if (ch == '\n' || ch == '\r' || ch == '\t' || ch == 0x0085 || ch == 0x2028) { + printHex(ch); + } + else if (ch == '<') { + _printer.printText("<"); + } + else if (ch == '&') { + _printer.printText("&"); + } + else if (ch == '"') { + _printer.printText("""); + } + else if ((ch >= ' ' && _encodingInfo.isPrintable((char) ch))) { + _printer.printText((char) ch); + } + else { + printHex(ch); + } } } @@ -344,54 +345,55 @@ extends XMLSerializer { if (!XML11Char.isXML11Valid(ch)) { // check if it is surrogate if (++index < length) { - surrogates(ch, text.charAt(index)); - } else { - fatalError( - "The character '" - + (char) ch - + "' is an invalid XML character"); + surrogates(ch, text.charAt(index), true); + } + else { + fatalError("The character '" + ch + "' is an invalid XML character"); } continue; - } else { - if (_encodingInfo.isPrintable((char) ch) - && XML11Char.isXML11ValidLiteral(ch)) { - _printer.printText((char) ch); - } else { - - // The character is not printable -- split CDATA section - _printer.printText("]]>&#x"); - _printer.printText(Integer.toHexString(ch)); - _printer.printText(";&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";'){ - // character sequence "]]>" can't appear in content, therefore - // we should escape '>' - _printer.printText(">"); - } else if ( _encodingInfo.isPrintable((char)ch) && XML11Char.isXML11ValidLiteral(ch)) { + } + else if (ch == '>'){ + // character sequence "]]>" can't appear in content, therefore + // we should escape '>' + _printer.printText(">"); + } + else if ( _encodingInfo.isPrintable((char)ch) && XML11Char.isXML11ValidLiteral(ch)) { _printer.printText((char)ch); - } else { - printHex(ch); + } + else { + printHex(ch); } } - protected final void surrogates(int high, int low) throws IOException{ + protected final void surrogates(int high, int low, boolean inContent) throws IOException{ if (XMLChar.isHighSurrogate(high)) { if (!XMLChar.isLowSurrogate(low)) { //Invalid XML @@ -404,7 +406,7 @@ extends XMLSerializer { fatalError("The character '"+(char)supplemental+"' is an invalid XML character"); } else { - if (content().inCData ) { + if (inContent && content().inCData) { _printer.printText("]]>&#x"); _printer.printText(Integer.toHexString(supplemental)); _printer.printText("; 0 ) { - ch = chars[start++]; + char ch = chars[start++]; if (!XML11Char.isXML11Valid(ch)) { // check if it is surrogate if ( length-- > 0) { - surrogates(ch, chars[start++]); + surrogates(ch, chars[start++], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; } - if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) + if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) { _printer.printText( ch ); - else + } + else { printXMLChar( ch ); + } } - } else { + } + else { // Not preserving spaces: print one part at a time, and // use spaces between parts to break them into different // lines. Spaces at beginning of line will be stripped // by printing mechanism. Line terminator is treated // no different than other text part. while ( length-- > 0 ) { - ch = chars[start++]; + char ch = chars[start++]; if (!XML11Char.isXML11Valid(ch)) { // check if it is surrogate if ( length-- > 0) { - surrogates(ch, chars[start++]); + surrogates(ch, chars[start++], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; } - if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) + if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) { _printer.printText( ch ); - else + } + else { printXMLChar( ch ); + } } } } - public boolean reset() { super.reset(); return true; - } } diff --git a/jaxp/src/com/sun/org/apache/xml/internal/serialize/XMLSerializer.java b/jaxp/src/com/sun/org/apache/xml/internal/serialize/XMLSerializer.java index e33fb5171b0..884fd4b5fe5 100644 --- a/jaxp/src/com/sun/org/apache/xml/internal/serialize/XMLSerializer.java +++ b/jaxp/src/com/sun/org/apache/xml/internal/serialize/XMLSerializer.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2002,2004,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 * @@ -18,8 +19,6 @@ * limitations under the License. */ - - // Sep 14, 2000: // Fixed problem with namespace handling. Contributed by // David Blondeau @@ -33,14 +32,13 @@ // Aug 21, 2000: // Added ability to omit DOCTYPE declaration. - package com.sun.org.apache.xml.internal.serialize; - import java.io.IOException; import java.io.OutputStream; import java.io.Writer; -import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; import com.sun.org.apache.xerces.internal.util.NamespaceSupport; @@ -50,6 +48,7 @@ import com.sun.org.apache.xerces.internal.util.XMLSymbols; import com.sun.org.apache.xerces.internal.xni.NamespaceContext; import org.w3c.dom.Attr; import org.w3c.dom.DOMError; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -71,9 +70,9 @@ import org.xml.sax.helpers.AttributesImpl; * The serializer supports both DOM and SAX. SAX serializing is done by firing * SAX events and using the serializer as a document handler. DOM serializing is done * by calling {@link #serialize(Document)} or by using DOM Level 3 - * {@link org.w3c.dom.ls.DOMSerializer} and - * serializing with {@link org.w3c.dom.ls.DOMSerializer#write}, - * {@link org.w3c.dom.ls.DOMSerializer#writeToString}. + * {@link org.w3c.dom.ls.LSSerializer} and + * serializing with {@link org.w3c.dom.ls.LSSerializer#write}, + * {@link org.w3c.dom.ls.LSSerializer#writeToString}. *

* If an I/O exception occurs while serializing, the serializer * will not throw an exception directly, but only throw it @@ -195,7 +194,7 @@ extends BaseMarkupSerializer { /** * This methods turns on namespace fixup algorithm during * DOM serialization. - * @see org.w3c.dom.ls.DOMSerializer + * @see org.w3c.dom.ls.LSSerializer * * @param namespaces */ @@ -222,7 +221,6 @@ extends BaseMarkupSerializer { ElementState state; String name; String value; - boolean addNSAttr = false; if (DEBUG) { System.out.println("==>startElement("+namespaceURI+","+localName+ @@ -277,13 +275,16 @@ extends BaseMarkupSerializer { if (namespaceURI != null && ! namespaceURI.equals( "" )) { String prefix; prefix = getPrefix( namespaceURI ); - if (prefix != null && prefix.length() > 0) + if (prefix != null && prefix.length() > 0) { rawName = prefix + ":" + localName; - else + } + else { rawName = localName; - } else + } + } + else { rawName = localName; - addNSAttr = true; + } } _printer.printText( '<' ); @@ -334,18 +335,18 @@ extends BaseMarkupSerializer { } if (_prefixes != null) { - Enumeration keys; - - keys = _prefixes.keys(); - while (keys.hasMoreElements()) { + Iterator entries = _prefixes.entrySet().iterator(); + while (entries.hasNext()) { _printer.printSpace(); - value = (String) keys.nextElement(); - name = (String) _prefixes.get( value ); + Map.Entry entry = (Map.Entry) entries.next(); + value = (String) entry.getKey(); + name = (String) entry.getValue(); if (name.length() == 0) { _printer.printText( "xmlns=\"" ); printEscaped( value ); _printer.printText( '"' ); - } else { + } + else { _printer.printText( "xmlns:" ); _printer.printText( name ); _printer.printText( "=\"" ); @@ -770,13 +771,11 @@ extends BaseMarkupSerializer { // xmlns:foo = "" } continue; - } else { // xmlns - // empty prefix is always bound ("" or some string) - - value = fSymbolTable.addSymbol(value); - fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, value); - continue; } + // xmlns --- empty prefix is always bound ("" or some string) + value = fSymbolTable.addSymbol(value); + fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, value); + continue; } // end-else: valid declaration } // end-if: namespace declaration } // end-for @@ -958,22 +957,20 @@ extends BaseMarkupSerializer { // xmlns:foo = "" } continue; - } else { // xmlns - // empty prefix is always bound ("" or some string) - - uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING); - localUri=fLocalNSBinder.getURI(XMLSymbols.EMPTY_STRING); - value = fSymbolTable.addSymbol(value); - if (localUri == null ){ - // declaration was not printed while fixing element namespace binding - if (fNamespacePrefixes) { - printNamespaceAttr(XMLSymbols.EMPTY_STRING, value); - } - // case 4 does not apply here since attributes can't use - // default namespace - } - continue; } + // xmlns --- empty prefix is always bound ("" or some string) + uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING); + localUri= fLocalNSBinder.getURI(XMLSymbols.EMPTY_STRING); + value = fSymbolTable.addSymbol(value); + if (localUri == null ) { + // declaration was not printed while fixing element namespace binding + if (fNamespacePrefixes) { + printNamespaceAttr(XMLSymbols.EMPTY_STRING, value); + } + // case 4 does not apply here since attributes can't use + // default namespace + } + continue; } uri = fSymbolTable.addSymbol(uri); @@ -1195,8 +1192,6 @@ extends BaseMarkupSerializer { AttributesImpl attrsOnly; String rawName; int i; - int indexColon; - String prefix; int length; if (attrs == null) { @@ -1233,7 +1228,7 @@ extends BaseMarkupSerializer { int ch = source.charAt(i); if (!XMLChar.isValid(ch)) { if (++i < length) { - surrogates(ch, source.charAt(i)); + surrogates(ch, source.charAt(i), false); } else { fatalError("The character '" + (char) ch + "' is an invalid XML character"); } @@ -1291,16 +1286,17 @@ extends BaseMarkupSerializer { if (!XMLChar.isValid(ch)) { // check if it is surrogate if (++index 0 ) { - ch = chars[start++]; + char ch = chars[start++]; if (!XMLChar.isValid(ch)) { // check if it is surrogate if ( length-- > 0 ) { - surrogates(ch, chars[start++]); + surrogates(ch, chars[start++], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; } @@ -1363,13 +1358,13 @@ extends BaseMarkupSerializer { // by printing mechanism. Line terminator is treated // no different than other text part. while ( length-- > 0 ) { - ch = chars[start++]; + char ch = chars[start++]; if (!XMLChar.isValid(ch)) { // check if it is surrogate if ( length-- > 0 ) { - surrogates(ch, chars[start++]); + surrogates(ch, chars[start++], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; } diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 705ba65194d..a7525e9cd6a 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -252,3 +252,4 @@ efe2bc258c78af49de9517a4a5699d3a2e630c44 jdk9-b02 da44a8bdf1f3fdd518e7d785d60cc1b15983b176 jdk9-b04 eae966c8133fec0a8bf9e16d1274a4ede3c0fb52 jdk9-b05 cf0a6e41670f990414cd337000ad5f3bd1908073 jdk9-b06 +856a9132f506cafe2f251c1a16a0b14e4d16048d jdk9-b07 diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/JDefinedClass.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/JDefinedClass.java index faf99d0a4d4..d0b234864d1 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/JDefinedClass.java +++ b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/JDefinedClass.java @@ -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 @@ -71,6 +71,9 @@ public class JDefinedClass /** Static initializer, if this class has one */ private JBlock init = null; + /** Instance initializer, if this class has one */ + private JBlock instanceInit = null; + /** class javadoc */ private JDocComment jdoc = null; @@ -517,6 +520,18 @@ public class JDefinedClass return init; } + /** + * Creates, if necessary, and returns the instance initializer + * for this class. + * + * @return JBlock containing initialization statements for this class + */ + public JBlock instanceInit() { + if (instanceInit == null) + instanceInit = new JBlock(); + return instanceInit; + } + /** * Adds a constructor to this class. * @@ -793,6 +808,8 @@ public class JDefinedClass f.d(field); if (init != null) f.nl().p("static").s(init); + if (instanceInit != null) + f.nl().s(instanceInit); for (JMethod m : constructors) { f.nl().d(m); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/EncoderFactory.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/EncoderFactory.java index 15905039cc8..f11c4e376d6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/EncoderFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/EncoderFactory.java @@ -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 @@ -28,46 +28,20 @@ */ package com.sun.codemodel.internal.util; -import java.lang.reflect.Constructor; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; /** * Creates {@link CharsetEncoder} from a charset name. * - * Fixes a MS1252 handling bug in JDK1.4.2. - * * @author * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) */ public class EncoderFactory { - public static CharsetEncoder createEncoder( String encodin ) { + public static CharsetEncoder createEncoder( String encodin ) { Charset cs = Charset.forName(System.getProperty("file.encoding")); CharsetEncoder encoder = cs.newEncoder(); - - if( cs.getClass().getName().equals("sun.nio.cs.MS1252") ) { - try { - // at least JDK1.4.2_01 has a bug in MS1252 encoder. - // specifically, it returns true for any character. - // return a correct encoder to workaround this problem - - // statically binding to MS1252Encoder will cause a Link error - // (at least in IBM JDK1.4.1) - @SuppressWarnings("unchecked") - Class ms1252encoder = (Class) Class.forName("com.sun.codemodel.internal.util.MS1252Encoder"); - Constructor c = ms1252encoder.getConstructor(new Class[]{ - Charset.class - }); - return c.newInstance(new Object[]{cs}); - } catch( Throwable t ) { - // if something funny happens, ignore it and fall back to - // a broken MS1252 encoder. It's probably still better - // than choking here. - return encoder; - } - } - return encoder; } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/MS1252Encoder.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/MS1252Encoder.java deleted file mode 100644 index 709dee31ac5..00000000000 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/MS1252Encoder.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 1997, 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. 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. - */ - -/* - * @(#)$Id: MS1252Encoder.java,v 1.2 2005/09/10 19:07:33 kohsuke Exp $ - */ -package com.sun.codemodel.internal.util; - -import java.nio.charset.Charset; - -/** - * MS1252 encoder that corrects a bug in JDK1.4.2_01. - * - *

- * See - * http://www.microsoft.com/globaldev/reference/sbcs/1252.htm - * for the normative definition. - * - * This code depends on Sun internal package, so we have to make sure - * it won't be executed on other JDKs. - */ -public final class MS1252Encoder extends SingleByteEncoder { - - public MS1252Encoder(Charset cs) { - super(cs, index1, index2, 0xFF00, 0x00FF, 8); - } - - private final static String index2 = - "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" + - "\b\t\n\u000B\f\r\u000E\u000F" + - "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" + - "\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F" + - "\u0020\u0021\"\u0023\u0024\u0025\u0026\'" + - "\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F" + - "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037" + - "\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F" + - "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047" + - "\u0048\u0049\u004A\u004B\u004C\u004D\u004E\u004F" + - "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057" + - "\u0058\u0059\u005A\u005B\\\u005D\u005E\u005F" + - "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067" + - "\u0068\u0069\u006A\u006B\u006C\u006D\u006E\u006F" + - "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077" + - "\u0078\u0079\u007A\u007B\u007C\u007D\u007E\u007F" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u00A0\u00A1\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7" + - "\u00A8\u00A9\u00AA\u00AB\u00AC\u00AD\u00AE\u00AF" + - "\u00B0\u00B1\u00B2\u00B3\u00B4\u00B5\u00B6\u00B7" + - "\u00B8\u00B9\u00BA\u00BB\u00BC\u00BD\u00BE\u00BF" + - "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7" + - "\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF" + - "\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7" + - "\u00D8\u00D9\u00DA\u00DB\u00DC\u00DD\u00DE\u00DF" + - "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7" + - "\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF" + - "\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7" + - "\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u008C\u009C\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u008A\u009A\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u009F\u0000\u0000\u0000\u0000\u008E\u009E\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0083\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0088\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0098\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0096\u0097\u0000" + - "\u0000\u0000\u0091\u0092\u0082\u0000\u0093\u0094" + - "\u0084\u0000\u0086\u0087\u0095\u0000\u0000\u0000" + - "\u0085\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0089\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u008B\u009B\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0080\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0099\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"; - - private final static short index1[] = { - 0, 256, 461, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 698, 920, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - }; - - public boolean canEncode(char c) { - char test = index2.charAt( index1[(c&0xFF00)>>8] + (c&0xFF) ); - return test!=0; - } - -} diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/SingleByteEncoder.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/SingleByteEncoder.java deleted file mode 100644 index 3ae1afba7f8..00000000000 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/SingleByteEncoder.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 1997, 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. 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. - */ - -/* - * @(#)SingleByteEncoder.java 1.14 03/01/23 - */ - -package com.sun.codemodel.internal.util; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; - -import sun.nio.cs.Surrogate; - - -abstract class SingleByteEncoder - extends CharsetEncoder -{ - - private final short index1[]; - private final String index2; - private final int mask1; - private final int mask2; - private final int shift; - - private final Surrogate.Parser sgp = new Surrogate.Parser(); - - protected SingleByteEncoder(Charset cs, - short[] index1, String index2, - int mask1, int mask2, int shift) - { - super(cs, 1.0f, 1.0f); - this.index1 = index1; - this.index2 = index2; - this.mask1 = mask1; - this.mask2 = mask2; - this.shift = shift; - } - - public boolean canEncode(char c) { - char testEncode; - testEncode = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - if (testEncode == '\u0000') - return false; - else - return true; - } - - private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { - char[] sa = src.array(); - int sp = src.arrayOffset() + src.position(); - int sl = src.arrayOffset() + src.limit(); - sp = (sp <= sl ? sp : sl); - byte[] da = dst.array(); - int dp = dst.arrayOffset() + dst.position(); - int dl = dst.arrayOffset() + dst.limit(); - dp = (dp <= dl ? dp : dl); - - try { - while (sp < sl) { - char c = sa[sp]; - if (Surrogate.is(c)) { - if (sgp.parse(c, sa, sp, sl) < 0) - return sgp.error(); - return sgp.unmappableResult(); - } - if (c >= '\uFFFE') - return CoderResult.unmappableForLength(1); - if (dl - dp < 1) - return CoderResult.OVERFLOW; - - char e = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - - // If output byte is zero because input char is zero - // then character is mappable, o.w. fail - if (e == '\u0000' && c != '\u0000') - return CoderResult.unmappableForLength(1); - - sp++; - da[dp++] = (byte)e; - } - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); - } - } - - private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { - int mark = src.position(); - try { - while (src.hasRemaining()) { - char c = src.get(); - if (Surrogate.is(c)) { - if (sgp.parse(c, src) < 0) - return sgp.error(); - return sgp.unmappableResult(); - } - if (c >= '\uFFFE') - return CoderResult.unmappableForLength(1); - if (!dst.hasRemaining()) - return CoderResult.OVERFLOW; - - char e = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - - // If output byte is zero because input char is zero - // then character is mappable, o.w. fail - if (e == '\u0000' && c != '\u0000') - return CoderResult.unmappableForLength(1); - - mark++; - dst.put((byte)e); - } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); - } - } - - protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { - if (true && src.hasArray() && dst.hasArray()) - return encodeArrayLoop(src, dst); - else - return encodeBufferLoop(src, dst); - } - - public byte encode(char inputChar) { - return (byte)index2.charAt(index1[(inputChar & mask1) >> shift] + - (inputChar & mask2)); - } -} diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/Surrogate.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/Surrogate.java deleted file mode 100644 index 51bb024c042..00000000000 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/Surrogate.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (c) 1997, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.codemodel.internal.util; - -import java.nio.CharBuffer; -import java.nio.charset.CoderResult; - - -/** - * Utility class for dealing with surrogates. - * - * @author Mark Reinhold - * @version 1.11, 03/01/23 - */ - -class Surrogate { - - private Surrogate() { } - - // UTF-16 surrogate-character ranges - // - public static final char MIN_HIGH = '\uD800'; - public static final char MAX_HIGH = '\uDBFF'; - public static final char MIN_LOW = '\uDC00'; - public static final char MAX_LOW = '\uDFFF'; - public static final char MIN = MIN_HIGH; - public static final char MAX = MAX_LOW; - - // Range of UCS-4 values that need surrogates in UTF-16 - // - public static final int UCS4_MIN = 0x10000; - public static final int UCS4_MAX = (1 << 20) + UCS4_MIN - 1; - - /** - * Tells whether or not the given UTF-16 value is a high surrogate. - */ - public static boolean isHigh(int c) { - return (MIN_HIGH <= c) && (c <= MAX_HIGH); - } - - /** - * Tells whether or not the given UTF-16 value is a low surrogate. - */ - public static boolean isLow(int c) { - return (MIN_LOW <= c) && (c <= MAX_LOW); - } - - /** - * Tells whether or not the given UTF-16 value is a surrogate character, - */ - public static boolean is(int c) { - return (MIN <= c) && (c <= MAX); - } - - /** - * Tells whether or not the given UCS-4 character must be represented as a - * surrogate pair in UTF-16. - */ - public static boolean neededFor(int uc) { - return (uc >= UCS4_MIN) && (uc <= UCS4_MAX); - } - - /** - * Returns the high UTF-16 surrogate for the given UCS-4 character. - */ - public static char high(int uc) { - return (char)(0xd800 | (((uc - UCS4_MIN) >> 10) & 0x3ff)); - } - - /** - * Returns the low UTF-16 surrogate for the given UCS-4 character. - */ - public static char low(int uc) { - return (char)(0xdc00 | ((uc - UCS4_MIN) & 0x3ff)); - } - - /** - * Converts the given surrogate pair into a 32-bit UCS-4 character. - */ - public static int toUCS4(char c, char d) { - return (((c & 0x3ff) << 10) | (d & 0x3ff)) + 0x10000; - } - - /** - * Surrogate parsing support. Charset implementations may use instances of - * this class to handle the details of parsing UTF-16 surrogate pairs. - */ - public static class Parser { - - public Parser() { } - - private int character; // UCS-4 - private CoderResult error = CoderResult.UNDERFLOW; - private boolean isPair; - - /** - * Returns the UCS-4 character previously parsed. - */ - public int character() { - return character; - } - - /** - * Tells whether or not the previously-parsed UCS-4 character was - * originally represented by a surrogate pair. - */ - public boolean isPair() { - return isPair; - } - - /** - * Returns the number of UTF-16 characters consumed by the previous - * parse. - */ - public int increment() { - return isPair ? 2 : 1; - } - - /** - * If the previous parse operation detected an error, return the object - * describing that error. - */ - public CoderResult error() { - return error; - } - - /** - * Returns an unmappable-input result object, with the appropriate - * input length, for the previously-parsed character. - */ - public CoderResult unmappableResult() { - return CoderResult.unmappableForLength(isPair ? 2 : 1); - } - - /** - * Parses a UCS-4 character from the given source buffer, handling - * surrogates. - * - * @param c The first character - * @param in The source buffer, from which one more character - * will be consumed if c is a high surrogate - * - * @return Either a parsed UCS-4 character, in which case the isPair() - * and increment() methods will return meaningful values, or - * -1, in which case error() will return a descriptive result - * object - */ - public int parse(char c, CharBuffer in) { - if (isHigh(c)) { - if (!in.hasRemaining()) { - error = CoderResult.UNDERFLOW; - return -1; - } - char d = in.get(); - if (isLow(d)) { - character = toUCS4(c, d); - isPair = true; - error = null; - return character; - } - error = CoderResult.malformedForLength(1); - return -1; - } - if (isLow(c)) { - error = CoderResult.malformedForLength(1); - return -1; - } - character = c; - isPair = false; - error = null; - return character; - } - - /** - * Parses a UCS-4 character from the given source buffer, handling - * surrogates. - * - * @param c The first character - * @param ia The input array, from which one more character - * will be consumed if c is a high surrogate - * @param ip The input index - * @param il The input limit - * - * @return Either a parsed UCS-4 character, in which case the isPair() - * and increment() methods will return meaningful values, or - * -1, in which case error() will return a descriptive result - * object - */ - public int parse(char c, char[] ia, int ip, int il) { - if (isHigh(c)) { - if (il - ip < 2) { - error = CoderResult.UNDERFLOW; - return -1; - } - char d = ia[ip + 1]; - if (isLow(d)) { - character = toUCS4(c, d); - isPair = true; - error = null; - return character; - } - error = CoderResult.malformedForLength(1); - return -1; - } - if (isLow(c)) { - error = CoderResult.malformedForLength(1); - return -1; - } - character = c; - isPair = false; - error = null; - return character; - } - - } - - /** - * Surrogate generation support. Charset implementations may use instances - * of this class to handle the details of generating UTF-16 surrogate - * pairs. - */ - public static class Generator { - - public Generator() { } - - private CoderResult error = CoderResult.OVERFLOW; - - /** - * If the previous generation operation detected an error, return the - * object describing that error. - */ - public CoderResult error() { - return error; - } - - /** - * Generates one or two UTF-16 characters to represent the given UCS-4 - * character. - * - * @param uc The UCS-4 character - * @param len The number of input bytes from which the UCS-4 value - * was constructed (used when creating result objects) - * @param dst The destination buffer, to which one or two UTF-16 - * characters will be written - * - * @return Either a positive count of the number of UTF-16 characters - * written to the destination buffer, or -1, in which case - * error() will return a descriptive result object - */ - public int generate(int uc, int len, CharBuffer dst) { - if (uc <= 0xffff) { - if (is(uc)) { - error = CoderResult.malformedForLength(len); - return -1; - } - if (dst.remaining() < 1) { - error = CoderResult.OVERFLOW; - return -1; - } - dst.put((char)uc); - error = null; - return 1; - } - if (uc < UCS4_MIN) { - error = CoderResult.malformedForLength(len); - return -1; - } - if (uc <= UCS4_MAX) { - if (dst.remaining() < 2) { - error = CoderResult.OVERFLOW; - return -1; - } - dst.put(high(uc)); - dst.put(low(uc)); - error = null; - return 2; - } - error = CoderResult.unmappableForLength(len); - return -1; - } - - /** - * Generates one or two UTF-16 characters to represent the given UCS-4 - * character. - * - * @param uc The UCS-4 character - * @param len The number of input bytes from which the UCS-4 value - * was constructed (used when creating result objects) - * @param da The destination array, to which one or two UTF-16 - * characters will be written - * @param dp The destination position - * @param dl The destination limit - * - * @return Either a positive count of the number of UTF-16 characters - * written to the destination buffer, or -1, in which case - * error() will return a descriptive result object - */ - public int generate(int uc, int len, char[] da, int dp, int dl) { - if (uc <= 0xffff) { - if (is(uc)) { - error = CoderResult.malformedForLength(len); - return -1; - } - if (dl - dp < 1) { - error = CoderResult.OVERFLOW; - return -1; - } - da[dp] = (char)uc; - error = null; - return 1; - } - if (uc < UCS4_MIN) { - error = CoderResult.malformedForLength(len); - return -1; - } - if (uc <= UCS4_MAX) { - if (dl - dp < 2) { - error = CoderResult.OVERFLOW; - return -1; - } - da[dp] = high(uc); - da[dp + 1] = low(uc); - error = null; - return 2; - } - error = CoderResult.unmappableForLength(len); - return -1; - } - - } - -} diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/writer/OutputStreamCodeWriter.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/writer/OutputStreamCodeWriter.java new file mode 100644 index 00000000000..76a0c9aecbf --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/writer/OutputStreamCodeWriter.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +/** + * Output all source files into a single stream. + * + * This is primarily for test purposes. + * + * @author + * Aleksei Valikov (valikov@gmx.net) + */ +package com.sun.codemodel.internal.writer; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import com.sun.codemodel.internal.CodeWriter; +import com.sun.codemodel.internal.JPackage; + +public class OutputStreamCodeWriter extends CodeWriter { + private final PrintStream out; + + /** + * @param os + * This stream will be closed at the end of the code generation. + */ + public OutputStreamCodeWriter(OutputStream os, String encoding) { + try { + this.out = new PrintStream(os, false, encoding); + } catch (UnsupportedEncodingException ueex) { + throw new IllegalArgumentException(ueex); + } + this.encoding = encoding; + } + + public OutputStream openBinary(JPackage pkg, String fileName) + throws IOException { + return new FilterOutputStream(out) { + public void close() { + // don't let this stream close + } + }; + } + + public void close() throws IOException { + out.close(); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties index 527ef0f4edd..dccb9d28c58 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties @@ -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,10 +30,10 @@ BASEDIR_DOESNT_EXIST = \ Non-existent directory: {0} VERSION = \ - schemagen 2.2.8-b130911.1802 + schemagen 2.2.9-b140218.1920 FULLVERSION = \ - schemagen full version "2.2.8-b130911.1802" + schemagen full version "2.2.9-b140218.1920" USAGE = \ Usage: schemagen [-options ...] \n\ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties index 0bd53b420ed..5a4be779856 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties @@ -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,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = Nicht erkanntes {0} in Zeile {1} Spalte {2} BASEDIR_DOESNT_EXIST = Nicht vorhandenes Verzeichnis: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen vollst\u00E4ndige Version "2.2.8-b130911.1802" +FULLVERSION = schemagen vollst\u00E4ndige Version "2.2.9-b140218.1920" USAGE = Verwendung: schemagen [-options ...] \nOptionen: \n\\ \\ \\ \\ -d : Gibt an, wo die von Prozessor und javac generierten Klassendateien gespeichert werden sollen\n\\ \\ \\ \\ -cp : Gibt an, wo die vom Benutzer angegebenen Dateien gespeichert sind\n\\ \\ \\ \\ -classpath : Gibt an, wo die vom Benutzer angegebenen Dateien gespeichert sind\n\\ \\ \\ \\ -encoding : Gibt die Codierung f\u00FCr die Annotationsverarbeitung/den javac-Aufruf an \n\\ \\ \\ \\ -episode : Generiert Episodendatei f\u00FCr separate Kompilierung\n\\ \\ \\ \\ -version : Zeigt Versionsinformation an\n\\ \\ \\ \\ -fullversion : Zeigt vollst\u00E4ndige Versionsinformationen an\n\\ \\ \\ \\ -help : Zeigt diese Verwendungsmeldung an diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties index 98e9702f276..938fbb767c6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties @@ -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,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = Aparece un {0} inesperado en la l\u00EDnea {1} y la colu BASEDIR_DOESNT_EXIST = Directorio no existente: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = versi\u00F3n completa de schemagen "2.2.8-b130911.1802" +FULLVERSION = versi\u00F3n completa de schemagen "2.2.9-b140218.1920" USAGE = Sintaxis: schemagen [-options ...] \nOpciones: \n\\ \\ \\ \\ -d : especifique d\u00F3nde se colocan los archivos de clase generados por javac y el procesador\n\\ \\ \\ \\ -cp : especifique d\u00F3nde se encuentran los archivos especificados por el usuario\n\\ \\ \\ \\ -encoding : especifique la codificaci\u00F3n que se va a utilizar para el procesamiento de anotaciones/llamada de javac\n\\ \\ \\ \\ -episode : genera un archivo de episodio para una compilaci\u00F3n diferente\n\\ \\ \\ \\ -version : muestra la informaci\u00F3n de la versi\u00F3n\n\\ \\ \\ \\ -fullversion : muestra la informaci\u00F3n completa de la versi\u00F3n\n\\ \\ \\ \\ -help : muestra este mensaje de sintaxis diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties index 10c3b15b701..183fdfdcb8d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties @@ -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,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = Un \u00E9l\u00E9ment {0} inattendu appara\u00EEt \u00E0 BASEDIR_DOESNT_EXIST = R\u00E9pertoire {0} inexistant -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = version compl\u00E8te de schemagen "2.2.8-b130911.1802" +FULLVERSION = version compl\u00E8te de schemagen "2.2.9-b140218.1920" USAGE = Syntaxe : schemagen [-options ...] \nOptions : \n\ \ \ \ -d : indiquez o\u00F9 placer les fichiers de classe g\u00E9n\u00E9r\u00E9s par le processeur et le compilateur javac\n\ \ \ \ -cp : indiquez o\u00F9 trouver les fichiers sp\u00E9cifi\u00E9s par l'utilisateur\n\ \ \ \ -classpath : indiquez o\u00F9 trouver les fichiers sp\u00E9cifi\u00E9s par l'utilisateur\n\ \ \ \ -encoding : indiquez l'encodage \u00E0 utiliser pour l'appel de javac/traitement de l'annotation \n\ \ \ \ -episode : g\u00E9n\u00E9rez un fichier d'\u00E9pisode pour la compilation s\u00E9par\u00E9e\n\ \ \ \ -version : affichez les informations de version\n\ \ \ \ -fullversion : affichez les informations compl\u00E8tes de version\n\ \ \ \ -help : affichez ce message de syntaxe diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties index 4cb120188fc..9275c115286 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties @@ -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,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = {0} imprevisto visualizzato sulla riga {1} colonna {2} BASEDIR_DOESNT_EXIST = Directory non esistente: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = versione completa schemagen "2.2.8-b130911.1802" +FULLVERSION = versione completa schemagen "2.2.9-b140218.1920" USAGE = Uso: schemagen [-options ...] \nOpzioni: \n\ \ \ \ -d : specifica dove posizionare il processore e i file della classe generata javac\n\ \ \ \ -cp : specifica dove trovare i file specificati dall'utente\n\ \ \ \ -classpath : specifica dove trovare i file specificati dall'utente\n\ \ \ \ -encoding : specifica la codifica da usare per l'elaborazione dell'annotazione/richiamo javac \n\ \ \ \ -episode : genera il file di episodio per la compilazione separata\n\ \ \ \ -version : visualizza le informazioni sulla versione\n\ \ \ \ -fullversion : visualizza le informazioni sulla versione completa\n\ \ \ \ -help : visualizza questo messaggio sull'uso diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties index 5e2fb5d1f46..f55d2632a9e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties @@ -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,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \u4E88\u671F\u3057\u306A\u3044{0}\u304C\u884C{1}\u3001\u BASEDIR_DOESNT_EXIST = \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u5B58\u5728\u3057\u307E\u305B\u3093: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.8-b130911.1802" +FULLVERSION = schemagen\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.9-b140218.1920" USAGE = \u4F7F\u7528\u65B9\u6CD5: schemagen [-options ...] \n\u30AA\u30D7\u30B7\u30E7\u30F3: \n\ \ \ \ -d : \u30D7\u30ED\u30BB\u30C3\u30B5\u304A\u3088\u3073javac\u304C\u751F\u6210\u3057\u305F\u30AF\u30E9\u30B9\u30FB\u30D5\u30A1\u30A4\u30EB\u3092\u7F6E\u304F\u4F4D\u7F6E\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -cp : \u30E6\u30FC\u30B6\u30FC\u304C\u6307\u5B9A\u3057\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u691C\u7D22\u3059\u308B\u4F4D\u7F6E\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -classpath : \u30E6\u30FC\u30B6\u30FC\u304C\u6307\u5B9A\u3057\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u691C\u7D22\u3059\u308B\u4F4D\u7F6E\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -encoding : \u6CE8\u91C8\u51E6\u7406/javac\u547C\u51FA\u3057\u306B\u4F7F\u7528\u3059\u308B\u30A8\u30F3\u30B3\u30FC\u30C7\u30A3\u30F3\u30B0\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -episode : \u30B3\u30F3\u30D1\u30A4\u30EB\u3054\u3068\u306B\u30A8\u30D4\u30BD\u30FC\u30C9\u30FB\u30D5\u30A1\u30A4\u30EB\u3092\u751F\u6210\u3057\u307E\u3059\n\ \ \ \ -version : \u30D0\u30FC\u30B8\u30E7\u30F3\u60C5\u5831\u3092\u8868\u793A\u3057\u307E\u3059\n\ \ \ \ -fullversion : \u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3\u60C5\u5831\u3092\u8868\u793A\u3057\u307E\u3059\n\ \ \ \ -help : \u3053\u306E\u4F7F\u7528\u4F8B\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u8868\u793A\u3057\u307E\u3059 diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties index 2a2936f39fe..0070635d69d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties @@ -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,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \uC608\uC0C1\uCE58 \uC54A\uC740 {0}\uC774(\uAC00) {1}\uD BASEDIR_DOESNT_EXIST = \uC874\uC7AC\uD558\uC9C0 \uC54A\uB294 \uB514\uB809\uD1A0\uB9AC: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen \uC815\uC2DD \uBC84\uC804 "2.2.8-b130911.1802" +FULLVERSION = schemagen \uC815\uC2DD \uBC84\uC804 "2.2.9-b140218.1920" USAGE = \uC0AC\uC6A9\uBC95: schemagen [-options ...] \n\uC635\uC158: \n\ \ \ \ -d : \uD504\uB85C\uC138\uC11C \uBC0F javac\uC5D0\uC11C \uC0DD\uC131\uD55C \uD074\uB798\uC2A4 \uD30C\uC77C\uC744 \uBC30\uCE58\uD560 \uC704\uCE58\uB97C \uC9C0\uC815\uD569\uB2C8\uB2E4.\n\ \ \ \ -cp : \uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC815\uD55C \uD30C\uC77C\uC744 \uCC3E\uC744 \uC704\uCE58\uB97C \uC9C0\uC815\uD569\uB2C8\uB2E4.\n\ \ \ \ -classpath : \uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC815\uD55C \uD30C\uC77C\uC744 \uCC3E\uC744 \uC704\uCE58\uB97C \uC9C0\uC815\uD569\uB2C8\uB2E4.\n\ \ \ \ -encoding : \uC8FC\uC11D \uCC98\uB9AC/javac \uD638\uCD9C\uC5D0 \uC0AC\uC6A9\uD560 \uC778\uCF54\uB529\uC744 \uC9C0\uC815\uD569\uB2C8\uB2E4. \n\ \ \ \ -episode : \uBCC4\uB3C4 \uCEF4\uD30C\uC77C\uC744 \uC704\uD574 episode \uD30C\uC77C\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4.\n\ \ \ \ -version : \uBC84\uC804 \uC815\uBCF4\uB97C \uD45C\uC2DC\uD569\uB2C8\uB2E4.\n\ \ \ \ -fullversion : \uC815\uC2DD \uBC84\uC804 \uC815\uBCF4\uB97C \uD45C\uC2DC\uD569\uB2C8\uB2E4.\n\ \ \ \ -help : \uC774 \uC0AC\uC6A9\uBC95 \uBA54\uC2DC\uC9C0\uB97C \uD45C\uC2DC\uD569\uB2C8\uB2E4. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties index 148448e1e1f..3ef7960b487 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties @@ -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,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = {0} inesperado aparece na linha {1} coluna {2} BASEDIR_DOESNT_EXIST = Diret\u00F3rio n\u00E3o existente: {0} -VERSION = gera\u00E7\u00E3o do esquema 2.2.8-b130911.1802 +VERSION = gera\u00E7\u00E3o do esquema 2.2.9-b140218.1920 -FULLVERSION = vers\u00E3o completa da gera\u00E7\u00E3o do esquema "2.2.8-b130911.1802" +FULLVERSION = vers\u00E3o completa da gera\u00E7\u00E3o do esquema "2.2.9-b140218.1920" USAGE = Uso: gera\u00E7\u00E3o do esquema [-options ...] \nOp\u00E7\u00F5es: \n\\ \\ \\ \\ -d : especificar onde colocar o processador e os arquivos da classe gerados por javac\n\\ \\ \\ \\ -cp : especificar onde localizar arquivos especificados pelo usu\u00E1rio\n\\ \\ \\ \\ -classpath : especificar onde localizar os arquivos especificados pelo usu\u00E1rio\n\\ \\ \\ \\ -encoding : especificar codifica\u00E7\u00E3o a ser usada para processamento de anota\u00E7\u00E3o/chamada javac \n\\ \\ \\ \\ -episode : gerar arquivo do epis\u00F3dio para compila\u00E7\u00E3o separada\n\\ \\ \\ \\ -version : exibir informa\u00E7\u00F5es da vers\u00E3o\n\\ \\ \\ \\ -fullversion : exibir informa\u00E7\u00F5es da vers\u00E3o completa\n\\ \\ \\ \\ -help : exibir esta mensagem de uso diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties index 09bac14c324..d800201019c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties @@ -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,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \u5728\u7B2C {1} \u884C, \u7B2C {2} \u5217\u51FA\u73B0\u BASEDIR_DOESNT_EXIST = \u4E0D\u5B58\u5728\u7684\u76EE\u5F55: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.8-b130911.1802" +FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.9-b140218.1920" USAGE = \u7528\u6CD5: schemagen [-options ...] \n\u9009\u9879: \n\ \ \ \ -d : \u6307\u5B9A\u653E\u7F6E\u5904\u7406\u7A0B\u5E8F\u548C javac \u751F\u6210\u7684\u7C7B\u6587\u4EF6\u7684\u4F4D\u7F6E\n\ \ \ \ -cp : \u6307\u5B9A\u67E5\u627E\u7528\u6237\u6307\u5B9A\u6587\u4EF6\u7684\u4F4D\u7F6E\n\ \ \ \ -classpath : \u6307\u5B9A\u67E5\u627E\u7528\u6237\u6307\u5B9A\u6587\u4EF6\u7684\u4F4D\u7F6E\n\ \ \ \ -encoding : \u6307\u5B9A\u7528\u4E8E\u6CE8\u91CA\u5904\u7406/javac \u8C03\u7528\u7684\u7F16\u7801\n\ \ \ \ -episode : \u751F\u6210\u7247\u6BB5\u6587\u4EF6\u4EE5\u4F9B\u5355\u72EC\u7F16\u8BD1\n\ \ \ \ -version : \u663E\u793A\u7248\u672C\u4FE1\u606F\n\ \ \ \ -fullversion : \u663E\u793A\u5B8C\u6574\u7684\u7248\u672C\u4FE1\u606F\n\ \ \ \ -help : \u663E\u793A\u6B64\u7528\u6CD5\u6D88\u606F diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties index 08fb9fe24e3..6976c6faf3c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties @@ -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,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \u672A\u9810\u671F\u7684 {0} \u986F\u793A\u65BC\u884C {1 BASEDIR_DOESNT_EXIST = \u4E0D\u5B58\u5728\u7684\u76EE\u9304: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.8-b130911.1802" +FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.9-b140218.1920" USAGE = \u7528\u6CD5: schemagen [-options ...] \n\u9078\u9805: \n\\ \\ \\ \\ -d : \u6307\u5B9A\u8655\u7406\u5668\u4EE5\u53CA javac \u7522\u751F\u7684\u985E\u5225\u6A94\u6848\u653E\u7F6E\u4F4D\u7F6E\n\\ \\ \\ \\ -cp : \u6307\u5B9A\u8981\u5C0B\u627E\u4F7F\u7528\u8005\u6307\u5B9A\u6A94\u6848\u7684\u4F4D\u7F6E\n\\ \\ \\ \\ -classpath : \u6307\u5B9A\u8981\u5C0B\u627E\u4F7F\u7528\u8005\u6307\u5B9A\u6A94\u6848\u7684\u4F4D\u7F6E\n\\ \\ \\ \\ -encoding : \u6307\u5B9A\u8981\u7528\u65BC\u8A3B\u89E3\u8655\u7406/javac \u547C\u53EB\u7684\u7DE8\u78BC \n\\ \\ \\ \\ -episode : \u7522\u751F\u7368\u7ACB\u7DE8\u8B6F\u7684\u4E8B\u4EF6 (episode) \u6A94\u6848\n\\ \\ \\ \\ -version : \u986F\u793A\u7248\u672C\u8CC7\u8A0A\n\\ \\ \\ \\ -fullversion : \u986F\u793A\u5B8C\u6574\u7248\u672C\u8CC7\u8A0A\n\\ \\ \\ \\ -help : \u986F\u793A\u6B64\u7528\u6CD5\u8A0A\u606F diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/model/Message.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/model/Message.java index b3fff34c764..8d1386f5094 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/model/Message.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/model/Message.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 @@ -177,7 +177,8 @@ public abstract class Message extends ModelObject { throw new AbortException(); } _parameters.add(p); - _parametersByName.put(p.getName(), p); + String name = p.getCustomName() != null ? p.getCustomName() : p.getName(); + _parametersByName.put(name, p); } public Parameter getParameterByName(String name) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/annotation/WebServiceVisitor.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/annotation/WebServiceVisitor.java index 26c868d716e..ec8e5ec6abb 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/annotation/WebServiceVisitor.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/annotation/WebServiceVisitor.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,7 +31,6 @@ import com.sun.tools.internal.ws.util.ClassNameInfo; import com.sun.tools.internal.ws.wsdl.document.soap.SOAPStyle; import com.sun.xml.internal.ws.model.RuntimeModeler; -import javax.annotation.processing.ProcessingEnvironment; import javax.jws.Oneway; import javax.jws.WebMethod; import javax.jws.WebParam; @@ -609,12 +608,6 @@ public abstract class WebServiceVisitor extends SimpleElementVisitor6 +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn Driver.FilePrologComment = \ - This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 \n\ + This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.9-b140218.1920 \n\ See http://java.sun.com/xml/jaxb \n\ Any modifications to this file will be lost upon recompilation of the source schema. \n\ Generated on: {0} \n Driver.Version = \ - xjc 2.2.8-b130911.1802 + xjc 2.2.9-b140218.1920 Driver.FullVersion = \ - xjc full version "2.2.8-b130911.1802" + xjc full version "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties index 6c14d7cf277..51d70085075 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties @@ -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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = Ein Schema wird kompiliert ... Driver.FailedToGenerateCode = Code konnte nicht erzeugt werden. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Diese Datei wurde mit der JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 generiert \nSiehe http://java.sun.com/xml/jaxb \n\u00c4nderungen an dieser Datei gehen bei einer Neukompilierung des Quellschemas verloren. \nGeneriert: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Diese Datei wurde mit der JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.9-b140218.1920 generiert \nSiehe http://java.sun.com/xml/jaxb \n\u00c4nderungen an dieser Datei gehen bei einer Neukompilierung des Quellschemas verloren. \nGeneriert: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = xjc vollst\u00E4ndige Version "2.2.8-b130911.1802" +Driver.FullVersion = xjc vollst\u00E4ndige Version "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties index e62bf41d574..acdbffd5ad1 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties @@ -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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = Compilando un esquema... Driver.FailedToGenerateCode = Fallo al producir c\u00f3digo. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Este archivo ha sido generado por la arquitectura JavaTM para la implantaci\u00f3n de la referencia de enlace (JAXB) XML v2.2.8-b130911.1802 \nVisite http://java.sun.com/xml/jaxb \nTodas las modificaciones realizadas en este archivo se perder\u00e1n si se vuelve a compilar el esquema de origen. \nGenerado el: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Este archivo ha sido generado por la arquitectura JavaTM para la implantaci\u00f3n de la referencia de enlace (JAXB) XML v2.2.9-b140218.1920 \nVisite http://java.sun.com/xml/jaxb \nTodas las modificaciones realizadas en este archivo se perder\u00e1n si se vuelve a compilar el esquema de origen. \nGenerado el: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = versi\u00F3n completa de xjc "2.2.8-b130911.1802" +Driver.FullVersion = versi\u00F3n completa de xjc "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties index 36adafe095a..76aec21fd2d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties @@ -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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = compilation d'un sch\u00e9ma... Driver.FailedToGenerateCode = Echec de la production du code. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Ce fichier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9 par l''impl\u00e9mentation de r\u00e9f\u00e9rence JavaTM Architecture for XML Binding (JAXB), v2.2.8-b130911.1802 \nVoir http://java.sun.com/xml/jaxb \nToute modification apport\u00e9e \u00e0 ce fichier sera perdue lors de la recompilation du sch\u00e9ma source. \nG\u00e9n\u00e9r\u00e9 le : {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Ce fichier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9 par l''impl\u00e9mentation de r\u00e9f\u00e9rence JavaTM Architecture for XML Binding (JAXB), v2.2.9-b140218.1920 \nVoir http://java.sun.com/xml/jaxb \nToute modification apport\u00e9e \u00e0 ce fichier sera perdue lors de la recompilation du sch\u00e9ma source. \nG\u00e9n\u00e9r\u00e9 le : {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = version compl\u00E8te xjc "2.2.8-b130911.1802" +Driver.FullVersion = version compl\u00E8te xjc "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties index 93b1533ec2a..9a9a5332e5c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties @@ -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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = compilazione di uno schema in corso... Driver.FailedToGenerateCode = Produzione del codice non riuscita. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Questo file \u00e8 stato generato dall''architettura JavaTM per XML Binding (JAXB) Reference Implementation, v2.2.8-b130911.1802 \nVedere http://java.sun.com/xml/jaxb \nQualsiasi modifica a questo file andr\u00e0 persa durante la ricompilazione dello schema di origine. \nGenerato il: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Questo file \u00e8 stato generato dall''architettura JavaTM per XML Binding (JAXB) Reference Implementation, v2.2.9-b140218.1920 \nVedere http://java.sun.com/xml/jaxb \nQualsiasi modifica a questo file andr\u00e0 persa durante la ricompilazione dello schema di origine. \nGenerato il: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = versione completa xjc "2.2.8-b130911.1802" +Driver.FullVersion = versione completa xjc "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties index 088938a1b7f..8fc9f7b12fd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties @@ -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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = \u30b9\u30ad\u30fc\u30de\u306e\u30b3\u30f3\u30d1\u30a4\ Driver.FailedToGenerateCode = \u30b3\u30fc\u30c9\u306e\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = \u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306f\u3001JavaTM Architecture for XML Binding(JAXB) Reference Implementation\u3001v2.2.8-b130911.1802\u306b\u3088\u3063\u3066\u751f\u6210\u3055\u308c\u307e\u3057\u305f \nhttp://java.sun.com/xml/jaxb\u3092\u53c2\u7167\u3057\u3066\u304f\u3060\u3055\u3044 \n\u30bd\u30fc\u30b9\u30fb\u30b9\u30ad\u30fc\u30de\u306e\u518d\u30b3\u30f3\u30d1\u30a4\u30eb\u6642\u306b\u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u5909\u66f4\u306f\u5931\u308f\u308c\u307e\u3059\u3002 \n\u751f\u6210\u65e5: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = \u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306f\u3001JavaTM Architecture for XML Binding(JAXB) Reference Implementation\u3001v2.2.9-b140218.1920\u306b\u3088\u3063\u3066\u751f\u6210\u3055\u308c\u307e\u3057\u305f \nhttp://java.sun.com/xml/jaxb\u3092\u53c2\u7167\u3057\u3066\u304f\u3060\u3055\u3044 \n\u30bd\u30fc\u30b9\u30fb\u30b9\u30ad\u30fc\u30de\u306e\u518d\u30b3\u30f3\u30d1\u30a4\u30eb\u6642\u306b\u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u5909\u66f4\u306f\u5931\u308f\u308c\u307e\u3059\u3002 \n\u751f\u6210\u65e5: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = xjc\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.8-b130911.1802" +Driver.FullVersion = xjc\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties index 5d2bc734884..7a34340441a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties @@ -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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = \uc2a4\ud0a4\ub9c8\ub97c \ucef4\ud30c\uc77c\ud558\ub294 Driver.FailedToGenerateCode = \ucf54\ub4dc \uc0dd\uc131\uc744 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = \uc774 \ud30c\uc77c\uc740 JAXB(JavaTM Architecture for XML Binding) \ucc38\uc870 \uad6c\ud604 2.2.8-b130911.1802 \ubc84\uc804\uc744 \ud1b5\ud574 \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \nhttp://java.sun.com/xml/jaxb\ub97c \ucc38\uc870\ud558\uc2ed\uc2dc\uc624. \n\uc774 \ud30c\uc77c\uc744 \uc218\uc815\ud558\uba74 \uc18c\uc2a4 \uc2a4\ud0a4\ub9c8\ub97c \uc7ac\ucef4\ud30c\uc77c\ud560 \ub54c \uc218\uc815 \uc0ac\ud56d\uc774 \uc190\uc2e4\ub429\ub2c8\ub2e4. \n\uc0dd\uc131 \ub0a0\uc9dc: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = \uc774 \ud30c\uc77c\uc740 JAXB(JavaTM Architecture for XML Binding) \ucc38\uc870 \uad6c\ud604 2.2.9-b140218.1920 \ubc84\uc804\uc744 \ud1b5\ud574 \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \nhttp://java.sun.com/xml/jaxb\ub97c \ucc38\uc870\ud558\uc2ed\uc2dc\uc624. \n\uc774 \ud30c\uc77c\uc744 \uc218\uc815\ud558\uba74 \uc18c\uc2a4 \uc2a4\ud0a4\ub9c8\ub97c \uc7ac\ucef4\ud30c\uc77c\ud560 \ub54c \uc218\uc815 \uc0ac\ud56d\uc774 \uc190\uc2e4\ub429\ub2c8\ub2e4. \n\uc0dd\uc131 \ub0a0\uc9dc: {0} \n -Driver.Version = XJC 2.2.8-b130911.1802 +Driver.Version = XJC 2.2.9-b140218.1920 -Driver.FullVersion = XJC \uC815\uC2DD \uBC84\uC804 "2.2.8-b130911.1802" +Driver.FullVersion = XJC \uC815\uC2DD \uBC84\uC804 "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties index 04bad425657..3f422db793f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties @@ -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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = compilando um esquema... Driver.FailedToGenerateCode = Falha ao produzir o c\u00f3digo. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Este arquivo foi gerado pela Arquitetura JavaTM para Implementa\u00e7\u00e3o de Refer\u00eancia (JAXB) de Bind XML, v2.2.8-b130911.1802 \nConsulte http://java.sun.com/xml/jaxb \nTodas as modifica\u00e7\u00f5es neste arquivo ser\u00e3o perdidas ap\u00f3s a recompila\u00e7\u00e3o do esquema de origem. \nGerado em: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Este arquivo foi gerado pela Arquitetura JavaTM para Implementa\u00e7\u00e3o de Refer\u00eancia (JAXB) de Bind XML, v2.2.9-b140218.1920 \nConsulte http://java.sun.com/xml/jaxb \nTodas as modifica\u00e7\u00f5es neste arquivo ser\u00e3o perdidas ap\u00f3s a recompila\u00e7\u00e3o do esquema de origem. \nGerado em: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = vers\u00E3o completa de xjc "2.2.8-b130911.1802" +Driver.FullVersion = vers\u00E3o completa de xjc "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties index adf97c7caff..4a858e47f17 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties @@ -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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = \u6b63\u5728\u7f16\u8bd1\u6a21\u5f0f... Driver.FailedToGenerateCode = \u65e0\u6cd5\u751f\u6210\u4ee3\u7801\u3002 -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = \u6b64\u6587\u4ef6\u662f\u7531 JavaTM Architecture for XML Binding (JAXB) \u5f15\u7528\u5b9e\u73b0 v2.2.8-b130911.1802 \u751f\u6210\u7684\n\u8bf7\u8bbf\u95ee http://java.sun.com/xml/jaxb \n\u5728\u91cd\u65b0\u7f16\u8bd1\u6e90\u6a21\u5f0f\u65f6, \u5bf9\u6b64\u6587\u4ef6\u7684\u6240\u6709\u4fee\u6539\u90fd\u5c06\u4e22\u5931\u3002\n\u751f\u6210\u65f6\u95f4: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = \u6b64\u6587\u4ef6\u662f\u7531 JavaTM Architecture for XML Binding (JAXB) \u5f15\u7528\u5b9e\u73b0 v2.2.9-b140218.1920 \u751f\u6210\u7684\n\u8bf7\u8bbf\u95ee http://java.sun.com/xml/jaxb \n\u5728\u91cd\u65b0\u7f16\u8bd1\u6e90\u6a21\u5f0f\u65f6, \u5bf9\u6b64\u6587\u4ef6\u7684\u6240\u6709\u4fee\u6539\u90fd\u5c06\u4e22\u5931\u3002\n\u751f\u6210\u65f6\u95f4: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.8-b130911.1802" +Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties index a8684e5ea84..add02eb0f7b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties @@ -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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = \u6b63\u5728\u7de8\u8b6f\u7db1\u8981... Driver.FailedToGenerateCode = \u7121\u6cd5\u7522\u751f\u7a0b\u5f0f\u78bc. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = \u6b64\u6a94\u6848\u662f\u7531 JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 \u6240\u7522\u751f \n\u8acb\u53c3\u95b1 http://java.sun.com/xml/jaxb \n\u4e00\u65e6\u91cd\u65b0\u7de8\u8b6f\u4f86\u6e90\u7db1\u8981, \u5c0d\u6b64\u6a94\u6848\u6240\u505a\u7684\u4efb\u4f55\u4fee\u6539\u90fd\u5c07\u6703\u907a\u5931. \n\u7522\u751f\u6642\u9593: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = \u6b64\u6a94\u6848\u662f\u7531 JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.9-b140218.1920 \u6240\u7522\u751f \n\u8acb\u53c3\u95b1 http://java.sun.com/xml/jaxb \n\u4e00\u65e6\u91cd\u65b0\u7de8\u8b6f\u4f86\u6e90\u7db1\u8981, \u5c0d\u6b64\u6a94\u6848\u6240\u505a\u7684\u4efb\u4f55\u4fee\u6539\u90fd\u5c07\u6703\u907a\u5931. \n\u7522\u751f\u6642\u9593: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.8-b130911.1802" +Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BIProperty.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BIProperty.java index c209cd7e688..ba8e6f4f50a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BIProperty.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BIProperty.java @@ -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 @@ -468,25 +468,22 @@ public final class BIProperty extends AbstractDeclarationImpl { r = ct.get(getBuilder().model); } else { FieldRendererFactory frf = getBuilder().fieldRendererFactory; - - if(prop.isOptionalPrimitive()) { + // according to the spec we should bahave as in jaxb1. So we ignore possiblity that property could be nullable + switch(opm) { // the property type can be primitive type if we are to ignore absence - switch(opm) { case PRIMITIVE: r = frf.getRequiredUnboxed(); break; case WRAPPER: // force the wrapper type - r = frf.getSingle(); + r = prop.isOptionalPrimitive() ? frf.getSingle() : frf.getDefault(); break; case ISSET: - r = frf.getSinglePrimitiveAccess(); + r = prop.isOptionalPrimitive() ? frf.getSinglePrimitiveAccess() : frf.getDefault(); break; default: throw new Error(); - } - } else { - r = frf.getDefault(); + } } if(opm==OptionalPropertyMode.ISSET) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java index f1a28b6a729..e7ff4433460 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.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 @@ -91,6 +91,9 @@ import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data; import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext; import com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx; import com.sun.xml.internal.bind.v2.util.DataSourceSource; +import java.util.logging.Logger; +import com.sun.xml.internal.bind.Util; +import java.util.logging.Level; import org.xml.sax.SAXException; @@ -105,6 +108,8 @@ import org.xml.sax.SAXException; public abstract class RuntimeBuiltinLeafInfoImpl extends BuiltinLeafInfoImpl implements RuntimeBuiltinLeafInfo, Transducer { + private static final Logger logger = Util.getClassLogger(); + private RuntimeBuiltinLeafInfoImpl(Class type, QName... typeNames) { super(type, typeNames); LEAVES.put(type,this); @@ -196,6 +201,7 @@ public abstract class RuntimeBuiltinLeafInfoImpl extends BuiltinLeafInfoImpl< public static final List> builtinBeanInfos; public static final String MAP_ANYURI_TO_URI = "mapAnyUriToUri"; + public static final String USE_OLD_GMONTH_MAPPING = "jaxb.ri.useOldGmonthMapping"; static { @@ -960,7 +966,14 @@ public abstract class RuntimeBuiltinLeafInfoImpl extends BuiltinLeafInfoImpl< m.put(DatatypeConstants.DATETIME, "%Y-%M-%DT%h:%m:%s"+ "%z"); m.put(DatatypeConstants.DATE, "%Y-%M-%D" +"%z"); m.put(DatatypeConstants.TIME, "%h:%m:%s"+ "%z"); - m.put(DatatypeConstants.GMONTH, "--%M--%z"); + if (System.getProperty(USE_OLD_GMONTH_MAPPING) == null) { + m.put(DatatypeConstants.GMONTH, "--%M%z"); // E2-12 Error. http://www.w3.org/2001/05/xmlschema-errata#e2-12 + } else { // backw. compatibility + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Old GMonth mapping used."); + } + m.put(DatatypeConstants.GMONTH, "--%M--%z"); + } m.put(DatatypeConstants.GDAY, "---%D" + "%z"); m.put(DatatypeConstants.GYEAR, "%Y" + "%z"); m.put(DatatypeConstants.GYEARMONTH, "%Y-%M" + "%z"); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/Navigator.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/Navigator.java index 69cf28b7b5c..b5ee5e65e2f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/Navigator.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/Navigator.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 @@ -25,10 +25,6 @@ package com.sun.xml.internal.bind.v2.model.nav; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.lang.reflect.Type; import java.util.Collection; import com.sun.xml.internal.bind.v2.runtime.Location; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/ReflectionNavigator.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/ReflectionNavigator.java index 665001f88cf..7f25c89d688 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/ReflectionNavigator.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/ReflectionNavigator.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 @@ -550,7 +550,7 @@ import com.sun.xml.internal.bind.v2.runtime.Location; @Override public Class loadObjectFactory(Class referencePoint, String pkg) { - ClassLoader cl= SecureLoader.getClassClassLoader(referencePoint); + ClassLoader cl = SecureLoader.getClassClassLoader(referencePoint); if (cl == null) cl = SecureLoader.getSystemClassLoader(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/SingleMapNodeProperty.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/SingleMapNodeProperty.java index 1d1a34638a8..be203b6681b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/SingleMapNodeProperty.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/SingleMapNodeProperty.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 @@ -140,22 +140,23 @@ final class SingleMapNodeProperty extends PropertyImpl */ private final Loader itemsLoader = new Loader(false) { - private ThreadLocal target = new ThreadLocal(); - private ThreadLocal map = new ThreadLocal(); - private int depthCounter = 0; // needed to clean ThreadLocals + private ThreadLocal> target = new ThreadLocal>(); + private ThreadLocal> map = new ThreadLocal>(); @Override public void startElement(UnmarshallingContext.State state, TagName ea) throws SAXException { // create or obtain the Map object try { - target.set((BeanT)state.prev.target); - map.set(acc.get(target.get())); - depthCounter++; - if(map.get() == null) { - map.set(ClassFactory.create(mapImplClass)); - } - map.get().clear(); - state.target = map.get(); + BeanT target = (BeanT) state.prev.target; + ValueT mapValue = acc.get(target); + if(mapValue == null) + mapValue = ClassFactory.create(mapImplClass); + else + mapValue.clear(); + + Stack.push(this.target, target); + Stack.push(map, mapValue); + state.target = mapValue; } catch (AccessorException e) { // recover from error by setting a dummy Map that receives and discards the values handleGenericException(e,true); @@ -167,11 +168,7 @@ final class SingleMapNodeProperty extends PropertyImpl public void leaveElement(State state, TagName ea) throws SAXException { super.leaveElement(state, ea); try { - acc.set(target.get(), map.get()); - if (--depthCounter == 0) { - target.remove(); - map.remove(); - } + acc.set(Stack.pop(target), Stack.pop(map)); } catch (AccessorException ex) { handleGenericException(ex,true); } @@ -289,4 +286,36 @@ final class SingleMapNodeProperty extends PropertyImpl return acc; return null; } + + private static final class Stack { + private Stack parent; + private T value; + + private Stack(Stack parent, T value) { + this.parent = parent; + this.value = value; + } + + private Stack(T value) { + this.value = value; + } + + private static void push(ThreadLocal> holder, T value) { + Stack parent = holder.get(); + if (parent == null) + holder.set(new Stack(value)); + else + holder.set(new Stack(parent, value)); + } + + private static T pop(ThreadLocal> holder) { + Stack current = holder.get(); + if (current.parent == null) + holder.remove(); + else + holder.set(current.parent); + return current.value; + } + + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java index 30c80801592..7633e1ce017 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.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 @@ -1070,18 +1070,22 @@ public final class XmlSchemaGenerator { } Collection refs = propInfo.ref(); - TypeInfo ti; - if ((refs != null) && (!refs.isEmpty()) && (elemName != null) - && ((ti = refs.iterator().next()) == null || ti instanceof ClassInfoImpl)) { - ClassInfoImpl cImpl = (ClassInfoImpl)ti; - if ((cImpl != null) && (cImpl.getElementName() != null)) { - e.ref(new QName(cImpl.getElementName().getNamespaceURI(), tn.getLocalPart())); - } else { - e.ref(new QName("", tn.getLocalPart())); + if ((refs != null) && (!refs.isEmpty()) && (elemName != null)){ + ClassInfoImpl cImpl = null; + for (TypeInfo ref : refs) { + if (ref == null || ref instanceof ClassInfoImpl) { + if (elemName.equals(((ClassInfoImpl)ref).getElementName())) { + cImpl = (ClassInfoImpl) ref; + break; + } + } } - } else { + if (cImpl != null) + e.ref(new QName(cImpl.getElementName().getNamespaceURI(), tn.getLocalPart())); + else + e.ref(new QName("", tn.getLocalPart())); + } else e.ref(tn); - } } } else { e.name(tn.getLocalPart()); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/LazyEnvelopeSource.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/LazyEnvelopeSource.java new file mode 100644 index 00000000000..151ae98e1fe --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/LazyEnvelopeSource.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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.messaging.saaj; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +/** + * LazyEnvelopeSource provides the source to create lazy Envelope + * + * @author shih-chang.chen@oracle.com + */ +public interface LazyEnvelopeSource extends javax.xml.transform.Source { + /** + * Retrieve payload qname without materializing its contents + * @return + * @throws SOAPException + */ + public QName getPayloadQName(); + public XMLStreamReader readToBodyStarTag() throws XMLStreamException; + public XMLStreamReader readPayload(); + public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException; + public boolean isPayloadStreamReader(); +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java index eeccdf1db4f..46e21c05e03 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.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 @@ -621,7 +621,8 @@ class HttpSOAPConnection extends SOAPConnection { String plain = user + ":"; byte[] nameBytes = plain.getBytes(); - byte[] passwdBytes = password.getBytes(); + byte[] passwdBytes = (password == null ? new byte[0] : password + .getBytes()); // concatenate user name and password bytes and encode them byte[] concat = new byte[nameBytes.length + passwdBytes.length]; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/MessagingException.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/MessagingException.java index e9b74eecd68..6a5ca2ccd23 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/MessagingException.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/MessagingException.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 @@ -84,7 +84,7 @@ public class MessagingException extends Exception { * * @return next Exception, null if none. */ - public Exception getNextException() { + public synchronized Exception getNextException() { return next; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java index eac9d5b465e..f2f053f148d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.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 @@ -40,7 +40,6 @@ import com.sun.xml.internal.messaging.saaj.packaging.mime.*; import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*; import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream; -import com.sun.xml.internal.messaging.saaj.util.FinalArrayList; /** * The MimeMultipart class is an implementation of the abstract Multipart @@ -393,13 +392,12 @@ public class BMMimeMultipart extends MimeMultipart { int i; int l = pattern.length; int lx = l -1; - int bufferLength = 0; BitSet eof = new BitSet(1); long[] posVector = new long[1]; while (true) { is.mark(l); - bufferLength = readNext(is, buffer, l, eof, posVector, sin); + readNext(is, buffer, l, eof, posVector, sin); if (eof.get(0)) { // End of stream return false; @@ -561,7 +559,7 @@ public class BMMimeMultipart extends MimeMultipart { if (prevBuffer[s-1] == (byte)13) { // if buffer[0] == (byte)10 if (buffer[0] == (byte)10) { - int j=lx-1; + int j; for(j = lx-1; j > 0; j--) { if (buffer[j+1] != pattern[j]) { break; @@ -695,7 +693,6 @@ public class BMMimeMultipart extends MimeMultipart { * Iterates through all the parts and outputs each Mime part * separated by a boundary. */ - byte[] buf = new byte[1024]; public void writeTo(OutputStream os) throws IOException, MessagingException { @@ -715,19 +712,25 @@ public class BMMimeMultipart extends MimeMultipart { if (in != null) { OutputUtil.writeln(bnd, os); // put out boundary if ((os instanceof ByteOutputStream) && lazyAttachments) { - ((ByteOutputStream)os).write(in); + ((ByteOutputStream) os).write(in); } else { - ByteOutputStream baos = new ByteOutputStream(in.available()); - baos.write(in); - baos.writeTo(os); - // reset the inputstream so that we can support a - //getAttachment later - in = baos.newInputStream(); + ByteOutputStream baos = null; + try { + baos = new ByteOutputStream(in.available()); + baos.write(in); + baos.writeTo(os); + // reset the inputstream so that we can support a + // getAttachment later + in = baos.newInputStream(); + } finally { + if (baos != null) + baos.close(); + } } // this will endup writing the end boundary } else { - // put out last boundary + // put out last boundary OutputUtil.writeAsAscii(bnd, os); OutputUtil.writeAsAscii("--", os); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeBodyPart.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeBodyPart.java index 314f7d2873d..c19c1dc5c2d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeBodyPart.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeBodyPart.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 @@ -193,13 +193,17 @@ public final class MimeBodyPart { SharedInputStream sis = (SharedInputStream) is; contentStream = sis.newStream(sis.getPosition(), -1); } else { + ByteOutputStream bos = null; try { - ByteOutputStream bos = new ByteOutputStream(); + bos = new ByteOutputStream(); bos.write(is); content = bos.getBytes(); contentLength = bos.getCount(); } catch (IOException ioex) { throw new MessagingException("Error reading input stream", ioex); + } finally { + if (bos != null) + bos.close(); } } @@ -1075,8 +1079,12 @@ public final class MimeBodyPart { */ protected void updateHeaders() throws MessagingException { DataHandler dh = getDataHandler(); - if (dh == null) // Huh ? - return; + /* + * Code flow indicates null is never returned from + * getdataHandler() - findbugs + */ + //if (dh == null) // Huh ? + // return; try { String type = dh.getContentType(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.java index 8a367fa0f15..a0017194f65 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.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 @@ -318,6 +318,7 @@ public class MimeMultipart { byte[] bndbytes = ASCIIUtility.getBytes(boundary); int bl = bndbytes.length; + ByteOutputStream buf = null; try { // Skip the preamble LineInputStream lin = new LineInputStream(in); @@ -370,7 +371,7 @@ public class MimeMultipart { if (!in.markSupported()) throw new MessagingException("Stream doesn't support mark"); - ByteOutputStream buf = null; + buf = null; // if we don't have a shared input stream, we copy the data if (sin == null) buf = new ByteOutputStream(); @@ -471,6 +472,9 @@ public class MimeMultipart { } } catch (IOException ioex) { throw new MessagingException("IO Error", ioex); + } finally { + if (buf != null) + buf.close(); } if (!ignoreMissingEndBoundary && !foundClosingBoundary && sin== null) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimePullMultipart.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimePullMultipart.java index bdef4532e48..0044a5c31cc 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimePullMultipart.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimePullMultipart.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 @@ -107,7 +107,7 @@ public class MimePullMultipart extends MimeMultipart { List prts = mm.getAttachments(); for(MIMEPart part : prts) { if (part != soapPart) { - AttachmentPart attach = new AttachmentPartImpl(part); + new AttachmentPartImpl(part); this.addBodyPart(new MimeBodyPart(part)); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/util/ASCIIUtility.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/util/ASCIIUtility.java index 22fd2c488fc..48a56e8068c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/util/ASCIIUtility.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/util/ASCIIUtility.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 @@ -141,10 +141,13 @@ public class ASCIIUtility { * Use {@link ByteOutputStream} and {@link ByteOutputStream#write(InputStream)}. */ public static byte[] getBytes(InputStream is) throws IOException { - ByteOutputStream bos = new ByteOutputStream(); + ByteOutputStream bos = null; try { + bos = new ByteOutputStream(); bos.write(is); } finally { + if (bos != null) + bos.close(); is.close(); } return bos.toByteArray(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java index 8d91b5ce769..76f6802b50d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.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 @@ -138,7 +138,6 @@ public class AttachmentPartImpl extends AttachmentPart { } public int getSize() throws SOAPException { - byte[] bytes; if (mimePart != null) { try { return mimePart.read().available(); @@ -388,6 +387,7 @@ public class AttachmentPartImpl extends AttachmentPart { } dataHandler = null; InputStream decoded = null; + ByteOutputStream bos = null; try { decoded = MimeUtility.decode(content, "base64"); InternetHeaders hdrs = new InternetHeaders(); @@ -395,7 +395,7 @@ public class AttachmentPartImpl extends AttachmentPart { //TODO: reading the entire attachment here is ineffcient. Somehow the MimeBodyPart // Ctor with inputStream causes problems based on the InputStream // has markSupported()==true - ByteOutputStream bos = new ByteOutputStream(); + bos = new ByteOutputStream(); bos.write(decoded); rawContent = new MimeBodyPart(hdrs, bos.getBytes(), bos.getCount()); setMimeHeader("Content-Type", contentType); @@ -403,8 +403,11 @@ public class AttachmentPartImpl extends AttachmentPart { log.log(Level.SEVERE, "SAAJ0578.soap.attachment.setbase64content.exception", e); throw new SOAPExceptionImpl(e.getLocalizedMessage()); } finally { + if (bos != null) + bos.close(); try { - decoded.close(); + if (decoded != null) + decoded.close(); } catch (IOException ex) { throw new SOAPException(ex); } @@ -478,13 +481,14 @@ public class AttachmentPartImpl extends AttachmentPart { mimePart = null; } dataHandler = null; + ByteOutputStream bos = null; try { InternetHeaders hdrs = new InternetHeaders(); hdrs.setHeader("Content-Type", contentType); //TODO: reading the entire attachment here is ineffcient. Somehow the MimeBodyPart // Ctor with inputStream causes problems based on whether the InputStream has // markSupported()==true or false - ByteOutputStream bos = new ByteOutputStream(); + bos = new ByteOutputStream(); bos.write(content); rawContent = new MimeBodyPart(hdrs, bos.getBytes(), bos.getCount()); setMimeHeader("Content-Type", contentType); @@ -492,6 +496,8 @@ public class AttachmentPartImpl extends AttachmentPart { log.log(Level.SEVERE, "SAAJ0576.soap.attachment.setrawcontent.exception", e); throw new SOAPExceptionImpl(e.getLocalizedMessage()); } finally { + if (bos != null) + bos.close(); try { content.close(); } catch (IOException ex) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/Envelope.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/Envelope.java index 14dc496ba4c..607e8c36c68 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/Envelope.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/Envelope.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 @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.OutputStream; import javax.xml.soap.SOAPEnvelope; +import javax.xml.soap.SOAPException; import javax.xml.transform.Source; /** @@ -52,4 +53,8 @@ public interface Envelope extends SOAPEnvelope { * Output the content. */ void output(OutputStream out, boolean isFastInfoset) throws IOException; + + void setStaxBridge(StaxBridge bridge) throws SOAPException; + + StaxBridge getStaxBridge() throws SOAPException; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java index 62fb9df4e6d..907c8ef9d91 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.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 @@ -29,18 +29,22 @@ import java.util.logging.Logger; import javax.xml.parsers.SAXParser; import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; +import com.sun.xml.internal.messaging.saaj.LazyEnvelopeSource; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.util.*; - import com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer; /** @@ -58,20 +62,73 @@ public class EnvelopeFactory { public static Envelope createEnvelope(Source src, SOAPPartImpl soapPart) throws SOAPException { + if (src instanceof JAXMStreamSource) { + try { + if (!SOAPPartImpl.lazyContentLength) { + ((JAXMStreamSource) src).reset(); + } + } catch (java.io.IOException ioe) { + log.severe("SAAJ0515.source.reset.exception"); + throw new SOAPExceptionImpl(ioe); + } + } + if (src instanceof LazyEnvelopeSource) { + return lazy((LazyEnvelopeSource)src, soapPart); + } + if (soapPart.message.isLazySoapBodyParsing()) { + return parseEnvelopeStax(src, soapPart); + } else { + return parseEnvelopeSax(src, soapPart); + } + } + + private static Envelope lazy(LazyEnvelopeSource src, SOAPPartImpl soapPart) throws SOAPException { + try { + StaxBridge staxBridge = new StaxLazySourceBridge(src, soapPart); + staxBridge.bridgeEnvelopeAndHeaders(); + Envelope env = (Envelope) soapPart.getEnvelope(); + env.setStaxBridge(staxBridge); + return env; + } catch (XMLStreamException e) { + throw new SOAPException(e); + } + } + + static private XMLInputFactory xmlInputFactory = null; + + private static Envelope parseEnvelopeStax(Source src, SOAPPartImpl soapPart) + throws SOAPException { + XMLStreamReader streamReader = null; + if (src instanceof StAXSource) { + streamReader = ((StAXSource) src).getXMLStreamReader(); + } + try { + if (streamReader == null) { + if (xmlInputFactory == null) xmlInputFactory = XMLInputFactory.newInstance(); + streamReader = xmlInputFactory.createXMLStreamReader(src); + } +// SaajStaxWriter saajWriter = new SaajStaxWriter(soapPart.message, soapPart.document); +// XMLStreamReaderToXMLStreamWriter readerWriterBridge = new XMLStreamReaderToXMLStreamWriter( +// streamReader, saajWriter, soapPart.getSOAPNamespace()); + + StaxBridge readerWriterBridge = new StaxReaderBridge(streamReader, soapPart); + //bridge will stop reading at body element, and parse upon request, so save it + //on the envelope + readerWriterBridge.bridgeEnvelopeAndHeaders(); + + Envelope env = (Envelope) soapPart.getEnvelope(); + env.setStaxBridge(readerWriterBridge); + return env; + } catch (Exception e) { + throw new SOAPException(e); + } + } + private static Envelope parseEnvelopeSax(Source src, SOAPPartImpl soapPart) + throws SOAPException { // Insert SAX filter to disallow Document Type Declarations since // they are not legal in SOAP SAXParser saxParser = null; if (src instanceof StreamSource) { - if (src instanceof JAXMStreamSource) { - try { - if (!SOAPPartImpl.lazyContentLength) { - ((JAXMStreamSource) src).reset(); - } - } catch (java.io.IOException ioe) { - log.severe("SAAJ0515.source.reset.exception"); - throw new SOAPExceptionImpl(ioe); - } - } try { saxParser = parserPool.get(); } catch (Exception e) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/LazyEnvelope.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/LazyEnvelope.java new file mode 100644 index 00000000000..1f83ca5cfde --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/LazyEnvelope.java @@ -0,0 +1,61 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.messaging.saaj.soap; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +public interface LazyEnvelope extends Envelope { + public XMLStreamReader getPayloadReader() throws SOAPException; + public boolean isLazy(); + public void writeTo(XMLStreamWriter writer) throws XMLStreamException, SOAPException; + + /** + * Retrieve payload qname without materializing its contents + * @return + * @throws SOAPException + */ + public QName getPayloadQName() throws SOAPException; + + /** + * Retrieve payload attribute value without materializing its contents + * @param localName + * @return + * @throws SOAPException + */ + public String getPayloadAttributeValue(String localName) throws SOAPException; + + /** + * Retrieve payload attribute value without materializing its contents + * @param qName + * @return + * @throws SOAPException + */ + public String getPayloadAttributeValue(QName qName) throws SOAPException; +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java index 9caff62d096..d7a0226671b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.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 @@ -29,6 +29,7 @@ import java.io.*; import java.util.logging.Logger; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamReader; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ContentType; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ParseException; @@ -66,12 +67,44 @@ public class MessageFactoryImpl extends MessageFactory { throw new UnsupportedOperationException(); } + public SOAPMessage createMessage(String protocol) throws SOAPException { + if (SOAPConstants.SOAP_1_1_PROTOCOL.equals(protocol)) + return new com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl(); + else + return new com.sun.xml.internal.messaging.saaj.soap.ver1_2.Message1_2Impl(); + } + public SOAPMessage createMessage(boolean isFastInfoset, boolean acceptFastInfoset) throws SOAPException { throw new UnsupportedOperationException(); } + public SOAPMessage createMessage(MimeHeaders headers, XMLStreamReader reader) throws SOAPException, IOException { + String contentTypeString = MessageImpl.getContentType(headers); + + if (listener != null) { + throw new SOAPException("Listener OutputStream is not supported with XMLStreamReader"); + } + + try { + ContentType contentType = new ContentType(contentTypeString); + int stat = MessageImpl.identifyContentType(contentType); + + if (MessageImpl.isSoap1_1Content(stat)) { + return new Message1_1Impl(headers,contentType,stat,reader); + } else if (MessageImpl.isSoap1_2Content(stat)) { + return new Message1_2Impl(headers,contentType,stat,reader); + } else { + log.severe("SAAJ0530.soap.unknown.Content-Type"); + throw new SOAPExceptionImpl("Unrecognized Content-Type"); + } + } catch (ParseException e) { + log.severe("SAAJ0531.soap.cannot.parse.Content-Type"); + throw new SOAPExceptionImpl( + "Unable to parse content type: " + e.getMessage()); + } + } public SOAPMessage createMessage(MimeHeaders headers, InputStream in) throws SOAPException, IOException { String contentTypeString = MessageImpl.getContentType(headers); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java index 5a5405ce91e..e9691568d5e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.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 @@ -33,7 +33,9 @@ import java.util.logging.Logger; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamReader; import javax.xml.transform.Source; +import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; import com.sun.xml.internal.messaging.saaj.packaging.mime.Header; @@ -110,6 +112,8 @@ public abstract class MessageImpl private InputStream inputStreamAfterSaveChanges = null; + public static final String LAZY_SOAP_BODY_PARSING = "saaj.lazy.soap.body"; + // switch back to old MimeMultipart incase of problem private static boolean switchOffBM = false; private static boolean switchOffLazyAttachment = false; @@ -341,7 +345,12 @@ public abstract class MessageImpl } - private void init(MimeHeaders headers, int stat, final ContentType contentType, final InputStream in) throws SOAPExceptionImpl { + public MessageImpl(MimeHeaders headers, ContentType ct, int stat, + XMLStreamReader reader) throws SOAPExceptionImpl { + init(headers, stat, ct, reader); + } + + private void init(MimeHeaders headers, int stat, final ContentType contentType, final Object input) throws SOAPExceptionImpl { this.headers = headers; try { @@ -382,20 +391,42 @@ public abstract class MessageImpl + " Expected: " + getExpectedContentType()); } - + InputStream in = null; + XMLStreamReader rdr = null; + if (input instanceof InputStream) { + in = (InputStream) input; + } else { + //is a StAX reader + rdr = (XMLStreamReader) input; + } if ((stat & PLAIN_XML_FLAG) != 0) { - if (isFastInfoset) { - getSOAPPart().setContent( - FastInfosetReflection.FastInfosetSource_new(in)); + if (in != null) { + if (isFastInfoset) { + getSOAPPart().setContent( + FastInfosetReflection.FastInfosetSource_new(in)); + } else { + initCharsetProperty(contentType); + getSOAPPart().setContent(new StreamSource(in)); + } } else { - initCharsetProperty(contentType); - getSOAPPart().setContent(new StreamSource(in)); + //is a StAX reader + if (isFastInfoset) { + //need to get FI stax reader + } else { + initCharsetProperty(contentType); + getSOAPPart().setContent(new StAXSource(rdr)); + } } } - else if ((stat & MIME_MULTIPART_FLAG) != 0) { + else if ((stat & MIME_MULTIPART_FLAG) != 0 && in == null) { + //only parse multipart in the inputstream case + //in stax reader case, we would be given the attachments separately + getSOAPPart().setContent(new StAXSource(rdr)); + } else if ((stat & MIME_MULTIPART_FLAG) != 0) { + final InputStream finalIn = in; DataSource ds = new DataSource() { public InputStream getInputStream() { - return in; + return finalIn; } public OutputStream getOutputStream() { @@ -487,7 +518,17 @@ public abstract class MessageImpl } } - if (soapPartInputStream == null && soapMessagePart != null) { + // findbugs correctly points out that we'd NPE instantiating + // the ContentType (just below here) if soapMessagePart were + // null. Hence are better off throwing a controlled exception + // at this point if it is null. + if (soapMessagePart == null) { + log.severe("SAAJ0510.soap.cannot.create.envelope"); + throw new SOAPExceptionImpl( + "Unable to create envelope from given source: SOAP part not found"); + } + + if (soapPartInputStream == null) { soapPartInputStream = soapMessagePart.getInputStream(); } @@ -541,6 +582,15 @@ public abstract class MessageImpl } } + public boolean isLazySoapBodyParsing() { + Object lazyParsingProp = getProperty(LAZY_SOAP_BODY_PARSING); + if (lazyParsingProp == null) return false; + if (lazyParsingProp instanceof Boolean) { + return ((Boolean) lazyParsingProp).booleanValue(); + } else { + return Boolean.valueOf(lazyParsingProp.toString()); + } + } public Object getProperty(String property) { return (String) properties.get(property); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java index 891342ab257..7dac69841a9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.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 @@ -107,11 +107,11 @@ public class SOAPDocumentImpl extends DocumentImpl implements SOAPDocument { } public org.w3c.dom.Text createTextNode(String data) { - return new TextImpl(this, data); + return new SOAPTextImpl(this, data); } public Comment createComment(String data) { - return new CommentImpl(this, data); + return new SOAPCommentImpl(this, data); } public CDATASection createCDATASection(String data) throws DOMException { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java index d30a316f06b..19cc1b4ec30 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.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 @@ -245,12 +245,18 @@ public abstract class SOAPPartImpl extends SOAPPart implements SOAPDocument { * getBytes() is called on a ByteInputStream. */ if (!(is instanceof ByteInputStream)) { - ByteOutputStream bout = new ByteOutputStream(); - bout.write(is); + ByteOutputStream bout = null; + try { + bout = new ByteOutputStream(); + bout.write(is); - // source.setInputStream(new ByteInputStream(...)) - FastInfosetReflection.FastInfosetSource_setInputStream( - source, bout.newInputStream()); + // source.setInputStream(new ByteInputStream(...)) + FastInfosetReflection.FastInfosetSource_setInputStream( + source, bout.newInputStream()); + } finally { + if (bout != null) + bout.close(); + } } this.source = source; } @@ -811,4 +817,6 @@ public abstract class SOAPPartImpl extends SOAPPart implements SOAPDocument { public String getSourceCharsetEncoding() { return sourceCharsetEncoding; } + + public abstract String getSOAPNamespace(); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxBridge.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxBridge.java new file mode 100644 index 00000000000..cf014b15623 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxBridge.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.messaging.saaj.soap; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import com.sun.xml.internal.org.jvnet.staxex.util.SaajStaxWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; + + +/** + * StaxBridge builds Envelope using a XMLStreamReaderToXMLStreamWriter + * + * @author shih-chang.chen@oracle.com + */ +public abstract class StaxBridge { + protected SaajStaxWriter saajWriter; + protected XMLStreamReaderToXMLStreamWriter readerToWriter; + protected XMLStreamReaderToXMLStreamWriter.Breakpoint breakpoint; + + + public StaxBridge(SOAPPartImpl soapPart) throws SOAPException { + readerToWriter = new XMLStreamReaderToXMLStreamWriter(); + saajWriter = new SaajStaxWriter(soapPart.message, soapPart.getSOAPNamespace()); + } + + public void bridgeEnvelopeAndHeaders() throws XMLStreamException { + readerToWriter.bridge(breakpoint); + } + + public void bridgePayload() throws XMLStreamException { + readerToWriter.bridge(breakpoint); + } + + abstract public XMLStreamReader getPayloadReader(); + + abstract public QName getPayloadQName(); + + abstract public String getPayloadAttributeValue(String attName) ; + + abstract public String getPayloadAttributeValue(QName attName) ; +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxLazySourceBridge.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxLazySourceBridge.java new file mode 100644 index 00000000000..07da44736bb --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxLazySourceBridge.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.messaging.saaj.soap; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import com.sun.xml.internal.messaging.saaj.LazyEnvelopeSource; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; + + +/** + * StaxBridge builds Envelope from LazyEnvelopeSource + * + * @author shih-chang.chen@oracle.com + */ +public class StaxLazySourceBridge extends StaxBridge { + private LazyEnvelopeSource lazySource; + + public StaxLazySourceBridge(LazyEnvelopeSource src, SOAPPartImpl soapPart) throws SOAPException { + super(soapPart); + lazySource = src; + final String soapEnvNS = soapPart.getSOAPNamespace(); + try { + breakpoint = new XMLStreamReaderToXMLStreamWriter.Breakpoint(src.readToBodyStarTag(), saajWriter) { + public boolean proceedAfterStartElement() { + if ("Body".equals(reader.getLocalName()) && soapEnvNS.equals(reader.getNamespaceURI()) ){ + return false; + } else + return true; + } + }; + } catch (XMLStreamException e) { + throw new SOAPException(e); + } + } + + @Override + public XMLStreamReader getPayloadReader() { + return lazySource.readPayload(); +// throw new UnsupportedOperationException(); + } + + @Override + public QName getPayloadQName() { + return lazySource.getPayloadQName(); + } + + @Override + public String getPayloadAttributeValue(String attName) { + if (lazySource.isPayloadStreamReader()) { + XMLStreamReader reader = lazySource.readPayload(); + if (reader.getEventType() == reader.START_ELEMENT) { + return reader.getAttributeValue(null, attName); + } + } + return null; + } + + @Override + public String getPayloadAttributeValue(QName attName) { + if (lazySource.isPayloadStreamReader()) { + XMLStreamReader reader = lazySource.readPayload(); + if (reader.getEventType() == reader.START_ELEMENT) { + return reader.getAttributeValue(attName.getNamespaceURI(), attName.getLocalPart()); + } + } + return null; + } + + public void bridgePayload() throws XMLStreamException { + //Assuming out is at Body + writePayloadTo(saajWriter); + } + + public void writePayloadTo(XMLStreamWriter writer) throws XMLStreamException { + lazySource.writePayloadTo(writer); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxReaderBridge.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxReaderBridge.java new file mode 100644 index 00000000000..9010a88368d --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxReaderBridge.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.messaging.saaj.soap; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamReader; + +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; + +/** + * StaxBridge builds Envelope using a XMLStreamReaderToXMLStreamWriter + * + * @author shih-chang.chen@oracle.com + */ +public class StaxReaderBridge extends StaxBridge { + private XMLStreamReader in; + + public StaxReaderBridge(XMLStreamReader reader, SOAPPartImpl soapPart) throws SOAPException { + super(soapPart); + in = reader; + final String soapEnvNS = soapPart.getSOAPNamespace(); + breakpoint = new XMLStreamReaderToXMLStreamWriter.Breakpoint(reader, saajWriter) { + boolean seenBody = false; + boolean stopedAtBody = false; + public boolean proceedBeforeStartElement() { + if (stopedAtBody) return true; + if (seenBody) { + stopedAtBody = true; + return false; + } + if ("Body".equals(reader.getLocalName()) && soapEnvNS.equals(reader.getNamespaceURI()) ){ + seenBody = true; + } + return true; + } + }; + } + + public XMLStreamReader getPayloadReader() { + return in; + } + + public QName getPayloadQName() { + return (in.getEventType() == in.START_ELEMENT) ? in.getName() : null; + } + + public String getPayloadAttributeValue(String attName) { + return (in.getEventType() == in.START_ELEMENT) ? in.getAttributeValue(null, attName) : null; + } + + public String getPayloadAttributeValue(QName attName) { + return (in.getEventType() == in.START_ELEMENT) ? in.getAttributeValue(attName.getNamespaceURI(), attName.getLocalPart()) : null; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/BodyImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/BodyImpl.java index 562386156f6..e761588902d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/BodyImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/BodyImpl.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,14 +31,18 @@ import java.util.logging.Level; import javax.xml.namespace.QName; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.*; +import org.w3c.dom.Node; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; +import com.sun.xml.internal.messaging.saaj.soap.StaxBridge; import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; /** @@ -48,6 +52,9 @@ import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; */ public abstract class BodyImpl extends ElementImpl implements SOAPBody { private SOAPFault fault; +// private XMLStreamReaderToXMLStreamWriter staxBridge; + private StaxBridge staxBridge; + private boolean payloadStreamRead = false; protected BodyImpl(SOAPDocumentImpl ownerDoc, NameImpl bodyName) { super(ownerDoc, bodyName); @@ -136,13 +143,22 @@ public abstract class BodyImpl extends ElementImpl implements SOAPBody { } public boolean hasFault() { - initializeFault(); - return fault != null; + QName payloadQName = getPayloadQName(); + return getFaultQName().equals(payloadQName); + } + + private Object getFaultQName() { + return new QName(getNamespaceURI(), "Fault"); } public SOAPFault getFault() { - if (hasFault()) + if (hasFault()) { + if (fault == null) { + //initialize fault member + fault = (SOAPFault) getFirstChildElement(); + } return fault; + } return null; } @@ -322,4 +338,130 @@ public abstract class BodyImpl extends ElementImpl implements SOAPBody { return document; } + private void materializePayloadWrapException() { + try { + materializePayload(); + } catch (SOAPException e) { + throw new RuntimeException(e); + } + } + private void materializePayload() throws SOAPException { + if (staxBridge != null) { + if (payloadStreamRead) { + //the payload has already been read via stream reader and the + //stream has been exhausted already. Throw an + //exception since we are now trying to materialize as DOM and + //there is no stream left to read + throw new SOAPException("SOAPBody payload stream has been fully read - cannot materialize as DOM!"); + } + try { + staxBridge.bridgePayload(); + staxBridge = null; + payloadStreamRead = true; + } catch (XMLStreamException e) { + throw new SOAPException(e); + } + } + } + + @Override + public boolean hasChildNodes() { + boolean hasChildren = super.hasChildNodes(); + //to answer this question we need to know _whether_ we have at least one child + //So no need to materialize body if we already know we have a header child + if (!hasChildren) { + materializePayloadWrapException(); + } + return super.hasChildNodes(); + } + + @Override + public NodeList getChildNodes() { + materializePayloadWrapException(); + return super.getChildNodes(); + } + + @Override + public Node getFirstChild() { + Node child = super.getFirstChild(); + if (child == null) { + materializePayloadWrapException(); + } + return super.getFirstChild(); + } + + public Node getFirstChildNoMaterialize() { + return super.getFirstChild(); + } + + @Override + public Node getLastChild() { + materializePayloadWrapException(); + return super.getLastChild(); + } + + XMLStreamReader getPayloadReader() { + return staxBridge.getPayloadReader(); + } + + void setStaxBridge(StaxBridge bridge) { + this.staxBridge = bridge; + } + + StaxBridge getStaxBridge() { + return staxBridge; + } + + void setPayloadStreamRead() { + this.payloadStreamRead = true; + } + + QName getPayloadQName() { + if (staxBridge != null) { + return staxBridge.getPayloadQName(); + } else { + //not lazy - Just get first child element and return its name + Element elem = getFirstChildElement(); + if (elem != null) { + String ns = elem.getNamespaceURI(); + String pref = elem.getPrefix(); + String local = elem.getLocalName(); + if (pref != null) return new QName(ns, local, pref); + if (ns != null) return new QName(ns, local); + return new QName(local); + } + } + return null; + } + + String getPayloadAttributeValue(String attName) { + if (staxBridge != null) { + return staxBridge.getPayloadAttributeValue(attName); + } else { + //not lazy -Just get first child element and return its attribute + Element elem = getFirstChildElement(); + if (elem != null) { + return elem.getAttribute(localName); + } + } + return null; + } + + String getPayloadAttributeValue(QName attNAme) { + if (staxBridge != null) { + return staxBridge.getPayloadAttributeValue(attNAme); + } else { + //not lazy -Just get first child element and return its attribute + Element elem = getFirstChildElement(); + if (elem != null) { + return elem.getAttributeNS(attNAme.getNamespaceURI(), attNAme.getLocalPart()); + } + } + return null; + } + + public boolean isLazy() { + return (staxBridge != null && !payloadStreamRead); + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java index 475bdffd244..59288cd8388 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.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 @@ -51,7 +51,7 @@ public class ElementImpl public static final String XENC_NS = "http://www.w3.org/2001/04/xmlenc#".intern(); public static final String WSU_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd".intern(); - private AttributeManager encodingStyleAttribute = new AttributeManager(); + private transient AttributeManager encodingStyleAttribute = new AttributeManager(); protected QName elementQName; @@ -424,7 +424,32 @@ public class ElementImpl } + Element getFirstChildElement() { + Node child = getFirstChild(); + while (child != null) { + if (child instanceof Element) { + return ((Element) child); + } + child = child.getNextSibling(); + } + return null; + } + protected SOAPElement findChild(NameImpl name) { + Node eachChild = getFirstChild(); + while (eachChild != null) { + if (eachChild instanceof SOAPElement) { + SOAPElement eachChildSoap = (SOAPElement) eachChild; + if (eachChildSoap.getElementName().equals(name)) { + return eachChildSoap; + } + } + eachChild = eachChild.getNextSibling(); + } + return null; + } + + protected SOAPElement findAndConvertChildElement(NameImpl name) { Iterator eachChild = getChildElementNodes(); while (eachChild.hasNext()) { SOAPElement child = (SOAPElement) eachChild.next(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/EnvelopeImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/EnvelopeImpl.java index 68454737ec2..08412891f6a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/EnvelopeImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/EnvelopeImpl.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 @@ -29,30 +29,36 @@ import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; -import java.util.Iterator; import java.util.logging.Level; -import org.w3c.dom.Document; import javax.xml.namespace.QName; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.sax.*; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; -import com.sun.xml.internal.messaging.saaj.soap.Envelope; +import com.sun.xml.internal.messaging.saaj.soap.LazyEnvelope; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; +import com.sun.xml.internal.messaging.saaj.soap.StaxBridge; +import com.sun.xml.internal.messaging.saaj.soap.StaxLazySourceBridge; import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection; +import com.sun.xml.internal.messaging.saaj.util.stax.LazyEnvelopeStaxReader; import com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer; +import com.sun.xml.internal.org.jvnet.staxex.util.DOMStreamReader; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; + /** * Our implementation of the SOAP envelope. * * @author Anil Vijendran (anil@sun.com) */ -public abstract class EnvelopeImpl extends ElementImpl implements Envelope { +public abstract class EnvelopeImpl extends ElementImpl implements LazyEnvelope { protected HeaderImpl header; protected BodyImpl body; String omitXmlDecl = "yes"; @@ -103,11 +109,9 @@ public abstract class EnvelopeImpl extends ElementImpl implements Envelope { NameImpl bodyName = getBodyName(prefix); HeaderImpl header = null; - SOAPElement firstChild = null; + SOAPElement firstChild = (SOAPElement) getFirstChildElement(); - Iterator eachChild = getChildElementNodes(); - if (eachChild.hasNext()) { - firstChild = (SOAPElement) eachChild.next(); + if (firstChild != null) { if (firstChild.getElementName().equals(headerName)) { log.severe("SAAJ0120.impl.header.already.exists"); throw new SOAPExceptionImpl("Can't add a header when one is already present."); @@ -254,6 +258,7 @@ public abstract class EnvelopeImpl extends ElementImpl implements Envelope { public void output(OutputStream out) throws IOException { try { +// materializeBody(); Transformer transformer = EfficientStreamingTransformer.newTransformer(); @@ -357,4 +362,77 @@ public abstract class EnvelopeImpl extends ElementImpl implements Envelope { + elementQName.getLocalPart() + " to " + newName.getLocalPart()); } + + @Override + public void setStaxBridge(StaxBridge bridge) throws SOAPException { + //set it on the body + ((BodyImpl) getBody()).setStaxBridge(bridge); + } + + @Override + public StaxBridge getStaxBridge() throws SOAPException { + return ((BodyImpl) getBody()).getStaxBridge(); + } + + @Override + public XMLStreamReader getPayloadReader() throws SOAPException { + return ((BodyImpl) getBody()).getPayloadReader(); + } + + @Override + public void writeTo(final XMLStreamWriter writer) throws XMLStreamException, SOAPException { + StaxBridge readBridge = this.getStaxBridge(); + if (readBridge != null && readBridge instanceof StaxLazySourceBridge) { +// StaxSoapWriteBridge writingBridge = new StaxSoapWriteBridge(this); +// writingBridge.write(writer); + final String soapEnvNS = this.getNamespaceURI(); + final DOMStreamReader reader = new DOMStreamReader(this); + XMLStreamReaderToXMLStreamWriter writingBridge = new XMLStreamReaderToXMLStreamWriter(); + writingBridge.bridge( new XMLStreamReaderToXMLStreamWriter.Breakpoint(reader, writer) { + public boolean proceedAfterStartElement() { + if ("Body".equals(reader.getLocalName()) && soapEnvNS.equals(reader.getNamespaceURI()) ){ + return false; + } else + return true; + } + });//bridgeToBodyStartTag + ((StaxLazySourceBridge)readBridge).writePayloadTo(writer); + writer.writeEndElement();//body + writer.writeEndElement();//env + writer.writeEndDocument(); + writer.flush(); + } else { + LazyEnvelopeStaxReader lazyEnvReader = new LazyEnvelopeStaxReader(this); + XMLStreamReaderToXMLStreamWriter writingBridge = new XMLStreamReaderToXMLStreamWriter(); + writingBridge.bridge(lazyEnvReader, writer); +// writingBridge.bridge(new XMLStreamReaderToXMLStreamWriter.Breakpoint(lazyEnvReader, writer)); + } + //Assume the staxBridge is exhausted now since we would have read the body reader + ((BodyImpl) getBody()).setPayloadStreamRead(); + } + + @Override + public QName getPayloadQName() throws SOAPException { + return ((BodyImpl) getBody()).getPayloadQName(); + } + + @Override + public String getPayloadAttributeValue(String localName) throws SOAPException { + return ((BodyImpl) getBody()).getPayloadAttributeValue(localName); + } + + @Override + public String getPayloadAttributeValue(QName qName) throws SOAPException { + return ((BodyImpl) getBody()).getPayloadAttributeValue(qName); + } + + @Override + public boolean isLazy() { + try { + return ((BodyImpl) getBody()).isLazy(); + } catch (SOAPException e) { + return false; + } + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/FaultImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/FaultImpl.java index c6f7bb8de52..218ce0a7f5c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/FaultImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/FaultImpl.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 @@ -70,17 +70,17 @@ public abstract class FaultImpl extends ElementImpl implements SOAPFault { protected void findFaultCodeElement() { this.faultCodeElement = - (SOAPFaultElement) findChild(getFaultCodeName()); + (SOAPFaultElement) findAndConvertChildElement(getFaultCodeName()); } protected void findFaultActorElement() { this.faultActorElement = - (SOAPFaultElement) findChild(getFaultActorName()); + (SOAPFaultElement) findAndConvertChildElement(getFaultActorName()); } protected void findFaultStringElement() { this.faultStringElement = - (SOAPFaultElement) findChild(getFaultStringName()); + (SOAPFaultElement) findAndConvertChildElement(getFaultStringName()); } public void setFaultCode(String faultCode) throws SOAPException { @@ -162,7 +162,7 @@ public abstract class FaultImpl extends ElementImpl implements SOAPFault { protected void initializeDetail() { NameImpl detailName = getDetailName(); - detail = (Detail) findChild(detailName); + detail = (Detail) findAndConvertChildElement(detailName); } public Detail getDetail() { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/HeaderImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/HeaderImpl.java index 26b3291e79e..74fb2045959 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/HeaderImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/HeaderImpl.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 @@ -32,6 +32,7 @@ import javax.xml.namespace.QName; import javax.xml.soap.*; import org.w3c.dom.Element; +import org.w3c.dom.Node; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPCommentImpl.java similarity index 95% rename from jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java rename to jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPCommentImpl.java index 8711b29bf92..c306beb74f9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPCommentImpl.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 @@ -37,7 +37,7 @@ import org.w3c.dom.Text; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; -public class CommentImpl +public class SOAPCommentImpl extends com.sun.org.apache.xerces.internal.dom.CommentImpl implements javax.xml.soap.Text, org.w3c.dom.Comment { @@ -47,7 +47,7 @@ public class CommentImpl protected static ResourceBundle rb = log.getResourceBundle(); - public CommentImpl(SOAPDocumentImpl ownerDoc, String text) { + public SOAPCommentImpl(SOAPDocumentImpl ownerDoc, String text) { super(ownerDoc, text); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPTextImpl.java similarity index 94% rename from jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java rename to jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPTextImpl.java index ce30ebee5cf..c088928ba90 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPTextImpl.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 @@ -33,7 +33,7 @@ import javax.xml.soap.SOAPException; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; -public class TextImpl +public class SOAPTextImpl extends com.sun.org.apache.xerces.internal.dom.TextImpl implements javax.xml.soap.Text, org.w3c.dom.Text { @@ -41,7 +41,7 @@ public class TextImpl Logger.getLogger(LogDomainConstants.SOAP_IMPL_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.impl.LocalStrings"); - public TextImpl(SOAPDocumentImpl ownerDoc, String text) { + public SOAPTextImpl(SOAPDocumentImpl ownerDoc, String text) { super(ownerDoc, text); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java index 2f51b167c00..e52640fc399 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.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 @@ -35,6 +35,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamReader; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ContentType; @@ -70,6 +71,11 @@ public class Message1_1Impl extends MessageImpl implements SOAPConstants { super(headers,ct,stat,in); } + public Message1_1Impl(MimeHeaders headers, ContentType ct, int stat, XMLStreamReader reader) + throws SOAPExceptionImpl { + super(headers,ct,stat,reader); + } + public SOAPPart getSOAPPart() { if (soapPartImpl == null) { soapPartImpl = new SOAPPart1_1Impl(this); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java index ebb038e042d..35a0d1025fd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.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 @@ -90,4 +90,9 @@ public class SOAPPart1_1Impl extends SOAPPartImpl implements SOAPConstants { return new SOAPPart1_1Impl(); } + @Override + public String getSOAPNamespace() { + return SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE; + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java index 5c08f028d0b..0733ebb68c3 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.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 @@ -284,7 +284,7 @@ public class Fault1_2Impl extends FaultImpl { } public String getFaultNode() { - SOAPElement faultNode = findChild(getFaultNodeName()); + SOAPElement faultNode = findAndConvertChildElement(getFaultNodeName()); if (faultNode == null) { return null; } @@ -292,7 +292,7 @@ public class Fault1_2Impl extends FaultImpl { } public void setFaultNode(String uri) throws SOAPException { - SOAPElement faultNode = findChild(getFaultNodeName()); + SOAPElement faultNode = findAndConvertChildElement(getFaultNodeName()); if (faultNode != null) { faultNode.detachNode(); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Message1_2Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Message1_2Impl.java index 87401620028..b63c8ed4f55 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Message1_2Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Message1_2Impl.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 @@ -33,6 +33,7 @@ import java.io.IOException; import java.io.InputStream; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamReader; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ContentType; @@ -63,6 +64,11 @@ public class Message1_2Impl extends MessageImpl implements SOAPConstants{ super(headers,ct,stat,in); } + public Message1_2Impl(MimeHeaders headers, ContentType ct, int stat, XMLStreamReader reader) + throws SOAPExceptionImpl { + super(headers,ct,stat,reader); + } + public SOAPPart getSOAPPart() { if (soapPartImpl == null) soapPartImpl = new SOAPPart1_2Impl(this); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java index e9681792a85..396c21fb06b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.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 @@ -87,4 +87,9 @@ public class SOAPPart1_2Impl extends SOAPPartImpl implements SOAPConstants{ return new SOAPPart1_2Impl(); } + @Override + public String getSOAPNamespace() { + return SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE; + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/JAXMStreamSource.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/JAXMStreamSource.java index b2a440880cd..02580c00e4c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/JAXMStreamSource.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/JAXMStreamSource.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 @@ -47,9 +47,15 @@ public class JAXMStreamSource extends StreamSource { } else if (is instanceof ByteInputStream) { this.in = (ByteInputStream) is; } else { - ByteOutputStream bout = new ByteOutputStream(); - bout.write(is); - this.in = bout.newInputStream(); + ByteOutputStream bout = null; + try { + bout = new ByteOutputStream(); + bout.write(is); + this.in = bout.newInputStream(); + } finally { + if (bout != null) + bout.close(); + } } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/ParserPool.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/ParserPool.java index 1f3be836648..b9c503c9f7f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/ParserPool.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/ParserPool.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 @@ -40,17 +40,15 @@ import org.xml.sax.SAXNotSupportedException; * Pool of SAXParser objects */ public class ParserPool { - private final BlockingQueue queue; + private final BlockingQueue queue; private SAXParserFactory factory; - private int capacity; public ParserPool(int capacity) { - this.capacity = capacity; - queue = new ArrayBlockingQueue(capacity); + queue = new ArrayBlockingQueue(capacity); //factory = SAXParserFactory.newInstance(); factory = new com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl(); factory.setNamespaceAware(true); - for (int i=0; i < capacity; i++) { + for (int i = 0; i < capacity; i++) { try { queue.put(factory.newSAXParser()); } catch (InterruptedException ex) { @@ -75,8 +73,8 @@ public class ParserPool { } - public void put(SAXParser parser) { - queue.offer(parser); + public boolean put(SAXParser parser) { + return queue.offer(parser); } public void returnParser(SAXParser saxParser) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/stax/LazyEnvelopeStaxReader.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/stax/LazyEnvelopeStaxReader.java new file mode 100644 index 00000000000..c8765a4667c --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/stax/LazyEnvelopeStaxReader.java @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.messaging.saaj.util.stax; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.w3c.dom.Node; + +import com.sun.xml.internal.messaging.saaj.soap.impl.BodyImpl; +import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl; + +/** + * "Hybrid" reader which + * @author desagar + * + */ +public class LazyEnvelopeStaxReader extends com.sun.xml.internal.org.jvnet.staxex.util.DOMStreamReader { +// EnvelopeImpl env; + XMLStreamReader payloadReader = null; + boolean usePayloadReaderDelegate = false; + private QName bodyQName; + + public LazyEnvelopeStaxReader(EnvelopeImpl env) throws SOAPException, XMLStreamException { + super(env); +// this.env = env; + bodyQName = new QName(env.getNamespaceURI(), "Body"); + payloadReader = env.getStaxBridge().getPayloadReader(); + int eventType = getEventType(); + while (eventType != START_ELEMENT) { + eventType = nextTag(); + } + } + + public Object getProperty(String name) throws IllegalArgumentException { + if (usePayloadReaderDelegate) return payloadReader.getProperty(name); + return super.getProperty(name); + } + + public int next() throws XMLStreamException { +// boolean previouslyUsingPayloadReader = usePayloadReaderDelegate; + //call checkReaderStatus to advance to payloadReader if needed + checkReaderStatus(true); + + if (usePayloadReaderDelegate) return payloadReader.getEventType(); + + //if we just moved to payload reader, don't advance the pointer +// if (usePayloadReaderDelegate && !previouslyUsingPayloadReader) return payloadReader.getEventType(); + +// if (usePayloadReaderDelegate) return payloadReader.next(); + return getEventType(); + } + + public void require(int type, String namespaceURI, String localName) + throws XMLStreamException { + if (usePayloadReaderDelegate) payloadReader.require(type, namespaceURI, localName); + else super.require(type, namespaceURI, localName); + } + + public String getElementText() throws XMLStreamException { + if (usePayloadReaderDelegate) return payloadReader.getElementText(); + return super.getElementText(); + } + + public int nextTag() throws XMLStreamException { + if (usePayloadReaderDelegate) return payloadReader.nextTag(); + return super.nextTag(); + } + + public boolean hasNext() throws XMLStreamException { + checkReaderStatus(false); + boolean hasNext; + if (usePayloadReaderDelegate) { + hasNext = payloadReader.hasNext(); + } else { + hasNext = super.hasNext(); + } + + /*if (!hasNext && payloadReader != null) { + usePayloadReaderDelegate = true; + hasNext = payloadReader.hasNext(); + }*/ + return hasNext; + } + + private void checkReaderStatus(boolean advanceToNext) throws XMLStreamException { + //if we are using payloadReader, make sure it is not exhausted + //if it is, return to DOM based reader for remaining end elements (body and envelope) + if (usePayloadReaderDelegate) { + if (!payloadReader.hasNext()) { + usePayloadReaderDelegate = false; + } + } else if (START_ELEMENT == getEventType()) { + //if not on payload reader, check if we need to switch to payload reader + + //if the current event is the SOAP body element start, + //and the body is lazy, switch to the payload reader + if (bodyQName.equals(getName())) { + //if we are just switching to payload reader, don't advance...payload reader + //will already be on the first payload element + usePayloadReaderDelegate = true; + advanceToNext = false; + } + } + + if (advanceToNext) { + if (usePayloadReaderDelegate) { + payloadReader.next(); + } else { + super.next(); + } + } + } + + public void close() throws XMLStreamException { + if (usePayloadReaderDelegate) payloadReader.close(); + else super.close(); + } + + public String getNamespaceURI(String prefix) { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceURI(prefix); + return super.getNamespaceURI(prefix); + } + + public boolean isStartElement() { + if (usePayloadReaderDelegate) return payloadReader.isStartElement(); + return super.isStartElement(); + } + + public boolean isEndElement() { + if (usePayloadReaderDelegate) return payloadReader.isEndElement(); + return super.isEndElement(); + } + + public boolean isCharacters() { + if (usePayloadReaderDelegate) return payloadReader.isCharacters(); + return super.isEndElement(); + } + + public boolean isWhiteSpace() { + if (usePayloadReaderDelegate) return payloadReader.isWhiteSpace(); + return super.isWhiteSpace(); + } + + public String getAttributeValue(String namespaceURI, String localName) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeValue(namespaceURI, localName); + return super.getAttributeValue(namespaceURI, localName); + } + + public int getAttributeCount() { + if (usePayloadReaderDelegate) return payloadReader.getAttributeCount(); + return super.getAttributeCount(); + } + + public QName getAttributeName(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeName(index); + return super.getAttributeName(index); + } + + public String getAttributeNamespace(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeNamespace(index); + return super.getAttributeNamespace(index); + } + + public String getAttributeLocalName(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeLocalName(index); + return super.getAttributeLocalName(index); + } + + public String getAttributePrefix(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributePrefix(index); + return super.getAttributePrefix(index); + } + + public String getAttributeType(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeType(index); + return super.getAttributeType(index); + } + + public String getAttributeValue(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeValue(index); + return super.getAttributeValue(index); + } + + public boolean isAttributeSpecified(int index) { + if (usePayloadReaderDelegate) return payloadReader.isAttributeSpecified(index); + return super.isAttributeSpecified(index); + } + + public int getNamespaceCount() { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceCount(); + return super.getNamespaceCount(); + } + + public String getNamespacePrefix(int index) { + if (usePayloadReaderDelegate) return payloadReader.getNamespacePrefix(index); + return super.getNamespacePrefix(index); + } + + public String getNamespaceURI(int index) { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceURI(index); + return super.getNamespaceURI(index); + } + + public NamespaceContext getNamespaceContext() { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceContext(); + return super.getNamespaceContext(); + } + + public int getEventType() { + if (usePayloadReaderDelegate) return payloadReader.getEventType(); + return super.getEventType(); + } + + public String getText() { + if (usePayloadReaderDelegate) return payloadReader.getText(); + return super.getText(); + } + + public char[] getTextCharacters() { + if (usePayloadReaderDelegate) return payloadReader.getTextCharacters(); + return super.getTextCharacters(); + } + + public int getTextCharacters(int sourceStart, char[] target, + int targetStart, int length) throws XMLStreamException { + if (usePayloadReaderDelegate) return payloadReader.getTextCharacters(sourceStart, target, targetStart, + length); + return super.getTextCharacters(sourceStart, target, targetStart, length); + } + + public int getTextStart() { + if (usePayloadReaderDelegate) return payloadReader.getTextStart(); + return super.getTextStart(); + } + + public int getTextLength() { + if (usePayloadReaderDelegate) return payloadReader.getTextLength(); + return super.getTextLength(); + } + + public String getEncoding() { + if (usePayloadReaderDelegate) return payloadReader.getEncoding(); + return super.getEncoding(); + } + + public boolean hasText() { + if (usePayloadReaderDelegate) return payloadReader.hasText(); + return super.hasText(); + } + + public Location getLocation() { + if (usePayloadReaderDelegate) return payloadReader.getLocation(); + return super.getLocation(); + } + + public QName getName() { + if (usePayloadReaderDelegate) return payloadReader.getName(); + return super.getName(); + } + + public String getLocalName() { + if (usePayloadReaderDelegate) return payloadReader.getLocalName(); + return super.getLocalName(); + } + + public boolean hasName() { + if (usePayloadReaderDelegate) return payloadReader.hasName(); + return super.hasName(); + } + + public String getNamespaceURI() { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceURI(); + return super.getNamespaceURI(); + } + + public String getPrefix() { + if (usePayloadReaderDelegate) return payloadReader.getPrefix(); + return super.getPrefix(); + } + + public String getVersion() { + if (usePayloadReaderDelegate) return payloadReader.getVersion(); + return super.getVersion(); + } + + public boolean isStandalone() { + if (usePayloadReaderDelegate) return payloadReader.isStandalone(); + return super.isStandalone(); + } + + public boolean standaloneSet() { + if (usePayloadReaderDelegate) return payloadReader.standaloneSet(); + return super.standaloneSet(); + } + + public String getCharacterEncodingScheme() { + if (usePayloadReaderDelegate) return payloadReader.getCharacterEncodingScheme(); + return super.getCharacterEncodingScheme(); + } + + public String getPITarget() { + if (usePayloadReaderDelegate) return payloadReader.getPITarget(); + return super.getPITarget(); + } + + public String getPIData() { + if (usePayloadReaderDelegate) return payloadReader.getPIData(); + return super.getPIData(); + } + + //make sure that message is not realized as a result of call + //to getFirstChild + protected Node getFirstChild(Node node) { + if (node instanceof BodyImpl) { + return ((BodyImpl) node).getFirstChildNoMaterialize(); + } else { + return node.getFirstChild(); + } + } + + protected Node getNextSibling(Node node) { + if (node instanceof BodyImpl) { + //body is not expected to have a next sibling - even if it does + //we would have to materialize the node to retrieve it. + //Since we don't want to materialize it right now, just return null + return null; + } + return node.getNextSibling(); + } + +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/CleanUpExecutorFactory.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/CleanUpExecutorFactory.java index 2621bc48818..e81a24319bd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/CleanUpExecutorFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/CleanUpExecutorFactory.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 @@ -25,7 +25,7 @@ package com.sun.xml.internal.org.jvnet.mimepull; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; public abstract class CleanUpExecutorFactory { private static final String DEFAULT_PROPERTY_NAME = CleanUpExecutorFactory.class @@ -42,5 +42,5 @@ public abstract class CleanUpExecutorFactory { } } - public abstract Executor getExecutor(); + public abstract ScheduledExecutorService getScheduledExecutorService(); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/WeakDataFile.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/WeakDataFile.java index 23e54a0ac79..5eda7fe70a6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/WeakDataFile.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/WeakDataFile.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 @@ -25,6 +25,8 @@ package com.sun.xml.internal.org.jvnet.mimepull; +import java.util.concurrent.TimeUnit; + import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; @@ -32,7 +34,7 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; import java.util.logging.Level; import java.util.logging.Logger; @@ -45,6 +47,7 @@ import java.util.logging.Logger; final class WeakDataFile extends WeakReference { private static final Logger LOGGER = Logger.getLogger(WeakDataFile.class.getName()); + private static int TIMEOUT = 10; //milliseconds //private static final int MAX_ITERATIONS = 2; private static ReferenceQueue refQueue = new ReferenceQueue(); private static List refList = new ArrayList(); @@ -52,28 +55,22 @@ final class WeakDataFile extends WeakReference { private final RandomAccessFile raf; private static boolean hasCleanUpExecutor = false; static { + int delay = 10; + try { + delay = Integer.getInteger("com.sun.xml.internal.org.jvnet.mimepull.delay", 10); + } catch (SecurityException se) { + if (LOGGER.isLoggable(Level.CONFIG)) { + LOGGER.log(Level.CONFIG, "Cannot read ''{0}'' property, using defaults.", + new Object[] {"com.sun.xml.internal.org.jvnet.mimepull.delay"}); + } + } CleanUpExecutorFactory executorFactory = CleanUpExecutorFactory.newInstance(); if (executorFactory!=null) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Initializing clean up executor for MIMEPULL: {0}", executorFactory.getClass().getName()); } - Executor executor = executorFactory.getExecutor(); - executor.execute(new Runnable() { - @Override - public void run() { - WeakDataFile weak; - while (true) { - try { - weak = (WeakDataFile) refQueue.remove(); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file); - } - weak.close(); - } catch (InterruptedException e) { - } - } - } - }); + ScheduledExecutorService scheduler = executorFactory.getScheduledExecutorService(); + scheduler.scheduleWithFixedDelay(new CleanupRunnable(), delay, delay, TimeUnit.SECONDS); hasCleanUpExecutor = true; } } @@ -157,4 +154,24 @@ final class WeakDataFile extends WeakReference { weak.close(); } } + +private static class CleanupRunnable implements Runnable { + @Override + public void run() { + try { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Running cleanup task"); + } + WeakDataFile weak = (WeakDataFile) refQueue.remove(TIMEOUT); + while (weak != null) { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file); + } + weak.close(); + weak = (WeakDataFile) refQueue.remove(TIMEOUT); + } + } catch (InterruptedException e) { + } + } +} } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/Base64Data.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/Base64Data.java index 62d6dcaab95..4fc6afdfa83 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/Base64Data.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/Base64Data.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 @@ -62,6 +62,7 @@ public class Base64Data implements CharSequence, Cloneable { private DataHandler dataHandler; private byte[] data; + private String hrefCid; /** * Length of the valid data in {@link #data}. @@ -531,4 +532,16 @@ public class Base64Data implements CharSequence, Cloneable { // // } + public String getHrefCid() { + if (hrefCid == null && dataHandler != null && dataHandler instanceof StreamingDataHandler) { + hrefCid = ((StreamingDataHandler)dataHandler).getHrefCid(); + } + return hrefCid; + } + + public void setHrefCid(final String cid) { + this.hrefCid = cid; + if (dataHandler != null && dataHandler instanceof StreamingDataHandler) ((StreamingDataHandler)dataHandler).setHrefCid(cid); + } + } diff --git a/jdk/src/share/classes/java/net/SdpSocketImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/BinaryText.java similarity index 64% rename from jdk/src/share/classes/java/net/SdpSocketImpl.java rename to jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/BinaryText.java index b5b023e2433..d3f5e887b34 100644 --- a/jdk/src/share/classes/java/net/SdpSocketImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/BinaryText.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 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 @@ -23,27 +23,18 @@ * questions. */ -package java.net; +package com.sun.xml.internal.org.jvnet.staxex; -import java.io.IOException; -import java.io.FileDescriptor; - -import sun.net.sdp.SdpSupport; +import javax.activation.DataHandler; +import javax.xml.soap.SOAPException; +import javax.xml.soap.Text; /** - * SocketImpl that supports the SDP protocol + * BinaryText represents a MTOM attachment. + * + * @author shih-chang.chen@oracle.com */ -class SdpSocketImpl extends PlainSocketImpl { - SdpSocketImpl() { } - - @Override - protected void create(boolean stream) throws IOException { - if (!stream) - throw new UnsupportedOperationException("Must be a stream socket"); - fd = SdpSupport.createSocket(); - if (socket != null) - socket.setCreated(); - if (serverSocket != null) - serverSocket.setCreated(); - } +public interface BinaryText extends Text { + public String getHref(); + public DataHandler getDataHandler() throws SOAPException; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/MtomEnabled.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/MtomEnabled.java new file mode 100644 index 00000000000..d3ce3ef7bbd --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/MtomEnabled.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex; + +import javax.activation.DataHandler; + +/** + * A SOAPElement implementation may support this interface to allow MTOM attachments. + * + * @author shih-chang.chen@oracle.com + */ +public interface MtomEnabled { + BinaryText addBinaryText(byte[] bytes); + BinaryText addBinaryText(String contentType, byte[] bytes); + BinaryText addBinaryText(String href, DataHandler dl); +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StAxSOAPBody.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StAxSOAPBody.java new file mode 100644 index 00000000000..ff1b1f8713c --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StAxSOAPBody.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +/** + * A StAxSOAPBody is a SOAPBody that allows to be loaded from a StAX style payload. + * + * @author shih-chang.chen@oracle.com + */ +public interface StAxSOAPBody { + + /** + * The StAxSOAPBody represents the StAX source of SOAPBody payload. + */ + public static interface Payload { + + /** + * Retrieve payload qname without materializing its contents + * @return + * @throws SOAPException + */ + public QName getPayloadQName(); + + public XMLStreamReader readPayload() throws XMLStreamException; + + public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException; + + /** + * Retrieve payload attribute value without materializing its contents + * @param localName + * @return + * @throws SOAPException + */ + public String getPayloadAttributeValue(String localName) throws XMLStreamException; + + /** + * Retrieve payload attribute value without materializing its contents + * @param qName + * @return + * @throws SOAPException + */ + public String getPayloadAttributeValue(QName qName) throws XMLStreamException; + + public void materialize() throws SOAPException; + } + + public void setPayload(Payload src) throws SOAPException; + + public Payload getPayload()throws SOAPException; + + public boolean hasStaxPayload(); + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StreamingDataHandler.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StreamingDataHandler.java index 409cea5c67e..dda4a38f36a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StreamingDataHandler.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StreamingDataHandler.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 @@ -52,6 +52,8 @@ import java.net.URL; */ public abstract class StreamingDataHandler extends DataHandler implements Closeable { + private String hrefCid; + public StreamingDataHandler(Object o, String s) { super(o, s); } @@ -142,4 +144,11 @@ public abstract class StreamingDataHandler extends DataHandler implements Closea */ public abstract void close() throws IOException; + public String getHrefCid() { + return hrefCid; + } + + public void setHrefCid(final String cid) { + this.hrefCid = cid; + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DOMStreamReader.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DOMStreamReader.java new file mode 100644 index 00000000000..74b73f7f0ca --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DOMStreamReader.java @@ -0,0 +1,895 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import static org.w3c.dom.Node.*; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.Collections; +import java.util.Iterator; + +/** + * Create an {@link XMLStreamReader} on top of a DOM tree. + * + *

+ * Since various libraries as well as users often create "incorrect" DOM node, + * this class spends a lot of efforts making sure that broken DOM trees are + * nevertheless interpreted correctly. + * + *

+ * For example, if a DOM level + * 1 tree is passed, each method will attempt to return the correct value + * by using {@link Node#getNodeName()}. + * + *

+ * Similarly, if DOM is missing explicit namespace declarations, + * this class attempts to emulate necessary declarations. + * + * + * @author Santiago.PericasGeertsen@sun.com + * @author Kohsuke Kawaguchi + */ +public class DOMStreamReader implements XMLStreamReader, NamespaceContext { + + /** + * Current DOM node being traversed. + */ + protected Node _current; + + /** + * Starting node of the subtree being traversed. + */ + private Node _start; + + /** + * Named mapping for attributes and NS decls for the current node. + */ + private NamedNodeMap _namedNodeMap; + + /** + * If the reader points at {@link #CHARACTERS the text node}, + * its whole value. + * + *

+ * This is simply a cache of {@link Text#getWholeText()} of {@link #_current}, + * but when a large binary data sent as base64 text, this could get very much + * non-trivial. + */ + protected String wholeText; + + /** + * List of attributes extracted from _namedNodeMap. + */ + private final FinalArrayList _currentAttributes = new FinalArrayList(); + + /** + * {@link Scope} buffer. + */ + protected Scope[] scopes = new Scope[8]; + + /** + * Depth of the current element. The first element gets depth==0. + * Also used as the index to {@link #scopes}. + */ + protected int depth = 0; + + /** + * State of this reader. Any of the valid states defined in StAX' + * XMLStreamConstants class. + */ + protected int _state; + + /** + * Namespace declarations on one element. + * + * Instances are reused. + */ + protected static final class Scope { + /** + * Scope for the parent element. + */ + final Scope parent; + + /** + * List of namespace declarations extracted from _namedNodeMap + */ + final FinalArrayList currentNamespaces = new FinalArrayList(); + + /** + * Additional namespace declarations obtained as a result of "fixing" DOM tree, + * which were not part of the original DOM tree. + * + * One entry occupies two spaces (prefix followed by URI.) + */ + final FinalArrayList additionalNamespaces = new FinalArrayList(); + + Scope(Scope parent) { + this.parent = parent; + } + + void reset() { + currentNamespaces.clear(); + additionalNamespaces.clear(); + } + + int getNamespaceCount() { + return currentNamespaces.size()+additionalNamespaces.size()/2; + } + + String getNamespacePrefix(int index) { + int sz = currentNamespaces.size(); + if(index< sz) { + Attr attr = currentNamespaces.get(index); + String result = attr.getLocalName(); + if (result == null) { + result = QName.valueOf(attr.getNodeName()).getLocalPart(); + } + return result.equals("xmlns") ? null : result; + } else { + return additionalNamespaces.get((index-sz)*2); + } + } + + String getNamespaceURI(int index) { + int sz = currentNamespaces.size(); + if(index< sz) { + return currentNamespaces.get(index).getValue(); + } else { + return additionalNamespaces.get((index-sz)*2+1); + } + } + + /** + * Returns the prefix bound to the given URI, or null. + * This method recurses to the parent. + */ + String getPrefix(String nsUri) { + for( Scope sp=this; sp!=null; sp=sp.parent ) { + for( int i=sp.currentNamespaces.size()-1; i>=0; i--) { + String result = getPrefixForAttr(sp.currentNamespaces.get(i),nsUri); + if(result!=null) + return result; + } + for( int i=sp.additionalNamespaces.size()-2; i>=0; i-=2 ) + if(sp.additionalNamespaces.get(i+1).equals(nsUri)) + return sp.additionalNamespaces.get(i); + } + return null; + } + + /** + * Returns the namespace URI bound by the given prefix. + * + * @param prefix + * Prefix to look up. + */ + String getNamespaceURI(String prefix) { + String nsDeclName = prefix.length()==0 ? "xmlns" : "xmlns:"+prefix; + + for( Scope sp=this; sp!=null; sp=sp.parent ) { + for( int i=sp.currentNamespaces.size()-1; i>=0; i--) { + Attr a = sp.currentNamespaces.get(i); + if(a.getNodeName().equals(nsDeclName)) + return a.getValue(); + } + for( int i=sp.additionalNamespaces.size()-2; i>=0; i-=2 ) + if(sp.additionalNamespaces.get(i).equals(prefix)) + return sp.additionalNamespaces.get(i+1); + } + return null; + } + } + + + public DOMStreamReader() { + } + + public DOMStreamReader(Node node) { + setCurrentNode(node); + } + + public void setCurrentNode(Node node) { + scopes[0] = new Scope(null); + depth=0; + + _start = _current = node; + _state = START_DOCUMENT; + // verifyDOMIntegrity(node); + // displayDOM(node, System.out); + } + + public void close() throws XMLStreamException { + } + + /** + * Called when the current node is {@link Element} to look at attribute list + * (which contains both ns decl and attributes in DOM) and split them + * to attributes-proper and namespace decls. + */ + protected void splitAttributes() { + // Clear attribute and namespace lists + _currentAttributes.clear(); + + Scope scope = allocateScope(); + + _namedNodeMap = _current.getAttributes(); + if (_namedNodeMap != null) { + final int n = _namedNodeMap.getLength(); + for (int i = 0; i < n; i++) { + final Attr attr = (Attr) _namedNodeMap.item(i); + final String attrName = attr.getNodeName(); + if (attrName.startsWith("xmlns:") || attrName.equals("xmlns")) { // NS decl? + scope.currentNamespaces.add(attr); + } + else { + _currentAttributes.add(attr); + } + } + } + + // verify that all the namespaces used in element and attributes are indeed available + ensureNs(_current); + for( int i=_currentAttributes.size()-1; i>=0; i-- ) { + Attr a = _currentAttributes.get(i); + if(fixNull(a.getNamespaceURI()).length()>0) + ensureNs(a); // no need to declare "" for attributes in the default namespace + } + } + + /** + * Sub-routine of {@link #splitAttributes()}. + * + *

+ * Makes sure that the namespace URI/prefix used in the given node is available, + * and if not, declare it on the current scope to "fix" it. + * + * It's often common to create DOM trees without putting namespace declarations, + * and this makes sure that such DOM tree will be properly marshalled. + */ + private void ensureNs(Node n) { + String prefix = fixNull(n.getPrefix()); + String uri = fixNull(n.getNamespaceURI()); + + Scope scope = scopes[depth]; + + String currentUri = scope.getNamespaceURI(prefix); + + if(prefix.length()==0) { + currentUri = fixNull(currentUri); + if(currentUri.equals(uri)) + return; // declared correctly + } else { + if(currentUri!=null && currentUri.equals(uri)) + return; // declared correctly + } + + if(prefix.equals("xml") || prefix.equals("xmlns")) + return; // implicitly declared namespaces + + // needs to be declared + scope.additionalNamespaces.add(prefix); + scope.additionalNamespaces.add(uri); + } + + /** + * Allocate new {@link Scope} for {@link #splitAttributes()}. + */ + private Scope allocateScope() { + if(scopes.length==++depth) { + Scope[] newBuf = new Scope[scopes.length*2]; + System.arraycopy(scopes,0,newBuf,0,scopes.length); + scopes = newBuf; + } + Scope scope = scopes[depth]; + if(scope==null) { + scope = scopes[depth] = new Scope(scopes[depth-1]); + } else { + scope.reset(); + } + return scope; + } + + public int getAttributeCount() { + if (_state == START_ELEMENT) + return _currentAttributes.size(); + throw new IllegalStateException("DOMStreamReader: getAttributeCount() called in illegal state"); + } + + /** + * Return an attribute's local name. Handle the case of DOM level 1 nodes. + */ + public String getAttributeLocalName(int index) { + if (_state == START_ELEMENT) { + String localName = _currentAttributes.get(index).getLocalName(); + return (localName != null) ? localName : + QName.valueOf(_currentAttributes.get(index).getNodeName()).getLocalPart(); + } + throw new IllegalStateException("DOMStreamReader: getAttributeLocalName() called in illegal state"); + } + + /** + * Return an attribute's qname. Handle the case of DOM level 1 nodes. + */ + public QName getAttributeName(int index) { + if (_state == START_ELEMENT) { + Node attr = _currentAttributes.get(index); + String localName = attr.getLocalName(); + if (localName != null) { + String prefix = attr.getPrefix(); + String uri = attr.getNamespaceURI(); + return new QName(fixNull(uri), localName, fixNull(prefix)); + } + else { + return QName.valueOf(attr.getNodeName()); + } + } + throw new IllegalStateException("DOMStreamReader: getAttributeName() called in illegal state"); + } + + public String getAttributeNamespace(int index) { + if (_state == START_ELEMENT) { + String uri = _currentAttributes.get(index).getNamespaceURI(); + return fixNull(uri); + } + throw new IllegalStateException("DOMStreamReader: getAttributeNamespace() called in illegal state"); + } + + public String getAttributePrefix(int index) { + if (_state == START_ELEMENT) { + String prefix = _currentAttributes.get(index).getPrefix(); + return fixNull(prefix); + } + throw new IllegalStateException("DOMStreamReader: getAttributePrefix() called in illegal state"); + } + + public String getAttributeType(int index) { + if (_state == START_ELEMENT) { + return "CDATA"; + } + throw new IllegalStateException("DOMStreamReader: getAttributeType() called in illegal state"); + } + + public String getAttributeValue(int index) { + if (_state == START_ELEMENT) { + return _currentAttributes.get(index).getNodeValue(); + } + throw new IllegalStateException("DOMStreamReader: getAttributeValue() called in illegal state"); + } + + public String getAttributeValue(String namespaceURI, String localName) { + if (_state == START_ELEMENT) { + if (_namedNodeMap != null) { + Node attr = _namedNodeMap.getNamedItemNS(namespaceURI, localName); + return attr != null ? attr.getNodeValue() : null; + } + return null; + } + throw new IllegalStateException("DOMStreamReader: getAttributeValue() called in illegal state"); + } + + public String getCharacterEncodingScheme() { + return null; + } + + public String getElementText() throws javax.xml.stream.XMLStreamException { + throw new RuntimeException("DOMStreamReader: getElementText() not implemented"); + } + + public String getEncoding() { + return null; + } + + public int getEventType() { + return _state; + } + + /** + * Return an element's local name. Handle the case of DOM level 1 nodes. + */ + public String getLocalName() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + String localName = _current.getLocalName(); + return localName != null ? localName : + QName.valueOf(_current.getNodeName()).getLocalPart(); + } + else if (_state == ENTITY_REFERENCE) { + return _current.getNodeName(); + } + throw new IllegalStateException("DOMStreamReader: getAttributeValue() called in illegal state"); + } + + public Location getLocation() { + return DummyLocation.INSTANCE; + } + + /** + * Return an element's qname. Handle the case of DOM level 1 nodes. + */ + public javax.xml.namespace.QName getName() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + String localName = _current.getLocalName(); + if (localName != null) { + String prefix = _current.getPrefix(); + String uri = _current.getNamespaceURI(); + return new QName(fixNull(uri), localName, fixNull(prefix)); + } + else { + return QName.valueOf(_current.getNodeName()); + } + } + throw new IllegalStateException("DOMStreamReader: getName() called in illegal state"); + } + + public NamespaceContext getNamespaceContext() { + return this; + } + + /** + * Verifies the current state to see if we can return the scope, and do so + * if appropriate. + * + * Used to implement a bunch of StAX API methods that have the same usage restriction. + */ + private Scope getCheckedScope() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + return scopes[depth]; + } + throw new IllegalStateException("DOMStreamReader: neither on START_ELEMENT nor END_ELEMENT"); + } + + public int getNamespaceCount() { + return getCheckedScope().getNamespaceCount(); + } + + public String getNamespacePrefix(int index) { + return getCheckedScope().getNamespacePrefix(index); + } + + public String getNamespaceURI(int index) { + return getCheckedScope().getNamespaceURI(index); + } + + public String getNamespaceURI() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + String uri = _current.getNamespaceURI(); + return fixNull(uri); + } + return null; + } + + /** + * This method is not particularly fast, but shouldn't be called very + * often. If we start to use it more, we should keep track of the + * NS declarations using a NamespaceContext implementation instead. + */ + public String getNamespaceURI(String prefix) { + if (prefix == null) { + throw new IllegalArgumentException("DOMStreamReader: getNamespaceURI(String) call with a null prefix"); + } + else if (prefix.equals("xml")) { + return "http://www.w3.org/XML/1998/namespace"; + } + else if (prefix.equals("xmlns")) { + return "http://www.w3.org/2000/xmlns/"; + } + + // check scopes + String nsUri = scopes[depth].getNamespaceURI(prefix); + if(nsUri!=null) return nsUri; + + // then ancestors above start node + Node node = findRootElement(); + String nsDeclName = prefix.length()==0 ? "xmlns" : "xmlns:"+prefix; + while (node.getNodeType() != DOCUMENT_NODE) { + // Is ns declaration on this element? + NamedNodeMap namedNodeMap = node.getAttributes(); + Attr attr = (Attr) namedNodeMap.getNamedItem(nsDeclName); + if (attr != null) + return attr.getValue(); + node = node.getParentNode(); + } + return null; + } + + public String getPrefix(String nsUri) { + if (nsUri == null) { + throw new IllegalArgumentException("DOMStreamReader: getPrefix(String) call with a null namespace URI"); + } + else if (nsUri.equals("http://www.w3.org/XML/1998/namespace")) { + return "xml"; + } + else if (nsUri.equals("http://www.w3.org/2000/xmlns/")) { + return "xmlns"; + } + + // check scopes + String prefix = scopes[depth].getPrefix(nsUri); + if(prefix!=null) return prefix; + + // then ancestors above start node + Node node = findRootElement(); + + while (node.getNodeType() != DOCUMENT_NODE) { + // Is ns declaration on this element? + NamedNodeMap namedNodeMap = node.getAttributes(); + for( int i=namedNodeMap.getLength()-1; i>=0; i-- ) { + Attr attr = (Attr)namedNodeMap.item(i); + prefix = getPrefixForAttr(attr,nsUri); + if(prefix!=null) + return prefix; + } + node = node.getParentNode(); + } + return null; + } + + /** + * Finds the root element node of the traversal. + */ + private Node findRootElement() { + int type; + + Node node = _start; + while ((type = node.getNodeType()) != DOCUMENT_NODE + && type != ELEMENT_NODE) { + node = node.getParentNode(); + } + return node; + } + + /** + * If the given attribute is a namespace declaration for the given namespace URI, + * return its prefix. Otherwise null. + */ + private static String getPrefixForAttr(Attr attr, String nsUri) { + String attrName = attr.getNodeName(); + if (!attrName.startsWith("xmlns:") && !attrName.equals("xmlns")) + return null; // not nsdecl + + if(attr.getValue().equals(nsUri)) { + if(attrName.equals("xmlns")) + return ""; + String localName = attr.getLocalName(); + return (localName != null) ? localName : + QName.valueOf(attrName).getLocalPart(); + } + + return null; + } + + public Iterator getPrefixes(String nsUri) { + // This is an incorrect implementation, + // but AFAIK it's not used in the JAX-WS runtime + String prefix = getPrefix(nsUri); + if(prefix==null) return Collections.emptyList().iterator(); + else return Collections.singletonList(prefix).iterator(); + } + + public String getPIData() { + if (_state == PROCESSING_INSTRUCTION) { + return ((ProcessingInstruction) _current).getData(); + } + return null; + } + + public String getPITarget() { + if (_state == PROCESSING_INSTRUCTION) { + return ((ProcessingInstruction) _current).getTarget(); + } + return null; + } + + public String getPrefix() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + String prefix = _current.getPrefix(); + return fixNull(prefix); + } + return null; + } + + public Object getProperty(String str) throws IllegalArgumentException { + return null; + } + + public String getText() { + if (_state == CHARACTERS) + return wholeText; + if(_state == CDATA || _state == COMMENT || _state == ENTITY_REFERENCE) + return _current.getNodeValue(); + throw new IllegalStateException("DOMStreamReader: getTextLength() called in illegal state"); + } + + public char[] getTextCharacters() { + return getText().toCharArray(); + } + + public int getTextCharacters(int sourceStart, char[] target, int targetStart, + int targetLength) throws XMLStreamException { + String text = getText(); + int copiedSize = Math.min(targetLength, text.length() - sourceStart); + text.getChars(sourceStart, sourceStart + copiedSize, target, targetStart); + + return copiedSize; + } + + public int getTextLength() { + return getText().length(); + } + + public int getTextStart() { + if (_state == CHARACTERS || _state == CDATA || _state == COMMENT || _state == ENTITY_REFERENCE) { + return 0; + } + throw new IllegalStateException("DOMStreamReader: getTextStart() called in illegal state"); + } + + public String getVersion() { + return null; + } + + public boolean hasName() { + return (_state == START_ELEMENT || _state == END_ELEMENT); + } + + public boolean hasNext() throws javax.xml.stream.XMLStreamException { + return (_state != END_DOCUMENT); + } + + public boolean hasText() { + if (_state == CHARACTERS || _state == CDATA || _state == COMMENT || _state == ENTITY_REFERENCE) { + return getText().trim().length() > 0; + } + return false; + } + + public boolean isAttributeSpecified(int param) { + return false; + } + + public boolean isCharacters() { + return (_state == CHARACTERS); + } + + public boolean isEndElement() { + return (_state == END_ELEMENT); + } + + public boolean isStandalone() { + return true; + } + + public boolean isStartElement() { + return (_state == START_ELEMENT); + } + + public boolean isWhiteSpace() { + if (_state == CHARACTERS || _state == CDATA) + return getText().trim().length()==0; + return false; + } + + private static int mapNodeTypeToState(int nodetype) { + switch (nodetype) { + case CDATA_SECTION_NODE: + return CDATA; + case COMMENT_NODE: + return COMMENT; + case ELEMENT_NODE: + return START_ELEMENT; + case ENTITY_NODE: + return ENTITY_DECLARATION; + case ENTITY_REFERENCE_NODE: + return ENTITY_REFERENCE; + case NOTATION_NODE: + return NOTATION_DECLARATION; + case PROCESSING_INSTRUCTION_NODE: + return PROCESSING_INSTRUCTION; + case TEXT_NODE: + return CHARACTERS; + default: + throw new RuntimeException("DOMStreamReader: Unexpected node type"); + } + } + + public int next() throws XMLStreamException { + while(true) { + int r = _next(); + switch (r) { + case CHARACTERS: + // if we are currently at text node, make sure that this is a meaningful text node. + Node prev = _current.getPreviousSibling(); + if(prev!=null && prev.getNodeType()==Node.TEXT_NODE) + continue; // nope. this is just a continuation of previous text that should be invisible + + Text t = (Text)_current; + wholeText = t.getWholeText(); + if(wholeText.length()==0) + continue; // nope. this is empty text. + return CHARACTERS; + case START_ELEMENT: + splitAttributes(); + return START_ELEMENT; + default: + return r; + } + } + } + + protected int _next() throws XMLStreamException { + Node child; + + switch (_state) { + case END_DOCUMENT: + throw new IllegalStateException("DOMStreamReader: Calling next() at END_DOCUMENT"); + case START_DOCUMENT: + // Don't skip document element if this is a fragment + if (_current.getNodeType() == ELEMENT_NODE) { + return (_state = START_ELEMENT); + } + + child = _current.getFirstChild(); + if (child == null) { + return (_state = END_DOCUMENT); + } + else { + _current = child; + return (_state = mapNodeTypeToState(_current.getNodeType())); + } + case START_ELEMENT: + child = _current.getFirstChild(); + if (child == null) { + return (_state = END_ELEMENT); + } + else { + _current = child; + return (_state = mapNodeTypeToState(_current.getNodeType())); + } + case END_ELEMENT: + case CHARACTERS: + case COMMENT: + case CDATA: + case ENTITY_REFERENCE: + case PROCESSING_INSTRUCTION: + if (_state == END_ELEMENT) depth--; + // If at the end of this fragment, then terminate traversal + if (_current == _start) { + return (_state = END_DOCUMENT); + } + + Node sibling = _current.getNextSibling(); + if (sibling == null) { + _current = _current.getParentNode(); + // getParentNode() returns null for fragments + _state = (_current == null || _current.getNodeType() == DOCUMENT_NODE) ? + END_DOCUMENT : END_ELEMENT; + return _state; + } + else { + _current = sibling; + return (_state = mapNodeTypeToState(_current.getNodeType())); + } + case DTD: + case ATTRIBUTE: + case NAMESPACE: + default: + throw new RuntimeException("DOMStreamReader: Unexpected internal state"); + } + } + + public int nextTag() throws javax.xml.stream.XMLStreamException { + int eventType = next(); + while (eventType == CHARACTERS && isWhiteSpace() + || eventType == CDATA && isWhiteSpace() + || eventType == SPACE + || eventType == PROCESSING_INSTRUCTION + || eventType == COMMENT) + { + eventType = next(); + } + if (eventType != START_ELEMENT && eventType != END_ELEMENT) { + throw new XMLStreamException("DOMStreamReader: Expected start or end tag"); + } + return eventType; + } + + public void require(int type, String namespaceURI, String localName) + throws javax.xml.stream.XMLStreamException + { + if (type != _state) { + throw new XMLStreamException("DOMStreamReader: Required event type not found"); + } + if (namespaceURI != null && !namespaceURI.equals(getNamespaceURI())) { + throw new XMLStreamException("DOMStreamReader: Required namespaceURI not found"); + } + if (localName != null && !localName.equals(getLocalName())) { + throw new XMLStreamException("DOMStreamReader: Required localName not found"); + } + } + + public boolean standaloneSet() { + return true; + } + + + + // -- Debugging ------------------------------------------------------ +/* + private static void displayDOM(Node node, java.io.OutputStream ostream) { + try { + System.out.println("\n====\n"); + XmlUtil.newTransformer().transform( + new DOMSource(node), new StreamResult(ostream)); + System.out.println("\n====\n"); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private static void verifyDOMIntegrity(Node node) { + switch (node.getNodeType()) { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + + // DOM level 1? + if (node.getLocalName() == null) { + System.out.println("WARNING: DOM level 1 node found"); + System.out.println(" -> node.getNodeName() = " + node.getNodeName()); + System.out.println(" -> node.getNamespaceURI() = " + node.getNamespaceURI()); + System.out.println(" -> node.getLocalName() = " + node.getLocalName()); + System.out.println(" -> node.getPrefix() = " + node.getPrefix()); + } + + if (node.getNodeType() == ATTRIBUTE_NODE) return; + + NamedNodeMap attrs = node.getAttributes(); + for (int i = 0; i < attrs.getLength(); i++) { + verifyDOMIntegrity(attrs.item(i)); + } + case DOCUMENT_NODE: + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + verifyDOMIntegrity(children.item(i)); + } + } + } +*/ + + private static String fixNull(String s) { + if(s==null) return ""; + else return s; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DummyLocation.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DummyLocation.java new file mode 100644 index 00000000000..8bcd3b83584 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DummyLocation.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import javax.xml.stream.Location; + +/** + * {@link Location} that returns no info. + * + * @author Santiago.PericasGeertsen@sun.com + */ +public final class DummyLocation implements Location { + private DummyLocation() {} + + public static final Location INSTANCE = new DummyLocation(); + + public int getCharacterOffset() { + return -1; + } + public int getColumnNumber() { + return -1; + } + public int getLineNumber() { + return -1; + } + public String getPublicId() { + return null; + } + public String getSystemId() { + return null; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/FinalArrayList.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/FinalArrayList.java new file mode 100644 index 00000000000..1c1eedbaa86 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/FinalArrayList.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * {@link ArrayList} with a final marker to help JIT. + * @author Kohsuke Kawaguchi + */ +public final class FinalArrayList extends ArrayList { + public FinalArrayList(int initialCapacity) { + super(initialCapacity); + } + + public FinalArrayList() { + } + + public FinalArrayList(Collection collection) { + super(collection); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/MtomStreamWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/MtomStreamWriter.java new file mode 100644 index 00000000000..a3435408de8 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/MtomStreamWriter.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import javax.xml.bind.attachment.AttachmentMarshaller; +import javax.xml.stream.XMLStreamWriter; + +/** + * A {@link XMLStreamWriter} that used for MTOM encoding may provide its own + * {@link AttachmentMarshaller}. The marshaller could do processing based on + * MTOM threshold, and make decisions about inlining the attachment data or not. + * + * @author Jitendra Kotamraju + * @see JAXBMessage + * @see MtomCodec + */ +public interface MtomStreamWriter { + AttachmentMarshaller getAttachmentMarshaller(); +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxReaderEx.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxReaderEx.java new file mode 100644 index 00000000000..75afe2b1351 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxReaderEx.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.util.Iterator; + +import javax.xml.soap.SOAPElement; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; + +import com.sun.xml.internal.org.jvnet.staxex.Base64Data; +import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx; +import com.sun.xml.internal.org.jvnet.staxex.BinaryText; + +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * SaajStaxReaderEx + * + * @author shih-chang.chen@oracle.com + */ +public class SaajStaxReaderEx extends DOMStreamReader implements XMLStreamReaderEx { + //TODO extends com.sun.xml.internal.ws.streaming.DOMStreamReader + private BinaryText binaryText = null; + private Base64Data base64AttData = null; + + public SaajStaxReaderEx(SOAPElement se) { + super(se); + } + + @Override + public int next() throws XMLStreamException { + binaryText = null; + base64AttData = null; + while(true) { + int r = _next(); + switch (r) { + case CHARACTERS: + if (_current instanceof BinaryText) { + binaryText = (BinaryText) _current; + base64AttData = new Base64Data(); + try { + base64AttData.set(binaryText.getDataHandler()); +//System.out.println("--------------- debug SaajStaxReaderEx binaryText " + binaryText); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } else { + // if we are currently at text node, make sure that this is a meaningful text node. + Node prev = _current.getPreviousSibling(); + if(prev!=null && prev.getNodeType()==Node.TEXT_NODE) + continue; // nope. this is just a continuation of previous text that should be invisible + + Text t = (Text)_current; + wholeText = t.getWholeText(); + if(wholeText.length()==0) + continue; // nope. this is empty text. + } + return CHARACTERS; + case START_ELEMENT: + splitAttributes(); + return START_ELEMENT; + default: + return r; + } + } + } + + @Override + public String getElementTextTrim() throws XMLStreamException { + // TODO Auto-generated method stub + return null; + } + + @Override + public CharSequence getPCDATA() throws XMLStreamException { + return (binaryText != null) ? base64AttData : getText(); + } + + @Override + public com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx getNamespaceContext() { + return new com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx() { + + @Override + public String getNamespaceURI(String prefix) { + return _current.lookupNamespaceURI(prefix); + } + + @Override + public String getPrefix(String uri) { + return _current.lookupPrefix(uri); + } + + @Override + public Iterator getPrefixes(String arg0) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Iterator iterator() { + // TODO Auto-generated method stub + return null; + } + + }; + } + + + @Override + public int getTextLength() { + return (binaryText != null) ? base64AttData.length() : super.getTextLength(); + } + + @Override + public int getTextStart() { + return (binaryText != null) ? 0: super.getTextStart(); + } + + @Override + public char[] getTextCharacters() { + if (binaryText != null) { + char[] chars = new char[base64AttData.length()]; + base64AttData.writeTo(chars, 0); + return chars; + } + return super.getTextCharacters(); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriter.java new file mode 100644 index 00000000000..8020bea1de4 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriter.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.util.Arrays; +import java.util.Iterator; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPElement; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.w3c.dom.Comment; +import org.w3c.dom.Node; + +/** + * SaajStaxWriter builds a SAAJ SOAPMessage by using XMLStreamWriter interface. + * + * @author shih-chang.chen@oracle.com + */ +public class SaajStaxWriter implements XMLStreamWriter { + + protected SOAPMessage soap; + protected String envURI; + protected SOAPElement currentElement; + + static final protected String Envelope = "Envelope"; + static final protected String Header = "Header"; + static final protected String Body = "Body"; + static final protected String xmlns = "xmlns"; + + public SaajStaxWriter(final SOAPMessage msg, String uri) throws SOAPException { + soap = msg; + this.envURI = uri; + } + + public SOAPMessage getSOAPMessage() { + return soap; + } + + protected SOAPElement getEnvelope() throws SOAPException { + return soap.getSOAPPart().getEnvelope(); + } + + @Override + public void writeStartElement(final String localName) throws XMLStreamException { + try { + currentElement = currentElement.addChildElement(localName); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void writeStartElement(final String ns, final String ln) throws XMLStreamException { + writeStartElement(null, ln, ns); + } + + @Override + public void writeStartElement(final String prefix, final String ln, final String ns) throws XMLStreamException { + try { + if (envURI.equals(ns)) { + if (Envelope.equals(ln)) { + currentElement = getEnvelope(); + fixPrefix(prefix); + return; + } else if (Header.equals(ln)) { + currentElement = soap.getSOAPHeader(); + fixPrefix(prefix); + return; + } else if (Body.equals(ln)) { + currentElement = soap.getSOAPBody(); + fixPrefix(prefix); + return; + } + } + currentElement = (prefix == null) ? + currentElement.addChildElement(new QName(ns, ln)) : + currentElement.addChildElement(ln, prefix, ns); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + private void fixPrefix(final String prfx) throws XMLStreamException { + String oldPrfx = currentElement.getPrefix(); + if (prfx != null && !prfx.equals(oldPrfx)) { + currentElement.setPrefix(prfx); + } + } + + @Override + public void writeEmptyElement(final String uri, final String ln) throws XMLStreamException { + writeStartElement(null, ln, uri); + } + + @Override + public void writeEmptyElement(final String prefix, final String ln, final String uri) throws XMLStreamException { + writeStartElement(prefix, ln, uri); + } + + @Override + public void writeEmptyElement(final String ln) throws XMLStreamException { + writeStartElement(null, ln, null); + } + + @Override + public void writeEndElement() throws XMLStreamException { + if (currentElement != null) currentElement = currentElement.getParentElement(); + } + + @Override + public void writeEndDocument() throws XMLStreamException { + } + + @Override + public void close() throws XMLStreamException { + } + + @Override + public void flush() throws XMLStreamException { + } + + @Override + public void writeAttribute(final String ln, final String val) throws XMLStreamException { + writeAttribute(null, null, ln, val); + } + + @Override + public void writeAttribute(final String prefix, final String ns, final String ln, final String value) throws XMLStreamException { + try { + if (ns == null) { + if (prefix == null && xmlns.equals(ln)) { + currentElement.addNamespaceDeclaration("", value); + } else { + currentElement.setAttributeNS("", ln, value); + } + } else { + QName name = (prefix == null) ? new QName(ns, ln) : new QName(ns, ln, prefix); + currentElement.addAttribute(name, value); + } + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void writeAttribute(final String ns, final String ln, final String val) throws XMLStreamException { + writeAttribute(null, ns, ln, val); + } + + @Override + public void writeNamespace(String prefix, final String uri) throws XMLStreamException { + + // make prefix default if null or "xmlns" (according to javadoc) + if (prefix == null || "xmlns".equals(prefix)) { + prefix = ""; + } + + try { + currentElement.addNamespaceDeclaration(prefix, uri); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void writeDefaultNamespace(final String uri) throws XMLStreamException { + writeNamespace("", uri); + } + + @Override + public void writeComment(final String data) throws XMLStreamException { + Comment c = soap.getSOAPPart().createComment(data); + currentElement.appendChild(c); + } + + @Override + public void writeProcessingInstruction(final String target) throws XMLStreamException { + Node n = soap.getSOAPPart().createProcessingInstruction(target, ""); + currentElement.appendChild(n); + } + + @Override + public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException { + Node n = soap.getSOAPPart().createProcessingInstruction(target, data); + currentElement.appendChild(n); + } + + @Override + public void writeCData(final String data) throws XMLStreamException { + Node n = soap.getSOAPPart().createCDATASection(data); + currentElement.appendChild(n); + } + + @Override + public void writeDTD(final String dtd) throws XMLStreamException { + //TODO ... Don't do anything here + } + + @Override + public void writeEntityRef(final String name) throws XMLStreamException { + Node n = soap.getSOAPPart().createEntityReference(name); + currentElement.appendChild(n); + } + + @Override + public void writeStartDocument() throws XMLStreamException { + } + + @Override + public void writeStartDocument(final String version) throws XMLStreamException { + if (version != null) soap.getSOAPPart().setXmlVersion(version); + } + + @Override + public void writeStartDocument(final String encoding, final String version) throws XMLStreamException { + if (version != null) soap.getSOAPPart().setXmlVersion(version); + if (encoding != null) { + try { + soap.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, encoding); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + } + + @Override + public void writeCharacters(final String text) throws XMLStreamException { + try { + currentElement.addTextNode(text); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException { + char[] chr = (start == 0 && len == text.length) ? text : Arrays.copyOfRange(text, start, start + len); + try { + currentElement.addTextNode(new String(chr)); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public String getPrefix(final String uri) throws XMLStreamException { + return currentElement.lookupPrefix(uri); + } + + @Override + public void setPrefix(final String prefix, final String uri) throws XMLStreamException { + try { + this.currentElement.addNamespaceDeclaration(prefix, uri); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void setDefaultNamespace(final String uri) throws XMLStreamException { + setPrefix("", uri); + } + + @Override + public void setNamespaceContext(final NamespaceContext context)throws XMLStreamException { + throw new UnsupportedOperationException(); + } + + @Override + public Object getProperty(final String name) throws IllegalArgumentException { + //TODO the following line is to make eclipselink happy ... they are aware of this problem - + if (javax.xml.stream.XMLOutputFactory.IS_REPAIRING_NAMESPACES.equals(name)) return Boolean.FALSE; + return null; + } + + @Override + public NamespaceContext getNamespaceContext() { + return new NamespaceContext() { + public String getNamespaceURI(final String prefix) { + return currentElement.getNamespaceURI(prefix); + } + public String getPrefix(final String namespaceURI) { + return currentElement.lookupPrefix(namespaceURI); + } + public Iterator getPrefixes(final String namespaceURI) { + return new Iterator() { + String prefix = getPrefix(namespaceURI); + public boolean hasNext() { + return (prefix != null); + } + public Object next() { + if (!hasNext()) throw new java.util.NoSuchElementException(); + String next = prefix; + prefix = null; + return next; + } + public void remove() {} + }; + } + }; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriterEx.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriterEx.java new file mode 100644 index 00000000000..e8b22cf46bd --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriterEx.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Iterator; +import java.util.UUID; + +import javax.activation.DataHandler; +import javax.xml.bind.attachment.AttachmentMarshaller; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; +import javax.xml.stream.XMLStreamException; + +import com.sun.xml.internal.org.jvnet.staxex.Base64Data; +import com.sun.xml.internal.org.jvnet.staxex.BinaryText; +import com.sun.xml.internal.org.jvnet.staxex.MtomEnabled; +import com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx; +import com.sun.xml.internal.org.jvnet.staxex.StreamingDataHandler; +import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx; +// +//import com.sun.xml.internal.ws.api.message.saaj.SaajStaxWriter; +//import com.sun.xml.internal.ws.developer.StreamingDataHandler; +//import com.sun.xml.internal.ws.streaming.MtomStreamWriter; + +/** + * SaajStaxWriterEx converts XMLStreamWriterEx calls to build an orasaaj SOAPMessage with BinaryTextImpl. + * + * @author shih-chang.chen@oracle.com + */ +public class SaajStaxWriterEx extends SaajStaxWriter implements XMLStreamWriterEx, MtomStreamWriter { + + static final protected String xopNS = "http://www.w3.org/2004/08/xop/include"; + static final protected String Include = "Include"; + static final protected String href = "href"; + + private enum State {xopInclude, others}; + private State state = State.others; + private BinaryText binaryText; + + public SaajStaxWriterEx(SOAPMessage msg, String uri) throws SOAPException { + super(msg, uri); + } + + public void writeStartElement(String prefix, String ln, String ns) throws XMLStreamException { + if (xopNS.equals(ns) && Include.equals(ln)) { + state = State.xopInclude; + return; + } else { + super.writeStartElement(prefix, ln, ns); + } + } + + @Override + public void writeEndElement() throws XMLStreamException { + if (state.equals(State.xopInclude)) { + state = State.others; + } else { + super.writeEndElement(); + } + } + + @Override + public void writeAttribute(String prefix, String ns, String ln, String value) throws XMLStreamException { + if (binaryText != null && href.equals(ln)) { + return; + } else { + super.writeAttribute(prefix, ns, ln, value); + } + } + +// @Override +// public void writeComment(String data) throws XMLStreamException { +// ((ElementImpl)currentElement).addCommentNode(data); +// } +// +// @Override +// public void writeCData(String data) throws XMLStreamException { +// CDataTextImpl cdt = new CDataTextImpl(soap.getSOAPPart(), data); +// currentElement.appendChild(cdt); +// } + + @Override + public NamespaceContextEx getNamespaceContext() { + return new NamespaceContextEx() { + public String getNamespaceURI(String prefix) { + return currentElement.getNamespaceURI(prefix); + } + public String getPrefix(String namespaceURI) { + return currentElement.lookupPrefix(namespaceURI); + } + public Iterator getPrefixes(final String namespaceURI) { + return new Iterator() { + String prefix = getPrefix(namespaceURI); + public boolean hasNext() { + return (prefix != null); + } + public Object next() { + if (prefix == null) throw new java.util.NoSuchElementException(); + String next = prefix; + prefix = null; + return next; + } + public void remove() {} + }; + } + public Iterator iterator() { + return new Iterator() { + public boolean hasNext() { return false; } + public Binding next() { return null; } + public void remove() {} + }; + } + }; + } + + @Override + public void writeBinary(DataHandler data) throws XMLStreamException { +// binaryText = BinaryTextImpl.createBinaryTextFromDataHandler((MessageImpl)soap, null, currentElement.getOwnerDocument(), data); +// currentElement.appendChild(binaryText); + addBinaryText(data); + } + + @Override + public OutputStream writeBinary(String arg0) throws XMLStreamException { + return null; + } + + @Override + public void writeBinary(byte[] data, int offset, int length, String contentType) throws XMLStreamException { +// if (mtomThreshold == -1 || mtomThreshold > length) return null; + byte[] bytes = (offset == 0 && length == data.length) ? data : Arrays.copyOfRange(data, offset, offset + length); + if (currentElement instanceof MtomEnabled) { + binaryText = ((MtomEnabled) currentElement).addBinaryText(bytes); + } else { + throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); + } + } + + @Override + public void writePCDATA(CharSequence arg0) throws XMLStreamException { + if (arg0 instanceof Base64Data) { + // The fix of StreamReaderBufferCreator preserves this dataHandler + addBinaryText(((Base64Data) arg0).getDataHandler()); + } else { + // We should not normally get here as we expect a DataHandler, + // but this is the most general solution. If we do get + // something other than a Data Handler, create a Text node with + // the data. Another alternative would be to throw an exception, + // but in the most general case, we don't know whether this input + // is expected. + try { + currentElement.addTextNode(arg0.toString()); + } catch (SOAPException e) { + throw new XMLStreamException("Cannot add Text node", e); + } + } + } + + static private String encodeCid() { + String cid = "example.jaxws.sun.com"; + String name = UUID.randomUUID() + "@"; + return name + cid; + } + + private String addBinaryText(DataHandler data) { + String hrefOrCid = null; + if (data instanceof StreamingDataHandler) { + hrefOrCid = ((StreamingDataHandler) data).getHrefCid(); + } + if (hrefOrCid == null) hrefOrCid = encodeCid(); + + String prefixedCid = (hrefOrCid.startsWith("cid:")) ? hrefOrCid : "cid:" + hrefOrCid; + // Should we do the threshold processing on DataHandler ? But that would be + // expensive as DataHolder need to read the data again from its source + //binaryText = BinaryTextImpl.createBinaryTextFromDataHandler((MessageImpl) soap, prefixedCid, currentElement.getOwnerDocument(), data); + //currentElement.appendChild(binaryText); + if (currentElement instanceof MtomEnabled) { + binaryText = ((MtomEnabled) currentElement).addBinaryText(prefixedCid, data); + } else { + throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); + } + return hrefOrCid; + } + + public AttachmentMarshaller getAttachmentMarshaller() { + return new AttachmentMarshaller() { + @Override + public String addMtomAttachment(DataHandler data, String ns, String ln) { +// if (mtomThreshold == -1) return null; + String hrefOrCid = addBinaryText(data); +// return binaryText.getHref(); + return hrefOrCid; + } + + @Override + public String addMtomAttachment(byte[] data, int offset, int length, String mimeType, String ns, String ln) { +// if (mtomThreshold == -1 || mtomThreshold > length) return null; + byte[] bytes = (offset == 0 && length == data.length) ? data : Arrays.copyOfRange(data, offset, offset + length); +// binaryText = (BinaryTextImpl) ((ElementImpl) currentElement).addAsBase64TextNode(bytes); + if (currentElement instanceof MtomEnabled) { + binaryText = ((MtomEnabled) currentElement).addBinaryText(bytes); + } else { + throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); + } + return binaryText.getHref(); + } + + @Override + public String addSwaRefAttachment(DataHandler data) { + return "cid:"+encodeCid(); + } + + @Override + public boolean isXOPPackage() { + return true; + } + }; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/XMLStreamReaderToXMLStreamWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/XMLStreamReaderToXMLStreamWriter.java new file mode 100644 index 00000000000..94643273907 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/XMLStreamReaderToXMLStreamWriter.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.io.IOException; + +import javax.xml.bind.attachment.AttachmentMarshaller; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.XMLConstants; + +import com.sun.xml.internal.org.jvnet.staxex.Base64Data; +import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx; +import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx; + +/** + * Reads a sub-tree from {@link XMLStreamReader} and writes to {@link XMLStreamWriter} + * as-is. + * + *

+ * This class can be sub-classed to implement a simple transformation logic. + * + * @author Kohsuke Kawaguchi + * @author Ryan Shoemaker + */ +public class XMLStreamReaderToXMLStreamWriter { + + static public class Breakpoint { + protected XMLStreamReader reader; + protected XMLStreamWriter writer; + + public Breakpoint(XMLStreamReader r, XMLStreamWriter w) { reader = r; writer = w; } + + public XMLStreamReader reader() { return reader; } + public XMLStreamWriter writer() { return writer; } + public boolean proceedBeforeStartElement() { return true; } + public boolean proceedAfterStartElement() { return true; } + } + + private static final int BUF_SIZE = 4096; + + protected XMLStreamReader in; + protected XMLStreamWriter out; + + private char[] buf; + + boolean optimizeBase64Data = false; + + AttachmentMarshaller mtomAttachmentMarshaller; + + /** + * Reads one subtree and writes it out. + * + *

+ * The {@link XMLStreamWriter} never receives a start/end document event. + * Those need to be written separately by the caller. + */ + public void bridge(XMLStreamReader in, XMLStreamWriter out) throws XMLStreamException { + bridge(in, out, null); + } + + public void bridge(Breakpoint breakPoint) throws XMLStreamException { + bridge(breakPoint.reader(), breakPoint.writer(), breakPoint); + } + + private void bridge(XMLStreamReader in, XMLStreamWriter out, Breakpoint breakPoint) throws XMLStreamException { + assert in!=null && out!=null; + this.in = in; + this.out = out; + + optimizeBase64Data = (in instanceof XMLStreamReaderEx); + + if (out instanceof XMLStreamWriterEx && out instanceof MtomStreamWriter) { + mtomAttachmentMarshaller = ((MtomStreamWriter) out).getAttachmentMarshaller(); + } + // remembers the nest level of elements to know when we are done. + int depth=0; + + buf = new char[BUF_SIZE]; + + // if the parser is at the start tag, proceed to the first element + int event = getEventType(); + + if( event!=XMLStreamConstants.START_ELEMENT) + throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event); + + do { + // These are all of the events listed in the javadoc for + // XMLEvent. + // The spec only really describes 11 of them. + switch (event) { + case XMLStreamConstants.START_ELEMENT : + if (breakPoint != null && !breakPoint.proceedBeforeStartElement()) return; + depth++; + handleStartElement(); + if (breakPoint != null && !breakPoint.proceedAfterStartElement()) return; + break; + case XMLStreamConstants.END_ELEMENT : + handleEndElement(); + depth--; + if(depth==0) + return; + break; + case XMLStreamConstants.CHARACTERS : + handleCharacters(); + break; + case XMLStreamConstants.ENTITY_REFERENCE : + handleEntityReference(); + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION : + handlePI(); + break; + case XMLStreamConstants.COMMENT : + handleComment(); + break; + case XMLStreamConstants.DTD : + handleDTD(); + break; + case XMLStreamConstants.CDATA : + handleCDATA(); + break; + case XMLStreamConstants.SPACE : + handleSpace(); + break; + case XMLStreamConstants.END_DOCUMENT: + throw new XMLStreamException("Malformed XML at depth="+depth+", Reached EOF. Event="+event); + default : + throw new XMLStreamException("Cannot process event: " + event); + } + + event=getNextEvent(); + } while (depth!=0); + } + + protected void handlePI() throws XMLStreamException { + out.writeProcessingInstruction( + in.getPITarget(), + in.getPIData()); + } + + + protected void handleCharacters() throws XMLStreamException { + + CharSequence c = null; + + if (optimizeBase64Data) { + c = ((XMLStreamReaderEx)in).getPCDATA(); + } + + if ((c != null) && (c instanceof Base64Data)) { + if (mtomAttachmentMarshaller != null) { + Base64Data b64d = (Base64Data) c; + ((XMLStreamWriterEx)out).writeBinary(b64d.getDataHandler()); + } else { + try { + ((Base64Data)c).writeTo(out); + } catch (IOException e) { + throw new XMLStreamException(e); + } + } + } else { + for (int start=0,read=buf.length; read == buf.length; start+=buf.length) { + read = in.getTextCharacters(start, buf, 0, buf.length); + out.writeCharacters(buf, 0, read); + } + } + } + + protected void handleEndElement() throws XMLStreamException { + out.writeEndElement(); + } + + protected void handleStartElement() throws XMLStreamException { + String nsUri = in.getNamespaceURI(); + if(nsUri==null) + out.writeStartElement(in.getLocalName()); + else + out.writeStartElement( + fixNull(in.getPrefix()), + in.getLocalName(), + nsUri + ); + + // start namespace bindings + int nsCount = in.getNamespaceCount(); + for (int i = 0; i < nsCount; i++) { + out.writeNamespace( + in.getNamespacePrefix(i), + fixNull(in.getNamespaceURI(i))); // zephyr doesn't like null, I don't know what is correct, so just fix null to "" for now + } + + // write attributes + int attCount = in.getAttributeCount(); + for (int i = 0; i < attCount; i++) { + handleAttribute(i); + } + } + + /** + * Writes out the {@code i}-th attribute of the current element. + * + *

+ * Used from {@link #handleStartElement()}. + */ + protected void handleAttribute(int i) throws XMLStreamException { + String nsUri = in.getAttributeNamespace(i); + String prefix = in.getAttributePrefix(i); + if (fixNull(nsUri).equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) { + //Its a namespace decl, ignore as it is already written. + return; + } + + if(nsUri==null || prefix == null || prefix.equals("")) { + out.writeAttribute( + in.getAttributeLocalName(i), + in.getAttributeValue(i) + ); + } else { + out.writeAttribute( + prefix, + nsUri, + in.getAttributeLocalName(i), + in.getAttributeValue(i) + ); + } + } + + protected void handleDTD() throws XMLStreamException { + out.writeDTD(in.getText()); + } + + protected void handleComment() throws XMLStreamException { + out.writeComment(in.getText()); + } + + protected void handleEntityReference() throws XMLStreamException { + out.writeEntityRef(in.getText()); + } + + protected void handleSpace() throws XMLStreamException { + handleCharacters(); + } + + protected void handleCDATA() throws XMLStreamException { + out.writeCData(in.getText()); + } + + private static String fixNull(String s) { + if(s==null) return ""; + else return s; + } + + private int getEventType() throws XMLStreamException { + int event = in.getEventType(); + // if the parser is at the start tag, proceed to the first element + //Note - need to do this every time because we could be using a composite reader + if(event == XMLStreamConstants.START_DOCUMENT) { + // nextTag doesn't correctly handle DTDs + while( !in.isStartElement() ) { + event = in.next(); + if (event == XMLStreamConstants.COMMENT) + handleComment(); + } + } + return event; + } + + private int getNextEvent() throws XMLStreamException { + in.next(); + return getEventType(); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/EPRSDDocumentFilter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/EPRSDDocumentFilter.java index b2d19ce7433..e1f39b91ea9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/EPRSDDocumentFilter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/EPRSDDocumentFilter.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,7 +30,7 @@ import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; import com.sun.xml.internal.ws.api.addressing.AddressingVersion; import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory; import com.sun.xml.internal.ws.util.xml.XMLStreamWriterFilter; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.server.WSEndpointImpl; import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; import com.sun.istack.internal.Nullable; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/addressing/WSEndpointReference.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/addressing/WSEndpointReference.java index b6b16abebe8..68ec6b5e1b4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/addressing/WSEndpointReference.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/addressing/WSEndpointReference.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 @@ -52,7 +52,7 @@ import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; import com.sun.xml.internal.ws.util.DOMUtil; import com.sun.xml.internal.ws.util.xml.XMLStreamWriterFilter; import com.sun.xml.internal.ws.util.xml.XmlUtil; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; import org.w3c.dom.Element; import org.xml.sax.*; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/FilterMessageImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/FilterMessageImpl.java index 6cbc2f9153e..194ba0a5810 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/FilterMessageImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/FilterMessageImpl.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 @@ -158,7 +158,7 @@ public class FilterMessageImpl extends Message { } public Message copy() { - return delegate.copy(); + return delegate.copy().copyFrom(delegate); } public @NotNull String getID(@NotNull WSBinding binding) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Message.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Message.java index cd473a7aec6..c118e6639d0 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Message.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Message.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 @@ -196,6 +196,12 @@ import java.util.UUID; */ public abstract class Message { + // See Packet for doc. + private boolean isProtocolMessage = false; + // next two are package protected - should only be used from Packet + boolean isProtocolMessage() { return isProtocolMessage; } + void setIsProtocolMessage() { isProtocolMessage = true; } + /** * Returns true if headers are present in the message. * @@ -724,11 +730,33 @@ public abstract class Message { *

* The restrictions placed on the use of copied {@link Message} can be * relaxed if necessary, but it will make the copy method more expensive. + * + *

IMPORTANT

+ *

WHEN YOU IMPLEMENT OR CHANGE A {@link .copy()} METHOD, YOU MUST + * USE THE {@link copyFrom(Message)} METHOD IN THE IMPLEMENTATION. */ // TODO: update the class javadoc with 'lifescope' // and move the discussion about life scope there. public abstract Message copy(); + /** + * The {@link Message#copy()} method is used as a shorthand + * throughout the codecase in place of calling a copy constructor. + * However, that shorthand make it difficult to have a concrete + * method here in the base to do common work. + * + *

Rather than have each {@code copy} method duplicate code, the + * following method is used in each {@code copy} implementation. + * It MUST be called. + * + * @return The Message that calls {@code copyFrom} inside the + * {@code copy} method after the copy constructor + */ + public final Message copyFrom(Message m) { + isProtocolMessage = m.isProtocolMessage; + return this; + } + /** * Retuns a unique id for the message. The id can be used for various things, * like debug assistance, logging, and MIME encoding(say for boundary). diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/MessageWrapper.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/MessageWrapper.java index 708c09710b2..a27a6be98bc 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/MessageWrapper.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/MessageWrapper.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 @@ -93,6 +93,11 @@ class MessageWrapper extends StreamMessage { return delegate.equals(obj); } + @Override + boolean isProtocolMessage() { return delegate.isProtocolMessage(); } + @Override + void setIsProtocolMessage() { delegate.setIsProtocolMessage(); } + @Override public boolean hasHeaders() { return delegate.hasHeaders(); @@ -105,7 +110,7 @@ class MessageWrapper extends StreamMessage { @Override public String toString() { - return delegate.toString(); + return "{MessageWrapper: " + delegate.toString() + "}"; } @Override @@ -214,7 +219,7 @@ class MessageWrapper extends StreamMessage { @Override public Message copy() { - return delegate.copy(); + return delegate.copy().copyFrom(delegate); } @Override diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Packet.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Packet.java index fc981a9e622..1bc4ca6b974 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Packet.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Packet.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 @@ -248,6 +248,26 @@ public final class Packet if (message != null) this.message.setMessageMedadata(this); } + // ALL NEW PACKETS SHOULD HAVE THIS AS false. + // SETTING TO true MUST BE DONE EXPLICITLY, + // NOT VIA COPYING/RELATING PACKETS. + public boolean isProtocolMessage() { + return message != null && message.isProtocolMessage(); + } + public void setIsProtocolMessage() { + assert message != null; + message.setIsProtocolMessage(); + } + + private String userStateId; + public String getUserStateId() { + return userStateId; + } + public void setUserStateId(final String x) { + assert x != null && x.length() <= 256; + userStateId = x; + } + private WSDLOperationMapping wsdlOperationMapping = null; private QName wsdlOperation; @@ -894,6 +914,7 @@ public final class Packet response.component = request.component; response.mtomAcceptable = request.mtomAcceptable; response.mtomRequest = request.mtomRequest; + response.userStateId = request.userStateId; // copy other properties that need to be copied. is there any? } @@ -1255,6 +1276,12 @@ public final class Packet return getCodec().encode(this, buffer); } + /** + * This content type may be set by one of the following ways: + * (1) By the codec as a result of decoding an incoming message + * (2) Cached by a codec after encoding the message + * (3) By a caller of Codec.decode(InputStream, String contentType, Packet) + */ private ContentType contentType; /** @@ -1410,6 +1437,13 @@ public final class Packet //Use the getter to make sure all the logic is executed correctly MTOMFeature myMtomFeature = getMtomFeature(); if(myMtomFeature != null && myMtomFeature.isEnabled()) { + //If the content type is set already on this outbound Packet, + //(e.g.) through Codec.decode(InputStream, String contentType, Packet) + //and it is a non-mtom content type, then don't use mtom to encode it + ContentType curContentType = getInternalContentType(); + if (curContentType != null && !isMtomContentType(curContentType)) { + return false; + } //On client, always use XOP encoding if MTOM is enabled //On Server, mtomAcceptable and mtomRequest will be set - use XOP encoding //if either request is XOP encoded (mtomRequest) or @@ -1432,11 +1466,14 @@ public final class Packet } private boolean isMtomContentType() { - return (getInternalContentType() != null) && - (getInternalContentType().getContentType().contains("application/xop+xml")); + return (getInternalContentType() != null && isMtomContentType(getInternalContentType())); } - /** + private boolean isMtomContentType(ContentType cType) { + return cType.getContentType().contains("application/xop+xml"); + } + + /** * @deprecated */ public void addSatellite(@NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/StreamingSOAP.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/StreamingSOAP.java index e84ae576f10..ad8ab56b0ad 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/StreamingSOAP.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/StreamingSOAP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -25,8 +25,17 @@ package com.sun.xml.internal.ws.api.message; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; public interface StreamingSOAP { public XMLStreamReader readEnvelope(); + public QName getPayloadQName(); + public XMLStreamReader readToBodyStarTag() throws XMLStreamException; + public XMLStreamReader readPayload() throws XMLStreamException; + public void writeToBodyStart(XMLStreamWriter w) throws XMLStreamException; + public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException; + public boolean isPayloadStreamReader(); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SAAJFactory.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SAAJFactory.java index a1bd1da3fc9..7bbbc064e61 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SAAJFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SAAJFactory.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 @@ -36,6 +36,7 @@ import javax.xml.soap.SOAPMessage; import javax.xml.stream.XMLStreamException; import org.xml.sax.SAXException; +import com.sun.xml.internal.org.jvnet.staxex.util.SaajStaxWriter; import com.sun.xml.internal.bind.marshaller.SAX2DOMEx; import com.sun.xml.internal.ws.api.SOAPVersion; @@ -265,7 +266,7 @@ public class SAAJFactory { */ public SOAPMessage readAsSOAPMessage(final SOAPVersion soapVersion, final Message message) throws SOAPException { SOAPMessage msg = soapVersion.getMessageFactory().createMessage(); - SaajStaxWriter writer = new SaajStaxWriter(msg); + SaajStaxWriter writer = new SaajStaxWriter(msg, soapVersion.nsUri); try { message.writeTo(writer); } catch (XMLStreamException e) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java index 6414593fee7..5786a0a2831 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -42,6 +42,8 @@ import org.w3c.dom.Node; /** * SaajStaxWriter builds a SAAJ SOAPMessage by using XMLStreamWriter interface. * + * @deprecated use com.sun.xml.internal.org.jvnet.staxex.util.SaajStaxWriter + * * @author shih-chang.chen@oracle.com */ public class SaajStaxWriter implements XMLStreamWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/SEIStub.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/SEIStub.java index 9ad1f6edfba..fd331c9ff49 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/SEIStub.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/SEIStub.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 @@ -28,7 +28,6 @@ package com.sun.xml.internal.ws.client.sei; import com.sun.istack.internal.NotNull; import com.sun.istack.internal.Nullable; import com.sun.xml.internal.ws.api.SOAPVersion; -import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; import com.sun.xml.internal.ws.api.client.WSPortInfo; import com.sun.xml.internal.ws.api.databinding.Databinding; import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; @@ -167,8 +166,7 @@ public final class SEIStub extends Stub implements InvocationHandler { if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) { throw new IllegalStateException("Passed object is not proxy!"); } - Class declaringClass = method.getDeclaringClass(); - if (method == null || declaringClass == null + if (method == null || method.getDeclaringClass() == null || Modifier.isStatic(method.getModifiers())) { throw new IllegalStateException("Invoking static method is not allowed!"); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/developer/StreamingDataHandler.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/developer/StreamingDataHandler.java index 9ba60a2c77d..5eaad4dbf23 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/developer/StreamingDataHandler.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/developer/StreamingDataHandler.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 @@ -50,8 +50,6 @@ import javax.activation.DataSource; */ public abstract class StreamingDataHandler extends com.sun.xml.internal.org.jvnet.staxex.StreamingDataHandler { - private String hrefCid; - public StreamingDataHandler(Object o, String s) { super(o, s); } @@ -63,13 +61,4 @@ public abstract class StreamingDataHandler extends com.sun.xml.internal.org.jvne public StreamingDataHandler(DataSource dataSource) { super(dataSource); } - - public String getHrefCid() { - return hrefCid; - } - - public void setHrefCid(final String cid) { - this.hrefCid = cid; - } - } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/ContentTypeImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/ContentTypeImpl.java index f8b3da89f3b..f4d61f5d004 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/ContentTypeImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/ContentTypeImpl.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 @@ -62,6 +62,7 @@ public final class ContentTypeImpl implements com.sun.xml.internal.ws.api.pipe.C try { internalContentType = new ContentType(contentType); tmpCharset = internalContentType.getParameter("charset"); + rootId = internalContentType.getParameter("start"); } catch(Exception e) { //Ignore the parsing exception. } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MimeCodec.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MimeCodec.java index f060a34fdb0..fb8e5f2a5a6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MimeCodec.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MimeCodec.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 @@ -118,12 +118,14 @@ abstract class MimeCodec implements Codec { } ContentTypeImpl ctImpl = (ContentTypeImpl)getStaticContentType(packet); String boundary = ctImpl.getBoundary(); + String rootId = ctImpl.getRootId(); boolean hasAttachments = (boundary != null); Codec rootCodec = getMimeRootCodec(packet); if (hasAttachments) { writeln("--"+boundary, out); ContentType ct = rootCodec.getStaticContentType(packet); String ctStr = (ct != null) ? ct.getContentType() : rootCodec.getMimeType(); + if (rootId != null) writeln("Content-ID: " + rootId, out); writeln("Content-Type: " + ctStr, out); writeln(out); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MtomCodec.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MtomCodec.java index 0db9233e6be..4d8194371a7 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MtomCodec.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MtomCodec.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 @@ -112,9 +112,15 @@ public class MtomCodec extends MimeCodec { } public static ContentType getStaticContentTypeStatic(Packet packet, SOAPVersion version) { - ContentType ct = (ContentType) packet.getInternalContentType(); - if ( ct != null ) return ct; - + ContentTypeImpl ct = (ContentTypeImpl) packet.getInternalContentType(); + if ( ct != null ) { + //Note - this case of boundary = null or root content ID = null should never happen + //after a recent bug fix in Packet.shouldUseMtom logic, but just in + //case we get here with a Packet that has a non-null content type with + //a null boundary, the content type of the Packet will be reset + if (ct.getBoundary() != null && ct.getRootId() != null) + return ct; + } String uuid = UUID.randomUUID().toString(); String boundary = "uuid:" + uuid; String rootId = ""; @@ -327,7 +333,7 @@ public class MtomCodec extends MimeCodec { } public static class MtomStreamWriterImpl extends XMLStreamWriterFilter implements XMLStreamWriterEx, - MtomStreamWriter, HasEncoding { + com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter, HasEncoding { private final List mtomAttachments; private final String boundary; private final MTOMFeature myMtomFeature; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/xml/XMLMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/xml/XMLMessage.java index f9f8e989c25..3680ef09c8e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/xml/XMLMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/xml/XMLMessage.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 @@ -326,7 +326,7 @@ public final class XMLMessage { } public Message copy() { - return getMessage().copy(); + return getMessage().copy().copyFrom(getMessage()); } protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException { @@ -449,7 +449,7 @@ public final class XMLMessage { } public Message copy() { - return getMessage().copy(); + return getMessage().copy().copyFrom(getMessage()); } protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException { @@ -507,6 +507,7 @@ public final class XMLMessage { super(that.soapVersion); this.ds = that.ds; this.headerList = HeaderList.copy(that.headerList); + this.copyFrom(that); } public boolean hasUnconsumedDataSource() { @@ -560,7 +561,7 @@ public final class XMLMessage { } public Message copy() { - return new UnknownContent(this); + return new UnknownContent(this).copyFrom(this); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/AbstractMessageImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/AbstractMessageImpl.java index 056b31b9efd..81a23a28fa4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/AbstractMessageImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/AbstractMessageImpl.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 @@ -120,6 +120,7 @@ public abstract class AbstractMessageImpl extends Message { */ protected AbstractMessageImpl(AbstractMessageImpl that) { this.soapVersion = that.soapVersion; + this.copyFrom(that); } @Override @@ -150,11 +151,7 @@ public abstract class AbstractMessageImpl extends Message { hasAttachments()? new AttachmentUnmarshallerImpl(getAttachments()) : null ); } - /** - * Default implementation that relies on {@link #writePayloadTo(XMLStreamWriter)} - */ - @Override - public void writeTo(XMLStreamWriter w) throws XMLStreamException { + public void writeToBodyStart(XMLStreamWriter w) throws XMLStreamException { String soapNsUri = soapVersion.nsUri; w.writeStartDocument(); w.writeStartElement("S","Envelope",soapNsUri); @@ -169,7 +166,14 @@ public abstract class AbstractMessageImpl extends Message { } // write the body w.writeStartElement("S","Body",soapNsUri); + } + /** + * Default implementation that relies on {@link #writePayloadTo(XMLStreamWriter)} + */ + @Override + public void writeTo(XMLStreamWriter w) throws XMLStreamException { + writeToBodyStart(w); writePayloadTo(w); w.writeEndElement(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/DOMMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/DOMMessage.java index 4052989b4bf..24b5a22f1ee 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/DOMMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/DOMMessage.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 @@ -80,6 +80,7 @@ public final class DOMMessage extends AbstractMessageImpl { super(that); this.headers = HeaderList.copy(that.headers); this.payload = that.payload; + this.copyFrom(that); } public boolean hasHeaders() { @@ -150,7 +151,7 @@ public final class DOMMessage extends AbstractMessageImpl { } public Message copy() { - return new DOMMessage(this); + return new DOMMessage(this).copyFrom(this); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/EmptyMessageImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/EmptyMessageImpl.java index 1ca4f0bab43..470ecf54bb8 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/EmptyMessageImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/EmptyMessageImpl.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 @@ -76,6 +76,7 @@ public class EmptyMessageImpl extends AbstractMessageImpl { super(that); this.headers = new HeaderList(that.headers); this.attachmentSet = that.attachmentSet; + this.copyFrom(that); } public boolean hasHeaders() { @@ -115,7 +116,7 @@ public class EmptyMessageImpl extends AbstractMessageImpl { } public Message copy() { - return new EmptyMessageImpl(this); + return new EmptyMessageImpl(this).copyFrom(this); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBDispatchMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBDispatchMessage.java index 4d3c82f84a6..b1896ab93bd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBDispatchMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBDispatchMessage.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 @@ -33,7 +33,7 @@ import com.sun.xml.internal.ws.message.AbstractMessageImpl; import com.sun.xml.internal.ws.message.PayloadElementSniffer; import com.sun.xml.internal.ws.spi.db.BindingContext; import com.sun.xml.internal.ws.spi.db.XMLBridge; -import com.sun.xml.internal.ws.streaming.MtomStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter; import com.sun.xml.internal.ws.streaming.XMLStreamWriterUtil; import org.xml.sax.ContentHandler; import org.xml.sax.ErrorHandler; @@ -87,6 +87,7 @@ public class JAXBDispatchMessage extends AbstractMessageImpl { jaxbObject = that.jaxbObject; rawContext = that.rawContext; bridge = that.bridge; + copyFrom(that); } public JAXBDispatchMessage(JAXBContext rawContext, Object jaxbObject, SOAPVersion soapVersion) { @@ -178,7 +179,7 @@ public class JAXBDispatchMessage extends AbstractMessageImpl { @Override public Message copy() { - return new JAXBDispatchMessage(this); + return new JAXBDispatchMessage(this).copyFrom(this); } @Override diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBMessage.java index 28047945b83..8d7891350b5 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBMessage.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 @@ -46,7 +46,7 @@ import com.sun.xml.internal.ws.spi.db.BindingContextFactory; import com.sun.xml.internal.ws.spi.db.XMLBridge; import com.sun.xml.internal.ws.streaming.XMLStreamWriterUtil; import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; -import com.sun.xml.internal.ws.streaming.MtomStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter; import com.sun.xml.internal.ws.util.xml.XMLReaderComposite; import com.sun.xml.internal.ws.util.xml.XMLReaderComposite.ElemInfo; @@ -240,6 +240,7 @@ public final class JAXBMessage extends AbstractMessageImpl implements StreamingS this.jaxbObject = that.jaxbObject; this.bridge = that.bridge; this.rawContext = that.rawContext; + this.copyFrom(that); } @Override @@ -411,7 +412,7 @@ public final class JAXBMessage extends AbstractMessageImpl implements StreamingS @Override public Message copy() { - return new JAXBMessage(this); + return new JAXBMessage(this).copyFrom(this); } public XMLStreamReader readEnvelope() { @@ -443,4 +444,35 @@ public final class JAXBMessage extends AbstractMessageImpl implements StreamingS throw new RuntimeException(e); } } + + public boolean isPayloadStreamReader() { return false; } + + public QName getPayloadQName() { + return new QName(getPayloadNamespaceURI(), getPayloadLocalPart()); + } + + public XMLStreamReader readToBodyStarTag() { + int base = soapVersion.ordinal()*3; + this.envelopeTag = DEFAULT_TAGS.get(base); + this.bodyTag = DEFAULT_TAGS.get(base+2); + List hReaders = new java.util.ArrayList(); + ElemInfo envElem = new ElemInfo(envelopeTag, null); + ElemInfo bdyElem = new ElemInfo(bodyTag, envElem); + for (Header h : getHeaders().asList()) { + try { + hReaders.add(h.readHeader()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + XMLStreamReader soapHeader = null; + if(hReaders.size()>0) { + headerTag = DEFAULT_TAGS.get(base+1); + ElemInfo hdrElem = new ElemInfo(headerTag, envElem); + soapHeader = new XMLReaderComposite(hdrElem, hReaders.toArray(new XMLStreamReader[hReaders.size()])); + } + XMLStreamReader soapBody = new XMLReaderComposite(bdyElem, new XMLStreamReader[]{}); + XMLStreamReader[] soapContent = (soapHeader != null) ? new XMLStreamReader[]{soapHeader, soapBody} : new XMLStreamReader[]{soapBody}; + return new XMLReaderComposite(envElem, soapContent); + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/saaj/SAAJMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/saaj/SAAJMessage.java index 72c054c869a..76f5d65e192 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/saaj/SAAJMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/saaj/SAAJMessage.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 @@ -492,9 +492,11 @@ public class SAAJMessage extends Message { * the {@link com.sun.xml.internal.ws.api.message.Message} implementation itself. */ public Message copy() { + Message result = null; try { + access(); if (!parsedMessage) { - return new SAAJMessage(readAsSOAPMessage()); + result = new SAAJMessage(readAsSOAPMessage()); } else { SOAPMessage msg = soapVersion.getMessageFactory().createMessage(); SOAPBody newBody = msg.getSOAPPart().getEnvelope().getBody(); @@ -503,8 +505,9 @@ public class SAAJMessage extends Message { newBody.appendChild(n); } addAttributes(newBody, bodyAttrs); - return new SAAJMessage(getHeaders(), getAttachments(), msg, soapVersion); + result = new SAAJMessage(getHeaders(), getAttachments(), msg, soapVersion); } + return result.copyFrom(this); } catch (SOAPException e) { throw new WebServiceException(e); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/source/ProtocolSourceMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/source/ProtocolSourceMessage.java index ad2fa7bed90..afdf853d443 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/source/ProtocolSourceMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/source/ProtocolSourceMessage.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 @@ -98,7 +98,7 @@ public class ProtocolSourceMessage extends Message { } public Message copy() { - return sm.copy(); + return sm.copy().copyFrom(sm); } public Source readEnvelopeAsSource() { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/PayloadStreamReaderMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/PayloadStreamReaderMessage.java index 7e025be7690..9b9ff8c8e6b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/PayloadStreamReaderMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/PayloadStreamReaderMessage.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 @@ -107,7 +107,7 @@ public class PayloadStreamReaderMessage extends AbstractMessageImpl { } public Message copy() { - return message.copy(); + return message.copy().copyFrom(message); } @Override diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java index 244471d1ab8..93e12e256d6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.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 @@ -50,7 +50,7 @@ import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; import com.sun.xml.internal.ws.util.xml.DummyLocation; import com.sun.xml.internal.ws.util.xml.StAXSource; import com.sun.xml.internal.ws.util.xml.XMLReaderComposite; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.util.xml.XMLReaderComposite.ElemInfo; import org.xml.sax.ContentHandler; @@ -61,6 +61,7 @@ import org.xml.sax.helpers.NamespaceSupport; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; import javax.xml.stream.*; import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT; @@ -415,11 +416,7 @@ public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP writeEnvelope(sw); } - /** - * This method should be called when the StreamMessage is created with a payload - * @param writer - */ - private void writeEnvelope(XMLStreamWriter writer) throws XMLStreamException { + public void writeToBodyStart(XMLStreamWriter writer) throws XMLStreamException { if ( envelopeReader != null ) readEnvelope(this); writer.writeStartDocument(); envelopeTag.writeStart(writer); @@ -437,6 +434,15 @@ public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP writer.writeEndElement(); } bodyTag.writeStart(writer); + + } + + /** + * This method should be called when the StreamMessage is created with a payload + * @param writer + */ + private void writeEnvelope(XMLStreamWriter writer) throws XMLStreamException { + writeToBodyStart(writer); if(hasPayload()) writePayloadTo(writer); writer.writeEndElement(); @@ -550,7 +556,7 @@ public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP proceedToRootElement(reader); proceedToRootElement(clone); - return new StreamMessage(envelopeTag, headerTag, attachmentSet, HeaderList.copy(headers), bodyPrologue, bodyTag, bodyEpilogue, clone, soapVersion); + return new StreamMessage(envelopeTag, headerTag, attachmentSet, HeaderList.copy(headers), bodyPrologue, bodyTag, bodyEpilogue, clone, soapVersion).copyFrom(this); } catch (XMLStreamException e) { throw new WebServiceException("Failed to copy a message",e); } @@ -763,4 +769,30 @@ public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP // the pipe line. return new MutableXMLStreamBuffer(); } + + public boolean isPayloadStreamReader() { return true; } + + public QName getPayloadQName() { + return this.hasPayload() ? new QName(payloadNamespaceURI, payloadLocalName) : null; + } + + public XMLStreamReader readToBodyStarTag() { + if ( envelopeReader != null ) readEnvelope(this); + List hReaders = new java.util.ArrayList(); + ElemInfo envElem = new ElemInfo(envelopeTag, null); + ElemInfo hdrElem = (headerTag != null) ? new ElemInfo(headerTag, envElem) : null; + ElemInfo bdyElem = new ElemInfo(bodyTag, envElem); + for (Header h : getHeaders().asList()) { + try { + hReaders.add(h.readHeader()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + XMLStreamReader soapHeader = (hdrElem != null) ? new XMLReaderComposite(hdrElem, hReaders.toArray(new XMLStreamReader[hReaders.size()])) : null; + XMLStreamReader[] payload = {}; + XMLStreamReader soapBody = new XMLReaderComposite(bdyElem, payload); + XMLStreamReader[] soapContent = (soapHeader != null) ? new XMLStreamReader[]{soapHeader, soapBody} : new XMLStreamReader[]{soapBody}; + return new XMLReaderComposite(envElem, soapContent); + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/PolicyMapUtil.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/PolicyMapUtil.java index 67433587cb6..7eed07d9470 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/PolicyMapUtil.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/PolicyMapUtil.java @@ -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 @@ -34,6 +34,7 @@ import com.sun.xml.internal.ws.policy.subject.WsdlBindingSubject; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; +import java.util.Map.Entry; import javax.xml.namespace.QName; /** @@ -102,17 +103,17 @@ public class PolicyMapUtil { } final PolicyMapKeyConverter converter = new PolicyMapKeyConverter(serviceName, portName); - for (WsdlBindingSubject wsdlSubject : subjectToPolicies.keySet()) { - final PolicySubject newSubject = new PolicySubject(wsdlSubject, subjectToPolicies.get(wsdlSubject)); + for (Entry> entry : subjectToPolicies.entrySet()) { + WsdlBindingSubject wsdlSubject = entry.getKey(); + Collection policySet = entry.getValue(); + final PolicySubject newSubject = new PolicySubject(wsdlSubject, policySet); PolicyMapKey mapKey = converter.getPolicyMapKey(wsdlSubject); if (wsdlSubject.isBindingSubject()) { policyMap.putSubject(ScopeType.ENDPOINT, mapKey, newSubject); - } - else if (wsdlSubject.isBindingOperationSubject()) { + } else if (wsdlSubject.isBindingOperationSubject()) { policyMap.putSubject(ScopeType.OPERATION, mapKey, newSubject); - } - else if (wsdlSubject.isBindingMessageSubject()) { + } else if (wsdlSubject.isBindingMessageSubject()) { switch (wsdlSubject.getMessageType()) { case INPUT: policyMap.putSubject(ScopeType.INPUT_MESSAGE, mapKey, newSubject); @@ -123,6 +124,8 @@ public class PolicyMapUtil { case FAULT: policyMap.putSubject(ScopeType.FAULT_MESSAGE, mapKey, newSubject); break; + default: + break; } } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/Localization.properties b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/Localization.properties index d12659622ad..ed591119b2f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/Localization.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/Localization.properties @@ -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 @@ -118,3 +118,4 @@ WSP_0092_CHARACTER_DATA_UNEXPECTED=WSP0092: Character data in unexpected element WSP_0093_INVALID_URI=WSP0093: Invalid URI "{0}" at location {1} WSP_0094_INVALID_URN=WSP0094: Internal implementation error. Apparently failed to pass valid URN. WSP_0095_INVALID_BOOLEAN_VALUE=WSP0095: A value of boolean type may have one of the values "true", "false", "1", "0". This value was "{0}". +WSP_0096_ERROR_WHILE_COMBINE=WSP0096: Error while combining {0}. diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/LocalizationMessages.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/LocalizationMessages.java index 4f28cb2cb61..2283e8806a6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/LocalizationMessages.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/LocalizationMessages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, 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 @@ -76,6 +76,18 @@ public final class LocalizationMessages { return localizer.localize(localizableWSP_0081_UNABLE_TO_INSERT_CHILD(arg0, arg1)); } + public static Localizable localizableWSP_0096_ERROR_WHILE_COMBINE(Object arg0) { + return messageFactory.getMessage("WSP_0096_ERROR_WHILE_COMBINE", arg0); + } + + /** + * WSP0096: Error while combining {0}. + * + */ + public static String WSP_0096_ERROR_WHILE_COMBINE(Object arg0) { + return localizer.localize(localizableWSP_0096_ERROR_WHILE_COMBINE(arg0)); + } + public static Localizable localizableWSP_0018_UNABLE_TO_ACCESS_POLICY_SOURCE_MODEL(Object arg0) { return messageFactory.getMessage("WSP_0018_UNABLE_TO_ACCESS_POLICY_SOURCE_MODEL", arg0); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/PolicyUtils.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/PolicyUtils.java index ec537d88358..975464e6eb9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/PolicyUtils.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/PolicyUtils.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 @@ -39,6 +39,7 @@ import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.Queue; +import java.util.logging.Level; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; @@ -200,6 +201,7 @@ public final class PolicyUtils { } public static class Collections { + private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyUtils.Collections.class); /** * TODO javadocs * @@ -245,7 +247,10 @@ public final class PolicyUtils { } else if (optionSize == 1) { base.addAll(option); } else { - optionProcessingQueue.offer(option); + boolean entered = optionProcessingQueue.offer(option); + if (!entered) { + throw LOGGER.logException(new RuntimePolicyUtilsException(LocalizationMessages.WSP_0096_ERROR_WHILE_COMBINE(option)), false, Level.WARNING); + } finalCombinationsSize *= optionSize; } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/EndpointFactory.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/EndpointFactory.java index c78aef5ffbf..ae5bf29bb1b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/EndpointFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/EndpointFactory.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 @@ -89,11 +89,16 @@ import javax.xml.ws.soap.SOAPBinding; import java.io.IOException; import java.net.URL; +import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; /** @@ -189,13 +194,24 @@ public class EndpointFactory { invoker = InstanceResolver.createDefault(implType).createInvoker(); } - List md = new ArrayList(); - if(metadata!=null) + // Performance analysis indicates that reading and parsing imported schemas is + // a major component of Endpoint creation time. Therefore, modify SDDocumentSource + // handling to delay iterating collection as long as possible. + Collection md = new CollectionCollection(); + if(primaryWsdl!=null) { + if(metadata!=null) { + Iterator it = metadata.iterator(); + if (it.hasNext() && primaryWsdl.equals(it.next())) + md.addAll(metadata); + else { + md.add(primaryWsdl); + md.addAll(metadata); + } + } else + md.add(primaryWsdl); + } else if(metadata!=null) md.addAll(metadata); - if(primaryWsdl!=null && !md.contains(primaryWsdl)) - md.add(primaryWsdl); - if(container==null) container = ContainerResolver.getInstance().getContainer(); @@ -227,7 +243,7 @@ public class EndpointFactory { } // Categorises the documents as WSDL, Schema etc - List docList = categoriseMetadata(md, serviceName, portTypeName); + Collection docList = categoriseMetadata(md.iterator(), serviceName, portTypeName); // Finds the primary WSDL and makes sure that metadata doesn't have // two concrete or abstract WSDLs SDDocumentImpl primaryDoc = primaryWsdl != null ? SDDocumentImpl.create(primaryWsdl,serviceName,portTypeName) : findPrimary(docList); @@ -326,50 +342,87 @@ public class EndpointFactory { * * @param primaryDoc primary WSDL doc * @param docList complete metadata - * @return new metadata that doesn't contain extraneous documnets. + * @return new metadata that doesn't contain extraneous documents. */ - private static List findMetadataClosure(SDDocumentImpl primaryDoc, List docList, EntityResolver resolver) { - // create a map for old metadata - Map oldMap = new HashMap(); - for(SDDocumentImpl doc : docList) { - oldMap.put(doc.getSystemId().toString(), doc); - } - // create a map for new metadata - Map newMap = new HashMap(); - newMap.put(primaryDoc.getSystemId().toString(), primaryDoc); + private static Collection findMetadataClosure( + final SDDocumentImpl primaryDoc, final Collection docList, final EntityResolver resolver) { + return new AbstractCollection() { + @Override + public Iterator iterator() { + // create a map for old metadata + Map oldMap = new HashMap(); + Iterator oldDocs = docList.iterator(); - List remaining = new ArrayList(); - remaining.addAll(primaryDoc.getImports()); - while(!remaining.isEmpty()) { - String url = remaining.remove(0); - SDDocumentImpl doc = oldMap.get(url); - if (doc == null) { - // old metadata doesn't have this imported doc, may be external - if (resolver != null) { - try { - InputSource source = resolver.resolveEntity(null, url); - if (source != null) { - MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer(); - XMLStreamReader reader = XmlUtil.newXMLInputFactory(true).createXMLStreamReader(source.getByteStream()); - xsb.createFromXMLStreamReader(reader); + // create a map for new metadata + Map newMap = new HashMap(); + newMap.put(primaryDoc.getSystemId().toString(), primaryDoc); - SDDocumentSource sdocSource = SDDocumentImpl.create(new URL(url), xsb); - doc = SDDocumentImpl.create(sdocSource, null, null); - } - } catch (Exception ex) { - ex.printStackTrace(); + List remaining = new ArrayList(); + remaining.addAll(primaryDoc.getImports()); + while(!remaining.isEmpty()) { + String url = remaining.remove(0); + SDDocumentImpl doc = oldMap.get(url); + if (doc == null) { + while (oldDocs.hasNext()) { + SDDocumentImpl old = oldDocs.next(); + String id = old.getSystemId().toString(); + oldMap.put(id, old); + if (id.equals(url)) { + doc = old; + break; + } } + + if (doc == null) { + // old metadata doesn't have this imported doc, may be external + if (resolver != null) { + try { + InputSource source = resolver.resolveEntity(null, url); + if (source != null) { + MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer(); + XMLStreamReader reader = XmlUtil.newXMLInputFactory(true).createXMLStreamReader(source.getByteStream()); + xsb.createFromXMLStreamReader(reader); + + SDDocumentSource sdocSource = SDDocumentImpl.create(new URL(url), xsb); + doc = SDDocumentImpl.create(sdocSource, null, null); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + } + // Check if new metadata already contains this doc + if (doc != null && !newMap.containsKey(url)) { + newMap.put(url, doc); + remaining.addAll(doc.getImports()); + } } + + return newMap.values().iterator(); } - // Check if new metadata already contains this doc - if (doc != null && !newMap.containsKey(url)) { - newMap.put(url, doc); - remaining.addAll(doc.getImports()); + + @Override + public int size() { + int size = 0; + Iterator it = iterator(); + while (it.hasNext()) { + it.next(); + size++; + } + return size; } - } - List newMetadata = new ArrayList(); - newMetadata.addAll(newMap.values()); - return newMetadata; + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEmpty() { + return docList.isEmpty(); + } + }; } private static void processHandlerAnnotation(WSBinding binding, Class implType, QName serviceName, QName portName) { @@ -599,7 +652,7 @@ public class EndpointFactory { * Generates the WSDL and XML Schema for the endpoint if necessary * It generates WSDL only for SOAP1.1, and for XSOAP1.2 bindings */ - private static SDDocumentImpl generateWSDL(WSBinding binding, AbstractSEIModelImpl seiModel, List docs, + private static SDDocumentImpl generateWSDL(WSBinding binding, AbstractSEIModelImpl seiModel, Collection docs, Container container, Class implType) { BindingID bindingId = binding.getBindingId(); if (!bindingId.canGenerateWSDL()) { @@ -634,14 +687,59 @@ public class EndpointFactory { /** * Builds {@link SDDocumentImpl} from {@link SDDocumentSource}. */ - private static List categoriseMetadata( - List src, QName serviceName, QName portTypeName) { + private static Collection categoriseMetadata( + final Iterator src, final QName serviceName, final QName portTypeName) { - List r = new ArrayList(src.size()); - for (SDDocumentSource doc : src) { - r.add(SDDocumentImpl.create(doc,serviceName,portTypeName)); - } - return r; + return new AbstractCollection() { + private final Collection theConverted = new ArrayList(); + + @Override + public boolean add(SDDocumentImpl arg0) { + return theConverted.add(arg0); + } + + @Override + public Iterator iterator() { + return new Iterator() { + private Iterator convIt = theConverted.iterator(); + @Override + public boolean hasNext() { + if (convIt != null && convIt.hasNext()) + return true; + return src.hasNext(); + } + + @Override + public SDDocumentImpl next() { + if (convIt != null && convIt.hasNext()) + return convIt.next(); + convIt = null; + if (!src.hasNext()) + throw new NoSuchElementException(); + SDDocumentImpl next = SDDocumentImpl.create(src.next(),serviceName,portTypeName); + theConverted.add(next); + return next; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public int size() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEmpty() { + if (!theConverted.isEmpty()) + return false; + return !src.hasNext(); + } + }; } /** @@ -675,7 +773,7 @@ public class EndpointFactory { * @return primay wsdl document, null if is not there in the docList * */ - private static @Nullable SDDocumentImpl findPrimary(@NotNull List docList) { + private static @Nullable SDDocumentImpl findPrimary(@NotNull Collection docList) { SDDocumentImpl primaryDoc = null; boolean foundConcrete = false; boolean foundAbstract = false; @@ -710,7 +808,7 @@ public class EndpointFactory { * @param container container in which this service is running * @return non-null wsdl port object */ - private static @NotNull WSDLPort getWSDLPort(SDDocumentSource primaryWsdl, List metadata, + private static @NotNull WSDLPort getWSDLPort(SDDocumentSource primaryWsdl, Collection metadata, @NotNull QName serviceName, @NotNull QName portName, Container container, EntityResolver resolver) { URL wsdlUrl = primaryWsdl.getSystemId(); @@ -746,13 +844,12 @@ public class EndpointFactory { * {@link XMLEntityResolver} that can resolve to {@link SDDocumentSource}s. */ private static final class EntityResolverImpl implements XMLEntityResolver { - private Map metadata = new HashMap(); + private Iterator origMetadata; + private Map metadata = new ConcurrentHashMap(); private EntityResolver resolver; - public EntityResolverImpl(List metadata, EntityResolver resolver) { - for (SDDocumentSource doc : metadata) { - this.metadata.put(doc.getSystemId().toExternalForm(),doc); - } + public EntityResolverImpl(Collection metadata, EntityResolver resolver) { + this.origMetadata = metadata.iterator(); this.resolver = resolver; } @@ -761,6 +858,15 @@ public class EndpointFactory { SDDocumentSource doc = metadata.get(systemId); if (doc != null) return new Parser(doc); + synchronized(this) { + while(origMetadata.hasNext()) { + doc = origMetadata.next(); + String extForm = doc.getSystemId().toExternalForm(); + this.metadata.put(extForm,doc); + if (systemId.equals(extForm)) + return new Parser(doc); + } + } } if (resolver != null) { try { @@ -780,4 +886,72 @@ public class EndpointFactory { private static final Logger logger = Logger.getLogger( com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server.endpoint"); + + private static class CollectionCollection extends AbstractCollection { + + private final Collection> cols = new ArrayList>(); + + @Override + public Iterator iterator() { + final Iterator> colIt = cols.iterator(); + return new Iterator() { + private Iterator current = null; + + @Override + public boolean hasNext() { + if (current == null || !current.hasNext()) { + do { + if (!colIt.hasNext()) + return false; + current = colIt.next().iterator(); + } while (!current.hasNext()); + return true; + } + return true; + } + + @Override + public T next() { + if (!hasNext()) + throw new NoSuchElementException(); + return current.next(); + } + + @Override + public void remove() { + if (current == null) + throw new IllegalStateException(); + current.remove(); + } + }; + } + + @Override + public int size() { + int size = 0; + for (Collection c : cols) + size += c.size(); + return size; + } + + @Override + public boolean add(T arg0) { + return cols.add(Collections.singleton(arg0)); + } + + @Override + public boolean addAll(Collection arg0) { + return cols.add(arg0); + } + + @Override + public void clear() { + cols.clear(); + } + + @Override + public boolean isEmpty() { + return !iterator().hasNext(); + } + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/SDDocumentImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/SDDocumentImpl.java index b7417af236b..5dd13151ece 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/SDDocumentImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/SDDocumentImpl.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,7 +31,7 @@ import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory; import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; import com.sun.xml.internal.ws.wsdl.SDDocumentResolver; import com.sun.xml.internal.ws.util.RuntimeVersion; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.wsdl.parser.ParserUtil; import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; import com.sun.xml.internal.ws.wsdl.writer.DocumentLocationResolver; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/ServiceDefinitionImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/ServiceDefinitionImpl.java index 07e09ab5cae..e31e77d872b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/ServiceDefinitionImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/ServiceDefinitionImpl.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 @@ -32,6 +32,7 @@ import com.sun.xml.internal.ws.api.server.ServiceDefinition; import com.sun.xml.internal.ws.wsdl.SDDocumentResolver; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -47,7 +48,7 @@ import java.util.Map; * @author Kohsuke Kawaguchi */ public final class ServiceDefinitionImpl implements ServiceDefinition, SDDocumentResolver { - private final List docs; + private final Collection docs; private final Map bySystemId; private final @NotNull SDDocumentImpl primaryWsdl; @@ -65,12 +66,20 @@ public final class ServiceDefinitionImpl implements ServiceDefinition, SDDocumen * There must be at least one entry. * The first document is considered {@link #getPrimary() primary}. */ - public ServiceDefinitionImpl(List docs, @NotNull SDDocumentImpl primaryWsdl) { + public ServiceDefinitionImpl(Collection docs, @NotNull SDDocumentImpl primaryWsdl) { assert docs.contains(primaryWsdl); this.docs = docs; this.primaryWsdl = primaryWsdl; + this.bySystemId = new HashMap(); + } + + private boolean isInitialized = false; + + private synchronized void init() { + if (isInitialized) + return; + isInitialized = true; - this.bySystemId = new HashMap(docs.size()); for (SDDocumentImpl doc : docs) { bySystemId.put(doc.getURL().toExternalForm(),doc); doc.setFilters(filters); @@ -95,6 +104,7 @@ public final class ServiceDefinitionImpl implements ServiceDefinition, SDDocumen } public Iterator iterator() { + init(); return (Iterator)docs.iterator(); } @@ -106,6 +116,7 @@ public final class ServiceDefinitionImpl implements ServiceDefinition, SDDocumen * null if none is found. */ public SDDocument resolve(String systemId) { + init(); return bySystemId.get(systemId); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSDLGenResolver.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSDLGenResolver.java index 0dbd8f0ab09..46fa601d429 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSDLGenResolver.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSDLGenResolver.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 @@ -35,9 +35,11 @@ import javax.xml.namespace.QName; import javax.xml.transform.Result; import javax.xml.ws.Holder; import javax.xml.ws.WebServiceException; + import java.net.URL; import java.net.MalformedURLException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -50,7 +52,7 @@ import java.util.Map; */ final class WSDLGenResolver implements com.oracle.webservices.internal.api.databinding.WSDLResolver { - private final List docs; + private final Collection docs; private final List newDocs = new ArrayList(); private SDDocumentSource concreteWsdlSource; @@ -65,7 +67,7 @@ final class WSDLGenResolver implements com.oracle.webservices.internal.api.datab private final QName serviceName; private final QName portTypeName; - public WSDLGenResolver(@NotNull List docs,QName serviceName,QName portTypeName) { + public WSDLGenResolver(@NotNull Collection docs,QName serviceName,QName portTypeName) { this.docs = docs; this.serviceName = serviceName; this.portTypeName = portTypeName; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldGetter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldGetter.java index ab01d6be48b..145f5be3911 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldGetter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldGetter.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 @@ -26,9 +26,7 @@ package com.sun.xml.internal.ws.spi.db; import java.lang.reflect.Field; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; +import javax.xml.ws.WebServiceException; /** @@ -42,6 +40,7 @@ public class FieldGetter extends PropertyGetterBase { protected Field field; public FieldGetter(Field f) { + verifyWrapperType(f.getDeclaringClass()); field = f; type = f.getType(); } @@ -50,43 +49,12 @@ public class FieldGetter extends PropertyGetterBase { return field; } - static class PrivilegedGetter implements PrivilegedExceptionAction { - private Object value; - private Field field; - private Object instance; - public PrivilegedGetter(Field field, Object instance) { - super(); - this.field = field; - this.instance = instance; - } - public Object run() throws IllegalAccessException { - if (!field.isAccessible()) { - field.setAccessible(true); - } - value = field.get(instance); - return null; - } - } - public Object get(final Object instance) { - if (field.isAccessible()) { - try { - return field.get(instance); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - PrivilegedGetter privilegedGetter = new PrivilegedGetter(field, instance); - try { - AccessController.doPrivileged(privilegedGetter); - } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return privilegedGetter.value; + try { + return field.get(instance); + } catch (Exception e) { + throw new WebServiceException(e); } - return null; } public A getAnnotation(Class annotationType) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldSetter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldSetter.java index fb606389ab1..10ae6b8d131 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldSetter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldSetter.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 @@ -26,10 +26,8 @@ package com.sun.xml.internal.ws.spi.db; import java.lang.reflect.Field; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; - +import javax.xml.ws.WebServiceException; +import static com.sun.xml.internal.ws.spi.db.PropertyGetterBase.verifyWrapperType; /** * FieldSetter @@ -41,6 +39,7 @@ public class FieldSetter extends PropertySetterBase { protected Field field; public FieldSetter(Field f) { + verifyWrapperType(f.getDeclaringClass()); field = f; type = f.getType(); } @@ -49,29 +48,12 @@ public class FieldSetter extends PropertySetterBase { return field; } - public void set(final Object instance, final Object resource) { - if (field.isAccessible()) { - try { - field.set(instance, resource); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws IllegalAccessException { - if (!field.isAccessible()) { - field.setAccessible(true); - } - field.set(instance, resource); - return null; - } - }); - } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + public void set(final Object instance, final Object val) { + final Object resource = (type.isPrimitive() && val == null)? uninitializedValue(type): val; + try { + field.set(instance, resource); + } catch (Exception e) { + throw new WebServiceException(e); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/JAXBWrapperAccessor.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/JAXBWrapperAccessor.java index 248c61c8939..9c0800e995b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/JAXBWrapperAccessor.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/JAXBWrapperAccessor.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 @@ -45,6 +45,8 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.namespace.QName; +import javax.xml.ws.WebServiceException; +import static com.sun.xml.internal.ws.spi.db.PropertyGetterBase.verifyWrapperType; /** * JAXBWrapperAccessor @@ -58,6 +60,7 @@ public class JAXBWrapperAccessor extends WrapperAccessor { protected HashMap elementDeclaredTypes; public JAXBWrapperAccessor(Class wrapperBean) { + verifyWrapperType(wrapperBean); contentClass = (Class) wrapperBean; HashMap setByQName = new HashMap(); @@ -142,18 +145,16 @@ public class JAXBWrapperAccessor extends WrapperAccessor { } } - // _return - if (fieldName.startsWith("_") && !localName.startsWith("_")) { - fieldName = fieldName.substring(1); + Method setMethod = accessor(publicSetters, fieldName, localName); + Method getMethod = accessor(publicGetters, fieldName, localName); + if ( isProperty(field, getMethod, setMethod) ) { + PropertySetter setter = createPropertySetter(field, setMethod); + PropertyGetter getter = createPropertyGetter(field, getMethod); + setByQName.put(qname, setter); + setByLocalpart.put(localName, setter); + getByQName.put(qname, getter); + getByLocalpart.put(localName, getter); } - Method setMethod = publicSetters.get(fieldName); - Method getMethod = publicGetters.get(fieldName); - PropertySetter setter = createPropertySetter(field, setMethod); - PropertyGetter getter = createPropertyGetter(field, getMethod); - setByQName.put(qname, setter); - setByLocalpart.put(localName, setter); - getByQName.put(qname, getter); - getByLocalpart.put(localName, getter); } if (this.elementLocalNameCollision) { this.propertySetters = setByQName; @@ -166,7 +167,25 @@ public class JAXBWrapperAccessor extends WrapperAccessor { } } - static protected List getAllFields(Class clz) { + static private Method accessor(HashMap map, String fieldName, String localName) { + Method a = map.get(fieldName); + if (a == null) a = map.get(localName); + if (a == null && fieldName.startsWith("_")) a = map.get(fieldName.substring(1)); + return a; + } + + static private boolean isProperty(Field field, Method getter, Method setter) { + if (java.lang.reflect.Modifier.isPublic(field.getModifiers())) return true; + if (getter == null) return false; + if (setter == null) { + return java.util.Collection.class.isAssignableFrom(field.getType()) || + java.util.Map.class.isAssignableFrom(field.getType()) ; + } else { + return true; + } + } + + static private List getAllFields(Class clz) { List list = new ArrayList(); while (!Object.class.equals(clz)) { list.addAll(Arrays.asList(getDeclaredFields(clz))); @@ -175,23 +194,20 @@ public class JAXBWrapperAccessor extends WrapperAccessor { return list; } - static protected Field[] getDeclaredFields(final Class clz) { + static private Field[] getDeclaredFields(final Class clz) { try { - return (System.getSecurityManager() == null) ? clz .getDeclaredFields() : - AccessController.doPrivileged(new PrivilegedExceptionAction() { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { @Override public Field[] run() throws IllegalAccessException { return clz.getDeclaredFields(); } }); } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; + throw new WebServiceException(e); } } - static protected PropertyGetter createPropertyGetter(Field field, Method getMethod) { + static private PropertyGetter createPropertyGetter(Field field, Method getMethod) { if (!field.isAccessible()) { if (getMethod != null) { MethodGetter methodGetter = new MethodGetter(getMethod); @@ -200,10 +216,10 @@ public class JAXBWrapperAccessor extends WrapperAccessor { } } } - return new FieldGetter(field); + return new PrivFieldGetter(field); } - static protected PropertySetter createPropertySetter(Field field, + static private PropertySetter createPropertySetter(Field field, Method setter) { if (!field.isAccessible()) { if (setter != null) { @@ -213,7 +229,7 @@ public class JAXBWrapperAccessor extends WrapperAccessor { } } } - return new FieldSetter(field); + return new PrivFieldSetter(field); } private Class getElementDeclaredType(QName name) { @@ -238,10 +254,10 @@ public class JAXBWrapperAccessor extends WrapperAccessor { public Object get(Object bean) throws DatabindingException { Object val; if (isJAXBElement) { - JAXBElement jaxbElement = (JAXBElement) getter.get(bean); + JAXBElement jaxbElement = (JAXBElement) JAXBWrapperAccessor.get(getter, bean); val = (jaxbElement == null) ? null : jaxbElement.getValue(); } else { - val = getter.get(bean); + val = JAXBWrapperAccessor.get(getter, bean); } if (val == null && isListType) { val = new java.util.ArrayList(); @@ -255,11 +271,95 @@ public class JAXBWrapperAccessor extends WrapperAccessor { if (isJAXBElement) { JAXBElement jaxbElement = new JAXBElement( n, elementDeclaredType, contentClass, value); - setter.set(bean, jaxbElement); + JAXBWrapperAccessor.set(setter, bean, jaxbElement); } else { - setter.set(bean, value); + JAXBWrapperAccessor.set(setter, bean, value); } } }; } + + static private Object get(PropertyGetter getter, Object wrapperInstance) { + return (getter instanceof PrivFieldGetter)? + ((PrivFieldGetter)getter).getPriv(wrapperInstance): + getter.get(wrapperInstance); + } + + static private void set(PropertySetter setter, Object wrapperInstance, Object value) { + if (setter instanceof PrivFieldSetter) + ((PrivFieldSetter)setter).setPriv(wrapperInstance, value); + else + setter.set(wrapperInstance, value); + } + + + static private class PrivFieldSetter extends FieldSetter { + private PrivFieldSetter(Field f) { + super(f); + } + private void setPriv(final Object instance, final Object val) { + final Object resource = (type.isPrimitive() && val == null)? uninitializedValue(type): val; + if (field.isAccessible()) { + try { + field.set(instance, resource); + } catch (Exception e) { + throw new WebServiceException(e); + } + } else { + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws IllegalAccessException { + if (!field.isAccessible()) { + field.setAccessible(true); + } + field.set(instance, resource); + return null; + } + }); + } catch (PrivilegedActionException e) { + throw new WebServiceException(e); + } + } + } + } + + static private class PrivFieldGetter extends FieldGetter { + private PrivFieldGetter(Field f) { + super(f); + } + static private class PrivilegedGetter implements PrivilegedExceptionAction { + private Object value; + private Field field; + private Object instance; + public PrivilegedGetter(Field field, Object instance) { + super(); + this.field = field; + this.instance = instance; + } + public Object run() throws IllegalAccessException { + if (!field.isAccessible()) { + field.setAccessible(true); + } + value = field.get(instance); + return null; + } + } + private Object getPriv(final Object instance) { + if (field.isAccessible()) { + try { + return field.get(instance); + } catch (Exception e) { + throw new WebServiceException(e); + } + } else { + PrivilegedGetter privilegedGetter = new PrivilegedGetter(field, instance); + try { + AccessController.doPrivileged(privilegedGetter); + } catch (PrivilegedActionException e) { + throw new WebServiceException(e); + } + return privilegedGetter.value; + } + } + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodGetter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodGetter.java index 67608951af0..99100dfdf2c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodGetter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodGetter.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 @@ -26,9 +26,7 @@ package com.sun.xml.internal.ws.spi.db; import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; +import javax.xml.ws.WebServiceException; /** @@ -41,6 +39,7 @@ public class MethodGetter extends PropertyGetterBase { private Method method; public MethodGetter(Method m) { + verifyWrapperType(m.getDeclaringClass()); method = m; type = m.getReturnType(); } @@ -54,49 +53,12 @@ public class MethodGetter extends PropertyGetterBase { return (A) method.getAnnotation(c); } - - static class PrivilegedGetter implements PrivilegedExceptionAction { - private Object value; - private Method method; - private Object instance; - public PrivilegedGetter(Method m, Object instance) { - super(); - this.method = m; - this.instance = instance; - } - public Object run() throws IllegalAccessException { - if (!method.isAccessible()) { - method.setAccessible(true); - } - try { - value = method.invoke(instance, new Object[0]); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; - } - } - public Object get(final Object instance) { final Object[] args = new Object[0]; try { - if (method.isAccessible()) { - return method.invoke(instance, args); - } else { - PrivilegedGetter privilegedGetter = new PrivilegedGetter(method, instance); - try { - AccessController.doPrivileged(privilegedGetter); - } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return privilegedGetter.value; - } + return method.invoke(instance, args); } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + throw new WebServiceException(e); } - return null; } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodSetter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodSetter.java index 15b14b44294..b641d094b14 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodSetter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodSetter.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 @@ -25,10 +25,9 @@ package com.sun.xml.internal.ws.spi.db; +import static com.sun.xml.internal.ws.spi.db.PropertyGetterBase.verifyWrapperType; import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; +import javax.xml.ws.WebServiceException; /** @@ -41,6 +40,7 @@ public class MethodSetter extends PropertySetterBase { private Method method; public MethodSetter(Method m) { + verifyWrapperType(m.getDeclaringClass()); method = m; type = m.getParameterTypes()[0]; } @@ -54,34 +54,13 @@ public class MethodSetter extends PropertySetterBase { return (A) method.getAnnotation(c); } - public void set(final Object instance, Object resource) { + public void set(final Object instance, Object val) { + final Object resource = (type.isPrimitive() && val == null)? uninitializedValue(type): val; final Object[] args = {resource}; - if (method.isAccessible()) { - try { - method.invoke(instance, args); - } catch (Exception e) { - e.printStackTrace(); - } - } else { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws IllegalAccessException { - if (!method.isAccessible()) { - method.setAccessible(true); - } - try { - method.invoke(instance, args); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; - } - }); - } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + try { + method.invoke(instance, args); + } catch (Exception e) { + throw new WebServiceException(e); } } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertyGetterBase.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertyGetterBase.java index f87cad25886..e2d4fa87910 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertyGetterBase.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertyGetterBase.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 @@ -25,6 +25,8 @@ package com.sun.xml.internal.ws.spi.db; +import javax.xml.ws.WebServiceException; + /** * This is the Gtter of a bean property. * @@ -46,7 +48,7 @@ public abstract class PropertyGetterBase implements PropertyGetter { method.getName().length() > 3) { return true; } else { - if (method.getReturnType().equals(boolean.class) && + if ((method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class)) && method.getName().startsWith("is") && method.getName().length() > 2) { return true; @@ -55,4 +57,11 @@ public abstract class PropertyGetterBase implements PropertyGetter { } return false; } + + static void verifyWrapperType(Class wrapperType) { + String className = wrapperType.getName(); + if (className.startsWith("java.") || className.startsWith("javax.")) { + throw new WebServiceException("Invalid wrapper type " + className); + } + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertySetterBase.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertySetterBase.java index 834653f3782..585f83a4b41 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertySetterBase.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertySetterBase.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 @@ -25,6 +25,9 @@ package com.sun.xml.internal.ws.spi.db; +import java.util.HashMap; +import java.util.Map; + /** * This is the Setter of a bean property. * @author shih-chang.chen@oracle.com @@ -44,4 +47,20 @@ public abstract class PropertySetterBase implements PropertySetter { method.getParameterTypes() != null && method.getParameterTypes().length == 1); } + + /** + * Uninitialized map keyed by their classes. + */ + private static final Map uninitializedValues = new HashMap(); + static { + uninitializedValues.put(byte.class, Byte.valueOf((byte) 0)); + uninitializedValues.put(boolean.class, false); + uninitializedValues.put(char.class, Character.valueOf((char) 0)); + uninitializedValues.put(float.class, Float.valueOf(0)); + uninitializedValues.put(double.class, Double.valueOf(0)); + uninitializedValues.put(int.class, Integer.valueOf(0)); + uninitializedValues.put(long.class, Long.valueOf(0)); + uninitializedValues.put(short.class, Short.valueOf((short) 0)); + } + static protected Object uninitializedValue(Class cls) { return uninitializedValues.get(cls); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/streaming/MtomStreamWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/streaming/MtomStreamWriter.java index fccf3febc70..3605c48ce8f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/streaming/MtomStreamWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/streaming/MtomStreamWriter.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 @@ -36,9 +36,12 @@ import javax.xml.stream.XMLStreamWriter; * {@link AttachmentMarshaller}. The marshaller could do processing based on * MTOM threshold, and make decisions about inlining the attachment data or not. * + * * @author Jitendra Kotamraju * @see JAXBMessage * @see MtomCodec + * + * @deprecated use com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter */ public interface MtomStreamWriter { AttachmentMarshaller getAttachmentMarshaller(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/HttpAdapter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/HttpAdapter.java index 452eb985cec..d0f2e601da0 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/HttpAdapter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/HttpAdapter.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 @@ -32,11 +32,14 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.HttpURLConnection; +import java.util.AbstractMap; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -172,43 +175,187 @@ public class HttpAdapter extends Adapter { * * @param sdef service definition */ - public final void initWSDLMap(ServiceDefinition sdef) { - this.serviceDefinition = sdef; - if(sdef==null) { + public final void initWSDLMap(final ServiceDefinition serviceDefinition) { + this.serviceDefinition = serviceDefinition; + if(serviceDefinition==null) { wsdls = Collections.emptyMap(); revWsdls = Collections.emptyMap(); } else { - wsdls = new HashMap(); // wsdl=1 --> Doc - // Sort WSDL, Schema documents based on SystemId so that the same - // document gets wsdl=x mapping - Map systemIds = new TreeMap(); - for (SDDocument sdd : sdef) { - if (sdd == sdef.getPrimary()) { // No sorting for Primary WSDL - wsdls.put("wsdl", sdd); - wsdls.put("WSDL", sdd); - } else { - systemIds.put(sdd.getURL().toString(), sdd); - } - } + wsdls = new AbstractMap() { + private Map delegate = null; - int wsdlnum = 1; - int xsdnum = 1; - for (Entry e : systemIds.entrySet()) { - SDDocument sdd = e.getValue(); - if (sdd.isWSDL()) { - wsdls.put("wsdl="+(wsdlnum++),sdd); - } - if (sdd.isSchema()) { - wsdls.put("xsd="+(xsdnum++),sdd); - } - } + private synchronized Map delegate() { + if (delegate != null) + return delegate; - revWsdls = new HashMap(); // Doc --> wsdl=1 - for (Entry e : wsdls.entrySet()) { - if (!e.getKey().equals("WSDL")) { // map Doc --> wsdl, not WSDL - revWsdls.put(e.getValue(),e.getKey()); + delegate = new HashMap(); // wsdl=1 --> Doc + // Sort WSDL, Schema documents based on SystemId so that the same + // document gets wsdl=x mapping + Map systemIds = new TreeMap(); + for (SDDocument sdd : serviceDefinition) { + if (sdd == serviceDefinition.getPrimary()) { // No sorting for Primary WSDL + delegate.put("wsdl", sdd); + delegate.put("WSDL", sdd); + } else { + systemIds.put(sdd.getURL().toString(), sdd); + } + } + + int wsdlnum = 1; + int xsdnum = 1; + for (Entry e : systemIds.entrySet()) { + SDDocument sdd = e.getValue(); + if (sdd.isWSDL()) { + delegate.put("wsdl="+(wsdlnum++),sdd); + } + if (sdd.isSchema()) { + delegate.put("xsd="+(xsdnum++),sdd); + } + } + + return delegate; } - } + + @Override + public void clear() { + delegate().clear(); + } + + @Override + public boolean containsKey(Object arg0) { + return delegate().containsKey(arg0); + } + + @Override + public boolean containsValue(Object arg0) { + return delegate.containsValue(arg0); + } + + @Override + public SDDocument get(Object arg0) { + return delegate().get(arg0); + } + + @Override + public boolean isEmpty() { + return delegate().isEmpty(); + } + + @Override + public Set keySet() { + return delegate().keySet(); + } + + @Override + public SDDocument put(String arg0, SDDocument arg1) { + return delegate().put(arg0, arg1); + } + + @Override + public void putAll( + Map arg0) { + delegate().putAll(arg0); + } + + @Override + public SDDocument remove(Object arg0) { + return delegate().remove(arg0); + } + + @Override + public int size() { + return delegate().size(); + } + + @Override + public Collection values() { + return delegate().values(); + } + + @Override + public Set> entrySet() { + return delegate().entrySet(); + } + }; + + revWsdls = new AbstractMap() { + private Map delegate = null; + + private synchronized Map delegate() { + if (delegate != null) + return delegate; + + delegate = new HashMap(); // Doc --> wsdl=1 + for (Entry e : wsdls.entrySet()) { + if (!e.getKey().equals("WSDL")) { // map Doc --> wsdl, not WSDL + delegate.put(e.getValue(),e.getKey()); + } + } + + return delegate; + } + + @Override + public void clear() { + delegate().clear(); + } + + @Override + public boolean containsKey(Object key) { + return delegate().containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return delegate().containsValue(value); + } + + @Override + public Set> entrySet() { + return delegate().entrySet(); + } + + @Override + public String get(Object key) { + return delegate().get(key); + } + + @Override + public boolean isEmpty() { + // TODO Auto-generated method stub + return super.isEmpty(); + } + + @Override + public Set keySet() { + return delegate().keySet(); + } + + @Override + public String put(SDDocument key, String value) { + return delegate().put(key, value); + } + + @Override + public void putAll(Map m) { + delegate().putAll(m); + } + + @Override + public String remove(Object key) { + return delegate().remove(key); + } + + @Override + public int size() { + return delegate().size(); + } + + @Override + public Collection values() { + return delegate().values(); + } + }; } } @@ -981,7 +1128,9 @@ public class HttpAdapter extends Adapter { } } try { - setPublishStatus(Boolean.getBoolean(HttpAdapter.class.getName() + ".publishStatusPage")); + if (System.getProperty(HttpAdapter.class.getName() + ".publishStatusPage") != null) { + setPublishStatus(Boolean.getBoolean(HttpAdapter.class.getName() + ".publishStatusPage")); + } } catch (SecurityException se) { if (LOGGER.isLoggable(Level.CONFIG)) { LOGGER.log(Level.CONFIG, "Cannot read ''{0}'' property, using defaults.", diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/client/HttpTransportPipe.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/client/HttpTransportPipe.java index f8633d182dc..004a122adbf 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/client/HttpTransportPipe.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/client/HttpTransportPipe.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 @@ -257,7 +257,14 @@ public class HttpTransportPipe extends AbstractTubeImpl { // Allows only certain http status codes for a binding. For all // other status codes, throws exception checkStatusCode(responseStream, con); // throws ClientTransportException - + //To avoid zero-length chunk for One-Way + if (cl ==-1 && con.statusCode == 202 && "Accepted".equals(con.statusMessage) && responseStream != null) { + ByteArrayBuffer buf = new ByteArrayBuffer(); + buf.write(responseStream); //What is within the responseStream? + responseStream.close(); + responseStream = (buf.size()==0)? null : buf.newInputStream(); + buf.close(); + } Packet reply = request.createClientResponse(null); reply.wasTransportSecure = con.isSecure(); if (responseStream != null) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/version.properties b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/version.properties index c0aaf9f9fa7..188bd319f70 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/version.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/version.properties @@ -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,7 +23,7 @@ # questions. # -build-id=2.2.9-b130926.1035 -build-version=JAX-WS RI 2.2.9-b130926.1035 -major-version=2.2.9 -svn-revision=8c29a9a53251ff741fca1664a8221dc876b2eac8 +build-id=2.2.10-b140228.1436 +build-version=JAX-WS RI 2.2.10-b140228.1436 +major-version=2.2.10 +svn-revision=e1d4708e8a2aee1ae9d38313452e14ce4b67851a diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/xml/XMLStreamReaderToXMLStreamWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/xml/XMLStreamReaderToXMLStreamWriter.java index 7a2abce1811..14ad9743353 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/xml/XMLStreamReaderToXMLStreamWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/xml/XMLStreamReaderToXMLStreamWriter.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 @@ -48,6 +48,8 @@ import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx; * * @author Kohsuke Kawaguchi * @author Ryan Shoemaker + * + * @deprecated use com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter */ public class XMLStreamReaderToXMLStreamWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/wsdl/writer/WSDLPatcher.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/wsdl/writer/WSDLPatcher.java index 3b6bb7cf309..17f5fe7a3fd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/wsdl/writer/WSDLPatcher.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/wsdl/writer/WSDLPatcher.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 @@ -27,7 +27,7 @@ package com.sun.xml.internal.ws.wsdl.writer; import com.sun.istack.internal.NotNull; import com.sun.xml.internal.ws.api.server.PortAddressResolver; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; import com.sun.xml.internal.ws.addressing.W3CAddressingConstants; import com.sun.xml.internal.ws.addressing.v200408.MemberSubmissionAddressingConstants; diff --git a/jaxws/src/share/jaxws_classes/javax/xml/bind/JAXBException.java b/jaxws/src/share/jaxws_classes/javax/xml/bind/JAXBException.java index c6b94d64920..218dceb7ae3 100644 --- a/jaxws/src/share/jaxws_classes/javax/xml/bind/JAXBException.java +++ b/jaxws/src/share/jaxws_classes/javax/xml/bind/JAXBException.java @@ -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 @@ -48,7 +48,7 @@ public class JAXBException extends Exception { * Exception reference * */ - private volatile Throwable linkedException; + private Throwable linkedException; static final long serialVersionUID = -5621384651494307979L; @@ -133,7 +133,7 @@ public class JAXBException extends Exception { * indicates that the linked exception does not exist or * is unknown). */ - public void setLinkedException( Throwable exception ) { + public synchronized void setLinkedException( Throwable exception ) { this.linkedException = exception; } diff --git a/jaxws/src/share/jaxws_classes/javax/xml/bind/TypeConstraintException.java b/jaxws/src/share/jaxws_classes/javax/xml/bind/TypeConstraintException.java index 9189d21135c..24a295b8d02 100644 --- a/jaxws/src/share/jaxws_classes/javax/xml/bind/TypeConstraintException.java +++ b/jaxws/src/share/jaxws_classes/javax/xml/bind/TypeConstraintException.java @@ -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 @@ -57,9 +57,8 @@ public class TypeConstraintException extends java.lang.RuntimeException { * Exception reference * */ - private volatile Throwable linkedException; + private Throwable linkedException; - static final long serialVersionUID = -3059799699420143848L; /** * Construct a TypeConstraintException with the specified detail message. The @@ -142,7 +141,7 @@ public class TypeConstraintException extends java.lang.RuntimeException { * indicates that the linked exception does not exist or * is unknown). */ - public void setLinkedException( Throwable exception ) { + public synchronized void setLinkedException( Throwable exception ) { this.linkedException = exception; } diff --git a/jdk/.hgtags b/jdk/.hgtags index 11331a15a8e..118a09481e8 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -249,3 +249,4 @@ d31cd980e1da31fa496a359caaf1a165aeb5791a jdk8-b120 627deed79b595a4789fc9151455b663a47381257 jdk9-b04 263198a1d8f1f4cb97d35f40c61704b08ebd3686 jdk9-b05 cac7b28b8b1e0e11d7a8e1ac1fe75a03b3749eab jdk9-b06 +f4e624447514f12dd7c51f1e5b0cb97efcd15be2 jdk9-b07 diff --git a/jdk/make/mapfiles/libnet/mapfile-vers b/jdk/make/mapfiles/libnet/mapfile-vers index 879fff4a850..ab621a923a8 100644 --- a/jdk/make/mapfiles/libnet/mapfile-vers +++ b/jdk/make/mapfiles/libnet/mapfile-vers @@ -94,6 +94,10 @@ SUNWprivate_1.1 { Java_sun_net_sdp_SdpSupport_create0; Java_sun_net_spi_DefaultProxySelector_init; Java_sun_net_spi_DefaultProxySelector_getSystemProxy; + Java_sun_net_ExtendedOptionsImpl_init; + Java_sun_net_ExtendedOptionsImpl_setFlowOption; + Java_sun_net_ExtendedOptionsImpl_getFlowOption; + Java_sun_net_ExtendedOptionsImpl_flowSupported; NET_AllocSockaddr; NET_SockaddrToInetAddress; NET_SockaddrEqualsInetAddress; diff --git a/jdk/src/share/classes/com/oracle/net/Sdp.java b/jdk/src/share/classes/com/oracle/net/Sdp.java deleted file mode 100644 index d22a95ed120..00000000000 --- a/jdk/src/share/classes/com/oracle/net/Sdp.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.net; - -import java.net.Socket; -import java.net.ServerSocket; -import java.net.SocketImpl; -import java.net.SocketImplFactory; -import java.net.SocketException; -import java.nio.channels.SocketChannel; -import java.nio.channels.ServerSocketChannel; -import java.io.IOException; -import java.io.FileDescriptor; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.lang.reflect.Constructor; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.InvocationTargetException; - -import sun.net.sdp.SdpSupport; - -/** - * This class consists exclusively of static methods that Sockets or Channels to - * sockets that support the InfiniBand Sockets Direct Protocol (SDP). - */ - -public final class Sdp { - private Sdp() { } - - /** - * The package-privage ServerSocket(SocketImpl) constructor - */ - private static final Constructor serverSocketCtor; - static { - try { - serverSocketCtor = - ServerSocket.class.getDeclaredConstructor(SocketImpl.class); - setAccessible(serverSocketCtor); - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } - } - - /** - * The package-private SdpSocketImpl() constructor - */ - private static final Constructor socketImplCtor; - static { - try { - Class cl = Class.forName("java.net.SdpSocketImpl", true, null); - socketImplCtor = (Constructor)cl.getDeclaredConstructor(); - setAccessible(socketImplCtor); - } catch (ClassNotFoundException e) { - throw new AssertionError(e); - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } - } - - private static void setAccessible(final AccessibleObject o) { - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - o.setAccessible(true); - return null; - } - }); - } - - /** - * SDP enabled Socket. - */ - private static class SdpSocket extends Socket { - SdpSocket(SocketImpl impl) throws SocketException { - super(impl); - } - } - - /** - * Creates a SDP enabled SocketImpl - */ - private static SocketImpl createSocketImpl() { - try { - return socketImplCtor.newInstance(); - } catch (InstantiationException x) { - throw new AssertionError(x); - } catch (IllegalAccessException x) { - throw new AssertionError(x); - } catch (InvocationTargetException x) { - throw new AssertionError(x); - } - } - - /** - * Creates an unconnected and unbound SDP socket. The {@code Socket} is - * associated with a {@link java.net.SocketImpl} of the system-default type. - * - * @return a new Socket - * - * @throws UnsupportedOperationException - * If SDP is not supported - * @throws IOException - * If an I/O error occurs - */ - public static Socket openSocket() throws IOException { - SocketImpl impl = createSocketImpl(); - return new SdpSocket(impl); - } - - /** - * Creates an unbound SDP server socket. The {@code ServerSocket} is - * associated with a {@link java.net.SocketImpl} of the system-default type. - * - * @return a new ServerSocket - * - * @throws UnsupportedOperationException - * If SDP is not supported - * @throws IOException - * If an I/O error occurs - */ - public static ServerSocket openServerSocket() throws IOException { - // create ServerSocket via package-private constructor - SocketImpl impl = createSocketImpl(); - try { - return serverSocketCtor.newInstance(impl); - } catch (IllegalAccessException x) { - throw new AssertionError(x); - } catch (InstantiationException x) { - throw new AssertionError(x); - } catch (InvocationTargetException x) { - Throwable cause = x.getCause(); - if (cause instanceof IOException) - throw (IOException)cause; - if (cause instanceof RuntimeException) - throw (RuntimeException)cause; - throw new RuntimeException(x); - } - } - - /** - * Opens a socket channel to a SDP socket. - * - *

The channel will be associated with the system-wide default - * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}. - * - * @return a new SocketChannel - * - * @throws UnsupportedOperationException - * If SDP is not supported or not supported by the default selector - * provider - * @throws IOException - * If an I/O error occurs. - */ - public static SocketChannel openSocketChannel() throws IOException { - FileDescriptor fd = SdpSupport.createSocket(); - return sun.nio.ch.Secrets.newSocketChannel(fd); - } - - /** - * Opens a socket channel to a SDP socket. - * - *

The channel will be associated with the system-wide default - * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}. - * - * @return a new ServerSocketChannel - * - * @throws UnsupportedOperationException - * If SDP is not supported or not supported by the default selector - * provider - * @throws IOException - * If an I/O error occurs - */ - public static ServerSocketChannel openServerSocketChannel() - throws IOException - { - FileDescriptor fd = SdpSupport.createSocket(); - return sun.nio.ch.Secrets.newServerSocketChannel(fd); - } -} diff --git a/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java b/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java index 6902d4b8b31..d1d8cf3ef23 100644 --- a/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java @@ -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 @@ -39,6 +39,8 @@ import javax.crypto.spec.OAEPParameterSpec; import sun.security.rsa.*; import sun.security.jca.Providers; +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; +import sun.security.util.KeyUtil; /** * RSA cipher implementation. Supports RSA en/decryption and signing/verifying @@ -91,8 +93,8 @@ public final class RSACipher extends CipherSpi { // padding object private RSAPadding padding; - // cipher parameter for OAEP padding - private OAEPParameterSpec spec = null; + // cipher parameter for OAEP padding and TLS RSA premaster secret + private AlgorithmParameterSpec spec = null; // buffer for the data private byte[] buffer; @@ -110,6 +112,9 @@ public final class RSACipher extends CipherSpi { // hash algorithm for OAEP private String oaepHashAlgorithm = "SHA-1"; + // the source of randomness + private SecureRandom random; + public RSACipher() { paddingType = PAD_PKCS1; } @@ -175,7 +180,7 @@ public final class RSACipher extends CipherSpi { // see JCE spec protected AlgorithmParameters engineGetParameters() { - if (spec != null) { + if (spec != null && spec instanceof OAEPParameterSpec) { try { AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP", @@ -276,8 +281,13 @@ public final class RSACipher extends CipherSpi { buffer = new byte[n]; } else if (paddingType == PAD_PKCS1) { if (params != null) { - throw new InvalidAlgorithmParameterException - ("Parameters not supported"); + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); + } + + spec = params; + this.random = random; // for TLS RSA premaster secret } int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 : RSAPadding.PAD_BLOCKTYPE_1; @@ -293,19 +303,18 @@ public final class RSACipher extends CipherSpi { throw new InvalidKeyException ("OAEP cannot be used to sign or verify signatures"); } - OAEPParameterSpec myParams; if (params != null) { if (!(params instanceof OAEPParameterSpec)) { throw new InvalidAlgorithmParameterException ("Wrong Parameters for OAEP Padding"); } - myParams = (OAEPParameterSpec) params; + spec = params; } else { - myParams = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1", + spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); } padding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, n, - random, myParams); + random, (OAEPParameterSpec)spec); if (encrypt) { int k = padding.getMaxDataSize(); buffer = new byte[k]; @@ -420,17 +429,40 @@ public final class RSACipher extends CipherSpi { if (wrappedKey.length > buffer.length) { throw new InvalidKeyException("Key is too long for unwrapping"); } + + boolean isTlsRsaPremasterSecret = + algorithm.equals("TlsRsaPremasterSecret"); + Exception failover = null; + byte[] encoded = null; + update(wrappedKey, 0, wrappedKey.length); try { - byte[] encoded = doFinal(); - return ConstructKeys.constructKey(encoded, algorithm, type); + encoded = doFinal(); } catch (BadPaddingException e) { - // should not occur - throw new InvalidKeyException("Unwrapping failed", e); + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("Unwrapping failed", e); + } } catch (IllegalBlockSizeException e) { // should not occur, handled with length check above throw new InvalidKeyException("Unwrapping failed", e); } + + if (isTlsRsaPremasterSecret) { + if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + encoded = KeyUtil.checkTlsPreMasterSecretKey( + ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(), + ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(), + random, encoded, (failover != null)); + } + + return ConstructKeys.constructKey(encoded, algorithm, type); } // see JCE spec @@ -438,5 +470,4 @@ public final class RSACipher extends CipherSpi { RSAKey rsaKey = RSAKeyFactory.toRSAKey(key); return rsaKey.getModulus().bitLength(); } - } diff --git a/jdk/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java b/jdk/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java index ef9098f24f7..2a25cb64d5c 100644 --- a/jdk/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java +++ b/jdk/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.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 @@ -56,7 +56,7 @@ public final class TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi { protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof TlsRsaPremasterSecretParameterSpec == false) { + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { throw new InvalidAlgorithmParameterException(MSG); } this.spec = (TlsRsaPremasterSecretParameterSpec)params; @@ -67,21 +67,20 @@ public final class TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi { throw new InvalidParameterException(MSG); } + // Only can be used in client side to generate TLS RSA premaster secret. protected SecretKey engineGenerateKey() { if (spec == null) { throw new IllegalStateException( "TlsRsaPremasterSecretGenerator must be initialized"); } - byte[] b = spec.getEncodedSecret(); - if (b == null) { - if (random == null) { - random = new SecureRandom(); - } - b = new byte[48]; - random.nextBytes(b); - b[0] = (byte)spec.getMajorVersion(); - b[1] = (byte)spec.getMinorVersion(); + + if (random == null) { + random = new SecureRandom(); } + byte[] b = new byte[48]; + random.nextBytes(b); + b[0] = (byte)spec.getMajorVersion(); + b[1] = (byte)spec.getMinorVersion(); return new SecretKeySpec(b, "TlsRsaPremasterSecret"); } diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java index d7acd36ae08..47b95927307 100644 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java @@ -1220,7 +1220,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throw new RuntimeOperationsException(new IllegalArgumentException(listener.getCanonicalName()), "The MBean " + listener.getCanonicalName() + - "does not implement the NotificationListener interface") ; + " does not implement the NotificationListener interface") ; } // ---------------- diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/LdapAttribute.java b/jdk/src/share/classes/com/sun/jndi/ldap/LdapAttribute.java index 7bb77cd52c6..50f6ac69f5f 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/LdapAttribute.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/LdapAttribute.java @@ -188,7 +188,7 @@ final class LdapAttribute extends BasicAttribute { if(syntaxAttr == null || syntaxAttr.size() == 0) { throw new NameNotFoundException( - getID() + "does not have a syntax associated with it"); + getID() + " does not have a syntax associated with it"); } String syntaxName = (String)syntaxAttr.get(); diff --git a/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/implementations/ResolverDirectHTTP.java b/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/implementations/ResolverDirectHTTP.java index a3359bdc675..137a5d4ae25 100644 --- a/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/implementations/ResolverDirectHTTP.java +++ b/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/implementations/ResolverDirectHTTP.java @@ -108,6 +108,7 @@ public class ResolverDirectHTTP extends ResourceResolverSpi { @Override public XMLSignatureInput engineResolveURI(ResourceResolverContext context) throws ResourceResolverException { + InputStream inputStream = null; try { // calculate new URI @@ -139,7 +140,7 @@ public class ResolverDirectHTTP extends ResourceResolverSpi { } String mimeType = urlConnection.getHeaderField("Content-Type"); - InputStream inputStream = urlConnection.getInputStream(); + inputStream = urlConnection.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte buf[] = new byte[4096]; int read = 0; @@ -168,6 +169,16 @@ public class ResolverDirectHTTP extends ResourceResolverSpi { throw new ResourceResolverException("generic.EmptyMessage", ex, context.attr, context.baseUri); } catch (IllegalArgumentException e) { throw new ResourceResolverException("generic.EmptyMessage", e, context.attr, context.baseUri); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, e.getMessage(), e); + } + } + } } } diff --git a/jdk/src/share/classes/java/lang/Math.java b/jdk/src/share/classes/java/lang/Math.java index 98e901ac942..4114076ed2d 100644 --- a/jdk/src/share/classes/java/lang/Math.java +++ b/jdk/src/share/classes/java/lang/Math.java @@ -765,8 +765,19 @@ public final class Math { * pseudorandom numbers at a great rate, it may reduce contention * for each thread to have its own pseudorandom-number generator. * + * @apiNote + * As the largest {@code double} value less than {@code 1.0} + * is {@code Math.nextDown(1.0)}, a value {@code x} in the closed range + * {@code [x1,x2]} where {@code x1<=x2} may be defined by the statements + * + *

{@code
+     * double f = Math.random()/Math.nextDown(1.0);
+     * double x = x1*(1.0 - f) + x2*f;
+     * }
+ * * @return a pseudorandom {@code double} greater than or equal * to {@code 0.0} and less than {@code 1.0}. + * @see #nextDown(double) * @see Random#nextDouble() */ public static double random() { diff --git a/jdk/src/share/classes/java/net/DatagramSocket.java b/jdk/src/share/classes/java/net/DatagramSocket.java index 31344b4391c..99565bb7aea 100644 --- a/jdk/src/share/classes/java/net/DatagramSocket.java +++ b/jdk/src/share/classes/java/net/DatagramSocket.java @@ -29,6 +29,8 @@ import java.io.IOException; import java.nio.channels.DatagramChannel; import java.security.AccessController; import java.security.PrivilegedExceptionAction; +import java.util.Set; +import java.util.Collections; /** * This class represents a socket for sending and receiving datagram packets. @@ -315,6 +317,7 @@ class DatagramSocket implements java.io.Closeable { } // creates a udp socket impl.create(); + impl.setDatagramSocket(this); created = true; } @@ -1258,4 +1261,94 @@ class DatagramSocket implements java.io.Closeable { } factory = fac; } + + /** + * Sets the value of a socket option. + * + * @param name The socket option + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * + * @return this DatagramSocket + * + * @throws UnsupportedOperationException if the datagram socket + * does not support the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @throws NullPointerException if name is {@code null} + * + * @since 1.9 + */ + public DatagramSocket setOption(SocketOption name, T value) + throws IOException + { + getImpl().setOption(name, value); + return this; + } + + /** + * Returns the value of a socket option. + * + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the datagram socket + * does not support the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + public T getOption(SocketOption name) throws IOException { + return getImpl().getOption(name); + } + + private static Set> options; + private static boolean optionsSet = false; + + /** + * Returns a set of the socket options supported by this socket. + * + * This method will continue to return the set of options even after + * the socket has been closed. + * + * @return A set of the socket options supported by this socket. This set + * may be empty if the socket's DatagramSocketImpl cannot be created. + * + * @since 1.9 + */ + public Set> supportedOptions() { + synchronized(DatagramSocket.class) { + if (optionsSet) { + return options; + } + try { + DatagramSocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (IOException e) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } } diff --git a/jdk/src/share/classes/java/net/DatagramSocketImpl.java b/jdk/src/share/classes/java/net/DatagramSocketImpl.java index 524f06b83ca..07b2724a2c7 100644 --- a/jdk/src/share/classes/java/net/DatagramSocketImpl.java +++ b/jdk/src/share/classes/java/net/DatagramSocketImpl.java @@ -28,6 +28,8 @@ package java.net; import java.io.FileDescriptor; import java.io.IOException; import java.io.InterruptedIOException; +import java.util.Set; +import java.util.HashSet; /** * Abstract datagram and multicast socket implementation base class. @@ -47,6 +49,20 @@ public abstract class DatagramSocketImpl implements SocketOptions { */ protected FileDescriptor fd; + /** + * The DatagramSocket or MulticastSocket + * that owns this impl + */ + DatagramSocket socket; + + void setDatagramSocket(DatagramSocket socket) { + this.socket = socket; + } + + DatagramSocket getDatagramSocket() { + return socket; + } + /** * Creates a datagram socket. * @exception SocketException if there is an error in the @@ -241,4 +257,116 @@ public abstract class DatagramSocketImpl implements SocketOptions { protected FileDescriptor getFileDescriptor() { return fd; } + + /** + * Called to set a socket option. + * + * @param name The socket option + * + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * + * @throws UnsupportedOperationException if the DatagramSocketImpl does not + * support the option + * + * @throws NullPointerException if name is {@code null} + * + * @since 1.9 + */ + protected void setOption(SocketOption name, T value) throws IOException { + if (name == StandardSocketOptions.SO_SNDBUF) { + setOption(SocketOptions.SO_SNDBUF, value); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + setOption(SocketOptions.SO_RCVBUF, value); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.IP_TOS) { + setOption(SocketOptions.IP_TOS, value); + } else if (name == StandardSocketOptions.IP_MULTICAST_IF && + (getDatagramSocket() instanceof MulticastSocket)) { + setOption(SocketOptions.IP_MULTICAST_IF2, value); + } else if (name == StandardSocketOptions.IP_MULTICAST_TTL && + (getDatagramSocket() instanceof MulticastSocket)) { + if (! (value instanceof Integer)) { + throw new IllegalArgumentException("not an integer"); + } + setTimeToLive((Integer)value); + } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP && + (getDatagramSocket() instanceof MulticastSocket)) { + setOption(SocketOptions.IP_MULTICAST_LOOP, value); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } + + /** + * Called to get a socket option. + * + * @param name The socket option + * + * @throws UnsupportedOperationException if the DatagramSocketImpl does not + * support the option + * + * @throws NullPointerException if name is {@code null} + * + * @since 1.9 + */ + protected T getOption(SocketOption name) throws IOException { + if (name == StandardSocketOptions.SO_SNDBUF) { + return (T) getOption(SocketOptions.SO_SNDBUF); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + return (T) getOption(SocketOptions.SO_RCVBUF); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + return (T) getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.IP_TOS) { + return (T) getOption(SocketOptions.IP_TOS); + } else if (name == StandardSocketOptions.IP_MULTICAST_IF && + (getDatagramSocket() instanceof MulticastSocket)) { + return (T) getOption(SocketOptions.IP_MULTICAST_IF2); + } else if (name == StandardSocketOptions.IP_MULTICAST_TTL && + (getDatagramSocket() instanceof MulticastSocket)) { + Integer ttl = getTimeToLive(); + return (T)ttl; + } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP && + (getDatagramSocket() instanceof MulticastSocket)) { + return (T) getOption(SocketOptions.IP_MULTICAST_LOOP); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } + + private static final Set> dgSocketOptions = + new HashSet<>(); + + private static final Set> mcSocketOptions = + new HashSet<>(); + + static { + dgSocketOptions.add(StandardSocketOptions.SO_SNDBUF); + dgSocketOptions.add(StandardSocketOptions.SO_RCVBUF); + dgSocketOptions.add(StandardSocketOptions.SO_REUSEADDR); + dgSocketOptions.add(StandardSocketOptions.IP_TOS); + + mcSocketOptions.add(StandardSocketOptions.SO_SNDBUF); + mcSocketOptions.add(StandardSocketOptions.SO_RCVBUF); + mcSocketOptions.add(StandardSocketOptions.SO_REUSEADDR); + mcSocketOptions.add(StandardSocketOptions.IP_TOS); + mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_IF); + mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_TTL); + mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_LOOP); + }; + + /** + * Returns a set of SocketOptions supported by this impl + * and by this impl's socket (DatagramSocket or MulticastSocket) + * + * @return a Set of SocketOptions + */ + protected Set> supportedOptions() { + if (getDatagramSocket() instanceof MulticastSocket) { + return mcSocketOptions; + } else { + return dgSocketOptions; + } + } } diff --git a/jdk/src/share/classes/java/net/ServerSocket.java b/jdk/src/share/classes/java/net/ServerSocket.java index e94790dd620..e60719eeb5a 100644 --- a/jdk/src/share/classes/java/net/ServerSocket.java +++ b/jdk/src/share/classes/java/net/ServerSocket.java @@ -30,6 +30,8 @@ import java.io.IOException; import java.nio.channels.ServerSocketChannel; import java.security.AccessController; import java.security.PrivilegedExceptionAction; +import java.util.Set; +import java.util.Collections; /** * This class implements server sockets. A server socket waits for @@ -919,4 +921,92 @@ class ServerSocket implements java.io.Closeable { /* Not implemented yet */ } + /** + * Sets the value of a socket option. + * + * @param name The socket option + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * @return this ServerSocket + * + * @throws UnsupportedOperationException if the server socket does not + * support the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + public ServerSocket setOption(SocketOption name, T value) + throws IOException + { + getImpl().setOption(name, value); + return this; + } + + /** + * Returns the value of a socket option. + * + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the server socket does not + * support the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + public T getOption(SocketOption name) throws IOException { + return getImpl().getOption(name); + } + + private static Set> options; + private static boolean optionsSet = false; + + /** + * Returns a set of the socket options supported by this server socket. + * + * This method will continue to return the set of options even after + * the socket has been closed. + * + * @return A set of the socket options supported by this socket. This set + * may be empty if the socket's SocketImpl cannot be created. + * + * @since 1.9 + */ + public Set> supportedOptions() { + synchronized (ServerSocket.class) { + if (optionsSet) { + return options; + } + try { + SocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (IOException e) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } } diff --git a/jdk/src/share/classes/java/net/Socket.java b/jdk/src/share/classes/java/net/Socket.java index b6df988d14b..d4b7656ce5e 100644 --- a/jdk/src/share/classes/java/net/Socket.java +++ b/jdk/src/share/classes/java/net/Socket.java @@ -32,6 +32,8 @@ import java.nio.channels.SocketChannel; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedAction; +import java.util.Set; +import java.util.Collections; /** * This class implements client sockets (also called just @@ -1720,4 +1722,93 @@ class Socket implements java.io.Closeable { { /* Not implemented yet */ } + + + /** + * Sets the value of a socket option. + * + * @param name The socket option + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * @return this Socket + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + public Socket setOption(SocketOption name, T value) throws IOException { + getImpl().setOption(name, value); + return this; + } + + /** + * Returns the value of a socket option. + * + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + @SuppressWarnings("unchecked") + public T getOption(SocketOption name) throws IOException { + return getImpl().getOption(name); + } + + private static Set> options; + private static boolean optionsSet = false; + + /** + * Returns a set of the socket options supported by this socket. + * + * This method will continue to return the set of options even after + * the socket has been closed. + * + * @return A set of the socket options supported by this socket. This set + * may be empty if the socket's SocketImpl cannot be created. + * + * @since 1.9 + */ + public Set> supportedOptions() { + synchronized (Socket.class) { + if (optionsSet) { + return options; + } + try { + SocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (IOException e) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } } diff --git a/jdk/src/share/classes/java/net/SocketImpl.java b/jdk/src/share/classes/java/net/SocketImpl.java index 67286a1cd60..4aadf09182d 100644 --- a/jdk/src/share/classes/java/net/SocketImpl.java +++ b/jdk/src/share/classes/java/net/SocketImpl.java @@ -29,6 +29,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.FileDescriptor; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; /** * The abstract class {@code SocketImpl} is a common superclass @@ -355,4 +358,106 @@ public abstract class SocketImpl implements SocketOptions { { /* Not implemented yet */ } + + /** + * Called to set a socket option. + * + * @param name The socket option + * + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * + * @throws UnsupportedOperationException if the SocketImpl does not + * support the option + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @since 1.9 + */ + protected void setOption(SocketOption name, T value) throws IOException { + if (name == StandardSocketOptions.SO_KEEPALIVE) { + setOption(SocketOptions.SO_KEEPALIVE, value); + } else if (name == StandardSocketOptions.SO_SNDBUF) { + setOption(SocketOptions.SO_SNDBUF, value); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + setOption(SocketOptions.SO_RCVBUF, value); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.SO_LINGER) { + setOption(SocketOptions.SO_LINGER, value); + } else if (name == StandardSocketOptions.IP_TOS) { + setOption(SocketOptions.IP_TOS, value); + } else if (name == StandardSocketOptions.TCP_NODELAY) { + setOption(SocketOptions.TCP_NODELAY, value); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } + + /** + * Called to get a socket option. + * + * @param name The socket option + * + * @return the value of the named option + * + * @throws UnsupportedOperationException if the SocketImpl does not + * support the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @since 1.9 + */ + protected T getOption(SocketOption name) throws IOException { + if (name == StandardSocketOptions.SO_KEEPALIVE) { + return (T)getOption(SocketOptions.SO_KEEPALIVE); + } else if (name == StandardSocketOptions.SO_SNDBUF) { + return (T)getOption(SocketOptions.SO_SNDBUF); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + return (T)getOption(SocketOptions.SO_RCVBUF); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + return (T)getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.SO_LINGER) { + return (T)getOption(SocketOptions.SO_LINGER); + } else if (name == StandardSocketOptions.IP_TOS) { + return (T)getOption(SocketOptions.IP_TOS); + } else if (name == StandardSocketOptions.TCP_NODELAY) { + return (T)getOption(SocketOptions.TCP_NODELAY); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } + + private static final Set> socketOptions = + new HashSet<>(); + + private static final Set> serverSocketOptions = + new HashSet<>(); + + static { + socketOptions.add(StandardSocketOptions.SO_KEEPALIVE); + socketOptions.add(StandardSocketOptions.SO_SNDBUF); + socketOptions.add(StandardSocketOptions.SO_RCVBUF); + socketOptions.add(StandardSocketOptions.SO_REUSEADDR); + socketOptions.add(StandardSocketOptions.SO_LINGER); + socketOptions.add(StandardSocketOptions.IP_TOS); + socketOptions.add(StandardSocketOptions.TCP_NODELAY); + + serverSocketOptions.add(StandardSocketOptions.SO_RCVBUF); + serverSocketOptions.add(StandardSocketOptions.SO_REUSEADDR); + }; + + /** + * Returns a set of SocketOptions supported by this impl + * and by this impl's socket (Socket or ServerSocket) + * + * @return a Set of SocketOptions + */ + protected Set> supportedOptions() { + if (getSocket() != null) { + return socketOptions; + } else { + return serverSocketOptions; + } + } } diff --git a/jdk/src/share/classes/java/net/URI.java b/jdk/src/share/classes/java/net/URI.java index 813de5cf453..0a05793b9a9 100644 --- a/jdk/src/share/classes/java/net/URI.java +++ b/jdk/src/share/classes/java/net/URI.java @@ -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 @@ -1337,7 +1337,7 @@ public final class URI */ public String getQuery() { if ((decodedQuery == null) && (query != null)) - decodedQuery = decode(query); + decodedQuery = decode(query, false); return decodedQuery; } @@ -1366,7 +1366,7 @@ public final class URI */ public String getFragment() { if ((decodedFragment == null) && (fragment != null)) - decodedFragment = decode(fragment); + decodedFragment = decode(fragment, false); return decodedFragment; } @@ -2764,6 +2764,12 @@ public final class URI // with a scope_id // private static String decode(String s) { + return decode(s, true); + } + + // This method was introduced as a generalization of URI.decode method + // to provide a fix for JDK-8037396 + private static String decode(String s, boolean ignorePercentInBrackets) { if (s == null) return s; int n = s.length(); @@ -2776,8 +2782,8 @@ public final class URI ByteBuffer bb = ByteBuffer.allocate(n); CharBuffer cb = CharBuffer.allocate(n); CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8") - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); // This is not horribly efficient, but it will do for now char c = s.charAt(0); @@ -2790,7 +2796,7 @@ public final class URI } else if (betweenBrackets && c == ']') { betweenBrackets = false; } - if (c != '%' || betweenBrackets) { + if (c != '%' || (betweenBrackets && ignorePercentInBrackets)) { sb.append(c); if (++i >= n) break; diff --git a/jdk/src/share/classes/java/security/Provider.java b/jdk/src/share/classes/java/security/Provider.java index e8c7a081b5a..05f670c29bd 100644 --- a/jdk/src/share/classes/java/security/Provider.java +++ b/jdk/src/share/classes/java/security/Provider.java @@ -1332,7 +1332,7 @@ public abstract class Provider extends Properties { addEngine("SSLContext", false, null); addEngine("TrustManagerFactory", false, null); // JGSS - addEngine("GssApiMechanism", false, null); + addEngine("GssApiMechanism", true, "sun.security.jgss.GSSCaller"); // SASL addEngine("SaslClientFactory", false, null); addEngine("SaslServerFactory", false, null); diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java index e92f3e9a122..3e1a2bdd2c9 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeFormatter.java +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java @@ -1644,12 +1644,13 @@ public final class DateTimeFormatter { * @return a formatter based on this formatter with the requested resolver style, not null */ public DateTimeFormatter withResolverFields(TemporalField... resolverFields) { - Objects.requireNonNull(resolverFields, "resolverFields"); - Set fields = new HashSet<>(Arrays.asList(resolverFields)); + Set fields = null; + if (resolverFields != null) { + fields = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(resolverFields))); + } if (Objects.equals(this.resolverFields, fields)) { return this; } - fields = Collections.unmodifiableSet(fields); return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, fields, chrono, zone); } @@ -1693,11 +1694,12 @@ public final class DateTimeFormatter { * @return a formatter based on this formatter with the requested resolver style, not null */ public DateTimeFormatter withResolverFields(Set resolverFields) { - Objects.requireNonNull(resolverFields, "resolverFields"); if (Objects.equals(this.resolverFields, resolverFields)) { return this; } - resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields)); + if (resolverFields != null) { + resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields)); + } return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone); } diff --git a/jdk/src/share/classes/java/util/AbstractMap.java b/jdk/src/share/classes/java/util/AbstractMap.java index a68a77b9870..143f228f904 100644 --- a/jdk/src/share/classes/java/util/AbstractMap.java +++ b/jdk/src/share/classes/java/util/AbstractMap.java @@ -305,8 +305,8 @@ public abstract class AbstractMap implements Map { * appropriate view the first time this view is requested. The views are * stateless, so there's no reason to create more than one of each. */ - transient volatile Set keySet = null; - transient volatile Collection values = null; + transient volatile Set keySet; + transient volatile Collection values; /** * {@inheritDoc} diff --git a/jdk/src/share/classes/java/util/Collections.java b/jdk/src/share/classes/java/util/Collections.java index c172c95f49b..e229f5f5dd4 100644 --- a/jdk/src/share/classes/java/util/Collections.java +++ b/jdk/src/share/classes/java/util/Collections.java @@ -1466,9 +1466,9 @@ public class Collections { throw new UnsupportedOperationException(); } - private transient Set keySet = null; - private transient Set> entrySet = null; - private transient Collection values = null; + private transient Set keySet; + private transient Set> entrySet; + private transient Collection values; public Set keySet() { if (keySet==null) @@ -2597,9 +2597,9 @@ public class Collections { synchronized (mutex) {m.clear();} } - private transient Set keySet = null; - private transient Set> entrySet = null; - private transient Collection values = null; + private transient Set keySet; + private transient Set> entrySet; + private transient Collection values; public Set keySet() { synchronized (mutex) { @@ -3082,7 +3082,7 @@ public class Collections { return c.add(e); } - private E[] zeroLengthElementArray = null; // Lazily initialized + private E[] zeroLengthElementArray; // Lazily initialized private E[] zeroLengthElementArray() { return zeroLengthElementArray != null ? zeroLengthElementArray : @@ -3643,7 +3643,7 @@ public class Collections { m.put(e.getKey(), e.getValue()); } - private transient Set> entrySet = null; + private transient Set> entrySet; public Set> entrySet() { if (entrySet==null) @@ -4877,9 +4877,9 @@ public class Collections { public boolean containsValue(Object value) {return eq(value, v);} public V get(Object key) {return (eq(key, k) ? v : null);} - private transient Set keySet = null; - private transient Set> entrySet = null; - private transient Collection values = null; + private transient Set keySet; + private transient Set> entrySet; + private transient Collection values; public Set keySet() { if (keySet==null) diff --git a/jdk/src/share/classes/java/util/EnumMap.java b/jdk/src/share/classes/java/util/EnumMap.java index 21be62d8d0b..7357ee381f3 100644 --- a/jdk/src/share/classes/java/util/EnumMap.java +++ b/jdk/src/share/classes/java/util/EnumMap.java @@ -367,7 +367,7 @@ public class EnumMap, V> extends AbstractMap * view the first time this view is requested. The view is stateless, * so there's no reason to create more than one. */ - private transient Set> entrySet = null; + private transient Set> entrySet; /** * Returns a {@link Set} view of the keys contained in this map. @@ -562,7 +562,7 @@ public class EnumMap, V> extends AbstractMap } private class EntryIterator extends EnumMapIterator> { - private Entry lastReturnedEntry = null; + private Entry lastReturnedEntry; public Map.Entry next() { if (!hasNext()) diff --git a/jdk/src/share/classes/java/util/Hashtable.java b/jdk/src/share/classes/java/util/Hashtable.java index ce706130070..4a89bd5816d 100644 --- a/jdk/src/share/classes/java/util/Hashtable.java +++ b/jdk/src/share/classes/java/util/Hashtable.java @@ -617,9 +617,9 @@ public class Hashtable * appropriate view the first time this view is requested. The views are * stateless, so there's no reason to create more than one of each. */ - private transient volatile Set keySet = null; - private transient volatile Set> entrySet = null; - private transient volatile Collection values = null; + private transient volatile Set keySet; + private transient volatile Set> entrySet; + private transient volatile Collection values; /** * Returns a {@link Set} view of the keys contained in this map. @@ -1300,8 +1300,8 @@ public class Hashtable private class Enumerator implements Enumeration, Iterator { Entry[] table = Hashtable.this.table; int index = table.length; - Entry entry = null; - Entry lastReturned = null; + Entry entry; + Entry lastReturned; int type; /** diff --git a/jdk/src/share/classes/java/util/IdentityHashMap.java b/jdk/src/share/classes/java/util/IdentityHashMap.java index 2b4f19d09b2..f96055bc6c1 100644 --- a/jdk/src/share/classes/java/util/IdentityHashMap.java +++ b/jdk/src/share/classes/java/util/IdentityHashMap.java @@ -842,7 +842,7 @@ public class IdentityHashMap private class EntryIterator extends IdentityHashMapIterator> { - private Entry lastReturnedEntry = null; + private Entry lastReturnedEntry; public Map.Entry next() { lastReturnedEntry = new Entry(nextIndex()); @@ -928,7 +928,7 @@ public class IdentityHashMap * view the first time this view is requested. The view is stateless, * so there's no reason to create more than one. */ - private transient Set> entrySet = null; + private transient Set> entrySet; /** * Returns an identity-based set view of the keys contained in this map. diff --git a/jdk/src/share/classes/java/util/LinkedList.java b/jdk/src/share/classes/java/util/LinkedList.java index 43ab9dfca2e..18a8b21ba80 100644 --- a/jdk/src/share/classes/java/util/LinkedList.java +++ b/jdk/src/share/classes/java/util/LinkedList.java @@ -869,7 +869,7 @@ public class LinkedList } private class ListItr implements ListIterator { - private Node lastReturned = null; + private Node lastReturned; private Node next; private int nextIndex; private int expectedModCount = modCount; diff --git a/jdk/src/share/classes/java/util/Map.java b/jdk/src/share/classes/java/util/Map.java index de8bbce01a2..19840b268fe 100644 --- a/jdk/src/share/classes/java/util/Map.java +++ b/jdk/src/share/classes/java/util/Map.java @@ -157,10 +157,10 @@ public interface Map { * key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) */ boolean containsKey(Object key); @@ -177,10 +177,10 @@ public interface Map { * specified value * @throws ClassCastException if the value is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified value is null and this * map does not permit null values - * (optional) + * (optional) */ boolean containsValue(Object value); @@ -204,10 +204,10 @@ public interface Map { * {@code null} if this map contains no mapping for the key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) */ V get(Object key); @@ -264,10 +264,10 @@ public interface Map { * is not supported by this map * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this * map does not permit null keys - * (optional) + * (optional) */ V remove(Object key); @@ -577,10 +577,10 @@ public interface Map { * {@code defaultValue} if this map contains no mapping for the key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) * @since 1.8 */ default V getOrDefault(Object key, V defaultValue) { @@ -659,13 +659,13 @@ public interface Map { * values * @throws ClassCastException if a replacement value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if function or a replacement value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of a replacement value * prevents it from being stored in this map - * (optional) + * (optional) * @throws ConcurrentModificationException if an entry is found to be * removed during iteration * @since 1.8 @@ -726,16 +726,16 @@ public interface Map { * if the implementation supports null values.) * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the key or value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V putIfAbsent(K key, V value) { @@ -772,13 +772,13 @@ public interface Map { * @return {@code true} if the value was removed * @throws UnsupportedOperationException if the {@code remove} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the key or value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @since 1.8 */ default boolean remove(Object key, Object value) { @@ -821,14 +821,14 @@ public interface Map { * @return {@code true} if the value was replaced * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of a specified key or value * prevents it from being stored in this map * @throws NullPointerException if a specified key or newValue is null, * and this map does not permit null keys or values * @throws NullPointerException if oldValue is null and this map does not * permit null values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of a specified key * or value prevents it from being stored in this map * @since 1.8 @@ -871,10 +871,10 @@ public interface Map { * if the implementation supports null values.) * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values * @throws IllegalArgumentException if some property of the specified key @@ -942,10 +942,10 @@ public interface Map { * is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V computeIfAbsent(K key, @@ -1003,10 +1003,10 @@ public interface Map { * remappingFunction is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V computeIfPresent(K key, @@ -1079,10 +1079,10 @@ public interface Map { * remappingFunction is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V compute(K key, @@ -1157,10 +1157,10 @@ public interface Map { * value is associated with the key * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not support null keys or the value or remappingFunction is * null diff --git a/jdk/src/share/classes/java/util/TreeMap.java b/jdk/src/share/classes/java/util/TreeMap.java index fda3e2a8e42..c04053656cf 100644 --- a/jdk/src/share/classes/java/util/TreeMap.java +++ b/jdk/src/share/classes/java/util/TreeMap.java @@ -120,7 +120,7 @@ public class TreeMap */ private final Comparator comparator; - private transient Entry root = null; + private transient Entry root; /** * The number of entries in the tree @@ -781,9 +781,9 @@ public class TreeMap * the first time this view is requested. Views are stateless, so * there's no reason to create more than one. */ - private transient EntrySet entrySet = null; - private transient KeySet navigableKeySet = null; - private transient NavigableMap descendingMap = null; + private transient EntrySet entrySet; + private transient KeySet navigableKeySet; + private transient NavigableMap descendingMap; /** * Returns a {@link Set} view of the keys contained in this map. @@ -1583,9 +1583,9 @@ public class TreeMap } // Views - transient NavigableMap descendingMapView = null; - transient EntrySetView entrySetView = null; - transient KeySet navigableKeySetView = null; + transient NavigableMap descendingMapView; + transient EntrySetView entrySetView; + transient KeySet navigableKeySetView; public final NavigableSet navigableKeySet() { KeySet nksv = navigableKeySetView; @@ -2046,8 +2046,8 @@ public class TreeMap static final class Entry implements Map.Entry { K key; V value; - Entry left = null; - Entry right = null; + Entry left; + Entry right; Entry parent; boolean color = BLACK; diff --git a/jdk/src/share/classes/java/util/WeakHashMap.java b/jdk/src/share/classes/java/util/WeakHashMap.java index 270c2d9c2bd..4dd8e99053d 100644 --- a/jdk/src/share/classes/java/util/WeakHashMap.java +++ b/jdk/src/share/classes/java/util/WeakHashMap.java @@ -759,21 +759,21 @@ public class WeakHashMap private abstract class HashIterator implements Iterator { private int index; - private Entry entry = null; - private Entry lastReturned = null; + private Entry entry; + private Entry lastReturned; private int expectedModCount = modCount; /** * Strong reference needed to avoid disappearance of key * between hasNext and next */ - private Object nextKey = null; + private Object nextKey; /** * Strong reference needed to avoid disappearance of key * between nextEntry() and any use of the entry */ - private Object currentKey = null; + private Object currentKey; HashIterator() { index = isEmpty() ? 0 : table.length; @@ -848,7 +848,7 @@ public class WeakHashMap // Views - private transient Set> entrySet = null; + private transient Set> entrySet; /** * Returns a {@link Set} view of the keys contained in this map. diff --git a/jdk/src/share/classes/java/util/logging/Logging.java b/jdk/src/share/classes/java/util/logging/Logging.java index 740a533063d..88624fc83e2 100644 --- a/jdk/src/share/classes/java/util/logging/Logging.java +++ b/jdk/src/share/classes/java/util/logging/Logging.java @@ -87,7 +87,7 @@ class Logging implements LoggingMXBean { Logger logger = logManager.getLogger(loggerName); if (logger == null) { throw new IllegalArgumentException("Logger " + loggerName + - "does not exist"); + " does not exist"); } Level level = null; diff --git a/jdk/src/share/classes/java/util/regex/Matcher.java b/jdk/src/share/classes/java/util/regex/Matcher.java index ebab02e3b82..e841294ed8e 100644 --- a/jdk/src/share/classes/java/util/regex/Matcher.java +++ b/jdk/src/share/classes/java/util/regex/Matcher.java @@ -65,9 +65,10 @@ import java.util.Objects; * new strings whose contents can, if desired, be computed from the match * result. The {@link #appendReplacement appendReplacement} and {@link * #appendTail appendTail} methods can be used in tandem in order to collect - * the result into an existing string buffer, or the more convenient {@link - * #replaceAll replaceAll} method can be used to create a string in which every - * matching subsequence in the input sequence is replaced. + * the result into an existing string buffer or string builder. Alternatively, + * the more convenient {@link #replaceAll replaceAll} method can be used to + * create a string in which every matching subsequence in the input sequence + * is replaced. * *

The explicit state of a matcher includes the start and end indices of * the most recent successful match. It also includes the start and end @@ -792,15 +793,115 @@ public final class Matcher implements MatchResult { * that does not exist in the pattern */ public Matcher appendReplacement(StringBuffer sb, String replacement) { - // If no match, return error if (first < 0) throw new IllegalStateException("No match available"); - - // Process substitution string to replace group references with groups - int cursor = 0; StringBuilder result = new StringBuilder(); + appendExpandedReplacement(replacement, result); + // Append the intervening text + sb.append(text, lastAppendPosition, first); + // Append the match substitution + sb.append(result); + lastAppendPosition = last; + return this; + } + /** + * Implements a non-terminal append-and-replace step. + * + *

This method performs the following actions:

+ * + *
    + * + *
  1. It reads characters from the input sequence, starting at the + * append position, and appends them to the given string builder. It + * stops after reading the last character preceding the previous match, + * that is, the character at index {@link + * #start()} - 1.

  2. + * + *
  3. It appends the given replacement string to the string builder. + *

  4. + * + *
  5. It sets the append position of this matcher to the index of + * the last character matched, plus one, that is, to {@link #end()}. + *

  6. + * + *
+ * + *

The replacement string may contain references to subsequences + * captured during the previous match: Each occurrence of + * $g will be replaced by the result of + * evaluating {@link #group(int) group}(g). + * The first number after the $ is always treated as part of + * the group reference. Subsequent numbers are incorporated into g if + * they would form a legal group reference. Only the numerals '0' + * through '9' are considered as potential components of the group + * reference. If the second group matched the string "foo", for + * example, then passing the replacement string "$2bar" would + * cause "foobar" to be appended to the string builder. A dollar + * sign ($) may be included as a literal in the replacement + * string by preceding it with a backslash (\$). + * + *

Note that backslashes (\) and dollar signs ($) in + * the replacement string may cause the results to be different than if it + * were being treated as a literal replacement string. Dollar signs may be + * treated as references to captured subsequences as described above, and + * backslashes are used to escape literal characters in the replacement + * string. + * + *

This method is intended to be used in a loop together with the + * {@link #appendTail appendTail} and {@link #find find} methods. The + * following code, for example, writes one dog two dogs in the + * yard to the standard-output stream:

+ * + *
+     * Pattern p = Pattern.compile("cat");
+     * Matcher m = p.matcher("one cat two cats in the yard");
+     * StringBuilder sb = new StringBuilder();
+     * while (m.find()) {
+     *     m.appendReplacement(sb, "dog");
+     * }
+     * m.appendTail(sb);
+     * System.out.println(sb.toString());
+ * + * @param sb + * The target string builder + * @param replacement + * The replacement string + * @return This matcher + * + * @throws IllegalStateException + * If no match has yet been attempted, + * or if the previous match operation failed + * @throws IllegalArgumentException + * If the replacement string refers to a named-capturing + * group that does not exist in the pattern + * @throws IndexOutOfBoundsException + * If the replacement string refers to a capturing group + * that does not exist in the pattern + * @since 1.9 + */ + public Matcher appendReplacement(StringBuilder sb, String replacement) { + // If no match, return error + if (first < 0) + throw new IllegalStateException("No match available"); + StringBuilder result = new StringBuilder(); + appendExpandedReplacement(replacement, result); + // Append the intervening text + sb.append(text, lastAppendPosition, first); + // Append the match substitution + sb.append(result); + lastAppendPosition = last; + return this; + } + + /** + * Processes replacement string to replace group references with + * groups. + */ + private StringBuilder appendExpandedReplacement( + String replacement, StringBuilder result) { + int cursor = 0; while (cursor < replacement.length()) { char nextChar = replacement.charAt(cursor); if (nextChar == '\\') { @@ -852,8 +953,8 @@ public final class Matcher implements MatchResult { cursor++; } else { // The first number is always a group - refNum = (int)nextChar - '0'; - if ((refNum < 0)||(refNum > 9)) + refNum = nextChar - '0'; + if ((refNum < 0) || (refNum > 9)) throw new IllegalArgumentException( "Illegal group reference"); cursor++; @@ -864,7 +965,7 @@ public final class Matcher implements MatchResult { break; } int nextDigit = replacement.charAt(cursor) - '0'; - if ((nextDigit < 0)||(nextDigit > 9)) { // not a number + if ((nextDigit < 0) || (nextDigit > 9)) { // not a number break; } int newRefNum = (refNum * 10) + nextDigit; @@ -884,13 +985,7 @@ public final class Matcher implements MatchResult { cursor++; } } - // Append the intervening text - sb.append(text, lastAppendPosition, first); - // Append the match substitution - sb.append(result); - - lastAppendPosition = last; - return this; + return result; } /** @@ -912,6 +1007,27 @@ public final class Matcher implements MatchResult { return sb; } + /** + * Implements a terminal append-and-replace step. + * + *

This method reads characters from the input sequence, starting at + * the append position, and appends them to the given string builder. It is + * intended to be invoked after one or more invocations of the {@link + * #appendReplacement appendReplacement} method in order to copy the + * remainder of the input sequence.

+ * + * @param sb + * The target string builder + * + * @return The target string builder + * + * @since 1.9 + */ + public StringBuilder appendTail(StringBuilder sb) { + sb.append(text, lastAppendPosition, getTextLength()); + return sb; + } + /** * Replaces every subsequence of the input sequence that matches the * pattern with the given replacement string. @@ -950,7 +1066,7 @@ public final class Matcher implements MatchResult { reset(); boolean result = find(); if (result) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); do { appendReplacement(sb, replacement); result = find(); @@ -1000,7 +1116,7 @@ public final class Matcher implements MatchResult { reset(); if (!find()) return text.toString(); - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); appendReplacement(sb, replacement); appendTail(sb); return sb.toString(); diff --git a/jdk/src/share/classes/java/util/zip/ZipFile.java b/jdk/src/share/classes/java/util/zip/ZipFile.java index 12aa0dcfaba..b101c33b04c 100644 --- a/jdk/src/share/classes/java/util/zip/ZipFile.java +++ b/jdk/src/share/classes/java/util/zip/ZipFile.java @@ -700,24 +700,26 @@ class ZipFile implements ZipConstants, Closeable { } public int read(byte b[], int off, int len) throws IOException { - if (rem == 0) { - return -1; - } - if (len <= 0) { - return 0; - } - if (len > rem) { - len = (int) rem; - } synchronized (ZipFile.this) { - ensureOpenOrZipException(); + long rem = this.rem; + long pos = this.pos; + if (rem == 0) { + return -1; + } + if (len <= 0) { + return 0; + } + if (len > rem) { + len = (int) rem; + } + ensureOpenOrZipException(); len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b, off, len); - } - if (len > 0) { - pos += len; - rem -= len; + if (len > 0) { + this.pos = (pos + len); + this.rem = (rem - len); + } } if (rem == 0) { close(); diff --git a/jdk/src/share/classes/javax/naming/NameImpl.java b/jdk/src/share/classes/javax/naming/NameImpl.java index f9643054dfe..65a67677677 100644 --- a/jdk/src/share/classes/javax/naming/NameImpl.java +++ b/jdk/src/share/classes/javax/naming/NameImpl.java @@ -232,7 +232,7 @@ class NameImpl { syntaxDirection = FLAT; } else { throw new IllegalArgumentException(syntaxDirectionStr + - "is not a valid value for the jndi.syntax.direction property"); + " is not a valid value for the jndi.syntax.direction property"); } if (syntaxDirection != FLAT) { diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java b/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java index 5c8b65f2703..a8d12131aaf 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java @@ -52,7 +52,20 @@ import javax.security.auth.DestroyFailedException; * application depends on the default JGSS Kerberos mechanism to access the * KerberosKey. In that case, however, the application will need an * appropriate - * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}. + * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}.

+ * + * When creating a {@code KerberosKey} using the + * {@link #KerberosKey(KerberosPrincipal, char[], String)} constructor, + * an implementation may accept non-IANA algorithm names (For example, + * "ArcFourMac" for "rc4-hmac"), but the {@link #getAlgorithm} method + * must always return the IANA algorithm name.

+ * + * @implNote Old algorithm names used before JDK 9 are supported in the + * {@link #KerberosKey(KerberosPrincipal, char[], String)} constructor in this + * implementation for compatibility reasons, which are "DES" (and null) for + * "des-cbc-md5", "DESede" for "des3-cbc-sha1-kd", "ArcFourHmac" for "rc4-hmac", + * "AES128" for "aes128-cts-hmac-sha1-96", and "AES256" for + * "aes256-cts-hmac-sha1-96". * * @author Mayank Upadhyay * @since 1.4 @@ -73,7 +86,7 @@ public class KerberosKey implements SecretKey, Destroyable { * * @serial */ - private int versionNum; + private final int versionNum; /** * {@code KeyImpl} is serialized by writing out the ASN1 Encoded bytes @@ -113,13 +126,16 @@ public class KerberosKey implements SecretKey, Destroyable { } /** - * Constructs a KerberosKey from a principal's password. + * Constructs a KerberosKey from a principal's password using the specified + * algorithm name. The algorithm name (case insensitive) should be provided + * as the encryption type string defined on the IANA + * Kerberos Encryption Type Numbers + * page. The version number of the key generated will be 0. * * @param principal the principal that this password belongs to * @param password the password that should be used to compute the key * @param algorithm the name for the algorithm that this key will be - * used for. This parameter may be null in which case the default - * algorithm "DES" will be assumed. + * used for * @throws IllegalArgumentException if the name of the * algorithm passed is unsupported. */ @@ -128,6 +144,7 @@ public class KerberosKey implements SecretKey, Destroyable { String algorithm) { this.principal = principal; + this.versionNum = 0; // Pass principal in for salt key = new KeyImpl(principal, password, algorithm); } @@ -170,13 +187,18 @@ public class KerberosKey implements SecretKey, Destroyable { */ /** - * Returns the standard algorithm name for this key. For - * example, "DES" would indicate that this key is a DES key. - * See Appendix A in the - * Java Cryptography Architecture API Specification & Reference - * - * for information about standard algorithm names. + * Returns the standard algorithm name for this key. The algorithm names + * are the encryption type string defined on the IANA + * Kerberos Encryption Type Numbers + * page. + *

+ * This method can return the following value not defined on the IANA page: + *

    + *
  1. none: for etype equal to 0
  2. + *
  3. unknown: for etype greater than 0 but unsupported by + * the implementation
  4. + *
  5. private: for etype smaller than 0
  6. + *
* * @return the name of the algorithm associated with this key. */ diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java b/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java index f4ee947212b..9d36d1e9ee1 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java @@ -36,7 +36,6 @@ import sun.security.krb5.PrincipalName; import sun.security.krb5.EncryptionKey; import sun.security.krb5.EncryptedData; import sun.security.krb5.KrbException; -import sun.security.krb5.KrbCryptoException; import sun.security.util.DerValue; /** @@ -86,8 +85,12 @@ class KeyImpl implements SecretKey, Destroyable, Serializable { try { PrincipalName princ = new PrincipalName(principal.getName()); - EncryptionKey key = - new EncryptionKey(password, princ.getSalt(), algorithm); + EncryptionKey key; + if ("none".equalsIgnoreCase(algorithm)) { + key = EncryptionKey.NULL_KEY; + } else { + key = new EncryptionKey(password, princ.getSalt(), algorithm); + } this.keyBytes = key.getBytes(); this.keyType = key.getEType(); } catch (KrbException e) { @@ -118,27 +121,28 @@ class KeyImpl implements SecretKey, Destroyable, Serializable { switch (eType) { case EncryptedData.ETYPE_DES_CBC_CRC: + return "des-cbc-crc"; + case EncryptedData.ETYPE_DES_CBC_MD5: - return "DES"; + return "des-cbc-md5"; case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD: - return "DESede"; + return "des3-cbc-sha1-kd"; case EncryptedData.ETYPE_ARCFOUR_HMAC: - return "ArcFourHmac"; + return "rc4-hmac"; case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: - return "AES128"; + return "aes128-cts-hmac-sha1-96"; case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: - return "AES256"; + return "aes256-cts-hmac-sha1-96"; case EncryptedData.ETYPE_NULL: - return "NULL"; + return "none"; default: - throw new IllegalArgumentException( - "Unsupported encryption type: " + eType); + return eType > 0 ? "unknown" : "private"; } } diff --git a/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java b/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java new file mode 100644 index 00000000000..8be1fe6a5dc --- /dev/null +++ b/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.net; + +import java.net.SocketOption; + +/** + * Defines extended socket options, beyond those defined in + * {@link java.net.StandardSocketOptions}. These options may be platform + * specific. + * + * @since 1.9 + */ +@jdk.Exported +public final class ExtendedSocketOptions { + + private static class ExtSocketOption implements SocketOption { + private final String name; + private final Class type; + ExtSocketOption(String name, Class type) { + this.name = name; + this.type = type; + } + @Override public String name() { return name; } + @Override public Class type() { return type; } + @Override public String toString() { return name; } + } + + private ExtendedSocketOptions() {} + + /** + * Service level properties. When a security manager is installed, + * setting or getting this option requires a {@link NetworkPermission} + * {@code ("setOption.SO_FLOW_SLA")} or {@code "getOption.SO_FLOW_SLA"} + * respectively. + */ + public static final SocketOption SO_FLOW_SLA = new + ExtSocketOption("SO_FLOW_SLA", SocketFlow.class); +} diff --git a/jdk/src/share/classes/jdk/net/NetworkPermission.java b/jdk/src/share/classes/jdk/net/NetworkPermission.java new file mode 100644 index 00000000000..0e853f0d527 --- /dev/null +++ b/jdk/src/share/classes/jdk/net/NetworkPermission.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.net; + +import java.security.BasicPermission; + +/** + * Represents permission to access the extended networking capabilities + * defined in the jdk.net package. These permissions contain a target + * name, but no actions list. Callers either possess the permission or not. + *

+ * The following targets are defined: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Permission Target NameWhat the Permission AllowsRisks of Allowing this Permission
setOption.SO_FLOW_SLAset the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA} option + * on any socket that supports itallows caller to set a higher priority or bandwidth allocation + * to sockets it creates, than they might otherwise be allowed.
getOption.SO_FLOW_SLAretrieve the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA} + * setting from any socket that supports the optionallows caller access to SLA information that it might not + * otherwise have
+ * + * @see jdk.net.ExtendedSocketOptions + * + * @since 1.9 + */ + +@jdk.Exported +public final class NetworkPermission extends BasicPermission { + + private static final long serialVersionUID = -2012939586906722291L; + + /** + * Creates a NetworkPermission with the given target name. + * + * @param name the permission target name + * @throws NullPointerException if {@code name} is {@code null}. + * @throws IllegalArgumentException if {@code name} is empty. + */ + public NetworkPermission(String name) + { + super(name); + } + + /** + * Creates a NetworkPermission with the given target name. + * + * @param name the permission target name + * @param actions should be {@code null}. Is ignored if not. + * @throws NullPointerException if {@code name} is {@code null}. + * @throws IllegalArgumentException if {@code name} is empty. + */ + public NetworkPermission(String name, String actions) + { + super(name, actions); + } +} diff --git a/jdk/src/share/classes/jdk/net/SocketFlow.java b/jdk/src/share/classes/jdk/net/SocketFlow.java new file mode 100644 index 00000000000..a102a3f35a0 --- /dev/null +++ b/jdk/src/share/classes/jdk/net/SocketFlow.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.net; + +import java.lang.annotation.Native; + +/** + * Represents the service level properties for the platform specific socket + * option {@link ExtendedSocketOptions#SO_FLOW_SLA}. + *

+ * The priority and bandwidth parameters must be set before + * setting the socket option. + *

+ * When the {@code SO_FLOW_SLA} option is set then it may not take effect + * immediately. If the value of the socket option is obtained with + * {@code getOption()} then the status may be returned as {@code INPROGRESS} + * until it takes effect. The priority and bandwidth values are only valid when + * the status is returned as OK. + *

+ * When a security manager is installed, a {@link NetworkPermission} + * is required to set or get this option. + * + * @since 1.9 + */ +@jdk.Exported +public class SocketFlow { + + private static final int UNSET = -1; + @Native public static final int NORMAL_PRIORITY = 1; + @Native public static final int HIGH_PRIORITY = 2; + + private int priority = NORMAL_PRIORITY; + + private long bandwidth = UNSET; + + private Status status = Status.NO_STATUS; + + private SocketFlow() {} + + /** + * Enumeration of the return values from the SO_FLOW_SLA + * socket option. Both setting and getting the option return + * one of these statuses, which reflect the state of socket's + * flow. + * + * @since 1.9 + */ + @jdk.Exported + public enum Status { + /** + * Set or get socket option has not been called yet. Status + * values can only be retrieved after calling set or get. + */ + NO_STATUS, + /** + * Flow successfully created. + */ + OK, + /** + * Caller has no permission to create flow. + */ + NO_PERMISSION, + /** + * Flow can not be created because socket is not connected. + */ + NOT_CONNECTED, + /** + * Flow creation not supported for this socket. + */ + NOT_SUPPORTED, + /** + * A flow already exists with identical attributes. + */ + ALREADY_CREATED, + /** + * A flow is being created. + */ + IN_PROGRESS, + /** + * Some other unspecified error. + */ + OTHER + } + + /** + * Creates a new SocketFlow that can be used to set the SO_FLOW_SLA + * socket option and create a socket flow. + */ + public static SocketFlow create() { + return new SocketFlow(); + } + + /** + * Sets this SocketFlow's priority. Must be either NORMAL_PRIORITY + * HIGH_PRIORITY. If not set, a flow's priority is normal. + * + * @throws IllegalArgumentException if priority is not NORMAL_PRIORITY or + * HIGH_PRIORITY. + */ + public SocketFlow priority(int priority) { + if (priority != NORMAL_PRIORITY && priority != HIGH_PRIORITY) { + throw new IllegalArgumentException("invalid priority"); + } + this.priority = priority; + return this; + } + + /** + * Sets this SocketFlow's bandwidth. Must be greater than or equal to zero. + * A value of zero drops all packets for the socket. + * + * @throws IllegalArgumentException if bandwidth is less than zero. + */ + public SocketFlow bandwidth(long bandwidth) { + if (bandwidth < 0) { + throw new IllegalArgumentException("invalid bandwidth"); + } else { + this.bandwidth = bandwidth; + } + return this; + } + + /** + * Returns this SocketFlow's priority. + */ + public int priority() { + return priority; + } + + /** + * Returns this SocketFlow's bandwidth. + * + * @return this SocketFlow's bandwidth, or {@code -1} if status is not OK. + */ + public long bandwidth() { + return bandwidth; + } + + /** + * Returns the Status value of this SocketFlow. NO_STATUS is returned + * if the object was not used in a call to set or get the option. + */ + public Status status() { + return status; + } +} diff --git a/jdk/src/share/classes/jdk/net/Sockets.java b/jdk/src/share/classes/jdk/net/Sockets.java new file mode 100644 index 00000000000..9f7d94a0323 --- /dev/null +++ b/jdk/src/share/classes/jdk/net/Sockets.java @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.net; + +import java.net.*; +import java.io.IOException; +import java.io.FileDescriptor; +import java.security.PrivilegedAction; +import java.security.AccessController; +import java.lang.reflect.Field; +import java.util.Set; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Collections; +import sun.net.ExtendedOptionsImpl; + +/** + * Defines static methods to set and get socket options defined by the + * {@link java.net.SocketOption} interface. All of the standard options defined + * by {@link java.net.Socket}, {@link java.net.ServerSocket}, and + * {@link java.net.DatagramSocket} can be set this way, as well as additional + * or platform specific options supported by each socket type. + *

+ * The {@link #supportedOptions(Class)} method can be called to determine + * the complete set of options available (per socket type) on the + * current system. + *

+ * When a security manager is installed, some non-standard socket options + * may require a security permission before being set or get. + * The details are specified in {@link ExtendedSocketOptions}. No permission + * is required for {@link java.net.StandardSocketOption}s. + * + * @see java.nio.channels.NetworkChannel + */ +@jdk.Exported +public class Sockets { + + private final static HashMap,Set>> + options = new HashMap<>(); + + static { + initOptionSets(); + } + + private Sockets() {} + + /** + * Sets the value of a socket option on a {@link java.net.Socket} + * + * @param s the socket + * @param name The socket option + * @param value The value of the socket option. May be null for some + * options. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or socket is closed. + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @throws NullPointerException if name is null + * + * @see java.net.StandardSocketOptions + */ + public static void setOption(Socket s, SocketOption name, T value) throws IOException + { + s.setOption(name, value); + } + + /** + * Returns the value of a socket option from a {@link java.net.Socket} + * + * @param s the socket + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @throws NullPointerException if name is null + * + * @see java.net.StandardSocketOptions + */ + public static T getOption(Socket s, SocketOption name) throws IOException + { + return s.getOption(name); + } + + /** + * Sets the value of a socket option on a {@link java.net.ServerSocket} + * + * @param s the socket + * @param name The socket option + * @param value The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws NullPointerException if name is null + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @see java.net.StandardSocketOptions + */ + public static void setOption(ServerSocket s, SocketOption name, T value) throws IOException + { + s.setOption(name, value); + } + + /** + * Returns the value of a socket option from a {@link java.net.ServerSocket} + * + * @param s the socket + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws NullPointerException if name is null + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @see java.net.StandardSocketOptions + */ + public static T getOption(ServerSocket s, SocketOption name) throws IOException + { + return s.getOption(name); + } + + /** + * Sets the value of a socket option on a {@link java.net.DatagramSocket} + * or {@link java.net.MulticastSocket} + * + * @param s the socket + * @param name The socket option + * @param value The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws NullPointerException if name is null + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @see java.net.StandardSocketOptions + */ + public static void setOption(DatagramSocket s, SocketOption name, T value) throws IOException + { + s.setOption(name, value); + } + + /** + * Returns the value of a socket option from a + * {@link java.net.DatagramSocket} or {@link java.net.MulticastSocket} + * + * @param s the socket + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws NullPointerException if name is null + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @see java.net.StandardSocketOptions + */ + public static T getOption(DatagramSocket s, SocketOption name) throws IOException + { + return s.getOption(name); + } + + /** + * Returns a set of {@link java.net.SocketOption}s supported by the + * given socket type. This set may include standard options and also + * non standard extended options. + * + * @param socketType the type of java.net socket + * + * @throws IllegalArgumentException if socketType is not a valid + * socket type from the java.net package. + */ + public static Set> supportedOptions(Class socketType) { + Set> set = options.get(socketType); + if (set == null) { + throw new IllegalArgumentException("unknown socket type"); + } + return set; + } + + private static void checkValueType(Object value, Class type) { + if (!type.isAssignableFrom(value.getClass())) { + String s = "Found: " + value.getClass().toString() + " Expected: " + + type.toString(); + throw new IllegalArgumentException(s); + } + } + + private static void initOptionSets() { + boolean flowsupported = ExtendedOptionsImpl.flowSupported(); + + // Socket + + Set> set = new HashSet<>(); + set.add(StandardSocketOptions.SO_KEEPALIVE); + set.add(StandardSocketOptions.SO_SNDBUF); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_REUSEADDR); + set.add(StandardSocketOptions.SO_LINGER); + set.add(StandardSocketOptions.IP_TOS); + set.add(StandardSocketOptions.TCP_NODELAY); + if (flowsupported) { + set.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + set = Collections.unmodifiableSet(set); + options.put(Socket.class, set); + + // ServerSocket + + set = new HashSet<>(); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_REUSEADDR); + set = Collections.unmodifiableSet(set); + options.put(ServerSocket.class, set); + + // DatagramSocket + + set = new HashSet<>(); + set.add(StandardSocketOptions.SO_SNDBUF); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_REUSEADDR); + set.add(StandardSocketOptions.IP_TOS); + if (flowsupported) { + set.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + set = Collections.unmodifiableSet(set); + options.put(DatagramSocket.class, set); + + // MulticastSocket + + set = new HashSet<>(); + set.add(StandardSocketOptions.SO_SNDBUF); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_REUSEADDR); + set.add(StandardSocketOptions.IP_TOS); + set.add(StandardSocketOptions.IP_MULTICAST_IF); + set.add(StandardSocketOptions.IP_MULTICAST_TTL); + set.add(StandardSocketOptions.IP_MULTICAST_LOOP); + if (flowsupported) { + set.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + set = Collections.unmodifiableSet(set); + options.put(MulticastSocket.class, set); + } +} diff --git a/jdk/src/share/classes/jdk/net/package-info.java b/jdk/src/share/classes/jdk/net/package-info.java new file mode 100644 index 00000000000..236d640dbfa --- /dev/null +++ b/jdk/src/share/classes/jdk/net/package-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Platform specific socket options for the {@code java.net} and {@code java.nio.channels} + * socket classes. + * + * @since 1.9 + */ + +@jdk.Exported +package jdk.net; diff --git a/jdk/src/share/classes/sun/misc/CharacterDecoder.java b/jdk/src/share/classes/sun/misc/CharacterDecoder.java index 76329ec8e39..c076f46df28 100644 --- a/jdk/src/share/classes/sun/misc/CharacterDecoder.java +++ b/jdk/src/share/classes/sun/misc/CharacterDecoder.java @@ -184,7 +184,7 @@ public abstract class CharacterDecoder { * @exception CEFormatException An error has occurred while decoding */ public byte[] decodeBuffer(String inputString) throws IOException { - byte inputBuffer[] = inputString.getBytes(); + byte inputBuffer[] = inputString.getBytes("ISO-8859-1"); ByteArrayInputStream inStream = new ByteArrayInputStream(inputBuffer); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); decodeBuffer(inStream, outStream); diff --git a/jdk/src/share/classes/sun/misc/CharacterEncoder.java b/jdk/src/share/classes/sun/misc/CharacterEncoder.java index 70c5ff90a44..d152f954cf9 100644 --- a/jdk/src/share/classes/sun/misc/CharacterEncoder.java +++ b/jdk/src/share/classes/sun/misc/CharacterEncoder.java @@ -190,7 +190,7 @@ public abstract class CharacterEncoder { try { encode(inStream, outStream); // explicit ascii->unicode conversion - retVal = outStream.toString("8859_1"); + retVal = outStream.toString("ISO-8859-1"); } catch (Exception IOException) { // This should never happen. throw new Error("CharacterEncoder.encode internal error"); diff --git a/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java b/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java new file mode 100644 index 00000000000..8fbcdd7b49d --- /dev/null +++ b/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.net; + +import java.net.*; +import jdk.net.*; +import java.io.IOException; +import java.io.FileDescriptor; +import java.security.PrivilegedAction; +import java.security.AccessController; +import java.lang.reflect.Field; +import java.util.Set; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Collections; + +/** + * Contains the native implementation for extended socket options + * together with some other static utilities + */ +public class ExtendedOptionsImpl { + + static { + AccessController.doPrivileged((PrivilegedAction)() -> { + System.loadLibrary("net"); + return null; + }); + init(); + } + + private ExtendedOptionsImpl() {} + + public static void checkSetOptionPermission(SocketOption option) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + return; + } + String check = "setOption." + option.name(); + sm.checkPermission(new NetworkPermission(check)); + } + + public static void checkGetOptionPermission(SocketOption option) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + return; + } + String check = "getOption." + option.name(); + sm.checkPermission(new NetworkPermission(check)); + } + + public static void checkValueType(Object value, Class type) { + if (!type.isAssignableFrom(value.getClass())) { + String s = "Found: " + value.getClass().toString() + " Expected: " + + type.toString(); + throw new IllegalArgumentException(s); + } + } + + private static native void init(); + + /* + * Extension native implementations + * + * SO_FLOW_SLA + */ + public static native void setFlowOption(FileDescriptor fd, SocketFlow f); + public static native void getFlowOption(FileDescriptor fd, SocketFlow f); + public static native boolean flowSupported(); +} diff --git a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java index d28bf90b83f..9899d759b71 100644 --- a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java @@ -39,6 +39,7 @@ import java.util.Collections; import java.util.concurrent.*; import java.util.concurrent.locks.*; import sun.net.NetHooks; +import sun.net.ExtendedOptionsImpl; /** * Base implementation of AsynchronousSocketChannel @@ -508,6 +509,9 @@ abstract class AsynchronousSocketChannelImpl set.add(StandardSocketOptions.SO_KEEPALIVE); set.add(StandardSocketOptions.SO_REUSEADDR); set.add(StandardSocketOptions.TCP_NODELAY); + if (ExtendedOptionsImpl.flowSupported()) { + set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); + } return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index c151afe570b..fe32f63880b 100644 --- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -33,6 +33,7 @@ import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; import sun.net.ResourceManager; +import sun.net.ExtendedOptionsImpl; /** * An implementation of DatagramChannels. @@ -317,6 +318,9 @@ class DatagramChannelImpl set.add(StandardSocketOptions.IP_MULTICAST_IF); set.add(StandardSocketOptions.IP_MULTICAST_TTL); set.add(StandardSocketOptions.IP_MULTICAST_LOOP); + if (ExtendedOptionsImpl.flowSupported()) { + set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); + } return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/share/classes/sun/nio/ch/Net.java b/jdk/src/share/classes/sun/nio/ch/Net.java index 79ebb2f36a5..753e5417310 100644 --- a/jdk/src/share/classes/sun/nio/ch/Net.java +++ b/jdk/src/share/classes/sun/nio/ch/Net.java @@ -27,11 +27,13 @@ package sun.nio.ch; import java.io.*; import java.net.*; +import jdk.net.*; import java.nio.channels.*; import java.util.*; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; +import sun.net.ExtendedOptionsImpl; public class Net { @@ -297,6 +299,16 @@ public class Net { // only simple values supported by this method Class type = name.type(); + + if (type == SocketFlow.class) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new NetworkPermission("setOption.SO_FLOW_SLA")); + } + ExtendedOptionsImpl.setFlowOption(fd, (SocketFlow)value); + return; + } + if (type != Integer.class && type != Boolean.class) throw new AssertionError("Should not reach here"); @@ -349,6 +361,16 @@ public class Net { { Class type = name.type(); + if (type == SocketFlow.class) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new NetworkPermission("getOption.SO_FLOW_SLA")); + } + SocketFlow flow = SocketFlow.create(); + ExtendedOptionsImpl.getFlowOption(fd, flow); + return flow; + } + // only simple values supported by this method if (type != Integer.class && type != Boolean.class) throw new AssertionError("Should not reach here"); diff --git a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java index a977ced312b..1e36aed74d0 100644 --- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -33,6 +33,7 @@ import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; import sun.net.NetHooks; +import sun.net.ExtendedOptionsImpl; /** @@ -237,6 +238,9 @@ class SocketChannelImpl // additional options required by socket adaptor set.add(StandardSocketOptions.IP_TOS); set.add(ExtendedSocketOption.SO_OOBINLINE); + if (ExtendedOptionsImpl.flowSupported()) { + set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); + } return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/share/classes/sun/nio/cs/UTF_8.java b/jdk/src/share/classes/sun/nio/cs/UTF_8.java index bfb7b7a977b..3ee2341f000 100644 --- a/jdk/src/share/classes/sun/nio/cs/UTF_8.java +++ b/jdk/src/share/classes/sun/nio/cs/UTF_8.java @@ -111,12 +111,18 @@ class UTF_8 extends Unicode (b4 & 0xc0) != 0x80; } - // only used when there is less than 4 bytes left in src buffer + // only used when there is less than 4 bytes left in src buffer. + // both b1 and b2 should be "& 0xff" before passed in. private static boolean isMalformed4_2(int b1, int b2) { - return (b1 == 0xf0 && b2 == 0x90) || + return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) || + (b1 == 0xf4 && (b2 & 0xf0) != 0x80) || (b2 & 0xc0) != 0x80; } + // tests if b1 and b2 are malformed as the first 2 bytes of a + // legal`4-byte utf-8 byte sequence. + // only used when there is less than 4 bytes left in src buffer, + // after isMalformed4_2 has been invoked. private static boolean isMalformed4_3(int b3) { return (b3 & 0xc0) != 0x80; } @@ -280,7 +286,9 @@ class UTF_8 extends Unicode // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx int srcRemaining = sl - sp; if (srcRemaining < 4 || dl - dp < 2) { - if (srcRemaining > 1 && isMalformed4_2(b1, sa[sp + 1])) + b1 &= 0xff; + if (b1 > 0xf4 || + srcRemaining > 1 && isMalformed4_2(b1, sa[sp + 1] & 0xff)) return malformedForLength(src, sp, dst, dp, 1); if (srcRemaining > 2 && isMalformed4_3(sa[sp + 2])) return malformedForLength(src, sp, dst, dp, 2); @@ -363,7 +371,9 @@ class UTF_8 extends Unicode // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx int srcRemaining = limit - mark; if (srcRemaining < 4 || dst.remaining() < 2) { - if (srcRemaining > 1 && isMalformed4_2(b1, src.get())) + b1 &= 0xff; + if (b1 > 0xf4 || + srcRemaining > 1 && isMalformed4_2(b1, src.get() & 0xff)) return malformedForLength(src, mark, 1); if (srcRemaining > 2 && isMalformed4_3(src.get())) return malformedForLength(src, mark, 2); @@ -518,8 +528,9 @@ class UTF_8 extends Unicode } if (malformedInputAction() != CodingErrorAction.REPLACE) return -1; - - if (sp < sl && isMalformed4_2(b1, sa[sp])) { + b1 &= 0xff; + if (b1 > 0xf4 || + sp < sl && isMalformed4_2(b1, sa[sp] & 0xff)) { da[dp++] = replacement().charAt(0); continue; } diff --git a/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java b/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java index a38a7faecf2..0741499b9a7 100644 --- a/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java +++ b/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java @@ -26,11 +26,11 @@ package sun.security.internal.spec; import java.security.spec.AlgorithmParameterSpec; +import java.security.AccessController; +import java.security.PrivilegedAction; /** - * Parameters for SSL/TLS RSA Premaster secret generation. - * This class is used by SSL/TLS client to initialize KeyGenerators of the - * type "TlsRsaPremasterSecret". + * Parameters for SSL/TLS RSA premaster secret. * *

Instances of this class are immutable. * @@ -43,90 +43,108 @@ import java.security.spec.AlgorithmParameterSpec; public class TlsRsaPremasterSecretParameterSpec implements AlgorithmParameterSpec { - private final int majorVersion; - private final int minorVersion; - private final byte[] encodedSecret; + /* + * The TLS spec says that the version in the RSA premaster secret must + * be the maximum version supported by the client (i.e. the version it + * requested in its client hello version). However, we (and other + * implementations) used to send the active negotiated version. The + * system property below allows to toggle the behavior. + */ + private final static String PROP_NAME = + "com.sun.net.ssl.rsaPreMasterSecretFix"; + + /* + * Default is "false" (old behavior) for compatibility reasons in + * SSLv3/TLSv1. Later protocols (TLSv1.1+) do not use this property. + */ + private final static boolean rsaPreMasterSecretFix = + AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + String value = System.getProperty(PROP_NAME); + if (value != null && value.equalsIgnoreCase("true")) { + return Boolean.TRUE; + } + + return Boolean.FALSE; + } + }); + + private final int clientVersion; + private final int serverVersion; /** * Constructs a new TlsRsaPremasterSecretParameterSpec. - *

- * The version numbers will be placed inside the premaster secret to - * detect version rollbacks attacks as described in the TLS specification. - * Note that they do not indicate the protocol version negotiated for - * the handshake. * - * @param majorVersion the major number of the protocol version - * @param minorVersion the minor number of the protocol version + * @param clientVersion the version of the TLS protocol by which the + * client wishes to communicate during this session + * @param serverVersion the negotiated version of the TLS protocol which + * contains the lower of that suggested by the client in the client + * hello and the highest supported by the server. * - * @throws IllegalArgumentException if minorVersion or majorVersion are - * negative or larger than 255 + * @throws IllegalArgumentException if clientVersion or serverVersion are + * negative or larger than (2^16 - 1) */ - public TlsRsaPremasterSecretParameterSpec(int majorVersion, - int minorVersion) { - this.majorVersion = - TlsMasterSecretParameterSpec.checkVersion(majorVersion); - this.minorVersion = - TlsMasterSecretParameterSpec.checkVersion(minorVersion); - this.encodedSecret = null; + public TlsRsaPremasterSecretParameterSpec( + int clientVersion, int serverVersion) { + + this.clientVersion = checkVersion(clientVersion); + this.serverVersion = checkVersion(serverVersion); } /** - * Constructs a new TlsRsaPremasterSecretParameterSpec. - *

- * The version numbers will be placed inside the premaster secret to - * detect version rollbacks attacks as described in the TLS specification. - * Note that they do not indicate the protocol version negotiated for - * the handshake. - *

- * Usually, the encoded secret key is a random number that acts as - * dummy pre_master_secret to avoid vulnerabilities described by - * section 7.4.7.1, RFC 5246. + * Returns the version of the TLS protocol by which the client wishes to + * communicate during this session. * - * @param majorVersion the major number of the protocol version - * @param minorVersion the minor number of the protocol version - * @param encodedSecret the encoded secret key - * - * @throws IllegalArgumentException if minorVersion or majorVersion are - * negative or larger than 255, or encodedSecret is not exactly 48 bytes. + * @return the version of the TLS protocol in ClientHello message */ - public TlsRsaPremasterSecretParameterSpec(int majorVersion, - int minorVersion, byte[] encodedSecret) { - this.majorVersion = - TlsMasterSecretParameterSpec.checkVersion(majorVersion); - this.minorVersion = - TlsMasterSecretParameterSpec.checkVersion(minorVersion); - - if (encodedSecret == null || encodedSecret.length != 48) { - throw new IllegalArgumentException( - "Encoded secret is not exactly 48 bytes"); - } - this.encodedSecret = encodedSecret.clone(); + public int getClientVersion() { + return clientVersion; } /** - * Returns the major version. + * Returns the negotiated version of the TLS protocol which contains the + * lower of that suggested by the client in the client hello and the + * highest supported by the server. * - * @return the major version. + * @return the negotiated version of the TLS protocol in ServerHello message + */ + public int getServerVersion() { + return serverVersion; + } + + /** + * Returns the major version used in RSA premaster secret. + * + * @return the major version used in RSA premaster secret. */ public int getMajorVersion() { - return majorVersion; + if (rsaPreMasterSecretFix || clientVersion >= 0x0302) { + // 0x0302: TLSv1.1 + return (clientVersion >>> 8) & 0xFF; + } + + return (serverVersion >>> 8) & 0xFF; } /** - * Returns the minor version. + * Returns the minor version used in RSA premaster secret. * - * @return the minor version. + * @return the minor version used in RSA premaster secret. */ public int getMinorVersion() { - return minorVersion; + if (rsaPreMasterSecretFix || clientVersion >= 0x0302) { + // 0x0302: TLSv1.1 + return clientVersion & 0xFF; + } + + return serverVersion & 0xFF; } - /** - * Returns the encoded secret. - * - * @return the encoded secret, may be null if no encoded secret. - */ - public byte[] getEncodedSecret() { - return encodedSecret == null ? null : encodedSecret.clone(); + private int checkVersion(int version) { + if ((version < 0) || (version > 0xFFFF)) { + throw new IllegalArgumentException( + "Version must be between 0 and 65,535"); + } + return version; } } diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java index ffae2cdc2fa..cc9626c14f7 100644 --- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java +++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java @@ -86,6 +86,10 @@ public final class Krb5MechFactory implements MechanismFactory { return result; } + public Krb5MechFactory() { + this(GSSCaller.CALLER_UNKNOWN); + } + public Krb5MechFactory(GSSCaller caller) { this.caller = caller; } diff --git a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoMechFactory.java b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoMechFactory.java index cb60230d4f9..511547b8a78 100644 --- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoMechFactory.java +++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoMechFactory.java @@ -96,6 +96,10 @@ public final class SpNegoMechFactory implements MechanismFactory { return result; } + public SpNegoMechFactory() { + this(GSSCaller.CALLER_UNKNOWN); + } + public SpNegoMechFactory(GSSCaller caller) { manager = new GSSManagerImpl(caller, false); Oid[] mechs = manager.getMechs(); diff --git a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java index b83fe8c8611..6887f85524c 100644 --- a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java +++ b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java @@ -271,15 +271,22 @@ public class EncryptionKey String salt, String algorithm) throws KrbCryptoException { - if (algorithm == null || algorithm.equalsIgnoreCase("DES")) { + if (algorithm == null || algorithm.equalsIgnoreCase("DES") + || algorithm.equalsIgnoreCase("des-cbc-md5")) { keyType = EncryptedData.ETYPE_DES_CBC_MD5; - } else if (algorithm.equalsIgnoreCase("DESede")) { + } else if (algorithm.equalsIgnoreCase("des-cbc-crc")) { + keyType = EncryptedData.ETYPE_DES_CBC_CRC; + } else if (algorithm.equalsIgnoreCase("DESede") + || algorithm.equalsIgnoreCase("des3-cbc-sha1-kd")) { keyType = EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD; - } else if (algorithm.equalsIgnoreCase("AES128")) { + } else if (algorithm.equalsIgnoreCase("AES128") + || algorithm.equalsIgnoreCase("aes128-cts-hmac-sha1-96")) { keyType = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96; - } else if (algorithm.equalsIgnoreCase("ArcFourHmac")) { + } else if (algorithm.equalsIgnoreCase("ArcFourHmac") + || algorithm.equalsIgnoreCase("rc4-hmac")) { keyType = EncryptedData.ETYPE_ARCFOUR_HMAC; - } else if (algorithm.equalsIgnoreCase("AES256")) { + } else if (algorithm.equalsIgnoreCase("AES256") + || algorithm.equalsIgnoreCase("aes256-cts-hmac-sha1-96")) { keyType = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96; // validate if AES256 is enabled if (!EType.isSupported(keyType)) { diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java index e2ff0fc73e4..253b8913a82 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java @@ -37,6 +37,8 @@ import javax.crypto.spec.*; import static sun.security.pkcs11.TemplateManager.*; import sun.security.pkcs11.wrapper.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; +import sun.security.util.KeyUtil; /** * RSA Cipher implementation class. We currently only support @@ -102,6 +104,12 @@ final class P11RSACipher extends CipherSpi { // maximum output size. this is the length of the key private int outputSize; + // cipher parameter for TLS RSA premaster secret + private AlgorithmParameterSpec spec = null; + + // the source of randomness + private SecureRandom random; + P11RSACipher(Token token, String algorithm, long mechanism) throws PKCS11Exception { super(); @@ -165,8 +173,12 @@ final class P11RSACipher extends CipherSpi { AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { if (params != null) { - throw new InvalidAlgorithmParameterException - ("Parameters not supported"); + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); + } + spec = params; + this.random = random; // for TLS RSA premaster secret } implInit(opmode, key); } @@ -176,8 +188,8 @@ final class P11RSACipher extends CipherSpi { SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { if (params != null) { - throw new InvalidAlgorithmParameterException - ("Parameters not supported"); + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); } implInit(opmode, key); } @@ -452,21 +464,101 @@ final class P11RSACipher extends CipherSpi { protected Key engineUnwrap(byte[] wrappedKey, String algorithm, int type) throws InvalidKeyException, NoSuchAlgorithmException { - // XXX implement unwrap using C_Unwrap() for all keys - implInit(Cipher.DECRYPT_MODE, p11Key); - if (wrappedKey.length > maxInputSize) { - throw new InvalidKeyException("Key is too long for unwrapping"); + boolean isTlsRsaPremasterSecret = + algorithm.equals("TlsRsaPremasterSecret"); + Exception failover = null; + + SecureRandom secureRandom = random; + if (secureRandom == null && isTlsRsaPremasterSecret) { + secureRandom = new SecureRandom(); } - implUpdate(wrappedKey, 0, wrappedKey.length); - try { - byte[] encoded = doFinal(); + + // Should C_Unwrap be preferred for non-TLS RSA premaster secret? + if (token.supportsRawSecretKeyImport()) { + // XXX implement unwrap using C_Unwrap() for all keys + implInit(Cipher.DECRYPT_MODE, p11Key); + if (wrappedKey.length > maxInputSize) { + throw new InvalidKeyException("Key is too long for unwrapping"); + } + + byte[] encoded = null; + implUpdate(wrappedKey, 0, wrappedKey.length); + try { + encoded = doFinal(); + } catch (BadPaddingException e) { + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("Unwrapping failed", e); + } + } catch (IllegalBlockSizeException e) { + // should not occur, handled with length check above + throw new InvalidKeyException("Unwrapping failed", e); + } + + if (isTlsRsaPremasterSecret) { + if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + TlsRsaPremasterSecretParameterSpec psps = + (TlsRsaPremasterSecretParameterSpec)spec; + encoded = KeyUtil.checkTlsPreMasterSecretKey( + psps.getClientVersion(), psps.getServerVersion(), + secureRandom, encoded, (failover != null)); + } + return ConstructKeys.constructKey(encoded, algorithm, type); - } catch (BadPaddingException e) { - // should not occur - throw new InvalidKeyException("Unwrapping failed", e); - } catch (IllegalBlockSizeException e) { - // should not occur, handled with length check above - throw new InvalidKeyException("Unwrapping failed", e); + } else { + Session s = null; + SecretKey secretKey = null; + try { + try { + s = token.getObjSession(); + long keyType = CKK_GENERIC_SECRET; + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + }; + attributes = token.getAttributes( + O_IMPORT, CKO_SECRET_KEY, keyType, attributes); + long keyID = token.p11.C_UnwrapKey(s.id(), + new CK_MECHANISM(mechanism), p11Key.keyID, + wrappedKey, attributes); + secretKey = P11Key.secretKey(s, keyID, + algorithm, 48 << 3, attributes); + } catch (PKCS11Exception e) { + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("unwrap() failed", e); + } + } + + if (isTlsRsaPremasterSecret) { + byte[] replacer = new byte[48]; + if (failover == null) { + // Does smart compiler dispose this operation? + secureRandom.nextBytes(replacer); + } + + TlsRsaPremasterSecretParameterSpec psps = + (TlsRsaPremasterSecretParameterSpec)spec; + + // Please use the tricky failover and replacer byte array + // as the parameters so that smart compiler won't dispose + // the unused variable . + secretKey = polishPreMasterSecretKey(token, s, + failover, replacer, secretKey, + psps.getClientVersion(), psps.getServerVersion()); + } + + return secretKey; + } finally { + token.releaseSession(s); + } } } @@ -475,6 +567,34 @@ final class P11RSACipher extends CipherSpi { int n = P11KeyFactory.convertKey(token, key, algorithm).length(); return n; } + + private static SecretKey polishPreMasterSecretKey( + Token token, Session session, + Exception failover, byte[] replacer, SecretKey secretKey, + int clientVersion, int serverVersion) { + + if (failover != null) { + CK_VERSION version = new CK_VERSION( + (clientVersion >>> 8) & 0xFF, clientVersion & 0xFF); + try { + CK_ATTRIBUTE[] attributes = token.getAttributes( + O_GENERATE, CKO_SECRET_KEY, + CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); + long keyID = token.p11.C_GenerateKey(session.id(), + // new CK_MECHANISM(CKM_TLS_PRE_MASTER_KEY_GEN, version), + new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version), + attributes); + return P11Key.secretKey(session, + keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); + } catch (PKCS11Exception e) { + throw new ProviderException( + "Could not generate premaster secret", e); + } + } + + return secretKey; + } + } final class ConstructKeys { diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java b/jdk/src/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java index ff9b183ee26..21c853794bc 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java @@ -73,7 +73,7 @@ final class P11TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi { protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof TlsRsaPremasterSecretParameterSpec == false) { + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { throw new InvalidAlgorithmParameterException(MSG); } this.spec = (TlsRsaPremasterSecretParameterSpec)params; @@ -83,38 +83,32 @@ final class P11TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi { throw new InvalidParameterException(MSG); } + // Only can be used in client side to generate TLS RSA premaster secret. protected SecretKey engineGenerateKey() { if (spec == null) { throw new IllegalStateException ("TlsRsaPremasterSecretGenerator must be initialized"); } - byte[] b = spec.getEncodedSecret(); - if (b == null) { - CK_VERSION version = new CK_VERSION( + CK_VERSION version = new CK_VERSION( spec.getMajorVersion(), spec.getMinorVersion()); - Session session = null; - try { - session = token.getObjSession(); - CK_ATTRIBUTE[] attributes = token.getAttributes( - O_GENERATE, CKO_SECRET_KEY, - CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); - long keyID = token.p11.C_GenerateKey(session.id(), - new CK_MECHANISM(mechanism, version), attributes); - SecretKey key = P11Key.secretKey(session, - keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); - return key; - } catch (PKCS11Exception e) { - throw new ProviderException( - "Could not generate premaster secret", e); - } finally { - token.releaseSession(session); - } + Session session = null; + try { + session = token.getObjSession(); + CK_ATTRIBUTE[] attributes = token.getAttributes( + O_GENERATE, CKO_SECRET_KEY, + CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); + long keyID = token.p11.C_GenerateKey(session.id(), + new CK_MECHANISM(mechanism, version), attributes); + SecretKey key = P11Key.secretKey(session, + keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); + return key; + } catch (PKCS11Exception e) { + throw new ProviderException( + "Could not generate premaster secret", e); + } finally { + token.releaseSession(session); } - - // Won't worry, the TlsRsaPremasterSecret will be soon converted to - // TlsMasterSecret. - return new SecretKeySpec(b, "TlsRsaPremasterSecret"); } } diff --git a/jdk/src/share/classes/sun/security/pkcs11/Token.java b/jdk/src/share/classes/sun/security/pkcs11/Token.java index b97ab0cc998..39d301ae7b8 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/Token.java +++ b/jdk/src/share/classes/sun/security/pkcs11/Token.java @@ -36,6 +36,7 @@ import javax.security.auth.login.LoginException; import sun.security.jca.JCAUtil; import sun.security.pkcs11.wrapper.*; +import static sun.security.pkcs11.TemplateManager.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; /** @@ -122,6 +123,9 @@ class Token implements Serializable { private final static CK_MECHANISM_INFO INVALID_MECH = new CK_MECHANISM_INFO(0, 0, 0); + // flag indicating whether the token supports raw secret key material import + private Boolean supportsRawSecretKeyImport; + Token(SunPKCS11 provider) throws PKCS11Exception { this.provider = provider; this.removable = provider.removable; @@ -160,6 +164,36 @@ class Token implements Serializable { return writeProtected; } + // return whether the token supports raw secret key material import + boolean supportsRawSecretKeyImport() { + if (supportsRawSecretKeyImport == null) { + SecureRandom random = JCAUtil.getSecureRandom(); + byte[] encoded = new byte[48]; + random.nextBytes(encoded); + + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[3]; + attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY); + attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET); + attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded); + + Session session = null; + try { + attributes = getAttributes(O_IMPORT, + CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes); + session = getObjSession(); + long keyID = p11.C_CreateObject(session.id(), attributes); + + supportsRawSecretKeyImport = Boolean.TRUE; + } catch (PKCS11Exception e) { + supportsRawSecretKeyImport = Boolean.FALSE; + } finally { + releaseSession(session); + } + } + + return supportsRawSecretKeyImport; + } + // return whether we are logged in // uses cached result if current. session is optional and may be null boolean isLoggedIn(Session session) throws PKCS11Exception { diff --git a/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java index 240bc052d47..d816a580ae4 100644 --- a/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java @@ -28,6 +28,7 @@ package sun.security.ssl; import java.io.*; import java.nio.channels.SocketChannel; import java.net.*; +import java.util.Set; import javax.net.ssl.*; @@ -634,6 +635,34 @@ abstract class BaseSSLSocketImpl extends SSLSocket { } } + @Override + public Socket setOption(SocketOption name, + T value) throws IOException { + if (self == this) { + return super.setOption(name, value); + } else { + return self.setOption(name, value); + } + } + + @Override + public T getOption(SocketOption name) throws IOException { + if (self == this) { + return super.getOption(name); + } else { + return self.getOption(name); + } + } + + @Override + public Set> supportedOptions() { + if (self == this) { + return super.supportedOptions(); + } else { + return self.supportedOptions(); + } + } + boolean isLayered() { return (self != this); } diff --git a/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java b/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java index 36e4310fef1..11da51e56d7 100644 --- a/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java +++ b/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java @@ -48,23 +48,6 @@ import sun.security.util.KeyUtil; */ final class RSAClientKeyExchange extends HandshakeMessage { - /** - * The TLS spec says that the version in the RSA premaster secret must - * be the maximum version supported by the client (i.e. the version it - * requested in its client hello version). However, we (and other - * implementations) used to send the active negotiated version. The - * system property below allows to toggle the behavior. - */ - private final static String PROP_NAME = - "com.sun.net.ssl.rsaPreMasterSecretFix"; - - /* - * Default is "false" (old behavior) for compatibility reasons in - * SSLv3/TLSv1. Later protocols (TLSv1.1+) do not use this property. - */ - private final static boolean rsaPreMasterSecretFix = - Debug.getBooleanProperty(PROP_NAME, false); - /* * The following field values were encrypted with the server's public * key (or temp key from server key exchange msg) and are presented @@ -88,22 +71,12 @@ final class RSAClientKeyExchange extends HandshakeMessage { } this.protocolVersion = protocolVersion; - int major, minor; - - if (rsaPreMasterSecretFix || maxVersion.v >= ProtocolVersion.TLS11.v) { - major = maxVersion.major; - minor = maxVersion.minor; - } else { - major = protocolVersion.major; - minor = protocolVersion.minor; - } - try { String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ? "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"); KeyGenerator kg = JsseJce.getKeyGenerator(s); - kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor), - generator); + kg.init(new TlsRsaPremasterSecretParameterSpec( + maxVersion.v, protocolVersion.v), generator); preMaster = kg.generateKey(); Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); @@ -138,18 +111,17 @@ final class RSAClientKeyExchange extends HandshakeMessage { } } - Exception failover = null; - byte[] encoded = null; try { Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); // Cannot generate key here, please don't use Cipher.UNWRAP_MODE! - cipher.init(Cipher.DECRYPT_MODE, privateKey); - encoded = cipher.doFinal(encrypted); - } catch (BadPaddingException bpe) { - failover = bpe; - encoded = null; - } catch (IllegalBlockSizeException ibse) { - // the message it too big to process with RSA + cipher.init(Cipher.UNWRAP_MODE, privateKey, + new TlsRsaPremasterSecretParameterSpec( + maxVersion.v, currentVersion.v), + generator); + preMaster = (SecretKey)cipher.unwrap(encrypted, + "TlsRsaPremasterSecret", Cipher.SECRET_KEY); + } catch (InvalidKeyException ibk) { + // the message is too big to process with RSA throw new SSLProtocolException( "Unable to process PreMasterSecret, may be too big"); } catch (Exception e) { @@ -160,124 +132,6 @@ final class RSAClientKeyExchange extends HandshakeMessage { } throw new RuntimeException("Could not generate dummy secret", e); } - - // polish the premaster secret - preMaster = polishPreMasterSecretKey( - currentVersion, maxVersion, generator, encoded, failover); - } - - /** - * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246, - * treating incorrectly formatted message blocks and/or mismatched - * version numbers in a manner indistinguishable from correctly - * formatted RSA blocks. - * - * RFC 5246 describes the approach as : - * - * 1. Generate a string R of 48 random bytes - * - * 2. Decrypt the message to recover the plaintext M - * - * 3. If the PKCS#1 padding is not correct, or the length of message - * M is not exactly 48 bytes: - * pre_master_secret = R - * else If ClientHello.client_version <= TLS 1.0, and version - * number check is explicitly disabled: - * premaster secret = M - * else If M[0..1] != ClientHello.client_version: - * premaster secret = R - * else: - * premaster secret = M - * - * Note that #2 has completed before the call of this method. - */ - private SecretKey polishPreMasterSecretKey(ProtocolVersion currentVersion, - ProtocolVersion clientHelloVersion, SecureRandom generator, - byte[] encoded, Exception failoverException) { - - this.protocolVersion = clientHelloVersion; - if (generator == null) { - generator = new SecureRandom(); - } - byte[] random = new byte[48]; - generator.nextBytes(random); - - if (failoverException == null && encoded != null) { - // check the length - if (encoded.length != 48) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "incorrect length of premaster secret: " + - encoded.length); - } - - return generatePreMasterSecret( - clientHelloVersion, random, generator); - } - - if (clientHelloVersion.major != encoded[0] || - clientHelloVersion.minor != encoded[1]) { - - if (clientHelloVersion.v <= ProtocolVersion.TLS10.v && - currentVersion.major == encoded[0] && - currentVersion.minor == encoded[1]) { - /* - * For compatibility, we maintain the behavior that the - * version in pre_master_secret can be the negotiated - * version for TLS v1.0 and SSL v3.0. - */ - this.protocolVersion = currentVersion; - } else { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Mismatching Protocol Versions, " + - "ClientHello.client_version is " + - clientHelloVersion + - ", while PreMasterSecret.client_version is " + - ProtocolVersion.valueOf(encoded[0], encoded[1])); - } - - encoded = random; - } - } - - return generatePreMasterSecret( - clientHelloVersion, encoded, generator); - } - - if (debug != null && Debug.isOn("handshake") && - failoverException != null) { - System.out.println("Error decrypting premaster secret:"); - failoverException.printStackTrace(System.out); - } - - return generatePreMasterSecret(clientHelloVersion, random, generator); - } - - // generate a premaster secret with the specified version number - private static SecretKey generatePreMasterSecret( - ProtocolVersion version, byte[] encodedSecret, - SecureRandom generator) { - - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Generating a random fake premaster secret"); - } - - try { - String s = ((version.v >= ProtocolVersion.TLS12.v) ? - "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"); - KeyGenerator kg = JsseJce.getKeyGenerator(s); - kg.init(new TlsRsaPremasterSecretParameterSpec( - version.major, version.minor, encodedSecret), generator); - return kg.generateKey(); - } catch (InvalidAlgorithmParameterException | - NoSuchAlgorithmException iae) { - // unlikely to happen, otherwise, must be a provider exception - if (debug != null && Debug.isOn("handshake")) { - System.out.println("RSA premaster secret generation error:"); - iae.printStackTrace(System.out); - } - throw new RuntimeException("Could not generate dummy secret", iae); - } } @Override diff --git a/jdk/src/share/classes/sun/security/util/KeyUtil.java b/jdk/src/share/classes/sun/security/util/KeyUtil.java index cbaa8a5e23a..9c881b8031c 100644 --- a/jdk/src/share/classes/sun/security/util/KeyUtil.java +++ b/jdk/src/share/classes/sun/security/util/KeyUtil.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 @@ -32,6 +32,7 @@ import java.security.InvalidKeyException; import java.security.interfaces.ECKey; import java.security.interfaces.RSAKey; import java.security.interfaces.DSAKey; +import java.security.SecureRandom; import java.security.spec.KeySpec; import javax.crypto.SecretKey; import javax.crypto.interfaces.DHKey; @@ -156,6 +157,79 @@ public final class KeyUtil { providerName.startsWith("SunPKCS11")); } + /** + * Check the format of TLS PreMasterSecret. + *

+ * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246, + * treating incorrectly formatted message blocks and/or mismatched + * version numbers in a manner indistinguishable from correctly + * formatted RSA blocks. + * + * RFC 5246 describes the approach as : + * + * 1. Generate a string R of 48 random bytes + * + * 2. Decrypt the message to recover the plaintext M + * + * 3. If the PKCS#1 padding is not correct, or the length of message + * M is not exactly 48 bytes: + * pre_master_secret = R + * else If ClientHello.client_version <= TLS 1.0, and version + * number check is explicitly disabled: + * premaster secret = M + * else If M[0..1] != ClientHello.client_version: + * premaster secret = R + * else: + * premaster secret = M + * + * Note that #2 should have completed before the call to this method. + * + * @param clientVersion the version of the TLS protocol by which the + * client wishes to communicate during this session + * @param serverVersion the negotiated version of the TLS protocol which + * contains the lower of that suggested by the client in the client + * hello and the highest supported by the server. + * @param encoded the encoded key in its "RAW" encoding format + * @param isFailover whether or not the previous decryption of the + * encrypted PreMasterSecret message run into problem + * @return the polished PreMasterSecret key in its "RAW" encoding format + */ + public static byte[] checkTlsPreMasterSecretKey( + int clientVersion, int serverVersion, SecureRandom random, + byte[] encoded, boolean isFailOver) { + + if (random == null) { + random = new SecureRandom(); + } + byte[] replacer = new byte[48]; + random.nextBytes(replacer); + + if (!isFailOver && (encoded != null)) { + // check the length + if (encoded.length != 48) { + // private, don't need to clone the byte array. + return replacer; + } + + int encodedVersion = + ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF); + if (clientVersion != encodedVersion) { + if (clientVersion > 0x0301 || // 0x0301: TLSv1 + serverVersion != encodedVersion) { + encoded = replacer; + } // Otherwise, For compatibility, we maintain the behavior + // that the version in pre_master_secret can be the + // negotiated version for TLS v1.0 and SSL v3.0. + } + + // private, don't need to clone the byte array. + return encoded; + } + + // private, don't need to clone the byte array. + return replacer; + } + /** * Returns whether the Diffie-Hellman public key is valid or not. * diff --git a/jdk/src/share/classes/sun/tools/java/Environment.java b/jdk/src/share/classes/sun/tools/java/Environment.java index 51b09dcb736..76f9c01e9a7 100644 --- a/jdk/src/share/classes/sun/tools/java/Environment.java +++ b/jdk/src/share/classes/sun/tools/java/Environment.java @@ -648,6 +648,7 @@ public class Environment implements Constants { * Return true if an implicit cast from this type to * the given type is allowed. */ + @SuppressWarnings("fallthrough") public boolean implicitCast(Type from, Type to) throws ClassNotFound { if (from == to) return true; diff --git a/jdk/src/share/classes/sun/tools/java/Scanner.java b/jdk/src/share/classes/sun/tools/java/Scanner.java index 9152f48b24f..7dfa6ee37c8 100644 --- a/jdk/src/share/classes/sun/tools/java/Scanner.java +++ b/jdk/src/share/classes/sun/tools/java/Scanner.java @@ -511,6 +511,7 @@ class Scanner implements Constants { * Scan a number. The first digit of the number should be the current * character. We may be scanning hex, decimal, or octal at this point */ + @SuppressWarnings("fallthrough") private void scanNumber() throws IOException { boolean seenNonOctal = false; boolean overflow = false; @@ -532,6 +533,7 @@ class Scanner implements Constants { // We can't yet throw an error if reading an octal. We might // discover we're really reading a real. seenNonOctal = true; + // Fall through case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': seenDigit = true; @@ -668,6 +670,7 @@ class Scanner implements Constants { * Scan a float. Should be called with the current character is either * the 'e', 'E' or '.' */ + @SuppressWarnings("fallthrough") private void scanReal() throws IOException { boolean seenExponent = false; boolean isSingleFloat = false; @@ -984,6 +987,7 @@ class Scanner implements Constants { return xscan(); } + @SuppressWarnings("fallthrough") protected long xscan() throws IOException { final ScannerInputReader in = this.in; long retPos = pos; @@ -1006,6 +1010,7 @@ class Scanner implements Constants { token = COMMENT; return retPos; } + // Fall through case ' ': case '\t': case '\f': diff --git a/jdk/src/share/classes/sun/tools/javac/Main.java b/jdk/src/share/classes/sun/tools/javac/Main.java index 2c50e3a3972..94308c5a0f3 100644 --- a/jdk/src/share/classes/sun/tools/javac/Main.java +++ b/jdk/src/share/classes/sun/tools/javac/Main.java @@ -192,6 +192,7 @@ class Main implements Constants { /** * Run the compiler */ + @SuppressWarnings("fallthrough") public synchronized boolean compile(String argv[]) { String sourcePathArg = null; String classPathArg = null; diff --git a/jdk/src/share/classes/sun/tools/jinfo/JInfo.java b/jdk/src/share/classes/sun/tools/jinfo/JInfo.java index c1e9d5ffb82..f02eb27d2e2 100644 --- a/jdk/src/share/classes/sun/tools/jinfo/JInfo.java +++ b/jdk/src/share/classes/sun/tools/jinfo/JInfo.java @@ -41,6 +41,7 @@ import sun.tools.attach.HotSpotVirtualMachine; */ public class JInfo { + @SuppressWarnings("fallthrough") public static void main(String[] args) throws Exception { if (args.length == 0) { usage(1); // no arguments @@ -118,6 +119,7 @@ public class JInfo { case "-help": case "-h": usage(0); + // Fall through default: if (args.length == 1) { // no flags specified, we do -sysprops and -flags diff --git a/jdk/src/share/classes/sun/tools/tree/AssignOpExpression.java b/jdk/src/share/classes/sun/tools/tree/AssignOpExpression.java index fdde301667e..b3493bc7d9a 100644 --- a/jdk/src/share/classes/sun/tools/tree/AssignOpExpression.java +++ b/jdk/src/share/classes/sun/tools/tree/AssignOpExpression.java @@ -53,7 +53,7 @@ class AssignOpExpression extends BinaryAssignExpression { * Select the type * */ - + @SuppressWarnings("fallthrough") final void selectType(Environment env, Context ctx, int tm) { Type rtype = null; // special conversion type for RHS switch(op) { diff --git a/jdk/src/share/classes/sun/tools/tree/NewInstanceExpression.java b/jdk/src/share/classes/sun/tools/tree/NewInstanceExpression.java index cb018a0f51a..0347c41efbf 100644 --- a/jdk/src/share/classes/sun/tools/tree/NewInstanceExpression.java +++ b/jdk/src/share/classes/sun/tools/tree/NewInstanceExpression.java @@ -487,6 +487,7 @@ class NewInstanceExpression extends NaryExpression { public void codeValue(Environment env, Context ctx, Assembler asm) { codeCommon(env, ctx, asm, true); } + @SuppressWarnings("fallthrough") private void codeCommon(Environment env, Context ctx, Assembler asm, boolean forValue) { asm.add(where, opc_new, field.getClassDeclaration()); diff --git a/jdk/src/share/native/java/net/net_util.h b/jdk/src/share/native/java/net/net_util.h index a31d849e0b9..43739a2c498 100644 --- a/jdk/src/share/native/java/net/net_util.h +++ b/jdk/src/share/native/java/net/net_util.h @@ -40,7 +40,7 @@ #define IPv6 2 #define NET_ERROR(env, ex, msg) \ -{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg) } +{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg); } /************************************************************************ * Cached field IDs diff --git a/jdk/src/share/npt/utf.c b/jdk/src/share/npt/utf.c index e4695597bd6..a3b437d346d 100644 --- a/jdk/src/share/npt/utf.c +++ b/jdk/src/share/npt/utf.c @@ -396,7 +396,7 @@ utf8mToUtf8s(struct UtfInst *ui, jbyte *string, int length, jbyte *newString, in /* ================================================================= */ -#if 1 /* Test program */ +#ifdef COMPILE_WITH_UTF_TEST /* Test program */ /* * Convert any byte array into a printable string. diff --git a/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java b/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java index 20bc6fbc394..1779cfb0663 100644 --- a/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java +++ b/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java @@ -25,6 +25,11 @@ package java.net; import java.io.IOException; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; +import jdk.net.*; +import static sun.net.ExtendedOptionsImpl.*; /* * On Unix systems we simply delegate to native methods. @@ -38,6 +43,42 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl init(); } + protected void setOption(SocketOption name, T value) throws IOException { + if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + super.setOption(name, value); + } else { + if (isClosed()) { + throw new SocketException("Socket closed"); + } + checkSetOptionPermission(name); + checkValueType(value, SocketFlow.class); + setFlowOption(getFileDescriptor(), (SocketFlow)value); + } + } + + protected T getOption(SocketOption name) throws IOException { + if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + return super.getOption(name); + } + if (isClosed()) { + throw new SocketException("Socket closed"); + } + checkGetOptionPermission(name); + SocketFlow flow = SocketFlow.create(); + getFlowOption(getFileDescriptor(), flow); + return (T)flow; + } + + protected Set> supportedOptions() { + HashSet> options = new HashSet( + super.supportedOptions()); + + if (flowSupported()) { + options.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + return options; + } + protected synchronized native void bind0(int lport, InetAddress laddr) throws SocketException; diff --git a/jdk/src/solaris/classes/java/net/PlainSocketImpl.java b/jdk/src/solaris/classes/java/net/PlainSocketImpl.java index 4846689a3e2..b0dfd0255dd 100644 --- a/jdk/src/solaris/classes/java/net/PlainSocketImpl.java +++ b/jdk/src/solaris/classes/java/net/PlainSocketImpl.java @@ -26,6 +26,12 @@ package java.net; import java.io.IOException; import java.io.FileDescriptor; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; +import jdk.net.*; + +import static sun.net.ExtendedOptionsImpl.*; /* * On Unix systems we simply delegate to native methods. @@ -51,6 +57,42 @@ class PlainSocketImpl extends AbstractPlainSocketImpl this.fd = fd; } + protected void setOption(SocketOption name, T value) throws IOException { + if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + super.setOption(name, value); + } else { + if (isClosedOrPending()) { + throw new SocketException("Socket closed"); + } + checkSetOptionPermission(name); + checkValueType(value, SocketFlow.class); + setFlowOption(getFileDescriptor(), (SocketFlow)value); + } + } + + protected T getOption(SocketOption name) throws IOException { + if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + return super.getOption(name); + } + if (isClosedOrPending()) { + throw new SocketException("Socket closed"); + } + checkGetOptionPermission(name); + SocketFlow flow = SocketFlow.create(); + getFlowOption(getFileDescriptor(), flow); + return (T)flow; + } + + protected Set> supportedOptions() { + HashSet> options = new HashSet( + super.supportedOptions()); + + if (getSocket() != null && flowSupported()) { + options.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + return options; + } + native void socketCreate(boolean isServer) throws IOException; native void socketConnect(InetAddress address, int port, int timeout) @@ -77,5 +119,4 @@ class PlainSocketImpl extends AbstractPlainSocketImpl native int socketGetOption(int opt, Object iaContainerObj) throws SocketException; native void socketSendUrgentData(int data) throws IOException; - } diff --git a/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c b/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c new file mode 100644 index 00000000000..086ac9f9dc6 --- /dev/null +++ b/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include + +#include "net_util.h" +#include "jdk_net_SocketFlow.h" + +static jclass sf_status_class; /* Status enum type */ + +static jfieldID sf_status; +static jfieldID sf_priority; +static jfieldID sf_bandwidth; + +static jfieldID sf_fd_fdID; /* FileDescriptor.fd */ + +/* References to the literal enum values */ + +static jobject sfs_NOSTATUS; +static jobject sfs_OK; +static jobject sfs_NOPERMISSION; +static jobject sfs_NOTCONNECTED; +static jobject sfs_NOTSUPPORTED; +static jobject sfs_ALREADYCREATED; +static jobject sfs_INPROGRESS; +static jobject sfs_OTHER; + +static jobject getEnumField(JNIEnv *env, char *name); +static void setStatus(JNIEnv *env, jobject obj, int errval); + +/* OS specific code is implemented in these three functions */ + +static jboolean flowSupported0() ; + +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init + (JNIEnv *env, jclass UNUSED) +{ + static int initialized = 0; + jclass c; + + /* Global class references */ + + if (initialized) { + return; + } + + c = (*env)->FindClass(env, "jdk/net/SocketFlow$Status"); + CHECK_NULL(c); + sf_status_class = (*env)->NewGlobalRef(env, c); + CHECK_NULL(sf_status_class); + + /* int "fd" field of java.io.FileDescriptor */ + + c = (*env)->FindClass(env, "java/io/FileDescriptor"); + CHECK_NULL(c); + sf_fd_fdID = (*env)->GetFieldID(env, c, "fd", "I"); + CHECK_NULL(sf_fd_fdID); + + + /* SocketFlow fields */ + + c = (*env)->FindClass(env, "jdk/net/SocketFlow"); + + /* status */ + + sf_status = (*env)->GetFieldID(env, c, "status", + "Ljdk/net/SocketFlow$Status;"); + CHECK_NULL(sf_status); + + /* priority */ + + sf_priority = (*env)->GetFieldID(env, c, "priority", "I"); + CHECK_NULL(sf_priority); + + /* bandwidth */ + + sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J"); + CHECK_NULL(sf_bandwidth); + + /* Initialize the static enum values */ + + sfs_NOSTATUS = getEnumField(env, "NO_STATUS"); + CHECK_NULL(sfs_NOSTATUS); + sfs_OK = getEnumField(env, "OK"); + CHECK_NULL(sfs_OK); + sfs_NOPERMISSION = getEnumField(env, "NO_PERMISSION"); + CHECK_NULL(sfs_NOPERMISSION); + sfs_NOTCONNECTED = getEnumField(env, "NOT_CONNECTED"); + CHECK_NULL(sfs_NOTCONNECTED); + sfs_NOTSUPPORTED = getEnumField(env, "NOT_SUPPORTED"); + CHECK_NULL(sfs_NOTSUPPORTED); + sfs_ALREADYCREATED = getEnumField(env, "ALREADY_CREATED"); + CHECK_NULL(sfs_ALREADYCREATED); + sfs_INPROGRESS = getEnumField(env, "IN_PROGRESS"); + CHECK_NULL(sfs_INPROGRESS); + sfs_OTHER = getEnumField(env, "OTHER"); + CHECK_NULL(sfs_OTHER); + initialized = JNI_TRUE; +} + +static jobject getEnumField(JNIEnv *env, char *name) +{ + jobject f; + jfieldID fID = (*env)->GetStaticFieldID(env, sf_status_class, name, + "Ljdk/net/SocketFlow$Status;"); + CHECK_NULL_RETURN(fID, NULL); + + f = (*env)->GetStaticObjectField(env, sf_status_class, fID); + CHECK_NULL_RETURN(f, NULL); + f = (*env)->NewGlobalRef(env, f); + CHECK_NULL_RETURN(f, NULL); + return f; +} + +/* + * Retrieve the int file-descriptor from a public socket type object. + * Gets impl, then the FileDescriptor from the impl, and then the fd + * from that. + */ +static int getFD(JNIEnv *env, jobject fileDesc) { + return (*env)->GetIntField(env, fileDesc, sf_fd_fdID); +} + +/** + * Sets the status field of a SocketFlow to one of the + * canned enum values + */ +static void setStatus (JNIEnv *env, jobject obj, int errval) +{ + switch (errval) { + case 0: /* OK */ + (*env)->SetObjectField(env, obj, sf_status, sfs_OK); + break; + case EPERM: + (*env)->SetObjectField(env, obj, sf_status, sfs_NOPERMISSION); + break; + case ENOTCONN: + (*env)->SetObjectField(env, obj, sf_status, sfs_NOTCONNECTED); + break; + case EOPNOTSUPP: + (*env)->SetObjectField(env, obj, sf_status, sfs_NOTSUPPORTED); + break; + case EALREADY: + (*env)->SetObjectField(env, obj, sf_status, sfs_ALREADYCREATED); + break; + case EINPROGRESS: + (*env)->SetObjectField(env, obj, sf_status, sfs_INPROGRESS); + break; + default: + (*env)->SetObjectField(env, obj, sf_status, sfs_OTHER); + break; + } +} + +#ifdef __solaris__ + +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: setFlowOption + * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V + */ +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + int fd = getFD(env, fileDesc); + + if (fd < 0) { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); + return; + } else { + sock_flow_props_t props; + jlong bandwidth; + int rv; + + jint priority = (*env)->GetIntField(env, flow, sf_priority); + memset(&props, 0, sizeof(props)); + props.sfp_version = SOCK_FLOW_PROP_VERSION1; + + if (priority != jdk_net_SocketFlow_UNSET) { + props.sfp_mask |= SFP_PRIORITY; + props.sfp_priority = priority; + } + bandwidth = (*env)->GetLongField(env, flow, sf_bandwidth); + if (bandwidth > -1) { + props.sfp_mask |= SFP_MAXBW; + props.sfp_maxbw = (uint64_t) bandwidth; + } + rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", + "set option SO_FLOW_SLA failed"); + } + return; + } + setStatus(env, flow, props.sfp_status); + } +} + +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: getFlowOption + * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V + */ +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + int fd = getFD(env, fileDesc); + + if (fd < 0) { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); + return; + } else { + sock_flow_props_t props; + int status; + socklen_t sz = sizeof(props); + + int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz); + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", + "set option SO_FLOW_SLA failed"); + } + return; + } + /* first check status to see if flow exists */ + status = props.sfp_status; + setStatus(env, flow, status); + if (status == 0) { /* OK */ + /* can set the other fields now */ + if (props.sfp_mask & SFP_PRIORITY) { + (*env)->SetIntField(env, flow, sf_priority, props.sfp_priority); + } + if (props.sfp_mask & SFP_MAXBW) { + (*env)->SetLongField(env, flow, sf_bandwidth, + (jlong)props.sfp_maxbw); + } + } + } +} + +static jboolean flowsupported; +static jboolean flowsupported_set = JNI_FALSE; + +static jboolean flowSupported0() +{ + /* Do a simple dummy call, and try to figure out from that */ + sock_flow_props_t props; + int rv, s; + if (flowsupported_set) { + return flowsupported; + } + s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s < 0) { + flowsupported = JNI_FALSE; + flowsupported_set = JNI_TRUE; + return JNI_FALSE; + } + memset(&props, 0, sizeof(props)); + props.sfp_version = SOCK_FLOW_PROP_VERSION1; + props.sfp_mask |= SFP_PRIORITY; + props.sfp_priority = SFP_PRIO_NORMAL; + rv = setsockopt(s, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); + if (rv != 0 && errno == ENOPROTOOPT) { + rv = JNI_FALSE; + } else { + rv = JNI_TRUE; + } + close(s); + flowsupported = rv; + flowsupported_set = JNI_TRUE; + return flowsupported; +} + +#else /* __solaris__ */ + +/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */ + +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); +} + +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); +} + +static jboolean flowSupported0() { + return JNI_FALSE; +} + +#endif /* __solaris__ */ + +JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported + (JNIEnv *env, jclass UNUSED) +{ + return flowSupported0(); +} diff --git a/jdk/src/solaris/native/java/net/net_util_md.h b/jdk/src/solaris/native/java/net/net_util_md.h index e7150da6018..31ed3f808eb 100644 --- a/jdk/src/solaris/native/java/net/net_util_md.h +++ b/jdk/src/solaris/native/java/net/net_util_md.h @@ -107,6 +107,47 @@ int getDefaultIPv6Interface(struct in6_addr *target_addr); #ifdef __solaris__ int net_getParam(char *driver, char *param); + +#ifndef SO_FLOW_SLA +#define SO_FLOW_SLA 0x1018 + +#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 +#pragma pack(4) #endif +/* + * Used with the setsockopt(SO_FLOW_SLA, ...) call to set + * per socket service level properties. + * When the application uses per-socket API, we will enforce the properties + * on both outbound and inbound packets. + * + * For now, only priority and maxbw are supported in SOCK_FLOW_PROP_VERSION1. + */ +typedef struct sock_flow_props_s { + int sfp_version; + uint32_t sfp_mask; + int sfp_priority; /* flow priority */ + uint64_t sfp_maxbw; /* bandwidth limit in bps */ + int sfp_status; /* flow create status for getsockopt */ +} sock_flow_props_t; + +#define SOCK_FLOW_PROP_VERSION1 1 + +/* bit mask values for sfp_mask */ +#define SFP_MAXBW 0x00000001 /* Flow Bandwidth Limit */ +#define SFP_PRIORITY 0x00000008 /* Flow priority */ + +/* possible values for sfp_priority */ +#define SFP_PRIO_NORMAL 1 +#define SFP_PRIO_HIGH 2 + +#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 +#pragma pack() +#endif /* _LONG_LONG_ALIGNMENT */ + +#endif /* SO_FLOW_SLA */ +#endif /* __solaris__ */ + +JNIEXPORT jboolean JNICALL NET_IsFlowSupported(); + #endif /* NET_UTILS_MD_H */ diff --git a/jdk/src/windows/classes/sun/print/Win32PrintService.java b/jdk/src/windows/classes/sun/print/Win32PrintService.java index b8b4dfda1b5..6ddbdba969f 100644 --- a/jdk/src/windows/classes/sun/print/Win32PrintService.java +++ b/jdk/src/windows/classes/sun/print/Win32PrintService.java @@ -1585,7 +1585,7 @@ public class Win32PrintService implements PrintService, AttributeUpdater, if (flavor != null && !isDocFlavorSupported(flavor)) { throw new IllegalArgumentException("flavor " + flavor + - "is not supported"); + " is not supported"); } if (attributes == null) { diff --git a/jdk/src/windows/classes/sun/security/mscapi/RSACipher.java b/jdk/src/windows/classes/sun/security/mscapi/RSACipher.java index 7ab29629a18..023725b6205 100644 --- a/jdk/src/windows/classes/sun/security/mscapi/RSACipher.java +++ b/jdk/src/windows/classes/sun/security/mscapi/RSACipher.java @@ -35,6 +35,8 @@ import javax.crypto.*; import javax.crypto.spec.*; import sun.security.rsa.RSAKeyFactory; +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; +import sun.security.util.KeyUtil; /** * RSA cipher implementation using the Microsoft Crypto API. @@ -92,9 +94,16 @@ public final class RSACipher extends CipherSpi { // the public key, if we were initialized using a public key private sun.security.mscapi.Key publicKey; + // the private key, if we were initialized using a private key private sun.security.mscapi.Key privateKey; + // cipher parameter for TLS RSA premaster secret + private AlgorithmParameterSpec spec = null; + + // the source of randomness + private SecureRandom random; + public RSACipher() { paddingType = PAD_PKCS1; } @@ -155,8 +164,12 @@ public final class RSACipher extends CipherSpi { throws InvalidKeyException, InvalidAlgorithmParameterException { if (params != null) { - throw new InvalidAlgorithmParameterException - ("Parameters not supported"); + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); + } + spec = params; + this.random = random; // for TLS RSA premaster secret } init(opmode, key); } @@ -356,39 +369,47 @@ public final class RSACipher extends CipherSpi { } // see JCE spec - protected java.security.Key engineUnwrap(byte[] wrappedKey, String algorithm, + protected java.security.Key engineUnwrap(byte[] wrappedKey, + String algorithm, int type) throws InvalidKeyException, NoSuchAlgorithmException { if (wrappedKey.length > buffer.length) { throw new InvalidKeyException("Key is too long for unwrapping"); } + + boolean isTlsRsaPremasterSecret = + algorithm.equals("TlsRsaPremasterSecret"); + Exception failover = null; + byte[] encoded = null; + update(wrappedKey, 0, wrappedKey.length); - try { - byte[] encoding = doFinal(); - - switch (type) { - case Cipher.PUBLIC_KEY: - return constructPublicKey(encoding, algorithm); - - case Cipher.PRIVATE_KEY: - return constructPrivateKey(encoding, algorithm); - - case Cipher.SECRET_KEY: - return constructSecretKey(encoding, algorithm); - - default: - throw new InvalidKeyException("Unknown key type " + type); - } - + encoded = doFinal(); } catch (BadPaddingException e) { - // should not occur - throw new InvalidKeyException("Unwrapping failed", e); - + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("Unwrapping failed", e); + } } catch (IllegalBlockSizeException e) { // should not occur, handled with length check above throw new InvalidKeyException("Unwrapping failed", e); } + + if (isTlsRsaPremasterSecret) { + if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + encoded = KeyUtil.checkTlsPreMasterSecretKey( + ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(), + ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(), + random, encoded, (failover != null)); + } + + return constructKey(encoded, algorithm, type); } // see JCE spec @@ -452,6 +473,22 @@ public final class RSACipher extends CipherSpi { return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); } + private static Key constructKey(byte[] encodedKey, + String encodedKeyAlgorithm, + int keyType) throws InvalidKeyException, NoSuchAlgorithmException { + + switch (keyType) { + case Cipher.PUBLIC_KEY: + return constructPublicKey(encodedKey, encodedKeyAlgorithm); + case Cipher.PRIVATE_KEY: + return constructPrivateKey(encodedKey, encodedKeyAlgorithm); + case Cipher.SECRET_KEY: + return constructSecretKey(encodedKey, encodedKeyAlgorithm); + default: + throw new InvalidKeyException("Unknown key type " + keyType); + } + } + /* * Encrypt/decrypt a data buffer using Microsoft Crypto API with HCRYPTKEY. * It expects and returns ciphertext data in big-endian form. diff --git a/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c b/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c new file mode 100644 index 00000000000..2bd955cd13e --- /dev/null +++ b/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c @@ -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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include + +#include "net_util.h" + +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init + (JNIEnv *env, jclass UNUSED) +{ +} + +/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */ + +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); +} + +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); +} + +static jboolean flowSupported0() { + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported + (JNIEnv *env, jclass UNUSED) +{ + return JNI_FALSE; +} diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 729a0d852dd..2b18741c05b 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -273,4 +273,7 @@ java/lang/instrument/NativeMethodPrefixAgent.java generic-all # 8031482 sun/tools/jcmd/TestJcmdSanity.java windows-all +# 8033104 +sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all + ############################################################################ diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index 8e45f1998f7..1d5895044da 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -102,8 +102,8 @@ jdk_nio = \ jdk_net = \ java/net \ com/sun/net/httpserver \ - com/oracle/net \ - sun/net + sun/net \ + jdk/net jdk_time = \ java/time @@ -285,7 +285,7 @@ jdk_stable = \ javax/accessibility \ com/sun/java/swing \ sun/pisces \ - com/sun/awt + com/sun/awt ############################################################################### @@ -295,7 +295,7 @@ jdk_stable = \ # - compact1, compact2, compact3, full JRE, JDK # # In addition they support testing of the minimal VM on compact1 and compact2. -# Essentially this defines groups based around the specified API's and VM +# Essentially this defines groups based around the specified API's and VM # services available in the runtime. # # The groups are defined hierarchically in two forms: @@ -507,7 +507,7 @@ compact2 = \ -:needs_jdk # Tests that require compact2 API's and a full VM -# +# needs_full_vm_compact2 = # Minimal VM on Compact 2 adds in some compact2 tests @@ -591,7 +591,7 @@ needs_compact2 = \ javax/crypto/Cipher/CipherStreamClose.java \ sun/misc/URLClassPath/ClassnameCharTest.java \ sun/net/www/protocol/https/HttpsURLConnection/HttpsCreateSockTest.java \ - sun/net/www/protocol/https/HttpsURLConnection/HttpsSocketFacTest.java + sun/net/www/protocol/https/HttpsURLConnection/HttpsSocketFacTest.java # Compact 1 adds full VM tests # diff --git a/jdk/test/com/oracle/net/Sanity.java b/jdk/test/com/oracle/net/Sanity.java deleted file mode 100644 index c4c97152779..00000000000 --- a/jdk/test/com/oracle/net/Sanity.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import com.oracle.net.Sdp; - -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.*; - -/** - * Exercise com.oracle.net.Sdp with each IP address plumbed to InfiniBand - * interfaces listed in a given file. - */ - -public class Sanity { - public static void main(String[] args) throws Exception { - // The file is a list of interfaces to test. - Scanner s = new Scanner(new File(args[0])); - try { - while (s.hasNextLine()) { - String link = s.nextLine(); - NetworkInterface ni = NetworkInterface.getByName(link); - if (ni != null) { - Enumeration addrs = ni.getInetAddresses(); - while (addrs.hasMoreElements()) { - InetAddress addr = addrs.nextElement(); - System.out.format("Testing %s: %s\n", link, addr.getHostAddress()); - test(addr); - } - } - } - } finally { - s.close(); - } - } - - static void test(InetAddress addr) throws Exception { - // Test SocketChannel and ServerSocketChannel - ServerSocketChannel ssc = Sdp.openServerSocketChannel(); - try { - ssc.socket().bind(new InetSocketAddress(addr, 0)); - int port = ssc.socket().getLocalPort(); - - // SocketChannel.connect (implicit bind) - SocketChannel client = Sdp.openSocketChannel(); - try { - client.connect(new InetSocketAddress(addr, port)); - SocketChannel peer = ssc.accept(); - try { - testConnection(Channels.newOutputStream(client), - Channels.newInputStream(peer)); - } finally { - peer.close(); - } - } finally { - client.close(); - } - - // SocketChannel.connect (explicit bind) - client = Sdp.openSocketChannel(); - try { - client.socket().bind(new InetSocketAddress(addr, 0)); - client.connect(new InetSocketAddress(addr, port)); - ssc.accept().close(); - } finally { - client.close(); - } - } finally { - ssc.close(); - } - - // Test Socket and ServerSocket - ServerSocket ss = Sdp.openServerSocket(); - try { - ss.bind(new InetSocketAddress(addr, 0)); - int port = ss.getLocalPort(); - - // Socket.connect (implicit bind) - Socket s = Sdp.openSocket(); - try { - s.connect(new InetSocketAddress(addr, port)); - Socket peer = ss.accept(); - try { - testConnection(s.getOutputStream(), peer.getInputStream()); - } finally { - peer.close(); - } - } finally { - s.close(); - } - - // Socket.connect (explicit bind) - s = Sdp.openSocket(); - try { - s.bind(new InetSocketAddress(addr, 0)); - s.connect(new InetSocketAddress(addr, port)); - ss.accept().close(); - } finally { - s.close(); - } - } finally { - ss.close(); - } - } - - static void testConnection(OutputStream out, InputStream in) - throws IOException - { - byte[] msg = "hello".getBytes(); - out.write(msg); - - byte[] ba = new byte[100]; - int nread = 0; - while (nread < msg.length) { - int n = in.read(ba); - if (n < 0) - throw new IOException("EOF not expected!"); - nread += n; - } - } -} diff --git a/jdk/test/com/oracle/net/sanity.sh b/jdk/test/com/oracle/net/sanity.sh deleted file mode 100644 index b4c26acce02..00000000000 --- a/jdk/test/com/oracle/net/sanity.sh +++ /dev/null @@ -1,66 +0,0 @@ -# -# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# @test -# @bug 6965072 -# @summary Unit test for SDP support -# @build Sanity -# @run shell sanity.sh - -IB_LINKS=ib.links - -OS=`uname -s` -case "$OS" in - SunOS ) - /usr/sbin/dladm show-part -o LINK -p > ${IB_LINKS} - if [ $? != 0 ]; then - echo "Unable to get InfiniBand parition link information" - exit 0 - fi - ;; - Linux ) - if [ ! -f /proc/net/sdp ]; then - echo "InfiniBand SDP module not installed" - exit 0 - fi - egrep "^[ \t]+ib" /proc/net/dev|cut -d':' -f1|tr -d '\t ' > ${IB_LINKS} - ;; - * ) - echo "This test only runs on Solaris or Linux" - exit 0 - ;; -esac - -if [ -z "$TESTJAVA" ]; then - JAVA=java - TESTCLASSES=. - TESTSRC=. -else - JAVA="${TESTJAVA}/bin/java" -fi - -CLASSPATH=${TESTCLASSES}:${TESTSRC} -export CLASSPATH - -# Run sanity test (IPv4-only for now) -$JAVA ${TESTVMOPTS} -Djava.net.preferIPv4Stack=true Sanity ${IB_LINKS} diff --git a/jdk/test/com/sun/crypto/provider/TLS/TestPremaster.java b/jdk/test/com/sun/crypto/provider/TLS/TestPremaster.java index bbbfbb6bdb3..f19e7546ddd 100644 --- a/jdk/test/com/sun/crypto/provider/TLS/TestPremaster.java +++ b/jdk/test/com/sun/crypto/provider/TLS/TestPremaster.java @@ -33,6 +33,7 @@ import java.security.Provider; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import java.util.Formatter; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; @@ -52,27 +53,51 @@ public class TestPremaster { System.out.println("OK: " + e); } - test(kg, 3, 0); - test(kg, 3, 1); - test(kg, 3, 2); - test(kg, 4, 0); + int[] protocolVersions = {0x0300, 0x0301, 0x0302, 0x0400}; + for (int clientVersion : protocolVersions) { + for (int serverVersion : protocolVersions) { + test(kg, clientVersion, serverVersion); + if (serverVersion >= clientVersion) { + break; + } + } + } System.out.println("Done."); } - private static void test(KeyGenerator kg, int major, int minor) - throws Exception { + private static void test(KeyGenerator kg, + int clientVersion, int serverVersion) throws Exception { + + System.out.printf( + "Testing RSA pre-master secret key generation between " + + "client (0x%04X) and server(0x%04X)%n", + clientVersion, serverVersion); + kg.init(new TlsRsaPremasterSecretParameterSpec( + clientVersion, serverVersion)); - kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor)); SecretKey key = kg.generateKey(); byte[] encoded = key.getEncoded(); - if (encoded.length != 48) { - throw new Exception("length: " + encoded.length); - } - if ((encoded[0] != major) || (encoded[1] != minor)) { - throw new Exception("version mismatch: " + encoded[0] + - "." + encoded[1]); - } - System.out.println("OK: " + major + "." + minor); + if (encoded != null) { // raw key material may be not extractable + if (encoded.length != 48) { + throw new Exception("length: " + encoded.length); + } + int v = versionOf(encoded[0], encoded[1]); + if (clientVersion != v) { + if (serverVersion != v || clientVersion >= 0x0302) { + throw new Exception(String.format( + "version mismatch: (0x%04X) rather than (0x%04X) " + + "is used in pre-master secret", v, clientVersion)); + } + System.out.printf("Use compatible version (0x%04X)%n", v); + } + System.out.println("Passed, version matches!"); + } else { + System.out.println("Raw key material is not extractable"); + } + } + + private static int versionOf(int major, int minor) { + return ((major & 0xFF) << 8) | (minor & 0xFF); } } diff --git a/jdk/test/com/sun/jdi/ShellScaffold.sh b/jdk/test/com/sun/jdi/ShellScaffold.sh index 16c41eae056..193aabcb907 100644 --- a/jdk/test/com/sun/jdi/ShellScaffold.sh +++ b/jdk/test/com/sun/jdi/ShellScaffold.sh @@ -199,30 +199,26 @@ findPid() return 1 fi - if [ -z "$isWin98" ] ; then - if [ "$osname" = SunOS ] ; then - # Solaris and OpenSolaris use pgrep and not ps in psCmd - findPidCmd="$psCmd" - elif [ "$osname" = AIX ] ; then - findPidCmd="$psCmd" - else + case "$osname" in + SunOS | AIX) + $psCmd | $grep '^ *'"$1 " > $devnull 2>&1 + res=$? + ;; + Windows* | CYGWIN*) + # Don't use ps on cygwin since it sometimes misses + # some processes (!). + tasklist /NH | $grep " $1 " > $devnull 2>&1 + res=$? + ;; + *) # Never use plain 'ps', which requires a "controlling terminal" # and will fail with a "ps: no controlling terminal" error. # Running under 'rsh' will cause this ps error. - # cygwin ps puts an I in column 1 for some reason. - findPidCmd="$psCmd -e" - fi - $findPidCmd | $grep '^I* *'"$1 " > $devnull 2>&1 - return $? - fi - - # mks 6.2a on win98 has $! getting a negative - # number and in ps, it shows up as 0x... - # Thus, we can't search in ps output for - # PIDs gotten via $! - # We don't know if it is running or not - assume it is. - # We don't really care about win98 anymore. - return 0 + $psCmd -e | $grep '^ *'"$1 " > $devnull 2>&1 + res=$? + ;; + esac + return $res } setup() @@ -252,16 +248,10 @@ setup() ulimitCmd= osname=`uname -s` - isWin98= isCygwin= case "$osname" in Windows* | CYGWIN*) devnull=NUL - if [ "$osname" = Windows_98 -o "$osname" = Windows_ME ]; then - isWin98=1 - debuggeeKeyword='we_cant_kill_debuggees_on_win98' - jdbKeyword='jdb\.exe' - fi case "$osname" in CYGWIN*) isCygwin=1 @@ -772,7 +762,7 @@ waitForJdbMsg() sleep ${sleep_seconds} findPid $topPid if [ $? != 0 ] ; then - # Top process is dead. We better die too + echo "--Top process ($topPid) is dead. We better die too" >&2 dojstack exit 1 fi @@ -977,19 +967,12 @@ waitForFinish() break fi - if [ ! -z "$isWin98" ] ; then - $psCmd | $grep -i 'JDB\.EXE' >$devnull 2>&1 - if [ $? != 0 ] ; then - break - fi - fi - # (Don't use jdbFailIfPresent here since it is not safe # to call from different processes) - $grep -s 'Input stream closed' $jdbOutFile > $devnull 2>&1 - if [ $? = 0 ] ; then + $grep -s 'Input stream closed' $jdbOutFile > $devnull 2>&1 + if [ $? = 0 ] ; then dofail "jdb input stream closed prematurely" - fi + fi # If a failure has occured, quit if [ -r "$failFile" ] ; then diff --git a/jdk/test/com/sun/jdi/SimulResumerTest.java b/jdk/test/com/sun/jdi/SimulResumerTest.java index f652494be45..83e74cb7cb4 100644 --- a/jdk/test/com/sun/jdi/SimulResumerTest.java +++ b/jdk/test/com/sun/jdi/SimulResumerTest.java @@ -177,12 +177,18 @@ public class SimulResumerTest extends TestScaffold { List frames = thr.frames(); // no failure return value here; could cause an NPE - int nframes = frames.size(); - if (nframes > 0) { - // hmm, how could it ever be 0? - kind = "frames(0, size - 1)"; + kind = "frames(0, size - 1)"; System.out.println("kind = " + kind); - thr.frames(0, frames.size() - 1); + int nframes = frames.size(); + while (nframes > 0) { + try { + thr.frames(0, nframes - 1); + break; + } catch (IndexOutOfBoundsException iobe) { + // 6815126. let's try to get less frames + iobe.printStackTrace(); + nframes--; + } } kind = "frameCount()"; diff --git a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java index 638b053f086..01a8a3b47c4 100644 --- a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java +++ b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java @@ -64,6 +64,11 @@ public class LowMemoryTest2 { // low memory notification static class BoundlessLoaderThread extends ClassLoader implements Runnable { + private final List pools; + + public BoundlessLoaderThread(List pools) { + this.pools = pools; + } static int count = 100000; @@ -139,26 +144,29 @@ public class LowMemoryTest2 { * Then wait for the memory threshold notification to be received. */ public void run() { - List pools = ManagementFactory.getMemoryPoolMXBeans(); - boolean thresholdExceeded = false; - // Load classes until MemoryPoolMXBean.getUsageThresholdCount() > 0 - while (!thresholdExceeded) { - // the classes are small so we load 10 at a time - for (int i=0; i<10; i++) { - loadNext(); - } - - // check if the threshold has been exceeded - for (MemoryPoolMXBean p : pools) { - if (p.getType() == MemoryType.NON_HEAP && - p.isUsageThresholdSupported() && - p.getUsageThresholdCount() > 0) - { - thresholdExceeded = true; - break; + boolean isThresholdCountSet = false; + try { + while (!isThresholdCountSet) { + // the classes are small so we load 10 at a time + for (int i=0; i<10; i++) { + loadNext(); } + + if (isAnyUsageAboveThreshold(pools)) { + // UsageThresholdCount is only updated during GC. + // Force GC to update counters. + // If we don't force a GC we may get an + // OutOfMemoryException before the counters are updated. + System.out.println("Force GC"); + System.gc(); + } + isThresholdCountSet = isAnyThresholdCountSet(pools); } + } catch (OutOfMemoryError e) { + e.printStackTrace(); + MemoryUtil.printMemoryPools(pools); + throw e; } System.out.println("thresholdExceeded. Waiting for notification"); @@ -168,16 +176,39 @@ public class LowMemoryTest2 { } catch (InterruptedException x) {} } } + + private boolean isAnyUsageAboveThreshold(List pools) { + for (MemoryPoolMXBean p : pools) { + if (p.isUsageThresholdExceeded()) { + System.out.println("isAnyUsageAboveThreshold is true for " + p.getName()); + MemoryUtil.printMemoryPool(p); + return true; + } + } + return false; + } + + private boolean isAnyThresholdCountSet(List pools) { + for (MemoryPoolMXBean p : pools) { + if (p.getUsageThresholdCount() > 0) { + System.out.println("isAnyThresholdCountSet is true for " + p.getName()); + MemoryUtil.printMemoryPool(p); + return true; + } + } + return false; + } } public static void main(String args[]) { - List pools = ManagementFactory.getMemoryPoolMXBeans(); + // The pools list will only contain the pools that we are interested in. + List pools = new ArrayList(); // Set threshold of 80% of all NON_HEAP memory pools // In the Hotspot implementation this means we should get a notification // if the CodeCache or metaspace fills up. - for (MemoryPoolMXBean p : pools) { + for (MemoryPoolMXBean p : ManagementFactory.getMemoryPoolMXBeans()) { if (p.getType() == MemoryType.NON_HEAP && p.isUsageThresholdSupported()) { // set threshold @@ -190,6 +221,7 @@ public class LowMemoryTest2 { long threshold = (max * 80) / 100; p.setUsageThreshold(threshold); + pools.add(p); System.out.println("Selected memory pool for low memory " + "detection."); @@ -209,7 +241,7 @@ public class LowMemoryTest2 { // Start the thread loading classes - Thread thr = new Thread(new BoundlessLoaderThread()); + Thread thr = new Thread(new BoundlessLoaderThread(pools)); thr.start(); // Wait for the thread to terminate diff --git a/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java b/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java index f6b88ab59e1..55605c6c1c4 100644 --- a/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java +++ b/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java @@ -54,6 +54,8 @@ public class MemoryUtil { pool.getUsage()); System.out.println(INDENT + "Threshold: " + (pool.isUsageThresholdSupported() ? pool.getUsageThreshold() : -1)); + System.out.println(INDENT + "ThresholdCount: " + + (pool.isUsageThresholdSupported() ? pool.getUsageThresholdCount() : -1)); System.out.print(INDENT + "Manager = ["); String[] mgrs = pool.getMemoryManagerNames(); for (int i = 0; i < mgrs.length; i++) { diff --git a/jdk/test/java/net/SocketOption/OptionsTest.java b/jdk/test/java/net/SocketOption/OptionsTest.java new file mode 100644 index 00000000000..f0952fc8377 --- /dev/null +++ b/jdk/test/java/net/SocketOption/OptionsTest.java @@ -0,0 +1,244 @@ +/* + * 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 8036979 + * @run main/othervm -Xcheck:jni OptionsTest + */ + +import java.net.*; +import java.util.*; + +public class OptionsTest { + + static class Test { + Test(SocketOption option, Object testValue) { + this.option = option; + this.testValue = testValue; + } + static Test create (SocketOption option, Object testValue) { + return new Test(option, testValue); + } + Object option; + Object testValue; + }; + + // The tests set the option using the new API, read back the set value + // which could be diferent, and then use the legacy get API to check + // these values are the same + + static Test[] socketTests = new Test[] { + Test.create(StandardSocketOptions.SO_KEEPALIVE, Boolean.TRUE), + Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)), + Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), + Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), + Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(80)), + Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)) + }; + + static Test[] serverSocketTests = new Test[] { + Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), + Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE) + }; + + static Test[] dgSocketTests = new Test[] { + Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)), + Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), + Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), + Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)) + }; + + static Test[] mcSocketTests = new Test[] { + Test.create(StandardSocketOptions.IP_MULTICAST_IF, getNetworkInterface()), + Test.create(StandardSocketOptions.IP_MULTICAST_TTL, Integer.valueOf(10)), + Test.create(StandardSocketOptions.IP_MULTICAST_LOOP, Boolean.TRUE) + }; + + static NetworkInterface getNetworkInterface() { + try { + Enumeration nifs = NetworkInterface.getNetworkInterfaces(); + if (nifs.hasMoreElements()) { + return (NetworkInterface)nifs.nextElement(); + } + } catch (Exception e) { + } + return null; + } + + static void doSocketTests() throws Exception { + try ( + ServerSocket srv = new ServerSocket(0); + Socket c = new Socket("127.0.0.1", srv.getLocalPort()); + Socket s = srv.accept(); + ) { + for (int i=0; i type, Object s, Object option) + + throws Exception + { + if (type.equals(Socket.class)) { + Socket socket = (Socket)s; + + if (option.equals(StandardSocketOptions.SO_KEEPALIVE)) { + return Boolean.valueOf(socket.getKeepAlive()); + } else if (option.equals(StandardSocketOptions.SO_SNDBUF)) { + return Integer.valueOf(socket.getSendBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) { + return Integer.valueOf(socket.getReceiveBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { + return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.SO_LINGER)) { + return Integer.valueOf(socket.getSoLinger()); + } else if (option.equals(StandardSocketOptions.IP_TOS)) { + return Integer.valueOf(socket.getTrafficClass()); + } else if (option.equals(StandardSocketOptions.TCP_NODELAY)) { + return Boolean.valueOf(socket.getTcpNoDelay()); + } else { + throw new RuntimeException("unexecpted socket option"); + } + } else if (type.equals(ServerSocket.class)) { + ServerSocket socket = (ServerSocket)s; + if (option.equals(StandardSocketOptions.SO_RCVBUF)) { + return Integer.valueOf(socket.getReceiveBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { + return Boolean.valueOf(socket.getReuseAddress()); + } else { + throw new RuntimeException("unexecpted socket option"); + } + } else if (type.equals(DatagramSocket.class)) { + DatagramSocket socket = (DatagramSocket)s; + + if (option.equals(StandardSocketOptions.SO_SNDBUF)) { + return Integer.valueOf(socket.getSendBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) { + return Integer.valueOf(socket.getReceiveBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { + return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.IP_TOS)) { + return Integer.valueOf(socket.getTrafficClass()); + } else { + throw new RuntimeException("unexecpted socket option"); + } + + } else if (type.equals(MulticastSocket.class)) { + MulticastSocket socket = (MulticastSocket)s; + + if (option.equals(StandardSocketOptions.SO_SNDBUF)) { + return Integer.valueOf(socket.getSendBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) { + return Integer.valueOf(socket.getReceiveBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { + return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.IP_TOS)) { + return Integer.valueOf(socket.getTrafficClass()); + } else if (option.equals(StandardSocketOptions.IP_MULTICAST_IF)) { + return socket.getNetworkInterface(); + } else if (option.equals(StandardSocketOptions.IP_MULTICAST_TTL)) { + return Integer.valueOf(socket.getTimeToLive()); + } else if (option.equals(StandardSocketOptions.IP_MULTICAST_LOOP)) { + return Boolean.valueOf(socket.getLoopbackMode()); + } else { + throw new RuntimeException("unexecpted socket option"); + } + } + throw new RuntimeException("unexecpted socket type"); + } + + public static void main(String args[]) throws Exception { + doSocketTests(); + doServerSocketTests(); + doDgSocketTests(); + doMcSocketTests(); + } +} diff --git a/jdk/test/java/net/URI/Test.java b/jdk/test/java/net/URI/Test.java index 05d4cdbbfac..8e0e9247acd 100644 --- a/jdk/test/java/net/URI/Test.java +++ b/jdk/test/java/net/URI/Test.java @@ -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 @@ -1367,6 +1367,17 @@ public class Test { cmp0(u, v, true); } + static void eq(String expected, String actual) { + if (expected == null && actual == null) { + return; + } + if (expected != null && expected.equals(actual)) { + return; + } + throw new AssertionError(String.format( + "Strings are not equal: '%s', '%s'", expected, actual)); + } + static void eqeq(URI u, URI v) { testCount++; if (u != v) @@ -1588,7 +1599,12 @@ public class Test { // miscellaneous bugs/rfes that don't fit in with the test framework static void bugs() { - // 6339649 - include detail message from nested exception + b6339649(); + b8037396(); + } + + // 6339649 - include detail message from nested exception + private static void b6339649() { try { URI uri = URI.create("http://nowhere.net/should not be permitted"); } catch (IllegalArgumentException e) { @@ -1598,6 +1614,39 @@ public class Test { } } + private static void b8037396() { + + // primary checks: + + URI u; + try { + u = new URI("http", "example.org", "/[a b]", "[a b]", "[a b]"); + } catch (URISyntaxException e) { + throw new AssertionError("shouldn't ever happen", e); + } + eq("/[a b]", u.getPath()); + eq("[a b]", u.getQuery()); + eq("[a b]", u.getFragment()); + + // additional checks: + // * '%' symbols are still decoded outside square brackets + // * the getRawXXX() functionality left intact + + try { + u = new URI("http", "example.org", "/a b[c d]", "a b[c d]", "a b[c d]"); + } catch (URISyntaxException e) { + throw new AssertionError("shouldn't ever happen", e); + } + + eq("/a b[c d]", u.getPath()); + eq("a b[c d]", u.getQuery()); + eq("a b[c d]", u.getFragment()); + + eq("/a%20b%5Bc%20d%5D", u.getRawPath()); + eq("a%20b[c%20d]", u.getRawQuery()); + eq("a%20b[c%20d]", u.getRawFragment()); + } + public static void main(String[] args) throws Exception { switch (args.length) { diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java index 8e2091e9888..9c0a783ec53 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java @@ -254,14 +254,20 @@ public class TCKDateTimeFormatter { assertEquals(parsed.isSupported(YEAR), false); // not in the list of resolverFields } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_resolverFields_Array_null() throws Exception { - DateTimeFormatter.ISO_DATE.withResolverFields((TemporalField[]) null); + DateTimeFormatter f = DateTimeFormatter.ISO_DATE.withResolverFields(MONTH_OF_YEAR); + assertEquals(f.getResolverFields().size(), 1); + f = f.withResolverFields((TemporalField[]) null); + assertEquals(f.getResolverFields(), null); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_resolverFields_Set_null() throws Exception { - DateTimeFormatter.ISO_DATE.withResolverFields((Set) null); + DateTimeFormatter f = DateTimeFormatter.ISO_DATE.withResolverFields(MONTH_OF_YEAR); + assertEquals(f.getResolverFields().size(), 1); + f = f.withResolverFields((Set) null); + assertEquals(f.getResolverFields(), null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/util/regex/RegExTest.java b/jdk/test/java/util/regex/RegExTest.java index cd6abd9be07..7cc7c784cf2 100644 --- a/jdk/test/java/util/regex/RegExTest.java +++ b/jdk/test/java/util/regex/RegExTest.java @@ -32,7 +32,7 @@ * 6358731 6178785 6284152 6231989 6497148 6486934 6233084 6504326 6635133 * 6350801 6676425 6878475 6919132 6931676 6948903 6990617 7014645 7039066 * 7067045 7014640 7189363 8007395 8013252 8013254 8012646 8023647 6559590 - * 8027645 8035076 + * 8027645 8035076 8039124 */ import java.util.regex.*; @@ -75,7 +75,10 @@ public class RegExTest { // Substitition tests on randomly generated sequences globalSubstitute(); stringbufferSubstitute(); + stringbuilderSubstitute(); + substitutionBasher(); + substitutionBasher2(); // Canonical Equivalence ceTest(); @@ -296,10 +299,12 @@ public class RegExTest { final Matcher m = Pattern.compile("xyz").matcher("xyz"); m.matches(); - check(new Runnable() { public void run() { m.appendTail(null);}}); + check(new Runnable() { public void run() { m.appendTail((StringBuffer)null);}}); + check(new Runnable() { public void run() { m.appendTail((StringBuilder)null);}}); check(new Runnable() { public void run() { m.replaceAll(null);}}); check(new Runnable() { public void run() { m.replaceFirst(null);}}); - check(new Runnable() { public void run() { m.appendReplacement(null, null);}}); + check(new Runnable() { public void run() { m.appendReplacement((StringBuffer)null, null);}}); + check(new Runnable() { public void run() { m.appendReplacement((StringBuilder)null, null);}}); check(new Runnable() { public void run() { m.reset(null);}}); check(new Runnable() { public void run() { Matcher.quoteReplacement(null);}}); //check(new Runnable() { public void run() { m.usePattern(null);}}); @@ -2973,6 +2978,286 @@ public class RegExTest { report("SB Substitution"); } + /** + * Tests the usage of Matcher.appendReplacement() with literal + * and group substitutions. + */ + private static void stringbuilderSubstitute() throws Exception { + // SB substitution with literal + String blah = "zzzblahzzz"; + Pattern p = Pattern.compile("blah"); + Matcher m = p.matcher(blah); + StringBuilder result = new StringBuilder(); + try { + m.appendReplacement(result, "blech"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "blech"); + if (!result.toString().equals("zzzblech")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzblechzzz")) + failCount++; + + // SB substitution with groups + blah = "zzzabcdzzz"; + p = Pattern.compile("(ab)(cd)*"); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals("zzzab")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabzzz")) + failCount++; + + // SB substitution with 3 groups + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1w$2w$3"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1w$2w$3"); + if (!result.toString().equals("zzzabwcdwef")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabwcdwefzzz")) + failCount++; + + // SB substitution with groups and three matches + // skipping middle match + blah = "zzzabcdzzzabcddzzzabcdzzz"; + p = Pattern.compile("(ab)(cd*)"); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals("zzzab")) + failCount++; + + m.find(); + m.find(); + m.appendReplacement(result, "$2"); + if (!result.toString().equals("zzzabzzzabcddzzzcd")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabzzzabcddzzzcdzzz")) + failCount++; + + // Check to make sure escaped $ is ignored + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, "$1w\\$2w$3"); + if (!result.toString().equals("zzzabw$2wef")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabw$2wefzzz")) + failCount++; + + // Check to make sure a reference to nonexistent group causes error + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + try { + m.appendReplacement(result, "$1w$5w$3"); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } + + // Check double digit group references + blah = "zzz123456789101112zzz"; + p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, "$1w$11w$3"); + if (!result.toString().equals("zzz1w11w3")) + failCount++; + + // Check to make sure it backs off $15 to $1 if only three groups + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, "$1w$15w$3"); + if (!result.toString().equals("zzzabwab5wef")) + failCount++; + + + // Supplementary character test + // SB substitution with literal + blah = toSupplementaries("zzzblahzzz"); + p = Pattern.compile(toSupplementaries("blah")); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, toSupplementaries("blech")); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, toSupplementaries("blech")); + if (!result.toString().equals(toSupplementaries("zzzblech"))) + failCount++; + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzblechzzz"))) + failCount++; + + // SB substitution with groups + blah = toSupplementaries("zzzabcdzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*")); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals(toSupplementaries("zzzab"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabzzz"))) + failCount++; + + // SB substitution with 3 groups + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, toSupplementaries("$1w$2w$3")); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$2w$3")); + if (!result.toString().equals(toSupplementaries("zzzabwcdwef"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabwcdwefzzz"))) + failCount++; + + // SB substitution with groups and three matches + // skipping middle match + blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd*)")); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals(toSupplementaries("zzzab"))) + failCount++; + + m.find(); + m.find(); + m.appendReplacement(result, "$2"); + if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcd"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcdzzz"))) + failCount++; + + // Check to make sure escaped $ is ignored + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w\\$2w$3")); + if (!result.toString().equals(toSupplementaries("zzzabw$2wef"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabw$2wefzzz"))) + failCount++; + + // Check to make sure a reference to nonexistent group causes error + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + try { + m.appendReplacement(result, toSupplementaries("$1w$5w$3")); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } + // Check double digit group references + blah = toSupplementaries("zzz123456789101112zzz"); + p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$11w$3")); + if (!result.toString().equals(toSupplementaries("zzz1w11w3"))) + failCount++; + + // Check to make sure it backs off $15 to $1 if only three groups + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$15w$3")); + if (!result.toString().equals(toSupplementaries("zzzabwab5wef"))) + failCount++; + // Check nothing has been appended into the output buffer if + // the replacement string triggers IllegalArgumentException. + p = Pattern.compile("(abc)"); + m = p.matcher("abcd"); + result = new StringBuilder(); + m.find(); + try { + m.appendReplacement(result, ("xyz$g")); + failCount++; + } catch (IllegalArgumentException iae) { + if (result.length() != 0) + failCount++; + } + report("SB Substitution 2"); + } + /* * 5 groups of characters are created to make a substitution string. * A base string will be created including random lead chars, the @@ -3059,6 +3344,93 @@ public class RegExTest { report("Substitution Basher"); } + /* + * 5 groups of characters are created to make a substitution string. + * A base string will be created including random lead chars, the + * substitution string, and random trailing chars. + * A pattern containing the 5 groups is searched for and replaced with: + * random group + random string + random group. + * The results are checked for correctness. + */ + private static void substitutionBasher2() { + for (int runs = 0; runs<1000; runs++) { + // Create a base string to work in + int leadingChars = generator.nextInt(10); + StringBuilder baseBuffer = new StringBuilder(100); + String leadingString = getRandomAlphaString(leadingChars); + baseBuffer.append(leadingString); + + // Create 5 groups of random number of random chars + // Create the string to substitute + // Create the pattern string to search for + StringBuilder bufferToSub = new StringBuilder(25); + StringBuilder bufferToPat = new StringBuilder(50); + String[] groups = new String[5]; + for(int i=0; i<5; i++) { + int aGroupSize = generator.nextInt(5)+1; + groups[i] = getRandomAlphaString(aGroupSize); + bufferToSub.append(groups[i]); + bufferToPat.append('('); + bufferToPat.append(groups[i]); + bufferToPat.append(')'); + } + String stringToSub = bufferToSub.toString(); + String pattern = bufferToPat.toString(); + + // Place sub string into working string at random index + baseBuffer.append(stringToSub); + + // Append random chars to end + int trailingChars = generator.nextInt(10); + String trailingString = getRandomAlphaString(trailingChars); + baseBuffer.append(trailingString); + String baseString = baseBuffer.toString(); + + // Create test pattern and matcher + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(baseString); + + // Reject candidate if pattern happens to start early + m.find(); + if (m.start() < leadingChars) + continue; + + // Reject candidate if more than one match + if (m.find()) + continue; + + // Construct a replacement string with : + // random group + random string + random group + StringBuilder bufferToRep = new StringBuilder(); + int groupIndex1 = generator.nextInt(5); + bufferToRep.append("$" + (groupIndex1 + 1)); + String randomMidString = getRandomAlphaString(5); + bufferToRep.append(randomMidString); + int groupIndex2 = generator.nextInt(5); + bufferToRep.append("$" + (groupIndex2 + 1)); + String replacement = bufferToRep.toString(); + + // Do the replacement + String result = m.replaceAll(replacement); + + // Construct expected result + StringBuilder bufferToRes = new StringBuilder(); + bufferToRes.append(leadingString); + bufferToRes.append(groups[groupIndex1]); + bufferToRes.append(randomMidString); + bufferToRes.append(groups[groupIndex2]); + bufferToRes.append(trailingString); + String expectedResult = bufferToRes.toString(); + + // Check results + if (!result.equals(expectedResult)) { + failCount++; + } + } + + report("Substitution Basher 2"); + } + /** * Checks the handling of some escape sequences that the Pattern * class should process instead of the java compiler. These are diff --git a/jdk/test/java/util/zip/ZipFile/MultiThreadedReadTest.java b/jdk/test/java/util/zip/ZipFile/MultiThreadedReadTest.java new file mode 100644 index 00000000000..c1f69a90587 --- /dev/null +++ b/jdk/test/java/util/zip/ZipFile/MultiThreadedReadTest.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 + * @bug 8038491 + * @summary Crash in ZipFile.read() when ZipFileInputStream is shared between threads + * @library /lib/testlibrary + * @build jdk.testlibrary.FileUtils + * @run main MultiThreadedReadTest + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.nio.file.Paths; +import java.util.Random; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; +import jdk.testlibrary.FileUtils; + +public class MultiThreadedReadTest extends Thread { + + private static final int NUM_THREADS = 10; + private static final String ZIPFILE_NAME = "large.zip"; + private static final String ZIPENTRY_NAME = "random.txt"; + private static InputStream is = null; + + public static void main(String args[]) throws Exception { + createZipFile(); + try (ZipFile zf = new ZipFile(new File(ZIPFILE_NAME))) { + is = zf.getInputStream(zf.getEntry(ZIPENTRY_NAME)); + Thread[] threadArray = new Thread[NUM_THREADS]; + for (int i = 0; i < threadArray.length; i++) { + threadArray[i] = new MultiThreadedReadTest(); + } + for (int i = 0; i < threadArray.length; i++) { + threadArray[i].start(); + } + for (int i = 0; i < threadArray.length; i++) { + threadArray[i].join(); + } + } finally { + FileUtils.deleteFileIfExistsWithRetry(Paths.get(ZIPFILE_NAME)); + } + } + + private static void createZipFile() throws Exception { + try (ZipOutputStream zos = + new ZipOutputStream(new FileOutputStream(ZIPFILE_NAME))) { + + zos.putNextEntry(new ZipEntry(ZIPENTRY_NAME)); + StringBuilder sb = new StringBuilder(); + Random rnd = new Random(); + for(int i = 0; i < 1000; i++) { + // append some random string for ZipEntry + sb.append(Long.toString(rnd.nextLong())); + } + byte[] b = sb.toString().getBytes(); + zos.write(b, 0, b.length); + } + } + + @Override + public void run() { + try { + while (is.read() != -1) { } + } catch (Exception e) { + // Swallow any Exceptions (which are expected) - we're only interested in the crash + } + } +} diff --git a/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java b/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java index 4001f83ed47..ccb90c6c182 100644 --- a/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java +++ b/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java @@ -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 @@ -28,7 +28,7 @@ /* * @test - * @bug 4366807 + * @bug 4366807 * @summary Need new APIs to get/set session timeout and session cache size. * @run main/othervm SessionCacheSizeTests */ @@ -110,6 +110,7 @@ public class SessionCacheSizeTests { SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort); + sslServerSocket.setSoTimeout(45000); // timeout to accept a connection serverPorts[createdPorts++] = sslServerSocket.getLocalPort(); /* @@ -128,16 +129,22 @@ public class SessionCacheSizeTests { SSLSession sessions [] = new SSLSession [serverConns]; SSLSessionContext sessCtx = sslctx.getServerSessionContext(); - while (nConnections < serverConns) { - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - read = sslIS.read(); - sessions[nConnections] = sslSocket.getSession(); - sslOS.write(85); - sslOS.flush(); - sslSocket.close(); - nConnections++; + try { + while (nConnections < serverConns) { + try (SSLSocket sslSocket = + (SSLSocket)sslServerSocket.accept()) { + sslSocket.setSoTimeout(90000); // timeout to read + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + read = sslIS.read(); + sessions[nConnections] = sslSocket.getSession(); + sslOS.write(85); + sslOS.flush(); + nConnections++; + } + } + } finally { + sslServerSocket.close(); } } diff --git a/jdk/test/javax/security/auth/kerberos/KerberosHashEqualsTest.java b/jdk/test/javax/security/auth/kerberos/KerberosHashEqualsTest.java index 906700c71cc..9578a59547a 100644 --- a/jdk/test/javax/security/auth/kerberos/KerberosHashEqualsTest.java +++ b/jdk/test/javax/security/auth/kerberos/KerberosHashEqualsTest.java @@ -25,7 +25,6 @@ * @test * @bug 4641821 * @summary hashCode() and equals() for KerberosKey and KerberosTicket - * @run main/manual KerberosHashEqualsTest */ /* @@ -60,8 +59,8 @@ public class KerberosHashEqualsTest { void check() throws Exception { KerberosKey k1, k2; - k1 = new KerberosKey(new KerberosPrincipal("A"), "pass".getBytes(), 1, 1); - k2 = new KerberosKey(new KerberosPrincipal("A"), "pass".getBytes(), 1, 1); + k1 = new KerberosKey(newKP("A"), "pass".getBytes(), 1, 1); + k2 = new KerberosKey(newKP("A"), "pass".getBytes(), 1, 1); checkSame(k1, k1); // me to me checkSame(k1, k2); // same @@ -73,13 +72,13 @@ public class KerberosHashEqualsTest { checkSame(k2, k2); // a little different - k2 = new KerberosKey(new KerberosPrincipal("B"), "pass".getBytes(), 1, 1); + k2 = new KerberosKey(newKP("B"), "pass".getBytes(), 1, 1); checkNotSame(k1, k2); - k2 = new KerberosKey(new KerberosPrincipal("A"), "ssap".getBytes(), 1, 1); + k2 = new KerberosKey(newKP("A"), "ssap".getBytes(), 1, 1); checkNotSame(k1, k2); - k2 = new KerberosKey(new KerberosPrincipal("A"), "pass".getBytes(), 2, 1); + k2 = new KerberosKey(newKP("A"), "pass".getBytes(), 2, 1); checkNotSame(k1, k2); - k2 = new KerberosKey(new KerberosPrincipal("A"), "pass".getBytes(), 1, 2); + k2 = new KerberosKey(newKP("A"), "pass".getBytes(), 1, 2); checkNotSame(k1, k2); k1 = new KerberosKey(null, "pass".getBytes(), 1, 2); @@ -90,33 +89,33 @@ public class KerberosHashEqualsTest { checkNotSame(k1, "Another Object"); KerberosTicket t1, t2; - t1 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t1 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkSame(t1, t1); checkSame(t1, t2); - t2 = new KerberosTicket("asn11".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn11".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client1"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client1"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server1"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server1"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass1".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass1".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 2, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 2, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {false, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {false, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(1), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(1), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(1), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(1), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(1), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(1), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), new InetAddress[2]); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), new InetAddress[2]); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(1), null); - t1 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(2), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(1), null); + t1 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(2), null); checkSame(t1, t2); // renewtill is useless t2.destroy(); @@ -126,11 +125,15 @@ public class KerberosHashEqualsTest { checkNotSame(t2, t1); checkSame(t2, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true, true, true, true, true, true, true, true, true}, new Date(0), new Date(0), new Date(0), new Date(1), null); - t1 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true, true, true, true, true, true, true, true, true}, new Date(0), new Date(0), new Date(0), new Date(2), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true, true, true, true, true, true, true, true, true}, new Date(0), new Date(0), new Date(0), new Date(1), null); + t1 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true, true, true, true, true, true, true, true, true}, new Date(0), new Date(0), new Date(0), new Date(2), null); checkNotSame(t1, t2); // renewtill is useful checkNotSame(t1, "Another Object"); System.out.println("Good!"); } + + KerberosPrincipal newKP(String s) { + return new KerberosPrincipal(s + "@JLABS.SFBAY.SUN.COM"); + } } diff --git a/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java b/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java index 2fed8d083cb..53b5ec8068a 100644 --- a/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java +++ b/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java @@ -25,7 +25,6 @@ * @test * @bug 6659990 * @summary test the immutability of the Date fields in KerberosTicket class. - * @run main/manual KerberosTixDateTest */ /* @@ -64,8 +63,8 @@ public class KerberosTixDateTest { public static void main(String[] args) throws Exception { byte[] asn1Bytes = "asn1".getBytes(); - KerberosPrincipal client = new KerberosPrincipal("client"); - KerberosPrincipal server = new KerberosPrincipal("server"); + KerberosPrincipal client = new KerberosPrincipal("client@JLABS.SFBAY.SUN.COM"); + KerberosPrincipal server = new KerberosPrincipal("server@JLABS.SFBAY.SUN.COM"); byte[] keyBytes = "sessionKey".getBytes(); long originalTime = 12345678L; Date inDate = new Date(originalTime); diff --git a/jdk/test/javax/security/auth/kerberos/StandardNames.java b/jdk/test/javax/security/auth/kerberos/StandardNames.java new file mode 100644 index 00000000000..40590f6d080 --- /dev/null +++ b/jdk/test/javax/security/auth/kerberos/StandardNames.java @@ -0,0 +1,108 @@ +/* + * 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 8035986 + * @summary KerberosKey algorithm names are not specified + */ + +import sun.security.krb5.EncryptedData; + +import javax.crypto.Cipher; +import javax.security.auth.kerberos.KerberosKey; +import javax.security.auth.kerberos.KerberosPrincipal; +import java.util.Locale; + +public class StandardNames { + static KerberosPrincipal kp = new KerberosPrincipal("user@REALM"); + static char[] pass = "secret".toCharArray(); + static byte[] keyBytes = new byte[1]; + + public static void main(String[] args) throws Exception { + for (EncType e: EncType.values()) { + if (e == EncType.e18) { + if (Cipher.getMaxAllowedKeyLength("AES") < 256) { + System.out.println("Skipping aes256-cts-hmac-sha1-96"); + continue; + } + } + checkByName(e.name, e); + checkByName(e.name.toUpperCase(Locale.US), e); + for (String n: e.oldnames) { + checkByName(n, e); + if (n != null) { + checkByName(n.toLowerCase(Locale.US), e); + } + } + checkByEType(e.etype, e.name); + } + checkByEType(100, "unknown"); + checkByEType(-1, "private"); + + try { + System.out.println("unsupported"); + new KerberosKey(kp, pass, "unsupported"); + throw new Exception("unsupported"); + } catch (IllegalArgumentException iae) { + // Expected + } + } + + private static void checkByName(String n, EncType e) throws Exception { + System.out.println("CheckByName " + n); + KerberosKey k = new KerberosKey(kp, pass, n); + if (!k.getAlgorithm().equals(e.name)) throw new Exception(n); + if (k.getKeyType() != e.etype) throw new Exception(n); + if (k.getVersionNumber() != 0) throw new Exception(n); + } + + private static void checkByEType(int i, String n) throws Exception { + System.out.println("CheckByInt " + i); + KerberosKey k = new KerberosKey(kp, keyBytes, i, 13); + if (!k.getAlgorithm().equals(n)) throw new Exception("" + i); + if (k.getKeyType() != i) throw new Exception("" + i); + if (k.getVersionNumber() != 13) throw new Exception("" + i); + } +} + +enum EncType { + e0("none", EncryptedData.ETYPE_NULL), + e1("des-cbc-crc", EncryptedData.ETYPE_DES_CBC_CRC), + e3("des-cbc-md5", EncryptedData.ETYPE_DES_CBC_MD5, "DES", null), + e16("des3-cbc-sha1-kd", EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD, "DESede"), + e17("aes128-cts-hmac-sha1-96", EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, "AES128"), + e18("aes256-cts-hmac-sha1-96", EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96, "AES256"), + e23("rc4-hmac", EncryptedData.ETYPE_ARCFOUR_HMAC, "ArcFourHmac"), + ; + + final String name; + final int etype; + final String[] oldnames; + + EncType(String name, int etype, String... oldnames) { + this.name = name; + this.etype = etype; + this.oldnames = oldnames; + } +} diff --git a/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl b/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl new file mode 100644 index 00000000000..df87852f240 --- /dev/null +++ b/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jdk/test/javax/xml/ws/8033113/WsImportTest.java b/jdk/test/javax/xml/ws/8033113/WsImportTest.java new file mode 100644 index 00000000000..aa1cf860ab4 --- /dev/null +++ b/jdk/test/javax/xml/ws/8033113/WsImportTest.java @@ -0,0 +1,152 @@ +/* + * 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 8033113 + * @summary wsimport fails on WSDL:header parameter name customization + * @run main/othervm WsImportTest + */ + +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.FileVisitResult; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +import static java.nio.file.FileVisitResult.*; + +public class WsImportTest { + + public static void main(String[] args) throws IOException { + + String wsimport = getWsImport(); + String customization = getWSDLFilePath("customization.xml"); + String wsdl = getWSDLFilePath("Organization_List.wsdl"); + + try { + log("Importing wsdl: " + wsdl); + String[] wsargs = { + wsimport, + "-keep", + "-verbose", + "-extension", + "-XadditionalHeaders", + "-Xdebug", + "-b", + customization, + wsdl + }; + + ProcessBuilder pb = new ProcessBuilder(wsargs); + pb.redirectErrorStream(true); + Process p = pb.start(); + logOutput(p); + int result = p.waitFor(); + p.destroy(); + + if (result != 0) { + fail("WsImport failed. TEST FAILED."); + } else { + log("Test PASSED."); + } + + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } finally { + deleteGeneratedFiles(); + } + } + + private static void fail(String message) { + throw new RuntimeException(message); + } + + private static void log(String msg) { + System.out.println(msg); + } + + private static void logOutput(Process p) throws IOException { + BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); + String s = r.readLine(); + while (s != null) { + log(s.trim()); + s = r.readLine(); + } + } + + private static void deleteGeneratedFiles() { + Path p = Paths.get("generated"); + if (Files.exists(p)) { + try { + Files.walkFileTree(p, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + + Files.delete(file); + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException exc) throws IOException { + + if (exc == null) { + Files.delete(dir); + return CONTINUE; + } else { + throw exc; + } + } + }); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + } + + private static String getWSDLFilePath(String filename) { + String testSrc = System.getProperty("test.src"); + if (testSrc == null) testSrc = "."; + return Paths.get(testSrc).resolve(filename).toString(); + } + + private static String getWsImport() { + String javaHome = System.getProperty("java.home"); + if (javaHome.endsWith("jre")) { + javaHome = new File(javaHome).getParent(); + } + String wsimport = javaHome + File.separator + "bin" + File.separator + "wsimport"; + if (System.getProperty("os.name").startsWith("Windows")) { + wsimport = wsimport.concat(".exe"); + } + return wsimport; + } +} diff --git a/jdk/test/javax/xml/ws/8033113/customization.xml b/jdk/test/javax/xml/ws/8033113/customization.xml new file mode 100644 index 00000000000..6f17e2f0a42 --- /dev/null +++ b/jdk/test/javax/xml/ws/8033113/customization.xml @@ -0,0 +1,45 @@ + + + false + + + + + + + + diff --git a/jdk/test/jdk/net/Sockets/Test.java b/jdk/test/jdk/net/Sockets/Test.java new file mode 100644 index 00000000000..da609bf7501 --- /dev/null +++ b/jdk/test/jdk/net/Sockets/Test.java @@ -0,0 +1,130 @@ +/* + * 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 8032808 + * @run main/othervm -Xcheck:jni Test + * @run main/othervm/policy=policy.fail -Xcheck:jni Test fail + * @run main/othervm/policy=policy.success -Xcheck:jni Test success + */ + +import java.net.*; +import java.nio.channels.*; +import java.util.concurrent.*; +import jdk.net.*; + +public class Test { + + static boolean security; + static boolean success; + + interface Runner { + public void run() throws Exception; + } + + public static void main(String[] args) throws Exception { + + // quick check to see if supportedOptions() working before + // creating any sockets and libnet loaded + + Sockets.supportedOptions(Socket.class); + + security = System.getSecurityManager() != null; + success = security && args[0].equals("success"); + + // Main thing is to check for JNI problems + // Doesn't matter if current system does not support the option + // and currently setting the option with the loopback interface + // doesn't work either + + System.out.println ("Security Manager enabled: " + security); + if (security) { + System.out.println ("Success expected: " + success); + } + + final SocketFlow flowIn = SocketFlow.create() + .bandwidth(1000) + .priority(SocketFlow.HIGH_PRIORITY); + + ServerSocket ss = new ServerSocket(0); + int tcp_port = ss.getLocalPort(); + final InetAddress loop = InetAddress.getByName("127.0.0.1"); + final InetSocketAddress loopad = new InetSocketAddress(loop, tcp_port); + + DatagramSocket dg = new DatagramSocket(0); + final int udp_port = dg.getLocalPort(); + + final Socket s = new Socket("127.0.0.1", tcp_port); + final SocketChannel sc = SocketChannel.open(); + sc.connect (new InetSocketAddress("127.0.0.1", tcp_port)); + + doTest(()->{ + Sockets.setOption(s, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + Sockets.getOption(s, ExtendedSocketOptions.SO_FLOW_SLA); + }); + doTest(()->{ + sc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + sc.getOption(ExtendedSocketOptions.SO_FLOW_SLA); + }); + doTest(()->{ + DatagramSocket dg1 = new DatagramSocket(0); + dg1.connect(loop, udp_port); + Sockets.setOption(dg1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + DatagramChannel dg2 = DatagramChannel.open(); + dg2.bind(new InetSocketAddress(loop, 0)); + dg2.connect(new InetSocketAddress(loop, udp_port)); + dg2.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + MulticastSocket mc1 = new MulticastSocket(0); + mc1.connect(loop, udp_port); + Sockets.setOption(mc1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + AsynchronousSocketChannel asc = AsynchronousSocketChannel.open(); + Future f = asc.connect(loopad); + f.get(); + asc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + } + + static void doTest(Runner func) throws Exception { + try { + func.run(); + if (security && !success) { + throw new RuntimeException("Test failed"); + } + } catch (SecurityException e) { + if (success) { + throw new RuntimeException("Test failed"); + } + } catch (UnsupportedOperationException e) {} + } +} diff --git a/jdk/test/jdk/net/Sockets/policy.fail b/jdk/test/jdk/net/Sockets/policy.fail new file mode 100644 index 00000000000..29d1215e708 --- /dev/null +++ b/jdk/test/jdk/net/Sockets/policy.fail @@ -0,0 +1,4 @@ +grant { + permission java.net.SocketPermission "127.0.0.1", "connect,accept" ; + permission java.net.SocketPermission "localhost", "listen" ; +}; diff --git a/jdk/test/jdk/net/Sockets/policy.success b/jdk/test/jdk/net/Sockets/policy.success new file mode 100644 index 00000000000..6f99151a38f --- /dev/null +++ b/jdk/test/jdk/net/Sockets/policy.success @@ -0,0 +1,6 @@ +grant { + permission java.net.SocketPermission "127.0.0.1", "connect,accept" ; + permission java.net.SocketPermission "localhost", "listen" ; + permission jdk.net.NetworkPermission "setOption.SO_FLOW_SLA"; + permission jdk.net.NetworkPermission "getOption.SO_FLOW_SLA"; +}; diff --git a/jdk/test/sun/nio/cs/TestUTF8.java b/jdk/test/sun/nio/cs/TestUTF8.java index c54ae66f4d9..010fbf17b43 100644 --- a/jdk/test/sun/nio/cs/TestUTF8.java +++ b/jdk/test/sun/nio/cs/TestUTF8.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4486841 7040220 7096080 + * @bug 4486841 7040220 7096080 8039751 * @summary Test UTF-8 charset */ @@ -291,14 +291,18 @@ public class TestUTF8 { {1, (byte)0xE0, (byte)0xC0, (byte)0xBF }, // invalid second byte {2, (byte)0xE0, (byte)0xA0, (byte)0x7F }, // invalid third byte {2, (byte)0xE0, (byte)0xA0, (byte)0xC0 }, // invalid third byte + {2, (byte)0xE1, (byte)0x80, (byte)0x42}, // invalid third byte + {1, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones {1, (byte)0xE0, (byte)0xC0, (byte)0x80 }, // invalid second byte {1, (byte)0xE0, (byte)0x80, (byte)0xC0 }, // invalid first byte {1, (byte)0xE0, (byte)0x41,}, // invalid second byte & 2 bytes + {1, (byte)0xE1, (byte)0x40,}, // invalid second byte & 2 bytes {3, (byte)0xED, (byte)0xAE, (byte)0x80 }, // 3 bytes surrogate {3, (byte)0xED, (byte)0xB0, (byte)0x80 }, // 3 bytes surrogate + // Four-byte sequences {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded {1, (byte)0xF0, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded @@ -323,6 +327,32 @@ public class TestUTF8 { {1, (byte)0xF4, (byte)0xC0, (byte)0x80, (byte)0xC0 }, // out-range 4-byte {1, (byte)0xF5, (byte)0x80, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + // #8039751 + {1, (byte)0xF6, (byte)0x80, (byte)0x80, (byte)0x80 }, // out-range 1st byte + {1, (byte)0xF6, (byte)0x80, (byte)0x80, }, + {1, (byte)0xF6, (byte)0x80, }, + {1, (byte)0xF6, }, + {1, (byte)0xF5, (byte)0x80, (byte)0x80, (byte)0x80 }, // out-range 1st byte + {1, (byte)0xF5, (byte)0x80, (byte)0x80, }, + {1, (byte)0xF5, (byte)0x80, }, + {1, (byte)0xF5 }, + + {1, (byte)0xF4, (byte)0x90, (byte)0x80, (byte)0x80 }, // out-range 2nd byte + {1, (byte)0xF4, (byte)0x90, (byte)0x80 }, + {1, (byte)0xF4, (byte)0x90 }, + + {1, (byte)0xF4, (byte)0x7f, (byte)0x80, (byte)0x80 }, // out-range/ascii 2nd byte + {1, (byte)0xF4, (byte)0x7f, (byte)0x80 }, + {1, (byte)0xF4, (byte)0x7f }, + + {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80 }, // out-range 2nd byte + {1, (byte)0xF0, (byte)0x80, (byte)0x80 }, + {1, (byte)0xF0, (byte)0x80 }, + + {1, (byte)0xF0, (byte)0xc0, (byte)0x80, (byte)0x80 }, // out-range 2nd byte + {1, (byte)0xF0, (byte)0xc0, (byte)0x80 }, + {1, (byte)0xF0, (byte)0xc0 }, + // Five-byte sequences {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid first byte {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded @@ -553,7 +583,6 @@ public class TestUTF8 { check4ByteSurrs("UTF-8"); checkMalformed("UTF-8", malformed); checkUnderOverflow("UTF-8"); - checkRoundtrip("CESU-8"); check6ByteSurrs("CESU-8"); checkMalformed("CESU-8", malformed_cesu8); diff --git a/jdk/test/sun/security/krb5/auto/AddressesAndNameType.java b/jdk/test/sun/security/krb5/auto/AddressesAndNameType.java new file mode 100644 index 00000000000..de0dc89491c --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/AddressesAndNameType.java @@ -0,0 +1,85 @@ +/* + * 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 4501327 4868379 8039132 + * @run main/othervm AddressesAndNameType 1 + * @run main/othervm AddressesAndNameType 2 + * @run main/othervm AddressesAndNameType 3 + * @summary noaddresses settings and server name type + */ + +import java.net.InetAddress; +import java.util.Set; +import sun.security.krb5.Config; + +import javax.security.auth.kerberos.KerberosPrincipal; +import javax.security.auth.kerberos.KerberosTicket; + +public class AddressesAndNameType { + + public static void main(String[] args) + throws Exception { + + OneKDC kdc = new OneKDC(null); + kdc.writeJAASConf(); + + String extraLine; + switch (args[0]) { + case "1": extraLine = "noaddresses = false"; break; + case "2": extraLine = "noaddresses = true"; break; + default: extraLine = ""; break; + } + + KDC.saveConfig(OneKDC.KRB5_CONF, kdc, + extraLine); + Config.refresh(); + + Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + Set tickets = + c.s().getPrivateCredentials(KerberosTicket.class); + + if (tickets.isEmpty()) throw new Exception(); + KerberosTicket ticket = tickets.iterator().next(); + InetAddress[] addresses = ticket.getClientAddresses(); + + switch (args[0]) { + case "1": + if (addresses == null || addresses.length == 0) { + throw new Exception("No addresses"); + } + if (ticket.getServer().getNameType() + != KerberosPrincipal.KRB_NT_SRV_INST) { + throw new Exception( + "Wrong type: " + ticket.getServer().getNameType()); + } + break; + default: + if (addresses != null && addresses.length != 0) { + throw new Exception("See addresses"); + } + break; + } + } +} diff --git a/jdk/test/sun/security/krb5/auto/UdpTcp.java b/jdk/test/sun/security/krb5/auto/UdpTcp.java new file mode 100644 index 00000000000..e66f5d459fb --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/UdpTcp.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. + */ + +/* + * @test + * @bug 4966382 8039132 + * @run main/othervm UdpTcp UDP + * @run main/othervm UdpTcp TCP + * @summary udp or tcp + */ + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import sun.security.krb5.Config; + +public class UdpTcp { + + public static void main(String[] args) + throws Exception { + + System.setProperty("sun.security.krb5.debug", "true"); + + OneKDC kdc = new OneKDC(null); + kdc.writeJAASConf(); + + KDC.saveConfig(OneKDC.KRB5_CONF, kdc, + "udp_preference_limit = " + + (args[0].equals("UDP") ? "1000" : "100")); + Config.refresh(); + + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + PrintStream oldout = System.out; + System.setOut(new PrintStream(bo)); + Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + System.setOut(oldout); + + for (String line: new String(bo.toByteArray()).split("\n")) { + if (line.contains(">>> KDCCommunication")) { + if (!line.contains(args[0])) { + throw new Exception("No " + args[0] + " in: " + line); + } + } + } + } +} diff --git a/jdk/test/sun/security/krb5/etype/UnsupportedKeyType.java b/jdk/test/sun/security/krb5/etype/UnsupportedKeyType.java new file mode 100644 index 00000000000..c54a73d9536 --- /dev/null +++ b/jdk/test/sun/security/krb5/etype/UnsupportedKeyType.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 + * @bug 5006629 + * @summary Kerberos library should only select keys of types that it supports + */ + +import javax.security.auth.kerberos.KerberosPrincipal; +import javax.security.auth.kerberos.KeyTab; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class UnsupportedKeyType { + + // Homemade keytab files: + // + // String KVNO Timestamp Principal (etype) + // -------- ---- -------------- ----------------------- + // camellia 4 4/3/14 9:58 AM u1@K1 (25:camellia128-cts-cmac) + // aes 5 4/3/14 9:58 AM u1@K1 (17:aes128-cts-hmac-sha1-96) + + static String aes = + "050200000027000100024b310002753100000001533cc04f0500110010e0eab6" + + "7f31608df2b2f8fffc6b21cc91"; + static String camellia = + "050200000027000100024b310002753100000001533cc03e0400190010d88678" + + "14e478b6b7d2d97375163b971e"; + + public static void main(String[] args) throws Exception { + + byte[] data = new byte[aes.length()/2]; + KerberosPrincipal kp = new KerberosPrincipal("u1@K1"); + + // aes128 + for (int i=0; i= clientVersion) { + break; + } + } + } System.out.println("Done."); } - private static void test(KeyGenerator kg, int major, int minor) - throws Exception { + private static void test(KeyGenerator kg, + int clientVersion, int serverVersion) throws Exception { - kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor)); + System.out.printf( + "Testing RSA pre-master secret key generation between " + + "client (0x%04X) and server(0x%04X)%n", + clientVersion, serverVersion); + kg.init(new TlsRsaPremasterSecretParameterSpec( + clientVersion, serverVersion)); SecretKey key = kg.generateKey(); byte[] encoded = key.getEncoded(); - if (encoded.length != 48) { - throw new Exception("length: " + encoded.length); - } - if ((encoded[0] != major) || (encoded[1] != minor)) { - throw new Exception("version mismatch: " + encoded[0] + - "." + encoded[1]); - } - System.out.println("OK: " + major + "." + minor); + if (encoded != null) { // raw key material may be not extractable + if (encoded.length != 48) { + throw new Exception("length: " + encoded.length); + } + int v = versionOf(encoded[0], encoded[1]); + if (clientVersion != v) { + if (serverVersion != v || clientVersion >= 0x0302) { + throw new Exception(String.format( + "version mismatch: (0x%04X) rather than (0x%04X) " + + "is used in pre-master secret", v, clientVersion)); + } + System.out.printf("Use compatible version (0x%04X)%n", v); + } + System.out.println("Passed, version matches!"); + } else { + System.out.println("Raw key material is not extractable"); + } } + + private static int versionOf(int major, int minor) { + return ((major & 0xFF) << 8) | (minor & 0xFF); + } + } diff --git a/jdk/test/sun/tools/jstatd/JstatdTest.java b/jdk/test/sun/tools/jstatd/JstatdTest.java index f07ce6b1742..0c003cfcb5e 100644 --- a/jdk/test/sun/tools/jstatd/JstatdTest.java +++ b/jdk/test/sun/tools/jstatd/JstatdTest.java @@ -27,6 +27,7 @@ import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.Arrays; +import java.util.regex.Pattern; import static jdk.testlibrary.Asserts.*; import jdk.testlibrary.JDKToolLauncher; @@ -34,6 +35,7 @@ import jdk.testlibrary.OutputAnalyzer; import jdk.testlibrary.ProcessThread; import jdk.testlibrary.TestThread; import jdk.testlibrary.Utils; +import jdk.testlibrary.ProcessTools; /** * The base class for tests of jstatd. @@ -93,8 +95,11 @@ public final class JstatdTest { if (tool == "rmiregistry") { processName = "registryimpl"; } + + Pattern toolInJpsPattern = + Pattern.compile("^\\d+\\s{1}" + processName + "\\s{1}.*-dparent\\.pid\\." + ProcessTools.getProcessId() + ".*"); for (String line : lines) { - if (line.toLowerCase().matches("^\\d+\\s{1}" + processName + "$")) { + if (toolInJpsPattern.matcher(line.toLowerCase()).matches()) { pid = line.split(" ")[0]; count++; } @@ -167,6 +172,8 @@ public final class JstatdTest { private OutputAnalyzer runJps() throws Exception { JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jps"); launcher.addVMArg("-XX:+UsePerfData"); + // Run jps with -v flag to obtain -Dparent.pid. + launcher.addToolArg("-v"); launcher.addToolArg(getDestination()); String[] cmd = launcher.getCommand(); @@ -286,7 +293,7 @@ public final class JstatdTest { * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -n serverName * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port -n serverName */ - private String[] getJstatdCmd() throws UnknownHostException { + private String[] getJstatdCmd() throws Exception { JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstatd"); launcher.addVMArg("-XX:+UsePerfData"); String testSrc = System.getProperty("test.src"); @@ -294,6 +301,8 @@ public final class JstatdTest { assertTrue(policy.exists() && policy.isFile(), "Security policy " + policy.getAbsolutePath() + " does not exist or not a file"); launcher.addVMArg("-Djava.security.policy=" + policy.getAbsolutePath()); + // -Dparent.pid. will help to identify jstad process started by this test + launcher.addVMArg("-Dparent.pid." + ProcessTools.getProcessId()); if (port != null) { launcher.addToolArg("-p"); launcher.addToolArg(port); diff --git a/langtools/.hgtags b/langtools/.hgtags index f651ed43a29..0f2ed6e96c3 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -249,3 +249,4 @@ f2c58a337c8aaa1ce84dfa8a8e8c5d4c8c1e12fa jdk9-b02 fa2ec6b6b1697ae4a78b03b609664dc6b47dee86 jdk9-b04 1d5e6fc88a4cca287090c16b0530a0d5849a5603 jdk9-b05 31946c0a3f4dc2c78f6f09a0524aaa2a0dad1c78 jdk9-b06 +e25d44c21b29e155734f8d832f2edac3d0debe35 jdk9-b07 diff --git a/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java b/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java index 092f79bf528..b6e89031270 100644 --- a/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java +++ b/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java @@ -74,15 +74,6 @@ public interface ClassDoc extends ProgramElementDoc, Type { */ boolean isExternalizable(); - /** - * Return true if this class can be used as a target type of a lambda expression - * or method reference. - * - * @return true if this class can be used as a target type of a lambda expression - * or method reference. - */ - boolean isFunctionalInterface(); - /** * Return the serialization methods for this class or * interface. diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java index a1ac09529d7..ebcb7b64cf3 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.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 @@ -29,6 +29,7 @@ import java.util.*; import com.sun.javadoc.*; import com.sun.tools.javac.jvm.Profile; +import com.sun.tools.javadoc.RootDocImpl; import com.sun.tools.doclets.formats.html.markup.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.builders.*; @@ -528,7 +529,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter * {@inheritDoc} */ public void addFunctionalInterfaceInfo (Content classInfoTree) { - if (classDoc.isFunctionalInterface()) { + if (isFunctionalInterface()) { Content dt = HtmlTree.DT(getResource("doclet.Functional_Interface")); Content dl = HtmlTree.DL(dt); Content dd = new HtmlTree(HtmlTag.DD); @@ -538,6 +539,19 @@ public class ClassWriterImpl extends SubWriterHolderWriter } } + public boolean isFunctionalInterface() { + if (configuration.root instanceof RootDocImpl) { + RootDocImpl root = (RootDocImpl) configuration.root; + AnnotationDesc[] annotationDescList = classDoc.annotations(); + for (AnnotationDesc annoDesc : annotationDescList) { + if (root.isFunctionalInterface(annoDesc)) { + return true; + } + } + } + return false; + } + /** * {@inheritDoc} */ diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java index bccbba16322..ff4da111a8e 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.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 @@ -1443,7 +1443,8 @@ public class HtmlDocletWriter extends HtmlDocWriter { } } if (configuration.currentcd != containing) { - refMemName = containing.name() + "." + refMemName; + refMemName = (refMem instanceof ConstructorDoc) ? + refMemName : containing.name() + "." + refMemName; } if (refMem instanceof ExecutableMemberDoc) { if (refMemName.indexOf('(') < 0) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SerializedFormWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SerializedFormWriterImpl.java index 23ef78005bf..a6bbc6e0da2 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SerializedFormWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SerializedFormWriterImpl.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,6 +26,7 @@ package com.sun.tools.doclets.formats.html; import java.io.*; +import java.util.*; import com.sun.javadoc.*; import com.sun.tools.doclets.formats.html.markup.*; import com.sun.tools.doclets.internal.toolkit.*; @@ -45,6 +46,8 @@ import com.sun.tools.doclets.internal.toolkit.util.DocletAbortException; public class SerializedFormWriterImpl extends SubWriterHolderWriter implements SerializedFormWriter { + List visibleClasses; + /** * @param configuration the configuration data for the doclet * @throws IOException @@ -53,6 +56,7 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter public SerializedFormWriterImpl(ConfigurationImpl configuration) throws IOException { super(configuration, DocPaths.SERIALIZED_FORM); + visibleClasses = Arrays.asList(configuration.root.classes()); } /** @@ -120,6 +124,16 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter return ul; } + /** + * Checks if a class is generated and is visible. + * + * @param classDoc the class being processed. + * @return true if the class, that is being processed, is generated and is visible. + */ + public boolean isVisibleClass(ClassDoc classDoc) { + return visibleClasses.contains(classDoc) && configuration.isGeneratedDoc(classDoc); + } + /** * Get the serializable class heading. * @@ -127,7 +141,7 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter * @return a content tree for the class header */ public Content getClassHeader(ClassDoc classDoc) { - Content classLink = (classDoc.isPublic() || classDoc.isProtected()) ? + Content classLink = (isVisibleClass(classDoc)) ? getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.DEFAULT, classDoc) .label(configuration.getClassName(classDoc))) : new StringContent(classDoc.qualifiedName()); diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java b/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java index e44bca373fc..e056df50a1e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java +++ b/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, 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 @@ -151,11 +151,4 @@ public class BasicJavacTask extends JavacTask { return context; } - /** - * For internal use only. This method will be - * removed without warning. - */ - public void updateContext(Context newContext) { - context = newContext; - } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java index 3b39e405ec2..9dba0badced 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.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 @@ -316,7 +316,7 @@ public class JavacTaskImpl extends BasicJavacTask { List units = compiler.enterTrees(roots.toList()); if (notYetEntered.isEmpty()) - compiler = compiler.processAnnotations(units); + compiler.processAnnotations(units); ListBuffer elements = new ListBuffer<>(); for (JCCompilationUnit unit : units) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java index ebcac8c0c19..14b238b2827 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java @@ -141,6 +141,7 @@ public abstract class Attribute implements AnnotationValue { * access this attribute. */ public final List> values; + public TypeAnnotationPosition position; private boolean synthesized = false; @@ -154,10 +155,67 @@ public abstract class Attribute implements AnnotationValue { } public Compound(Type type, - List> values) { + List> values, + TypeAnnotationPosition position) { super(type); this.values = values; + this.position = position; } + + public Compound(Type type, + List> values) { + this(type, values, null); + } + + @Override + public TypeAnnotationPosition getPosition() { + if (hasUnknownPosition()) { + if (values.size() != 0) { + Name valueName = values.head.fst.name.table.names.value; + Pair res = getElemPair(valueName); + position = res == null ? null : res.snd.getPosition(); + } + } + return position; + } + + public boolean isContainerTypeCompound() { + if (isSynthesized() && values.size() == 1) + return getFirstEmbeddedTC() != null; + return false; + } + + private Compound getFirstEmbeddedTC() { + if (values.size() == 1) { + Pair val = values.get(0); + if (val.fst.getSimpleName().contentEquals("value") + && val.snd instanceof Array) { + Array arr = (Array) val.snd; + if (arr.values.length != 0 + && arr.values[0] instanceof Attribute.TypeCompound) + return (Attribute.TypeCompound) arr.values[0]; + } + } + return null; + } + + public boolean tryFixPosition() { + if (!isContainerTypeCompound()) + return false; + + Compound from = getFirstEmbeddedTC(); + if (from != null && from.position != null && + from.position.type != TargetType.UNKNOWN) { + position = from.position; + return true; + } + return false; + } + + public boolean hasUnknownPosition() { + return position.type == TargetType.UNKNOWN; + } + public void accept(Visitor v) { v.visitCompound(this); } /** @@ -215,16 +273,6 @@ public abstract class Attribute implements AnnotationValue { return (DeclaredType) type; } - @Override - public TypeAnnotationPosition getPosition() { - if (values.size() != 0) { - Name valueName = values.head.fst.name.table.names.value; - Pair res = getElemPair(valueName); - return res == null ? null : res.snd.getPosition(); - } - return null; - } - public Map getElementValues() { Map valmap = new LinkedHashMap<>(); for (Pair value : values) @@ -234,62 +282,15 @@ public abstract class Attribute implements AnnotationValue { } public static class TypeCompound extends Compound { - public TypeAnnotationPosition position; - public TypeCompound(Compound compound, - TypeAnnotationPosition position) { - this(compound.type, compound.values, position); + TypeAnnotationPosition position) { + super(compound.type, compound.values, position); } + public TypeCompound(Type type, - List> values, - TypeAnnotationPosition position) { - super(type, values); - this.position = position; - } - - @Override - public TypeAnnotationPosition getPosition() { - if (hasUnknownPosition()) { - position = super.getPosition(); - } - return position; - } - - public boolean hasUnknownPosition() { - return position.type == TargetType.UNKNOWN; - } - - public boolean isContainerTypeCompound() { - if (isSynthesized() && values.size() == 1) - return getFirstEmbeddedTC() != null; - return false; - } - - private TypeCompound getFirstEmbeddedTC() { - if (values.size() == 1) { - Pair val = values.get(0); - if (val.fst.getSimpleName().contentEquals("value") - && val.snd instanceof Array) { - Array arr = (Array) val.snd; - if (arr.values.length != 0 - && arr.values[0] instanceof Attribute.TypeCompound) - return (Attribute.TypeCompound) arr.values[0]; - } - } - return null; - } - - public boolean tryFixPosition() { - if (!isContainerTypeCompound()) - return false; - - TypeCompound from = getFirstEmbeddedTC(); - if (from != null && from.position != null && - from.position.type != TargetType.UNKNOWN) { - position = from.position; - return true; - } - return false; + List> values, + TypeAnnotationPosition position) { + super(type, values, position); } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java index ded0bb42a1f..517f5fc67a2 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java @@ -219,6 +219,9 @@ public enum Source { public boolean allowTypeAnnotations() { return compareTo(JDK1_8) >= 0; } + public boolean allowAnnotationsAfterTypeParams() { + return compareTo(JDK1_8) >= 0; + } public boolean allowRepeatedAnnotations() { return compareTo(JDK1_8) >= 0; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java index 1af2b332cc0..6e0f5ad2369 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java @@ -34,7 +34,6 @@ import javax.lang.model.element.*; import javax.tools.JavaFileObject; import com.sun.tools.javac.code.Type.*; -import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.comp.Attr; import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; @@ -153,10 +152,6 @@ public abstract class Symbol extends AnnoConstruct implements Element { } } - public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { - initedMetadata().appendTypeAttributesWithCompletion(ctx); - } - public void appendUniqueTypeAttributes(List l) { if (l.nonEmpty()) { initedMetadata().appendUniqueTypes(l); @@ -211,10 +206,6 @@ public abstract class Symbol extends AnnoConstruct implements Element { } } - public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { - initedMetadata().setDeclarationAttributesWithCompletion(ctx); - } - public void setTypeAttributes(List a) { if (metadata != null || a.nonEmpty()) { if (metadata == null) @@ -905,6 +896,12 @@ public abstract class Symbol extends AnnoConstruct implements Element { public R accept(Symbol.Visitor v, P p) { return v.visitPackageSymbol(this, p); } + + /**Resets the Symbol into the state good for next round of annotation processing.*/ + public void reset() { + metadata = null; + } + } /** A class for class symbols @@ -1154,6 +1151,26 @@ public abstract class Symbol extends AnnoConstruct implements Element { public R accept(Symbol.Visitor v, P p) { return v.visitClassSymbol(this, p); } + + /**Resets the Symbol into the state good for next round of annotation processing.*/ + public void reset() { + kind = TYP; + erasure_field = null; + members_field = null; + flags_field = 0; + if (type instanceof ClassType) { + ClassType t = (ClassType)type; + t.setEnclosingType(Type.noType); + t.rank_field = -1; + t.typarams_field = null; + t.allparams_field = null; + t.supertype_field = null; + t.interfaces_field = null; + t.all_interfaces_field = null; + } + metadata = null; + } + } diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/SymbolMetadata.java b/langtools/src/share/classes/com/sun/tools/javac/code/SymbolMetadata.java index f41dae9f5cf..ca7c9ff634b 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/SymbolMetadata.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/SymbolMetadata.java @@ -25,19 +25,9 @@ package com.sun.tools.javac.code; -import java.util.Map; -import javax.tools.JavaFileObject; - -import com.sun.tools.javac.comp.Annotate; -import com.sun.tools.javac.comp.AttrContext; -import com.sun.tools.javac.comp.Env; -import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Log; -import com.sun.tools.javac.util.Pair; -import static com.sun.tools.javac.code.Kinds.PCK; /** * Container for all annotations (attributes in javac) on a Symbol. @@ -157,70 +147,6 @@ public class SymbolMetadata { setClassInitTypeAttributes(other.getClassInitTypeAttributes()); } - public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { - Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK)); - this.setDeclarationAttributes(getAttributesForCompletion(ctx)); - } - - public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { - this.appendUniqueTypes(getAttributesForCompletion(ctx)); - } - - private List getAttributesForCompletion( - final Annotate.AnnotateRepeatedContext ctx) { - - Map> annotated = ctx.annotated; - boolean atLeastOneRepeated = false; - List buf = List.nil(); - for (ListBuffer lb : annotated.values()) { - if (lb.size() == 1) { - buf = buf.prepend(lb.first()); - } else { // repeated - // This will break when other subtypes of Attributs.Compound - // are introduced, because PlaceHolder is a subtype of TypeCompound. - T res; - @SuppressWarnings("unchecked") - T ph = (T) new Placeholder<>(ctx, lb.toList(), sym); - res = ph; - buf = buf.prepend(res); - atLeastOneRepeated = true; - } - } - - if (atLeastOneRepeated) { - // The Symbol s is now annotated with a combination of - // finished non-repeating annotations and placeholders for - // repeating annotations. - // - // We need to do this in two passes because when creating - // a container for a repeating annotation we must - // guarantee that the @Repeatable on the - // contained annotation is fully annotated - // - // The way we force this order is to do all repeating - // annotations in a pass after all non-repeating are - // finished. This will work because @Repeatable - // is non-repeating and therefore will be annotated in the - // fist pass. - - // Queue a pass that will replace Attribute.Placeholders - // with Attribute.Compound (made from synthesized containers). - ctx.annotateRepeated(new Annotate.Worker() { - @Override - public String toString() { - return "repeated annotation pass of: " + sym + " in: " + sym.owner; - } - - @Override - public void run() { - complete(ctx); - } - }); - } - // Add non-repeating attributes - return buf.reverse(); - } - public SymbolMetadata reset() { attributes = DECL_IN_PROGRESS; return this; @@ -313,143 +239,4 @@ public class SymbolMetadata { private boolean isStarted() { return attributes != DECL_NOT_STARTED; } - - private List getPlaceholders() { - List res = List.nil(); - for (Attribute.Compound a : filterDeclSentinels(attributes)) { - if (a instanceof Placeholder) { - res = res.prepend(a); - } - } - return res.reverse(); - } - - private List getTypePlaceholders() { - List res = List.nil(); - for (Attribute.TypeCompound a : type_attributes) { - if (a instanceof Placeholder) { - res = res.prepend(a); - } - } - return res.reverse(); - } - - /* - * Replace Placeholders for repeating annotations with their containers - */ - private void complete(Annotate.AnnotateRepeatedContext ctx) { - Log log = ctx.log; - Env env = ctx.env; - JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); - try { - // TODO: can we reduce duplication in the following branches? - if (ctx.isTypeCompound) { - Assert.check(!isTypesEmpty()); - - if (isTypesEmpty()) { - return; - } - - List result = List.nil(); - for (Attribute.TypeCompound a : getTypeAttributes()) { - if (a instanceof Placeholder) { - @SuppressWarnings("unchecked") - Placeholder ph = (Placeholder) a; - Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext()); - - if (null != replacement) { - result = result.prepend(replacement); - } - } else { - result = result.prepend(a); - } - } - - type_attributes = result.reverse(); - - Assert.check(SymbolMetadata.this.getTypePlaceholders().isEmpty()); - } else { - Assert.check(!pendingCompletion()); - - if (isEmpty()) { - return; - } - - List result = List.nil(); - for (Attribute.Compound a : getDeclarationAttributes()) { - if (a instanceof Placeholder) { - @SuppressWarnings("unchecked") - Attribute.Compound replacement = replaceOne((Placeholder) a, ctx); - - if (null != replacement) { - result = result.prepend(replacement); - } - } else { - result = result.prepend(a); - } - } - - attributes = result.reverse(); - - Assert.check(SymbolMetadata.this.getPlaceholders().isEmpty()); - } - } finally { - log.useSource(oldSource); - } - } - - private T replaceOne(Placeholder placeholder, Annotate.AnnotateRepeatedContext ctx) { - Log log = ctx.log; - - // Process repeated annotations - T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym); - - if (validRepeated != null) { - // Check that the container isn't manually - // present along with repeated instances of - // its contained annotation. - ListBuffer manualContainer = ctx.annotated.get(validRepeated.type.tsym); - if (manualContainer != null) { - log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present", - manualContainer.first().type.tsym); - } - } - - // A null return will delete the Placeholder - return validRepeated; - } - - private static class Placeholder extends Attribute.TypeCompound { - - private final Annotate.AnnotateRepeatedContext ctx; - private final List placeholderFor; - private final Symbol on; - - public Placeholder(Annotate.AnnotateRepeatedContext ctx, - List placeholderFor, Symbol on) { - super(on.type, List.>nil(), - ctx.isTypeCompound ? - ((Attribute.TypeCompound)placeholderFor.head).position : - // TODO: Eventually, we will need to get rid of this - // use of unknown, either by using null, or by - // throwing an assertion failure here. - TypeAnnotationPosition.unknown); - this.ctx = ctx; - this.placeholderFor = placeholderFor; - this.on = on; - } - - @Override - public String toString() { - return ""; - } - - public List getPlaceholderFor() { - return placeholderFor; - } - - public Annotate.AnnotateRepeatedContext getRepeatedContext() { - return ctx; - } - } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java index 4e011f04368..1ac90cd88c0 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java @@ -4684,4 +4684,12 @@ public class Types { } } // + + public void newRound() { + descCache._map.clear(); + isDerivedRawCache.clear(); + implCache._map.clear(); + membersCache._map.clear(); + closureCache.clear(); + } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java index 1a9e0626b1c..04e475e7b3c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -189,53 +189,72 @@ public class Annotate { * This context contains all the information needed to synthesize new * annotations trees by the completer for repeating annotations. */ - public class AnnotateRepeatedContext { + private class AnnotationContext { public final Env env; public final Map> annotated; public final Map pos; - public final Log log; public final boolean isTypeCompound; - public AnnotateRepeatedContext(Env env, - Map> annotated, - Map pos, - Log log, - boolean isTypeCompound) { + public AnnotationContext(Env env, + Map> annotated, + Map pos, + boolean isTypeCompound) { Assert.checkNonNull(env); Assert.checkNonNull(annotated); Assert.checkNonNull(pos); - Assert.checkNonNull(log); this.env = env; this.annotated = annotated; this.pos = pos; - this.log = log; this.isTypeCompound = isTypeCompound; } - /** - * Process a list of repeating annotations returning a new - * Attribute.Compound that is the attribute for the synthesized tree - * for the container. - * - * @param repeatingAnnotations a List of repeating annotations - * @return a new Attribute.Compound that is the container for the repeatingAnnotations - */ - public T processRepeatedAnnotations(List repeatingAnnotations, Symbol sym) { - return Annotate.this.processRepeatedAnnotations(repeatingAnnotations, this, sym); - } - - /** - * Queue the Worker a on the repeating annotations queue of the - * Annotate instance this context belongs to. - * - * @param a the Worker to enqueue for repeating annotation annotating - */ - public void annotateRepeated(Worker a) { - Annotate.this.repeated(a); + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("RepeatedContext["); + for (Map.Entry> entry : + annotated.entrySet()) { + sb.append(" "); + sb.append(entry.getKey()); + sb.append(" = { "); + sb.append(entry.getValue()); + sb.append(" }"); + } + sb.append(" ]"); + return sb.toString(); } } + private static class Placeholder extends Attribute.Compound { + + private final Annotate.AnnotationContext ctx; + private final List placeholderFor; + private final Symbol on; + + public Placeholder(Annotate.AnnotationContext ctx, + List placeholderFor, Symbol on) { + super(on.type, List.>nil(), + placeholderFor.head.position); + this.ctx = ctx; + this.placeholderFor = placeholderFor; + this.on = on; + } + + @Override + public String toString() { + return ""; + } + + public List getPlaceholderFor() { + return placeholderFor; + } + + public Annotate.AnnotationContext getRepeatedContext() { + return ctx; + } + } + + /* ******************************************************************** * Compute an attribute from its annotation. *********************************************************************/ @@ -247,24 +266,44 @@ public class Annotate { Attribute.Compound enterAnnotation(JCAnnotation a, Type expected, Env env) { - return enterAnnotation(a, expected, env, false); + List> elems = + enterAttributeValues(a, expected, env); + Attribute.Compound ac = new Attribute.Compound(a.type, elems); + a.attribute = ac; + + return ac; } Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a, - Type expected, - Env env) { - return (Attribute.TypeCompound) enterAnnotation(a, expected, env, true); + Type expected, + Env env) { + List> elems = + enterAttributeValues(a, expected, env); + + if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) { + // Create a new TypeCompound + + Attribute.TypeCompound tc = + new Attribute.TypeCompound(a.type, elems, + // TODO: Eventually, we will get rid of this use of + // unknown, because we'll get a position from + // MemberEnter (task 8027262). + TypeAnnotationPosition.unknown); + a.attribute = tc; + return tc; + } else { + // Use an existing TypeCompound + return (Attribute.TypeCompound)a.attribute; + } } - // boolean typeAnnotation determines whether the method returns - // a Compound (false) or TypeCompound (true). - Attribute.Compound enterAnnotation(JCAnnotation a, - Type expected, - Env env, - boolean typeAnnotation) { - // The annotation might have had its type attributed (but not checked) - // by attr.attribAnnotationTypes during MemberEnter, in which case we do not - // need to do it again. + private List> + enterAttributeValues(JCAnnotation a, + Type expected, + Env env) { + // The annotation might have had its type attributed (but not + // checked) by attr.attribAnnotationTypes during MemberEnter, + // in which case we do not need to do it again. Type at = (a.annotationType.type != null ? a.annotationType.type : attr.attribType(a.annotationType, env)); a.type = chk.checkType(a.annotationType.pos(), at, expected); @@ -312,27 +351,7 @@ public class Annotate { buf.append(new Pair<>((MethodSymbol)method, value)); t.type = result; } - if (typeAnnotation) { - if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) { - // Create a new TypeCompound - - Attribute.TypeCompound tc = - new Attribute.TypeCompound(a.type, buf.toList(), - // TODO: Eventually, we will get rid of this use of - // unknown, because we'll get a position from - // MemberEnter (task 8027262). - TypeAnnotationPosition.unknown); - a.attribute = tc; - return tc; - } else { - // Use an existing TypeCompound - return a.attribute; - } - } else { - Attribute.Compound ac = new Attribute.Compound(a.type, buf.toList()); - a.attribute = ac; - return ac; - } + return buf.toList(); } Attribute enterAttributeValue(Type expected, @@ -459,7 +478,7 @@ public class Annotate { * annotation are invalid. This method reports errors/warnings. */ private T processRepeatedAnnotations(List annotations, - AnnotateRepeatedContext ctx, + AnnotationContext ctx, Symbol on) { T firstOccurrence = annotations.head; List repeated = List.nil(); @@ -686,6 +705,172 @@ public class Annotate { return fatalError ? null : containerValueSymbol; } + private AnnotationContext + prepareEnterAnnotations(List annotations, + Env env, + Symbol sym, + AttributeCreator creator, + boolean isTypeCompound) { + Map> annotated = new LinkedHashMap<>(); + Map pos = new HashMap<>(); + + for (List al = annotations; !al.isEmpty(); al = al.tail) { + JCAnnotation a = al.head; + T c = creator.create(a, syms.annotationType, env); + + Assert.checkNonNull(c, "Failed to create annotation"); + + if (annotated.containsKey(a.type.tsym)) { + if (!allowRepeatedAnnos) { + log.error(a.pos(), "repeatable.annotations.not.supported.in.source"); + allowRepeatedAnnos = true; + } + ListBuffer l = annotated.get(a.type.tsym); + l = l.append(c); + annotated.put(a.type.tsym, l); + pos.put(c, a.pos()); + } else { + annotated.put(a.type.tsym, ListBuffer.of(c)); + pos.put(c, a.pos()); + } + + // Note: @Deprecated has no effect on local variables and parameters + if (!c.type.isErroneous() + && sym.owner.kind != MTH + && types.isSameType(c.type, syms.deprecatedType)) { + sym.flags_field |= Flags.DEPRECATED; + } + } + + return new AnnotationContext<>(env, annotated, pos, + isTypeCompound); + } + + // Gather up annotations into a map from type symbols to lists of + // Compound attributes, then continue on with repeating + // annotations processing + private + void attachAttributesLater(final List annotations, + final Env env, + final Symbol sym, + final boolean isTypeCompound, + final AttributeCreator creator, + final AttributeAttacher attacher) { + final AnnotationContext ctx = + prepareEnterAnnotations(annotations, env, sym, creator, isTypeCompound); + final Map> annotated = + ctx.annotated; + boolean hasRepeated = false; + + List buf = List.nil(); + for (ListBuffer lb : annotated.values()) { + if (lb.size() == 1) { + buf = buf.prepend(lb.first()); + } else { + @SuppressWarnings("unchecked") + T res = (T) new Placeholder<>(ctx, lb.toList(), sym); + buf = buf.prepend(res); + hasRepeated = true; + } + } + + final List attrs = buf.reverse(); + + if (!isTypeCompound) { + // Attach declaration attributes early, so + // that @Repeatable and other annotations get attached. + // Since the attacher uses setDeclarationAttributes, this + // will be overwritten later. + attacher.attach(sym, attrs); + } + if (hasRepeated) { + repeated(new Annotate.Worker() { + @Override + public String toString() { + return "repeated annotation pass of: " + sym + " in: " + sym.owner; + } + + @Override + public void run() { + JavaFileObject oldSource = + log.useSource(env.toplevel.sourcefile); + try { + attacher.attach(sym, replacePlaceholders(attrs, ctx, sym)); + } finally { + log.useSource(oldSource); + } + } + }); + } else { + attacher.attach(sym, attrs); + } + } + + private interface AttributeAttacher { + public void attach(Symbol sym, List attrs); + } + + private final AttributeAttacher declAnnotationsAttacher = + new AttributeAttacher() { + @Override + public void attach(Symbol sym, List attrs) { + sym.resetAnnotations(); + sym.setDeclarationAttributes(attrs); + } + }; + + private final AttributeAttacher typeAnnotationsAttacher = + new AttributeAttacher() { + @Override + public void attach(Symbol sym, List attrs) { + sym.appendUniqueTypeAttributes(attrs); + } + }; + + private List + replacePlaceholders(List buf, + Annotate.AnnotationContext ctx, + Symbol sym) { + List result = List.nil(); + for (T a : buf) { + if (a instanceof Placeholder) { + @SuppressWarnings("unchecked") + T replacement = replaceOne((Placeholder) a, ctx, sym); + + if (null != replacement) { + result = result.prepend(replacement); + } + } else { + result = result.prepend(a); + } + } + + return result.reverse(); + } + + private T replaceOne(Placeholder placeholder, + Annotate.AnnotationContext ctx, + Symbol sym) { + // Process repeated annotations + T validRepeated = + processRepeatedAnnotations(placeholder.getPlaceholderFor(), + ctx, sym); + + if (validRepeated != null) { + // Check that the container isn't manually + // present along with repeated instances of + // its contained annotation. + ListBuffer manualContainer = ctx.annotated.get(validRepeated.type.tsym); + if (manualContainer != null) { + log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present", + manualContainer.first().type.tsym); + } + } + + // A null return will delete the Placeholder + return validRepeated; + } + /* ******************************************************************** * Annotation processing *********************************************************************/ @@ -745,44 +930,39 @@ public class Annotate { }); } + private interface AttributeCreator { + public T create(JCAnnotation a, Type expected, Env env); + } + + // TODO: When SE8 features can be used, these can go away and be + // replaced by method refs. + private final AttributeCreator enterAnnotationsCreator = + new AttributeCreator() { + @Override + public Attribute.Compound create(JCAnnotation a, + Type expected, + Env env) { + return enterAnnotation(a, syms.annotationType, env); + } + }; + private final AttributeCreator enterTypeAnnotationsCreator = + new AttributeCreator() { + @Override + public Attribute.TypeCompound create(JCAnnotation a, + Type expected, + Env env) { + return enterTypeAnnotation(a, syms.annotationType, env); + } + }; + /** Enter a set of annotations. */ private void actualEnterAnnotations(List annotations, Env env, Symbol s) { - Map> annotated = new LinkedHashMap<>(); - Map pos = new HashMap<>(); - - for (List al = annotations; !al.isEmpty(); al = al.tail) { - JCAnnotation a = al.head; - Attribute.Compound c = enterAnnotation(a, syms.annotationType, env); - if (c == null) { - continue; - } - - if (annotated.containsKey(a.type.tsym)) { - if (!allowRepeatedAnnos) { - log.error(a.pos(), "repeatable.annotations.not.supported.in.source"); - allowRepeatedAnnos = true; - } - ListBuffer l = annotated.get(a.type.tsym); - l = l.append(c); - annotated.put(a.type.tsym, l); - pos.put(c, a.pos()); - } else { - annotated.put(a.type.tsym, ListBuffer.of(c)); - pos.put(c, a.pos()); - } - - // Note: @Deprecated has no effect on local variables and parameters - if (!c.type.isErroneous() - && s.owner.kind != MTH - && types.isSameType(c.type, syms.deprecatedType)) { - s.flags_field |= Flags.DEPRECATED; - } - } - - s.setDeclarationAttributesWithCompletion( - new AnnotateRepeatedContext<>(env, annotated, pos, log, false)); + Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null"); + attachAttributesLater(annotations, env, s, false, + enterAnnotationsCreator, + declAnnotationsAttacher); } /* @@ -792,9 +972,7 @@ public class Annotate { final Env env, final Symbol s, final DiagnosticPosition deferPos) { - Map> annotated = new LinkedHashMap<>(); - Map pos = new HashMap<>(); - + Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/"); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); DiagnosticPosition prevLintPos = null; @@ -802,32 +980,9 @@ public class Annotate { prevLintPos = deferredLintHandler.setPos(deferPos); } try { - - for (List al = annotations; !al.isEmpty(); al = al.tail) { - JCAnnotation a = al.head; - Attribute.TypeCompound tc = - enterTypeAnnotation(a, syms.annotationType, env); - - Assert.checkNonNull(tc, "Failed to create type annotation"); - - if (annotated.containsKey(a.type.tsym)) { - if (!allowRepeatedAnnos) { - log.error(a.pos(), "repeatable.annotations.not.supported.in.source"); - allowRepeatedAnnos = true; - } - ListBuffer l = annotated.get(a.type.tsym); - l = l.append(tc); - annotated.put(a.type.tsym, l); - pos.put(tc, a.pos()); - } else { - annotated.put(a.type.tsym, ListBuffer.of(tc)); - pos.put(tc, a.pos()); - } - } - - Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is null"); - s.appendTypeAttributesWithCompletion( - new AnnotateRepeatedContext<>(env, annotated, pos, log, true)); + attachAttributesLater(annotations, env, s, true, + enterTypeAnnotationsCreator, + typeAnnotationsAttacher); } finally { if (prevLintPos != null) deferredLintHandler.setPos(prevLintPos); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index 1ab10af50e0..1db0f325214 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -804,6 +804,10 @@ public class Attr extends JCTree.Visitor { boolean classExpected, boolean interfaceExpected, boolean checkExtensible) { + if (t.tsym.isAnonymous()) { + log.error(tree.pos(), "cant.inherit.from.anon"); + return types.createErrorType(t); + } if (t.isErroneous()) return t; if (t.hasTag(TYPEVAR) && !classExpected && !interfaceExpected) { @@ -2112,10 +2116,8 @@ public class Attr extends JCTree.Visitor { // // This expression is then *transformed* as follows: // - // (1) add a STATIC flag to the class definition - // if the current environment is static - // (2) add an extends or implements clause - // (3) add a constructor. + // (1) add an extends or implements clause + // (2) add a constructor. // // For instance, if C is a class, and ET is the type of E, // the expression @@ -2132,7 +2134,6 @@ public class Attr extends JCTree.Visitor { // } // ... // } - if (Resolve.isStatic(env)) cdef.mods.flags |= STATIC; if (clazztype.tsym.isInterface()) { cdef.implementing = List.of(clazz); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index 1bec67e8a0c..6c2d1de3ded 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -425,6 +425,10 @@ public class Check { } } + public void newRound() { + compiled.clear(); + } + /* ************************************************************************* * Type Checking **************************************************************************/ @@ -1072,9 +1076,6 @@ public class Check { if (sym.isLocal()) { mask = LocalClassFlags; if (sym.name.isEmpty()) { // Anonymous class - // Anonymous classes in static methods are themselves static; - // that's why we admit STATIC here. - mask |= STATIC; // JLS: Anonymous classes are final. implicit |= FINAL; } @@ -1625,7 +1626,7 @@ public class Check { protection(m.flags()) > protection(other.flags())) { log.error(TreeInfo.diagnosticPositionFor(m, tree), "override.weaker.access", cannotOverride(m, other), - other.flags() == 0 ? + (other.flags() & AccessFlags) == 0 ? "package" : asFlagSet(other.flags() & AccessFlags)); m.flags_field |= BAD_OVERRIDE; diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java index cb2d88e6f1f..c9985f7c997 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java @@ -154,6 +154,10 @@ public class Enter extends JCTree.Visitor { return typeEnvs.get(sym); } + public Iterable> getEnvs() { + return typeEnvs.values(); + } + public Env getClassEnv(TypeSymbol sym) { Env localEnv = getEnv(sym); Env lintEnv = localEnv; @@ -514,4 +518,8 @@ public class Enter extends JCTree.Visitor { annotate.enterDone(); } } + + public void newRound() { + typeEnvs.clear(); + } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java index d7046596483..31f5095e93b 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java @@ -2919,15 +2919,65 @@ public class Lower extends TreeTranslator { // constant propagation would require that we take care to // preserve possible side-effects in the condition expression. + // One common case is equality expressions involving a constant and null. + // Since null is not a constant expression (because null cannot be + // represented in the constant pool), equality checks involving null are + // not captured by Flow.isTrue/isFalse. + // Equality checks involving a constant and null, e.g. + // "" == null + // are safe to simplify as no side-effects can occur. + + private boolean isTrue(JCTree exp) { + if (exp.type.isTrue()) + return true; + Boolean b = expValue(exp); + return b == null ? false : b; + } + private boolean isFalse(JCTree exp) { + if (exp.type.isFalse()) + return true; + Boolean b = expValue(exp); + return b == null ? false : !b; + } + /* look for (in)equality relations involving null. + * return true - if expression is always true + * false - if expression is always false + * null - if expression cannot be eliminated + */ + private Boolean expValue(JCTree exp) { + while (exp.hasTag(PARENS)) + exp = ((JCParens)exp).expr; + + boolean eq; + switch (exp.getTag()) { + case EQ: eq = true; break; + case NE: eq = false; break; + default: + return null; + } + + // we have a JCBinary(EQ|NE) + // check if we have two literals (constants or null) + JCBinary b = (JCBinary)exp; + if (b.lhs.type.hasTag(BOT)) return expValueIsNull(eq, b.rhs); + if (b.rhs.type.hasTag(BOT)) return expValueIsNull(eq, b.lhs); + return null; + } + private Boolean expValueIsNull(boolean eq, JCTree t) { + if (t.type.hasTag(BOT)) return Boolean.valueOf(eq); + if (t.hasTag(LITERAL)) return Boolean.valueOf(!eq); + return null; + } + /** Visitor method for conditional expressions. */ @Override public void visitConditional(JCConditional tree) { JCTree cond = tree.cond = translate(tree.cond, syms.booleanType); - if (cond.type.isTrue()) { + if (isTrue(cond)) { result = convert(translate(tree.truepart, tree.type), tree.type); addPrunedInfo(cond); - } else if (cond.type.isFalse()) { + } else if (isFalse(cond)) { result = convert(translate(tree.falsepart, tree.type), tree.type); addPrunedInfo(cond); } else { @@ -2951,10 +3001,10 @@ public class Lower extends TreeTranslator { */ public void visitIf(JCIf tree) { JCTree cond = tree.cond = translate(tree.cond, syms.booleanType); - if (cond.type.isTrue()) { + if (isTrue(cond)) { result = translate(tree.thenpart); addPrunedInfo(cond); - } else if (cond.type.isFalse()) { + } else if (isFalse(cond)) { if (tree.elsepart != null) { result = translate(tree.elsepart); } else { @@ -3333,21 +3383,21 @@ public class Lower extends TreeTranslator { JCTree lhs = tree.lhs = translate(tree.lhs, formals.head); switch (tree.getTag()) { case OR: - if (lhs.type.isTrue()) { + if (isTrue(lhs)) { result = lhs; return; } - if (lhs.type.isFalse()) { + if (isFalse(lhs)) { result = translate(tree.rhs, formals.tail.head); return; } break; case AND: - if (lhs.type.isFalse()) { + if (isFalse(lhs)) { result = lhs; return; } - if (lhs.type.isTrue()) { + if (isTrue(lhs)) { result = translate(tree.rhs, formals.tail.head); return; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java index 9c30d1b9834..29f0215137c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -748,7 +748,7 @@ public class TransTypes extends TreeTranslator { tree.clazz = translate(tree.clazz, null); Type originalTarget = tree.type; tree.type = erasure(tree.type); - tree.expr = translate(tree.expr, tree.type); + tree.expr = translate(tree.expr, erasure(tree.expr.type)); if (originalTarget.isCompound()) { Type.IntersectionClassType ict = (Type.IntersectionClassType)originalTarget; for (Type c : ict.getExplicitComponents()) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java index 48d1f13fdcc..c7b92919886 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, 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 @@ -107,10 +107,6 @@ public class ZipFileIndexArchive implements Archive { */ ZipFileIndex.Entry entry; - /** The InputStream for this zip entry (file.) - */ - InputStream inputStream = null; - /** The name of the zip file where this entry resides. */ File zipName; @@ -146,11 +142,8 @@ public class ZipFileIndexArchive implements Archive { @Override public InputStream openInputStream() throws IOException { - if (inputStream == null) { - Assert.checkNonNull(entry); // see constructor - inputStream = new ByteArrayInputStream(zfIndex.read(entry)); - } - return inputStream; + Assert.checkNonNull(entry); // see constructor + return new ByteArrayInputStream(zfIndex.read(entry)); } @Override diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java index ba6fc9e4cf1..c1fdd998dec 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -2501,6 +2501,8 @@ public class ClassReader { return; } catch (IOException ex) { throw badClassFile("unable.to.access.file", ex.getMessage()); + } catch (ArrayIndexOutOfBoundsException ex) { + throw badClassFile("bad.class.file", c.flatname); } finally { currentClassFile = previousClassFile; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java index cd30dbcd0df..18db5cf5554 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -298,12 +298,6 @@ public class JavaCompiler { */ protected MultiTaskListener taskListener; - /** - * Annotation processing may require and provide a new instance - * of the compiler to be used for the analyze and generate phases. - */ - protected JavaCompiler delegateCompiler; - /** * SourceCompleter that delegates to the complete-method of this class. */ @@ -567,12 +561,8 @@ public class JavaCompiler { /** The number of errors reported so far. */ public int errorCount() { - if (delegateCompiler != null && delegateCompiler != this) - return delegateCompiler.errorCount(); - else { - if (werror && log.nerrors == 0 && log.nwarnings > 0) { - log.error("warnings.and.werror"); - } + if (werror && log.nerrors == 0 && log.nwarnings > 0) { + log.error("warnings.and.werror"); } return log.nerrors; } @@ -588,10 +578,7 @@ public class JavaCompiler { /** The number of warnings reported so far. */ public int warningCount() { - if (delegateCompiler != null && delegateCompiler != this) - return delegateCompiler.warningCount(); - else - return log.nwarnings; + return log.nwarnings; } /** Try to open input stream with given name. @@ -759,21 +746,32 @@ public class JavaCompiler { * @param c The class the source file of which needs to be compiled. */ public void complete(ClassSymbol c) throws CompletionFailure { + complete(null, c); + } + + /** Complete a ClassSymbol from source, optionally using the given compilation unit as + * the source tree. + * @param tree the compilation unit int which the given ClassSymbol resides, + * or null if should be parsed from source + * @param c the ClassSymbol to complete + */ + public void complete(JCCompilationUnit tree, ClassSymbol c) throws CompletionFailure { // System.err.println("completing " + c);//DEBUG if (completionFailureName == c.fullname) { throw new CompletionFailure(c, "user-selected completion failure by class name"); } - JCCompilationUnit tree; JavaFileObject filename = c.classfile; JavaFileObject prev = log.useSource(filename); - try { - tree = parse(filename, filename.getCharContent(false)); - } catch (IOException e) { - log.error("error.reading.file", filename, JavacFileManager.getMessage(e)); - tree = make.TopLevel(List.nil(), null, List.nil()); - } finally { - log.useSource(prev); + if (tree == null) { + try { + tree = parse(filename, filename.getCharContent(false)); + } catch (IOException e) { + log.error("error.reading.file", filename, JavacFileManager.getMessage(e)); + tree = make.TopLevel(List.nil(), null, List.nil()); + } finally { + log.useSource(prev); + } } if (!taskListener.isEmpty()) { @@ -851,35 +849,16 @@ public class JavaCompiler { initProcessAnnotations(processors); // These method calls must be chained to avoid memory leaks - delegateCompiler = - processAnnotations( - enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))), - classnames); + processAnnotations( + enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))), + classnames); // If it's safe to do so, skip attr / flow / gen for implicit classes if (taskListener.isEmpty() && implicitSourcePolicy == ImplicitSourcePolicy.NONE) { - delegateCompiler.todo.retainFiles(delegateCompiler.inputFiles); + todo.retainFiles(inputFiles); } - delegateCompiler.compile2(); - delegateCompiler.close(); - elapsed_msec = delegateCompiler.elapsed_msec; - } catch (Abort ex) { - if (devVerbose) - ex.printStackTrace(System.err); - } finally { - if (procEnvImpl != null) - procEnvImpl.close(); - } - } - - /** - * The phases following annotation processing: attribution, - * desugar, and finally code generation. - */ - private void compile2() { - try { switch (compilePolicy) { case ATTR_ONLY: attribute(todo); @@ -912,18 +891,21 @@ public class JavaCompiler { } catch (Abort ex) { if (devVerbose) ex.printStackTrace(System.err); - } + } finally { + if (verbose) { + elapsed_msec = elapsed(start_msec); + log.printVerbose("total", Long.toString(elapsed_msec)); + } - if (verbose) { - elapsed_msec = elapsed(start_msec); - log.printVerbose("total", Long.toString(elapsed_msec)); - } + reportDeferredDiagnostics(); - reportDeferredDiagnostics(); - - if (!log.hasDiagnosticListener()) { - printCount("error", errorCount()); - printCount("warn", warningCount()); + if (!log.hasDiagnosticListener()) { + printCount("error", errorCount()); + printCount("warn", warningCount()); + } + close(); + if (procEnvImpl != null) + procEnvImpl.close(); } } @@ -1069,8 +1051,8 @@ public class JavaCompiler { } // TODO: called by JavacTaskImpl - public JavaCompiler processAnnotations(List roots) { - return processAnnotations(roots, List.nil()); + public void processAnnotations(List roots) { + processAnnotations(roots, List.nil()); } /** @@ -1084,8 +1066,8 @@ public class JavaCompiler { // By the time this method exits, log.deferDiagnostics must be set back to false, // and all deferredDiagnostics must have been handled: i.e. either reported // or determined to be transient, and therefore suppressed. - public JavaCompiler processAnnotations(List roots, - List classnames) { + public void processAnnotations(List roots, + List classnames) { if (shouldStop(CompileState.PROCESS)) { // Errors were encountered. // Unless all the errors are resolve errors, the errors were parse errors @@ -1094,7 +1076,7 @@ public class JavaCompiler { if (unrecoverableError()) { deferredDiagnosticHandler.reportDeferredDiagnostics(); log.popDiagnosticHandler(deferredDiagnosticHandler); - return this; + return ; } } @@ -1117,7 +1099,7 @@ public class JavaCompiler { classnames); } Assert.checkNull(deferredDiagnosticHandler); - return this; // continue regular compilation + return ; // continue regular compilation } Assert.checkNonNull(deferredDiagnosticHandler); @@ -1133,7 +1115,7 @@ public class JavaCompiler { classnames); deferredDiagnosticHandler.reportDeferredDiagnostics(); log.popDiagnosticHandler(deferredDiagnosticHandler); - return this; // TODO: Will this halt compilation? + return ; // TODO: Will this halt compilation? } else { boolean errors = false; for (String nameStr : classnames) { @@ -1167,25 +1149,26 @@ public class JavaCompiler { if (errors) { deferredDiagnosticHandler.reportDeferredDiagnostics(); log.popDiagnosticHandler(deferredDiagnosticHandler); - return this; + return ; } } } try { - JavaCompiler c = procEnvImpl.doProcessing(context, roots, classSymbols, pckSymbols, - deferredDiagnosticHandler); - if (c != this) - annotationProcessingOccurred = c.annotationProcessingOccurred = true; + annotationProcessingOccurred = + procEnvImpl.doProcessing(roots, + classSymbols, + pckSymbols, + deferredDiagnosticHandler); // doProcessing will have handled deferred diagnostics - return c; } finally { procEnvImpl.close(); } } catch (CompletionFailure ex) { log.error("cant.access", ex.sym, ex.getDetailValue()); - deferredDiagnosticHandler.reportDeferredDiagnostics(); - log.popDiagnosticHandler(deferredDiagnosticHandler); - return this; + if (deferredDiagnosticHandler != null) { + deferredDiagnosticHandler.reportDeferredDiagnostics(); + log.popDiagnosticHandler(deferredDiagnosticHandler); + } } } @@ -1213,6 +1196,10 @@ public class JavaCompiler { options.isSet(XPRINT); } + public void setDeferredDiagnosticHandler(Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { + this.deferredDiagnosticHandler = deferredDiagnosticHandler; + } + /** * Attribute a list of parse trees, such as found on the "todo" list. * Note that attributing classes may cause additional files to be @@ -1674,10 +1661,6 @@ public class JavaCompiler { /** Close the compiler, flushing the logs */ public void close() { - close(true); - } - - public void close(boolean disposeNames) { rootClasses = null; reader = null; make = null; @@ -1704,7 +1687,7 @@ public class JavaCompiler { } catch (IOException e) { throw new Abort(e); } finally { - if (names != null && disposeNames) + if (names != null) names.dispose(); names = null; @@ -1750,14 +1733,8 @@ public class JavaCompiler { return now() - then; } - public void initRound(JavaCompiler prev) { - genEndPos = prev.genEndPos; - keepComments = prev.keepComments; - start_msec = prev.start_msec; - hasBeenUsed = true; - closeables = prev.closeables; - prev.closeables = List.nil(); - shouldStopPolicyIfError = prev.shouldStopPolicyIfError; - shouldStopPolicyIfNoError = prev.shouldStopPolicyIfNoError; + public void newRound() { + inputFiles.clear(); + todo.clear(); } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java index 669c897627b..2c7f2f55939 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/Main.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 @@ -506,6 +506,11 @@ public class Main { } } + if (options.get(XSTDOUT) != null) { + // Stdout reassigned - ask compiler to close it when it is done + comp.closeables = comp.closeables.prepend(log.getWriter(WriterKind.NOTICE)); + } + fileManager = context.get(JavaFileManager.class); if (!files.isEmpty()) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/Option.java b/langtools/src/share/classes/com/sun/tools/javac/main/Option.java index 6ecf168d894..8821970f904 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/Option.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/Option.java @@ -399,7 +399,6 @@ public enum Option { public boolean process(OptionHelper helper, String option, String arg) { try { Log log = helper.getLog(); - // TODO: this file should be closed at the end of compilation log.setWriters(new PrintWriter(new FileWriter(arg), true)); } catch (java.io.IOException e) { helper.error("err.error.writing.file", arg, e); diff --git a/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java b/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java index b1a6cd19ba7..dbe7bb59d7c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.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 @@ -60,11 +60,11 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*; */ public class JavacElements implements Elements { - private JavaCompiler javaCompiler; - private Symtab syms; - private Names names; - private Types types; - private Enter enter; + private final JavaCompiler javaCompiler; + private final Symtab syms; + private final Names names; + private final Types types; + private final Enter enter; public static JavacElements instance(Context context) { JavacElements instance = context.get(JavacElements.class); @@ -73,18 +73,7 @@ public class JavacElements implements Elements { return instance; } - /** - * Public for use only by JavacProcessingEnvironment - */ protected JavacElements(Context context) { - setContext(context); - } - - /** - * Use a new context. May be called from outside to update - * internal state for a new annotation-processing round. - */ - public void setContext(Context context) { context.put(JavacElements.class, this); javaCompiler = JavaCompiler.instance(context); syms = Symtab.instance(context); diff --git a/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java b/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java index e56eedd7a9a..5b780ede81d 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java +++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.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 @@ -48,8 +48,8 @@ import com.sun.tools.javac.util.*; */ public class JavacTypes implements javax.lang.model.util.Types { - private Symtab syms; - private Types types; + private final Symtab syms; + private final Types types; public static JavacTypes instance(Context context) { JavacTypes instance = context.get(JavacTypes.class); @@ -58,18 +58,7 @@ public class JavacTypes implements javax.lang.model.util.Types { return instance; } - /** - * Public for use only by JavacProcessingEnvironment - */ protected JavacTypes(Context context) { - setContext(context); - } - - /** - * Use a new context. May be called from outside to update - * internal state for a new annotation-processing round. - */ - public void setContext(Context context) { context.put(JavacTypes.class, this); syms = Symtab.instance(context); types = Types.instance(context); diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index aba1c7bc73a..c8a26f35f61 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -161,6 +161,7 @@ public class JavacParser implements Parser { this.allowStaticInterfaceMethods = source.allowStaticInterfaceMethods(); this.allowIntersectionTypesInCast = source.allowIntersectionTypesInCast(); this.allowTypeAnnotations = source.allowTypeAnnotations(); + this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams(); this.keepDocComments = keepDocComments; docComments = newDocCommentTable(keepDocComments, fac); this.keepLineMap = keepLineMap; @@ -254,6 +255,10 @@ public class JavacParser implements Parser { */ boolean allowTypeAnnotations; + /** Switch: should we allow annotations after the method type parameters? + */ + boolean allowAnnotationsAfterTypeParams; + /** Switch: is "this" allowed as an identifier? * This is needed to parse receiver types. */ @@ -2026,7 +2031,7 @@ public class JavacParser implements Parser { /** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest ) */ JCExpression creator(int newpos, List typeArgs) { - List newAnnotations = annotationsOpt(Tag.ANNOTATION); + List newAnnotations = typeAnnotationsOpt(); switch (token.kind) { case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: @@ -3355,7 +3360,7 @@ public class JavacParser implements Parser { ? arguments() : List.nil(); JCClassDecl body = null; if (token.kind == LBRACE) { - JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC); + JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM); List defs = classOrInterfaceBody(names.empty, false); body = toP(F.at(identPos).AnonymousClassDef(mods1, defs)); } @@ -3464,6 +3469,7 @@ public class JavacParser implements Parser { nextToken(); } else { if (annosAfterParams.nonEmpty()) { + checkAnnotationsAfterTypeParams(annosAfterParams.head.pos); mods.annotations = mods.annotations.appendList(annosAfterParams); if (mods.pos == Position.NOPOS) mods.pos = mods.annotations.head.pos; @@ -4063,6 +4069,12 @@ public class JavacParser implements Parser { allowTypeAnnotations = true; } } + void checkAnnotationsAfterTypeParams(int pos) { + if (!allowAnnotationsAfterTypeParams) { + log.error(pos, "annotations.after.type.params.not.supported.in.source", source.name); + allowAnnotationsAfterTypeParams = true; + } + } /* * a functional source tree and end position mappings diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java index fc830c40e51..06e033c8b5c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.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 @@ -564,9 +564,7 @@ public class JavacFiler implements Filer, Closeable { /** * Update internal state for a new round. */ - public void newRound(Context context) { - this.context = context; - this.log = Log.instance(context); + public void newRound() { clearRoundState(); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacMessager.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacMessager.java index bc6acc1a096..0cb3c8f3e6f 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacMessager.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacMessager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, 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 @@ -176,8 +176,7 @@ public class JavacMessager implements Messager { return warningCount; } - public void newRound(Context context) { - log = Log.instance(context); + public void newRound() { errorCount = 0; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 1f48ab27287..a0b3fe64a21 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -38,27 +38,27 @@ import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.*; import javax.lang.model.util.*; -import javax.tools.DiagnosticListener; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import static javax.tools.StandardLocation.*; -import com.sun.source.util.JavacTask; import com.sun.source.util.TaskEvent; -import com.sun.tools.javac.api.BasicJavacTask; -import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.api.MultiTaskListener; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.*; -import com.sun.tools.javac.file.FSInfo; +import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Check; +import com.sun.tools.javac.comp.Enter; +import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.jvm.ClassReader.BadClassFile; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.model.JavacElements; import com.sun.tools.javac.model.JavacTypes; -import com.sun.tools.javac.parser.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Abort; @@ -103,6 +103,8 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea private final JavacMessager messager; private final JavacElements elementUtils; private final JavacTypes typeUtils; + private final Types types; + private final JavaCompiler compiler; /** * Holds relevant state history of which processors have been @@ -131,7 +133,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea /** The log to be used for error reporting. */ - Log log; + final Log log; /** Diagnostic factory. */ @@ -151,8 +153,13 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea private JavacMessages messages; private MultiTaskListener taskListener; + private final Symtab symtab; + private final Names names; + private final Enter enter; + private final Completer initialCompleter; + private final Check chk; - private Context context; + private final Context context; /** Get the JavacProcessingEnvironment instance for this context. */ public static JavacProcessingEnvironment instance(Context context) { @@ -173,8 +180,8 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea printRounds = options.isSet(XPRINTROUNDS); verbose = options.isSet(VERBOSE); lint = Lint.instance(context).isEnabled(PROCESSING); + compiler = JavaCompiler.instance(context); if (options.isSet(PROC, "only") || options.isSet(XPRINT)) { - JavaCompiler compiler = JavaCompiler.instance(context); compiler.shouldStopPolicyIfNoError = CompileState.PROCESS; } fatalErrors = options.isSet("fatalEnterError"); @@ -188,16 +195,22 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea messager = new JavacMessager(context, this); elementUtils = JavacElements.instance(context); typeUtils = JavacTypes.instance(context); - processorOptions = initProcessorOptions(context); + types = Types.instance(context); + processorOptions = initProcessorOptions(); unmatchedProcessorOptions = initUnmatchedProcessorOptions(); messages = JavacMessages.instance(context); taskListener = MultiTaskListener.instance(context); + symtab = Symtab.instance(context); + names = Names.instance(context); + enter = Enter.instance(context); + initialCompleter = ClassReader.instance(context).getCompleter(); + chk = Check.instance(context); initProcessorClassLoader(); } public void setProcessors(Iterable processors) { Assert.checkNull(discoveredProcs); - initProcessorIterator(context, processors); + initProcessorIterator(processors); } private Set initPlatformAnnotations() { @@ -221,7 +234,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea : fileManager.getClassLoader(CLASS_PATH); if (processorClassLoader != null && processorClassLoader instanceof Closeable) { - JavaCompiler compiler = JavaCompiler.instance(context); compiler.closeables = compiler.closeables.prepend((Closeable) processorClassLoader); } } catch (SecurityException e) { @@ -229,8 +241,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } } - private void initProcessorIterator(Context context, Iterable processors) { - Log log = Log.instance(context); + private void initProcessorIterator(Iterable processors) { Iterator processorIterator; if (options.isSet(XPRINT)) { @@ -447,8 +458,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea return discoveredProcs.iterator().hasNext(); } - private Map initProcessorOptions(Context context) { - Options options = Options.instance(context); + private Map initProcessorOptions() { Set keySet = options.keySet(); Map tempOptions = new LinkedHashMap<>(); @@ -653,8 +663,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } } - private void discoverAndRunProcs(Context context, - Set annotationsPresent, + private void discoverAndRunProcs(Set annotationsPresent, List topLevelClasses, List packageInfoFiles) { Map unmatchedAnnotations = new HashMap<>(annotationsPresent.size()); @@ -724,7 +733,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea // Remove annotations processed by javac unmatchedAnnotations.keySet().removeAll(platformAnnotations); if (unmatchedAnnotations.size() > 0) { - log = Log.instance(context); log.warning("proc.annotations.without.processors", unmatchedAnnotations.keySet()); } @@ -761,14 +769,14 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea public Set visitType(TypeElement e, Set p) { // Type parameters are not considered to be enclosed by a type scan(e.getTypeParameters(), p); - return scan(e.getEnclosedElements(), p); + return super.visitType(e, p); } @Override public Set visitExecutable(ExecutableElement e, Set p) { // Type parameters are not considered to be enclosed by an executable scan(e.getTypeParameters(), p); - return scan(e.getEnclosedElements(), p); + return super.visitExecutable(e, p); } void addAnnotations(Element e, Set p) { @@ -812,17 +820,13 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea class Round { /** The round number. */ final int number; - /** The context for the round. */ - final Context context; - /** The compiler for the round. */ - final JavaCompiler compiler; - /** The log for the round. */ - final Log log; /** The diagnostic handler for the round. */ final Log.DeferredDiagnosticHandler deferredDiagnosticHandler; /** The ASTs to be compiled. */ List roots; + /** The trees that need to be cleaned - includes roots and implicitly parsed trees. */ + Set treesToClean; /** The classes to be compiler that have were generated. */ Map genClassFiles; @@ -834,39 +838,33 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea List packageInfoFiles; /** Create a round (common code). */ - private Round(Context context, int number, int priorErrors, int priorWarnings, + private Round(int number, Set treesToClean, Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { - this.context = context; this.number = number; - compiler = JavaCompiler.instance(context); - log = Log.instance(context); - log.nerrors = priorErrors; - log.nwarnings = priorWarnings; if (number == 1) { Assert.checkNonNull(deferredDiagnosticHandler); this.deferredDiagnosticHandler = deferredDiagnosticHandler; } else { this.deferredDiagnosticHandler = new Log.DeferredDiagnosticHandler(log); + compiler.setDeferredDiagnosticHandler(this.deferredDiagnosticHandler); } - // the following is for the benefit of JavacProcessingEnvironment.getContext() - JavacProcessingEnvironment.this.context = context; - // the following will be populated as needed topLevelClasses = List.nil(); packageInfoFiles = List.nil(); + this.treesToClean = treesToClean; } /** Create the first round. */ - Round(Context context, List roots, List classSymbols, - Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { - this(context, 1, 0, 0, deferredDiagnosticHandler); + Round(List roots, + List classSymbols, + Set treesToClean, + Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { + this(1, treesToClean, deferredDiagnosticHandler); this.roots = roots; genClassFiles = new HashMap<>(); - compiler.todo.clear(); // free the compiler's resources - // The reverse() in the following line is to maintain behavioural // compatibility with the previous revision of the code. Strictly speaking, // it should not be necessary, but a javah golden file test fails without it. @@ -881,15 +879,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea /** Create a new round. */ private Round(Round prev, Set newSourceFiles, Map newClassFiles) { - this(prev.nextContext(), - prev.number+1, - prev.compiler.log.nerrors, - prev.compiler.log.nwarnings, - null); + this(prev.number+1, prev.treesToClean, null); + prev.newRound(); this.genClassFiles = prev.genClassFiles; List parsedFiles = compiler.parseFiles(newSourceFiles); - roots = cleanTrees(prev.roots).appendList(parsedFiles); + roots = prev.roots.appendList(parsedFiles); // Check for errors after parsing if (unrecoverableError()) @@ -916,24 +911,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea /** Create the next round to be used. */ Round next(Set newSourceFiles, Map newClassFiles) { - try { - return new Round(this, newSourceFiles, newClassFiles); - } finally { - compiler.close(false); - } + return new Round(this, newSourceFiles, newClassFiles); } - /** Create the compiler to be used for the final compilation. */ - JavaCompiler finalCompiler() { - try { - Context nextCtx = nextContext(); - JavacProcessingEnvironment.this.context = nextCtx; - JavaCompiler c = JavaCompiler.instance(nextCtx); - c.log.initRound(compiler.log); - return c; - } finally { - compiler.close(false); - } + /** Prepare the compiler for the final compilation. */ + void finalCompiler() { + newRound(); } /** Return the number of errors found so far in this round. @@ -984,8 +967,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea /** Enter a set of generated class files. */ private List enterClassFiles(Map classFiles) { - Symtab symtab = Symtab.instance(context); - Names names = Names.instance(context); List list = List.nil(); for (Map.Entry entry : classFiles.entrySet()) { @@ -1000,10 +981,16 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (p.package_info == null) p.package_info = symtab.enterClass(Convert.shortName(name), p); cs = p.package_info; + cs.reset(); if (cs.classfile == null) cs.classfile = file; - } else - cs = symtab.enterClass(name, file); + cs.completer = initialCompleter; + } else { + cs = symtab.enterClass(name); + cs.reset(); + cs.classfile = file; + cs.completer = initialCompleter; + } list = list.prepend(cs); } return list.reverse(); @@ -1031,7 +1018,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea JavacProcessingEnvironment.this); discoveredProcs.iterator().runContributingProcs(renv); } else { - discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles); + discoverAndRunProcs(annotationsPresent, topLevelClasses, packageInfoFiles); } } catch (Throwable t) { // we're specifically expecting Abort here, but if any Throwable @@ -1039,6 +1026,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea // drop them on the ground. deferredDiagnosticHandler.reportDeferredDiagnostics(); log.popDiagnosticHandler(deferredDiagnosticHandler); + compiler.setDeferredDiagnosticHandler(null); throw t; } finally { if (!taskListener.isEmpty()) @@ -1054,6 +1042,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } deferredDiagnosticHandler.reportDeferredDiagnostics(kinds); log.popDiagnosticHandler(deferredDiagnosticHandler); + compiler.setDeferredDiagnosticHandler(null); } /** Print info about this round. */ @@ -1069,104 +1058,68 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } } - /** Get the context for the next round of processing. - * Important values are propagated from round to round; - * other values are implicitly reset. + /** Prepare for new round of annotation processing. Cleans trees, resets symbols, and + * asks selected services to prepare to a new round of annotation processing. */ - private Context nextContext() { - Context next = new Context(context); + private void newRound() { + //ensure treesToClean contains all trees, including implicitly parsed ones + for (Env env : enter.getEnvs()) { + treesToClean.add(env.toplevel); + } + for (JCCompilationUnit node : treesToClean) { + treeCleaner.scan(node); + } + chk.newRound(); + enter.newRound(); + filer.newRound(); + messager.newRound(); + compiler.newRound(); + types.newRound(); - Options options = Options.instance(context); - Assert.checkNonNull(options); - next.put(Options.optionsKey, options); + boolean foundError = false; - Locale locale = context.get(Locale.class); - if (locale != null) - next.put(Locale.class, locale); - - Assert.checkNonNull(messages); - next.put(JavacMessages.messagesKey, messages); - - final boolean shareNames = true; - if (shareNames) { - Names names = Names.instance(context); - Assert.checkNonNull(names); - next.put(Names.namesKey, names); + for (ClassSymbol cs : symtab.classes.values()) { + if (cs.kind == Kinds.ERR) { + foundError = true; + break; + } } - DiagnosticListener dl = context.get(DiagnosticListener.class); - if (dl != null) - next.put(DiagnosticListener.class, dl); - - MultiTaskListener mtl = context.get(MultiTaskListener.taskListenerKey); - if (mtl != null) - next.put(MultiTaskListener.taskListenerKey, mtl); - - FSInfo fsInfo = context.get(FSInfo.class); - if (fsInfo != null) - next.put(FSInfo.class, fsInfo); - - JavaFileManager jfm = context.get(JavaFileManager.class); - Assert.checkNonNull(jfm); - next.put(JavaFileManager.class, jfm); - if (jfm instanceof JavacFileManager) { - ((JavacFileManager)jfm).setContext(next); + if (foundError) { + for (ClassSymbol cs : symtab.classes.values()) { + if (cs.classfile != null || cs.kind == Kinds.ERR) { + cs.reset(); + cs.type = new ClassType(cs.type.getEnclosingType(), null, cs); + if (cs.completer == null) { + cs.completer = initialCompleter; + } + } + } } - - Names names = Names.instance(context); - Assert.checkNonNull(names); - next.put(Names.namesKey, names); - - Tokens tokens = Tokens.instance(context); - Assert.checkNonNull(tokens); - next.put(Tokens.tokensKey, tokens); - - Log nextLog = Log.instance(next); - nextLog.initRound(log); - - JavaCompiler oldCompiler = JavaCompiler.instance(context); - JavaCompiler nextCompiler = JavaCompiler.instance(next); - nextCompiler.initRound(oldCompiler); - - filer.newRound(next); - messager.newRound(next); - elementUtils.setContext(next); - typeUtils.setContext(next); - - JavacTask task = context.get(JavacTask.class); - if (task != null) { - next.put(JavacTask.class, task); - if (task instanceof BasicJavacTask) - ((BasicJavacTask) task).updateContext(next); - } - - JavacTrees trees = context.get(JavacTrees.class); - if (trees != null) { - next.put(JavacTrees.class, trees); - trees.updateContext(next); - } - - context.clear(); - return next; } } // TODO: internal catch clauses?; catch and rethrow an annotation // processing error - public JavaCompiler doProcessing(Context context, - List roots, - List classSymbols, - Iterable pckSymbols, - Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { - log = Log.instance(context); + public boolean doProcessing(List roots, + List classSymbols, + Iterable pckSymbols, + Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { + final Set treesToClean = + Collections.newSetFromMap(new IdentityHashMap()); + + //fill already attributed implicit trees: + for (Env env : enter.getEnvs()) { + treesToClean.add(env.toplevel); + } Set specifiedPackages = new LinkedHashSet<>(); for (PackageSymbol psym : pckSymbols) specifiedPackages.add(psym); this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages); - Round round = new Round(context, roots, classSymbols, deferredDiagnosticHandler); + Round round = new Round(roots, classSymbols, treesToClean, deferredDiagnosticHandler); boolean errorStatus; boolean moreToDo; @@ -1217,9 +1170,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea Set newSourceFiles = new LinkedHashSet<>(filer.getGeneratedSourceFileObjects()); - roots = cleanTrees(round.roots); + roots = round.roots; - JavaCompiler compiler = round.finalCompiler(); + errorStatus = errorStatus || (compiler.errorCount() > 0); + + if (!errorStatus) + round.finalCompiler(); if (newSourceFiles.size() > 0) roots = roots.appendList(compiler.parseFiles(newSourceFiles)); @@ -1235,12 +1191,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (errorStatus) { if (compiler.errorCount() == 0) compiler.log.nerrors++; - return compiler; + return true; } compiler.enterTreesIfNeeded(roots); - return compiler; + return true; } private void warnIfUnmatchedOptions() { @@ -1342,23 +1298,46 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea return false; } - private static List cleanTrees(List nodes) { - for (T node : nodes) - treeCleaner.scan(node); - return nodes; + class ImplicitCompleter implements Completer { + + private final JCCompilationUnit topLevel; + + public ImplicitCompleter(JCCompilationUnit topLevel) { + this.topLevel = topLevel; + } + + @Override public void complete(Symbol sym) throws CompletionFailure { + compiler.complete(topLevel, (ClassSymbol) sym); + } } - private static final TreeScanner treeCleaner = new TreeScanner() { + private final TreeScanner treeCleaner = new TreeScanner() { public void scan(JCTree node) { super.scan(node); if (node != null) node.type = null; } + JCCompilationUnit topLevel; public void visitTopLevel(JCCompilationUnit node) { + if (node.packge != null) { + if (node.packge.package_info != null) { + node.packge.package_info.reset(); + } + node.packge.reset(); + } node.packge = null; - super.visitTopLevel(node); + topLevel = node; + try { + super.visitTopLevel(node); + } finally { + topLevel = null; + } } public void visitClassDef(JCClassDecl node) { + if (node.sym != null) { + node.sym.reset(); + node.sym.completer = new ImplicitCompleter(topLevel); + } node.sym = null; super.visitClassDef(node); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java index 1b1ec416e6a..d41c6241e30 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java @@ -137,14 +137,14 @@ public class JavacRoundEnvironment implements RoundEnvironment { public Set visitType(TypeElement e, TypeElement p) { // Type parameters are not considered to be enclosed by a type scan(e.getTypeParameters(), p); - return scan(e.getEnclosedElements(), p); + return super.visitType(e, p); } @Override public Set visitExecutable(ExecutableElement e, TypeElement p) { // Type parameters are not considered to be enclosed by an executable scan(e.getTypeParameters(), p); - return scan(e.getEnclosedElements(), p); + return super.visitExecutable(e, p); } @Override diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 8ed68e04151..8f792bd15e8 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -123,6 +123,9 @@ compiler.err.anon.class.impl.intf.no.typeargs=\ compiler.err.anon.class.impl.intf.no.qual.for.new=\ anonymous class implements interface; cannot have qualifier for new +compiler.err.cant.inherit.from.anon=\ + cannot inherit from anonymous class + # 0: symbol, 1: symbol, 2: symbol compiler.err.array.and.varargs=\ cannot declare both {0} and {1} in {2} @@ -1709,6 +1712,10 @@ compiler.err.cant.access=\ cannot access {0}\n\ {1} +# 0: class name +compiler.misc.bad.class.file=\ + class file is invalid for class {0} + # 0: file name, 1: message segment compiler.misc.bad.class.file.header=\ bad class file: {0}\n\ @@ -2320,6 +2327,11 @@ compiler.err.type.annotations.not.supported.in.source=\ type annotations are not supported in -source {0}\n\ (use -source 8 or higher to enable type annotations) +# 0: string +compiler.err.annotations.after.type.params.not.supported.in.source=\ + annotations after method type parameters are not supported in -source {0}\n\ +(use -source 8 or higher to enable annotations after method type parameters) + # 0: string compiler.err.repeatable.annotations.not.supported.in.source=\ repeated annotations are not supported in -source {0}\n\ diff --git a/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java b/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java index fe36e9ff54a..6591d95ba96 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java +++ b/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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,6 +147,8 @@ public abstract class Profiles { final int maxProfile = 4; // Three compact profiles plus full JRE MakefileProfiles(Properties p) { + // consider crypto, only if java/lang package exists + boolean foundJavaLang = false; for (int profile = 1; profile <= maxProfile; profile++) { String prefix = (profile < maxProfile ? "PROFILE_" + profile : "FULL_JRE"); String inclPackages = p.getProperty(prefix + "_RTJAR_INCLUDE_PACKAGES"); @@ -155,6 +157,8 @@ public abstract class Profiles { for (String pkg: inclPackages.substring(1).trim().split("\\s+")) { if (pkg.endsWith("/")) pkg = pkg.substring(0, pkg.length() - 1); + if (foundJavaLang == false && pkg.equals("java/lang")) + foundJavaLang = true; includePackage(profile, pkg); } String inclTypes = p.getProperty(prefix + "_RTJAR_INCLUDE_TYPES"); @@ -172,6 +176,15 @@ public abstract class Profiles { } } } + /* + * A hack to force javax/crypto package into the compact1 profile, + * because this package exists in jce.jar, and therefore not in + * ct.sym. Note javax/crypto should exist in a profile along with + * javax/net/ssl package. Thus, this package is added to compact1, + * implying that it should exist in all three profiles. + */ + if (foundJavaLang) + includePackage(1, "javax/crypto"); } @Override diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/Context.java b/langtools/src/share/classes/com/sun/tools/javac/util/Context.java index 8216d1e49bf..3768afad935 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/Context.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Context.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, 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 @@ -119,7 +119,7 @@ public class Context { * or * {@literal Key -> Factory } */ - private Map,Object> ht = new HashMap<>(); + private final Map,Object> ht = new HashMap<>(); /** Set the factory for the key in this context. */ public void put(Key key, Factory fac) { @@ -166,18 +166,12 @@ public class Context { /** * The table of preregistered factories. */ - private Map,Factory> ft = new HashMap<>(); - - public Context(Context prev) { - kt.putAll(prev.kt); // retain all implicit keys - ft.putAll(prev.ft); // retain all factory objects - ht.putAll(prev.ft); // init main table with factories - } + private final Map,Factory> ft = new HashMap<>(); /* * The key table, providing a unique Key for each Class. */ - private Map, Key> kt = new HashMap<>(); + private final Map, Key> kt = new HashMap<>(); private Key key(Class clss) { checkState(kt); @@ -214,12 +208,6 @@ public class Context { System.err.println(value == null ? null : value.getClass()); } - public void clear() { - ht = null; - kt = null; - ft = null; - } - private static void checkState(Map t) { if (t == null) throw new IllegalStateException(); diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java index 710a8310e1b..2bd1ee5b9e9 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Log.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 @@ -390,19 +390,6 @@ public class Log extends AbstractLog { noticeWriter = warnWriter = errWriter = pw; } - /** - * Propagate the previous log's information. - */ - public void initRound(Log other) { - this.noticeWriter = other.noticeWriter; - this.warnWriter = other.warnWriter; - this.errWriter = other.errWriter; - this.sourceMap = other.sourceMap; - this.recorded = other.recorded; - this.nerrors = other.nerrors; - this.nwarnings = other.nwarnings; - } - /** * Replace the specified diagnostic handler with the * handler that was current at the time this handler was created. diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java index 7428b97e0f6..f9fcaa74864 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java @@ -288,10 +288,6 @@ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc { return false; } - public boolean isFunctionalInterface() { - return env.types.isFunctionalInterface(tsym) && env.source.allowLambda(); - } - /** * Return the package that this class is contained in. */ diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java index 9046bc02a6b..25ab5561dee 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.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 @@ -381,6 +381,11 @@ public class RootDocImpl extends DocImpl implements RootDoc { env.initDoclint(opts, customTagNames); } + public boolean isFunctionalInterface(AnnotationDesc annotationDesc) { + return annotationDesc.annotationType().qualifiedName().equals( + env.syms.functionalInterfaceType.toString()) && env.source.allowLambda(); + } + public boolean showTagMessages() { return env.showTagMessages(); } diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java index 03abe7ba117..a5e79118da8 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java @@ -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 @@ -398,7 +398,8 @@ class SeeTagImpl extends TagImpl implements SeeTag, LayoutCharacters { private MemberDoc findExecutableMember(String memName, String[] paramarr, ClassDoc referencedClass) { - if (memName.equals(referencedClass.name())) { + String className = referencedClass.name(); + if (memName.equals(className.substring(className.lastIndexOf(".") + 1))) { return ((ClassDocImpl)referencedClass).findConstructor(memName, paramarr); } else { // it's a method. diff --git a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java index 83b8ba8e9e1..a483775b78b 100644 --- a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java @@ -202,7 +202,6 @@ public class ClassWriter extends BasicWriter { if (options.verbose) { println(); indent(+1); - attrWriter.write(cf, cf.attributes, constant_pool); println("minor version: " + cf.minor_version); println("major version: " + cf.major_version); writeList("flags: ", flags.getClassFlags(), "\n"); @@ -218,6 +217,10 @@ public class ClassWriter extends BasicWriter { writeMethods(); indent(-1); println("}"); + + if (options.verbose) { + attrWriter.write(cf, cf.attributes, constant_pool); + } } // where class JavaTypePrinter implements Type.Visitor { diff --git a/langtools/src/share/classes/javax/lang/model/util/Types.java b/langtools/src/share/classes/javax/lang/model/util/Types.java index 7dc7652a400..e4bc4e8b66f 100644 --- a/langtools/src/share/classes/javax/lang/model/util/Types.java +++ b/langtools/src/share/classes/javax/lang/model/util/Types.java @@ -132,12 +132,15 @@ public interface Types { boolean isSubsignature(ExecutableType m1, ExecutableType m2); /** - * Returns the direct supertypes of a type. The interface types, if any, - * will appear last in the list. + * Returns the direct supertypes of a type. The interface types, if any, + * will appear last in the list. For an interface type with no direct + * super-interfaces, a type mirror representing {@code java.lang.Object} + * is returned. * * @param t the type being examined * @return the direct supertypes, or an empty list if none * @throws IllegalArgumentException if given an executable or package type + * @jls 4.10 Subtyping */ List directSupertypes(TypeMirror t); diff --git a/langtools/test/com/sun/javadoc/testConstructors/TestConstructors.java b/langtools/test/com/sun/javadoc/testConstructors/TestConstructors.java index 90524af51af..52cebb631e7 100644 --- a/langtools/test/com/sun/javadoc/testConstructors/TestConstructors.java +++ b/langtools/test/com/sun/javadoc/testConstructors/TestConstructors.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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8025524 + * @bug 8025524 8031625 * @summary Test for constructor name which should be a non-qualified name. * @author Bhavesh Patel * @library ../lib/ @@ -37,6 +37,21 @@ public class TestConstructors extends JavadocTester { //Input for string search tests. private static final String[][] TEST = { + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "

See Also:
" + NL + + "
Inner(), " + NL + + "Inner(int), " + NL + + "NestedInner(), " + NL + + "NestedInner(int), " + NL + + "Outer(), " + NL + + "Outer(int)" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Link: Inner(), " + + "Outer(int), " + + "" + + "NestedInner(int)" + }, {BUG_ID + FS + "pkg1" + FS + "Outer.html", "Outer()" }, @@ -87,6 +102,18 @@ public class TestConstructors extends JavadocTester { }, {BUG_ID + FS + "pkg1" + FS + "Outer.Inner.NestedInner.html", "Outer.Inner.NestedInner-int-" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Outer.Inner()" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Outer.Inner(int)" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Outer.Inner.NestedInner()" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Outer.Inner.NestedInner(int)" } }; diff --git a/langtools/test/com/sun/javadoc/testConstructors/pkg1/Outer.java b/langtools/test/com/sun/javadoc/testConstructors/pkg1/Outer.java index 7cf5ef63bb2..9d8f76fefb9 100644 --- a/langtools/test/com/sun/javadoc/testConstructors/pkg1/Outer.java +++ b/langtools/test/com/sun/javadoc/testConstructors/pkg1/Outer.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 @@ -23,6 +23,17 @@ package pkg1; +/** + * Test link tag. + * Link: {@link pkg1.Outer.Inner#Inner()}, {@link pkg1.Outer#Outer(int)}, {@link pkg1.Outer.Inner.NestedInner#NestedInner(int)} + * + * @see Outer.Inner#Inner() + * @see Outer.Inner#Inner(int) + * @see Outer.Inner.NestedInner#NestedInner() + * @see Outer.Inner.NestedInner#NestedInner(int) + * @see Outer#Outer() + * @see Outer#Outer(int) + */ public class Outer { /** diff --git a/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java b/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java index 0fb47c1eddc..dc0a04db0b5 100644 --- a/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java +++ b/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8004893 8022738 + * @bug 8004893 8022738 8029143 * @summary Make sure that the lambda feature changes work fine in * javadoc. * @author bpatel @@ -87,6 +87,11 @@ public class TestLambdaFeature extends JavadocTester { "
default default void defaultMethod()
"}, {BUG_ID + FS + "pkg" + FS + "B.html", "default void"}, + {BUG_ID + FS + "pkg1" + FS + "NotAFuncInf.html", + "
" + NL + "
Functional Interface:
" + NL + + "
This is a functional interface and can therefore be used as " + + "the assignment target for a lambda expression or method " + + "reference.
" + NL + "
"}, {BUG_ID + FS + "pkg" + FS + "B.html", "
" + NL + "
Functional Interface:
"} }; diff --git a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/A.java b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/A.java index c52f249b491..8e5992baebf 100644 --- a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/A.java +++ b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/A.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 @@ -23,6 +23,7 @@ package pkg; +@FunctionalInterface public interface A { public void method1(); diff --git a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/FuncInf.java b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/FuncInf.java index 566acf596ca..bace6ea9b98 100644 --- a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/FuncInf.java +++ b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/FuncInf.java @@ -23,6 +23,7 @@ package pkg1; +@FunctionalInterface public interface FuncInf { V call() throws Exception; diff --git a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/NotAFuncInf.java b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/NotAFuncInf.java new file mode 100644 index 00000000000..24ad4cd393e --- /dev/null +++ b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/NotAFuncInf.java @@ -0,0 +1,29 @@ +/* + * 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 pkg1; + +public interface NotAFuncInf { + + V call() throws Exception; +} diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/TestSerializedForm.java b/langtools/test/com/sun/javadoc/testSerializedForm/TestSerializedForm.java index 7749bb92b67..bfc19852a1a 100644 --- a/langtools/test/com/sun/javadoc/testSerializedForm/TestSerializedForm.java +++ b/langtools/test/com/sun/javadoc/testSerializedForm/TestSerializedForm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, 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 @@ -26,7 +26,7 @@ import java.io.*; /* * @test - * @bug 4341304 4485668 4966728 + * @bug 4341304 4485668 4966728 8032066 * @summary Test that methods readResolve and writeReplace show * up in serialized-form.html the same way that readObject and writeObject do. * If the doclet includes readResolve and writeReplace in the serialized-form @@ -54,12 +54,70 @@ public class TestSerializedForm extends JavadocTester implements Serializable { "protected java.lang.Object readObjectNoData()"}, {BUG_ID + FS + "serialized-form.html", "See Also"}, + {BUG_ID + "/serialized-form.html", + "

Class pkg1.NestedInnerClass.InnerClass.ProNestedInnerClass " + + "extends java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class pkg1.PrivateIncludeInnerClass.PriInnerClass extends " + + "java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class pkg1.ProtectedInnerClass.ProInnerClass extends " + + "java.lang.Object implements Serializable

"} + }; + + private static final String[][] TEST_PRIVATE = { + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.NestedInnerClass.InnerClass.ProNestedInnerClass " + + "extends java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class " + + "pkg1.PrivateIncludeInnerClass.PriInnerClass extends java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class " + + "pkg1.ProtectedInnerClass.ProInnerClass extends java.lang.Object implements Serializable

"} + }; + + private static final String[][] NEGATED_TEST = { + {BUG_ID + "/serialized-form.html", + "

Class pkg1.NestedInnerClass.InnerClass.ProNestedInnerClass " + + "extends java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class " + + "pkg1.PrivateInnerClass.PriInnerClass extends java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class " + + "pkg1.ProtectedInnerClass.ProInnerClass extends java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class pkg1.PublicExcludeInnerClass.PubInnerClass extends java.lang.Object implements " + + "Serializable

"} + }; + + private static final String[][] NEGATED_TEST_PRIVATE = { + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.NestedInnerClass.InnerClass.ProNestedInnerClass " + + "extends java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.PrivateInnerClass.PriInnerClass extends " + + "java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.ProtectedInnerClass.ProInnerClass extends " + + "java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.PublicExcludeInnerClass.PubInnerClass " + + "extends java.lang.Object implements Serializable

"} }; - private static final String[][] NEGATED_TEST = NO_TEST; private static final String[] ARGS = new String[] { "-d", BUG_ID, "-sourcepath", SRC_DIR, - SRC_DIR + FS + "TestSerializedForm.java" + SRC_DIR + "/TestSerializedForm.java", "pkg1" + }; + + private static final String[] ARGS_PRIVATE = new String[] { + "-private", "-d", BUG_ID + "-1", "-sourcepath", SRC_DIR, + SRC_DIR + "/TestSerializedForm.java", "pkg1" }; /** @@ -74,7 +132,8 @@ public class TestSerializedForm extends JavadocTester implements Serializable { */ public static void main(String[] args) { TestSerializedForm tester = new TestSerializedForm(); - int actualExitCode = run(tester, ARGS, TEST, NEGATED_TEST); + run(tester, ARGS, TEST, NEGATED_TEST); + run(tester, ARGS_PRIVATE, TEST_PRIVATE, NEGATED_TEST_PRIVATE); tester.printSummary(); } @@ -93,34 +152,39 @@ public class TestSerializedForm extends JavadocTester implements Serializable { } /** + * @param s ObjectInputStream. * @throws IOException when there is an I/O error. * @serial */ - private void readObject(ObjectInputStream s) {} + private void readObject(ObjectInputStream s) throws IOException {} /** + * @param s ObjectOutputStream. * @throws IOException when there is an I/O error. * @serial */ - private void writeObject(ObjectOutputStream s) {} + private void writeObject(ObjectOutputStream s) throws IOException {} /** * @throws IOException when there is an I/O error. * @serialData This is a serial data comment. + * @return an object. */ - protected Object readResolve(){return null;} + protected Object readResolve() throws IOException {return null;} /** * @throws IOException when there is an I/O error. * @serialData This is a serial data comment. + * @return an object. */ - protected Object writeReplace(){return null;} + protected Object writeReplace() throws IOException {return null;} /** * @throws IOException when there is an I/O error. * @serialData This is a serial data comment. + * @return an object. */ - protected Object readObjectNoData() { + protected Object readObjectNoData() throws IOException { return null; } diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/NestedInnerClass.java b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/NestedInnerClass.java new file mode 100644 index 00000000000..2b7e2912894 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/NestedInnerClass.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg1; + +import java.io.*; + +/** + * A test class where the outer class is package private and the inner class is private + * and a nested inner class is protected. + * + * @author Bhavesh Patel + */ + +class NestedInnerClass { + + private static class InnerClass { + + protected static class ProNestedInnerClass implements java.io.Serializable { + + public final int SERIALIZABLE_CONSTANT = 1; + + /** + * @param s ObjectInputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void readObject(ObjectInputStream s) throws IOException { + } + + /** + * @param s ObjectOutputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void writeObject(ObjectOutputStream s) throws IOException { + } + } + } +} diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PrivateIncludeInnerClass.java b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PrivateIncludeInnerClass.java new file mode 100644 index 00000000000..e81ba1862c0 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PrivateIncludeInnerClass.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg1; + +import java.io.*; + +/** + * A test class where the outer class is package private and inner class + * is private which is included using the tag. + * + * @author Bhavesh Patel + */ + +class PrivateIncludeInnerClass { + + /** + * @serial include + */ + private static class PriInnerClass implements java.io.Serializable { + + public final int SERIALIZABLE_CONSTANT = 1; + + /** + * @param s ObjectInputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void readObject(ObjectInputStream s) throws IOException { + } + + /** + * @param s ObjectOutputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void writeObject(ObjectOutputStream s) throws IOException { + } + } +} diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/ProtectedInnerClass.java b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/ProtectedInnerClass.java new file mode 100644 index 00000000000..8eee8e18d37 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/ProtectedInnerClass.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. 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 pkg1; + +import java.io.*; + +/** + * A test class where outer class is package private and the inner class is + * protected. + * + * @author Bhavesh Patel + */ + +class ProtectedInnerClass { + + protected static class ProInnerClass implements java.io.Serializable { + + public final int SERIALIZABLE_CONSTANT = 1; + + /** + * @param s ObjectInputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void readObject(ObjectInputStream s) throws IOException { + } + + /** + * @param s ObjectOutputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void writeObject(ObjectOutputStream s) throws IOException { + } + } +} diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PublicExcludeInnerClass.java b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PublicExcludeInnerClass.java new file mode 100644 index 00000000000..0c110600380 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PublicExcludeInnerClass.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg1; + +import java.io.*; + +/** + * A test class where the outer class is package private and inner class + * is public which is excluded using the tag. + * + * @author Bhavesh Patel + */ + +class PublicExcludeInnerClass { + + /** + * @serial exclude + */ + public static class PubInnerClass implements java.io.Serializable { + + public final int SERIALIZABLE_CONSTANT = 1; + + /** + * @param s ObjectInputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void readObject(ObjectInputStream s) throws IOException { + } + + /** + * @param s ObjectOutputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void writeObject(ObjectOutputStream s) throws IOException { + } + } +} diff --git a/langtools/test/tools/javac/6668794/badSource/Test.out b/langtools/test/tools/javac/6668794/badSource/Test.out index 94e1416d7a7..2c8d26b4b4c 100644 --- a/langtools/test/tools/javac/6668794/badSource/Test.out +++ b/langtools/test/tools/javac/6668794/badSource/Test.out @@ -1 +1,2 @@ Test.java:10:6: compiler.err.cant.access: p.A, (compiler.misc.bad.source.file.header: A.java, (compiler.misc.file.doesnt.contain.class: p.A)) +1 error diff --git a/langtools/test/tools/javac/AnonymousSubclassTest.java b/langtools/test/tools/javac/AnonymousSubclassTest.java new file mode 100644 index 00000000000..6545c75b5f7 --- /dev/null +++ b/langtools/test/tools/javac/AnonymousSubclassTest.java @@ -0,0 +1,91 @@ +/* + * 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 8023945 + * @summary javac wrongly allows a subclass of an anonymous class + * @library /tools/javac/lib + * @build ToolBox + * @run main AnonymousSubclassTest + */ + +import java.util.ArrayList; +import java.io.IOException; + +public class AnonymousSubclassTest { + public static void main(String... args) throws Exception { + new AnonymousSubclassTest().run(); + } + + // To trigger the error we want, first we need to compile + // a class with an anonymous inner class: Foo$1. + final String foo = + "public class Foo {" + + " void m() { Foo f = new Foo() {}; }" + + "}"; + + // Then, we try to subclass the anonymous class + // Note: we must do this in two classes because a different + // error will be generated if we don't load Foo$1 through the + // class reader. + final String test1 = + "public class Test1 {" + + " void m() {"+ + " Foo f1 = new Foo();"+ + " Foo f2 = new Foo$1(f1) {};"+ + " }" + + "}"; + + final String test2 = + "public class Test2 {" + + " class T extends Foo$1 {" + + " public T(Foo f) { super(f); }" + + " }"+ + "}"; + + void compOk(String code) throws Exception { + ToolBox.javac(new ToolBox.JavaToolArgs().setSources(code)); + } + + void compFail(String code) throws Exception { + ArrayList errors = new ArrayList<>(); + ToolBox.JavaToolArgs args = new ToolBox.JavaToolArgs(); + args.setSources(code) + .appendArgs("-cp", ".", "-XDrawDiagnostics") + .set(ToolBox.Expect.FAIL) + .setErrOutput(errors); + ToolBox.javac(args); + + if (!errors.get(0).contains("cant.inherit.from.anon")) { + System.out.println(errors.get(0)); + throw new Exception("test failed"); + } + } + + void run() throws Exception { + compOk(foo); + compFail(test1); + compFail(test2); + } +} diff --git a/langtools/test/tools/javac/ConstFoldTest.java b/langtools/test/tools/javac/ConstFoldTest.java new file mode 100644 index 00000000000..c9865f3a476 --- /dev/null +++ b/langtools/test/tools/javac/ConstFoldTest.java @@ -0,0 +1,86 @@ +/* + * 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 8025505 + * @summary Constant folding deficiency + * @library /tools/javac/lib + * @build ToolBox + * @run main ConstFoldTest + */ + +import java.net.URL; +import java.util.List; + +public class ConstFoldTest { + public static void main(String... args) throws Exception { + new ConstFoldTest().run(); + } + + // This is the test case. This class should end up + // as straight-line code with no conditionals + class CFTest { + void m() { + int x; + if (1 != 2) x=1; else x=0; + if (1 == 2) x=1; else x=0; + if ("" != null) x=1; else x=0; + if ("" == null) x=1; else x=0; + if (null == null) x=1; else x=0; + if (null != null) x=1; else x=0; + + x = 1 != 2 ? 1 : 0; + x = 1 == 2 ? 1 : 0; + x = "" != null ? 1 : 0; + x = "" == null ? 1 : 0; + x = null == null ? 1 : 0; + x = null != null ? 1 : 0; + + boolean b; + b = 1 != 2 && true; + b = 1 == 2 || true; + b = ("" != null) && true; + b = ("" == null) || true; + b = (null == null) && true; + b = (null != null) || true; + } + } + + // All of the conditionals above should be eliminated. + // these if* bytecodes should not be seen + final String regex = "\\sif(?:null|nonnull|eq|ne){1}\\s"; + + void run() throws Exception { + URL url = ConstFoldTest.class.getResource("ConstFoldTest$CFTest.class"); + String result = ToolBox.javap(new ToolBox.JavaToolArgs().setAllArgs("-c", url.getFile())); + System.out.println(result); + + List bad_codes = ToolBox.grep(regex, result, "\n"); + if (!bad_codes.isEmpty()) { + for (String code : bad_codes) + System.out.println("Bad OpCode Found: " + code); + throw new Exception("constant folding failed"); + } + } +} diff --git a/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.java b/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.java new file mode 100644 index 00000000000..8369c66fb7a --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.java @@ -0,0 +1,16 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8035956 + * @summary javac, incomplete error message + * @author kizune + * + * @run compile/fail/ref=IncompleteMessageOverride.out -XDrawDiagnostics IncompleteMessageOverride.java + */ + +class Super { + static void m() {} +} + +class Sub extends Super { + private static void m() {} +} diff --git a/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.out b/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.out new file mode 100644 index 00000000000..62cab888c9e --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.out @@ -0,0 +1,2 @@ +IncompleteMessageOverride.java:15:25: compiler.err.override.weaker.access: (compiler.misc.cant.override: m(), Sub, m(), Super), package +1 error diff --git a/langtools/test/tools/javac/StdoutCloseTest.java b/langtools/test/tools/javac/StdoutCloseTest.java new file mode 100644 index 00000000000..f6cb8b86a4f --- /dev/null +++ b/langtools/test/tools/javac/StdoutCloseTest.java @@ -0,0 +1,90 @@ +/* + * 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 7118295 + * @summary javac does not explicitly close -Xstdout file + * @run main StdoutCloseTest + */ + + +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.main.Main; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +public class StdoutCloseTest { + + public static void main(String[] args) throws Exception { + new StdoutCloseTest().test(); + } + + static final String program = "public class Test {\n" + + " public boolean test() {\n" + + " int i;\n" + + " if (i > 0) return true;\n" + + " return false;\n" + + " }\n" + + "}\n"; + + public void test() throws Exception { + final String sourceName = "Test.java"; + final String outName = "Test.out"; + File source = new File(sourceName); + PrintWriter pw = new PrintWriter(source); + pw.write(program); + pw.flush(); + pw.close(); + + PrintWriter log = compileClass(sourceName, outName); + + File outFile = new File(outName); + if (!outFile.exists()) { + throw new Exception("Output file was not created!"); + } + if (!log.checkError()) { // will return true if the stream is still open + log.close(); // Close output PrintWriter manually + throw new Exception("Output file was still open!"); + } + } + + public PrintWriter compileClass(String src, String out) { + List options = new ArrayList<>(); + options.add("-Xstdout"); + options.add(out); + options.add(src); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + Main compiler = new Main("javac", pw); + compiler.compile(options.toArray(new String[options.size()])); + pw.flush(); + if (sw.getBuffer().length() > 0) { + System.err.println(sw.toString()); + } + return compiler.log.getWriter(Log.WriterKind.NOTICE); + } +} diff --git a/langtools/test/tools/javac/T6358168.java b/langtools/test/tools/javac/T6358168.java index fe7fec2417d..9023e9d1855 100644 --- a/langtools/test/tools/javac/T6358168.java +++ b/langtools/test/tools/javac/T6358168.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -99,10 +99,9 @@ public class T6358168 extends AbstractProcessor { "-d", "."}); JavaCompiler compiler = JavaCompiler.instance(context); - compiler.initProcessAnnotations(null); - JavaCompiler compiler2 = compiler.processAnnotations(compiler.enterTrees(compiler.parseFiles(List.of(f)))); + compiler.compile(List.of(f)); try { - compiler2.compile(List.of(f)); + compiler.compile(List.of(f)); throw new Error("Error: AssertionError not thrown after second call of compile"); } catch (AssertionError e) { System.err.println("Exception from compiler (expected): " + e); diff --git a/langtools/test/tools/javac/T7053059/DoubleCastTest.java b/langtools/test/tools/javac/T7053059/DoubleCastTest.java new file mode 100644 index 00000000000..6c96bd930d3 --- /dev/null +++ b/langtools/test/tools/javac/T7053059/DoubleCastTest.java @@ -0,0 +1,76 @@ +/* + * 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 8015499 + * @summary javac, Gen is generating extra checkcast instructions in some corner cases + * @run main DoubleCastTest + */ + +import java.util.List; +import java.util.ArrayList; +import com.sun.tools.classfile.*; +import com.sun.tools.javac.util.Assert; + +public class DoubleCastTest { + class C { + Object x; + Object m() { return null; } + void m1(byte[] b) {} + void m2() { + Object o; + Object[] os = null; + m1((byte[])(o = null)); + m1((byte[])o); + m1((byte[])(o == null ? o : o)); + m1((byte[])m()); + m1((byte[])os[0]); + m1((byte[])this.x); + } + } + + public static void main(String... cmdline) throws Exception { + + ClassFile cls = ClassFile.read(DoubleCastTest.class.getResourceAsStream("DoubleCastTest$C.class")); + for (Method m: cls.methods) + check(m); + } + + static void check(Method m) throws Exception { + boolean last_is_cast = false; + int last_ref = 0; + Code_attribute ea = (Code_attribute)m.attributes.get(Attribute.Code); + for (Instruction i : ea.getInstructions()) { + if (i.getOpcode() == Opcode.CHECKCAST) { + Assert.check + (!(last_is_cast && last_ref == i.getUnsignedShort(1)), + "Double cast found - Test failed"); + last_is_cast = true; + last_ref = i.getUnsignedShort(1); + } else { + last_is_cast = false; + } + } + } +} diff --git a/langtools/test/tools/javac/T8034044.java b/langtools/test/tools/javac/T8034044.java new file mode 100644 index 00000000000..47d92870e3b --- /dev/null +++ b/langtools/test/tools/javac/T8034044.java @@ -0,0 +1,60 @@ +/* + * 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 8034044 + * @summary An anonymous class should not be static + */ + +import static java.lang.reflect.Modifier.*; + +public class T8034044 { + enum En { + V() {} + } + + static class InnStat { + static Object o = new Object() {}; + } + + public static void main(String[] args) + throws Throwable { + Object o = new Object() {}; + test(o.getClass()); + test(En.V.getClass()); + test(InnStat.o.getClass()); + new T8034044().f(); + } + + public void f() { + Object o = new Object() {}; + test(o.getClass()); + } + + static void test(Class clazz) { + if ((clazz.getModifiers() & STATIC) != 0) + throw new AssertionError(clazz.toString() + + " should not be static"); + } +} diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out index d2144ab86b0..638b91d14ee 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out @@ -6,6 +6,7 @@ CantAnnotateScoping.java:47:18: compiler.err.cant.type.annotate.scoping.1: @TA CantAnnotateScoping.java:56:37: compiler.err.cant.type.annotate.scoping: @TA,@TA2 CantAnnotateScoping.java:40:14: compiler.err.cant.type.annotate.scoping.1: @TA CantAnnotateScoping.java:42:34: compiler.err.cant.type.annotate.scoping: @TA,@DA,@TA2 +CantAnnotateScoping.java:42:25: compiler.err.annotation.type.not.applicable CantAnnotateScoping.java:44:38: compiler.err.cant.type.annotate.scoping: @TA,@DA CantAnnotateScoping.java:44:34: compiler.err.annotation.type.not.applicable -10 errors \ No newline at end of file +11 errors diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CheckErrorsForSource7.java b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CheckErrorsForSource7.java new file mode 100644 index 00000000000..56c8adf588e --- /dev/null +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CheckErrorsForSource7.java @@ -0,0 +1,195 @@ +/* + * 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 8035890 + * @summary Verify that the parser correctly checks for source level 8 on the new places where + * annotations can appear in 8. + * @run main CheckErrorsForSource7 CheckErrorsForSource7.java + */ +import java.io.File; +import java.io.IOException; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import com.sun.source.tree.AnnotationTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.file.JavacFileManager; + +/**For each place where an annotation can syntactically appear with -source 8, but not with + * -source 7, this test verifies that an error is correctly emitted from the parser for + * the annotation for -source 7. This test first gathers the occurrences of @TA from + * the CheckErrorsForSource7Data class below, and then repeatedly removes all these annotations + * except one and checks the parser reports an expected error. This is needed as as the parser + * typically produces only one 'insufficient source level' error for each new feature used. + */ +public class CheckErrorsForSource7 { + public static void main(String... args) throws IOException, URISyntaxException { + new CheckErrorsForSource7().run(args); + } + + private void run(String... args) throws IOException, URISyntaxException { + //the first and only parameter must be the name of the file to be analyzed: + if (args.length != 1) throw new IllegalStateException("Must provide source file!"); + File testSrc = new File(System.getProperty("test.src")); + File testFile = new File(testSrc, args[0]); + if (!testFile.canRead()) throw new IllegalStateException("Cannot read the test source"); + JavacFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); + + //gather spans of the @TA annotations into typeAnnotationSpans: + JavacTask task = JavacTool.create().getTask(null, + fm, + null, + Collections.emptyList(), + null, + fm.getJavaFileObjects(testFile)); + final Trees trees = Trees.instance(task); + final CompilationUnitTree cut = task.parse().iterator().next(); + final List typeAnnotationSpans = new ArrayList<>(); + + new TreePathScanner() { + @Override + public Void visitAnnotation(AnnotationTree node, Void p) { + if (node.getAnnotationType().getKind() == Kind.IDENTIFIER && + ((IdentifierTree) node.getAnnotationType()).getName().contentEquals("TA")) { + int start = (int) trees.getSourcePositions().getStartPosition(cut, node); + int end = (int) trees.getSourcePositions().getEndPosition(cut, node); + typeAnnotationSpans.add(new int[] {start, end}); + } + return null; + } + }.scan(cut, null); + + //sort the spans in the reverse order, to simplify removing them from the source: + Collections.sort(typeAnnotationSpans, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + return o2[0] - o1[0]; + } + }); + + //verify the errors are produce correctly: + String originalSource = cut.getSourceFile().getCharContent(false).toString(); + + for (int[] toKeep : typeAnnotationSpans) { + //prepare updated source code by removing all the annotations except the toKeep one: + String updated = originalSource; + + for (int[] span : typeAnnotationSpans) { + if (span == toKeep) continue; + + updated = updated.substring(0, span[0]) + updated.substring(span[1]); + } + + //parse and verify: + JavaFileObject updatedFile = new TestFO(cut.getSourceFile().toUri(), updated); + DiagnosticCollector errors = new DiagnosticCollector<>(); + JavacTask task2 = JavacTool.create().getTask(null, + fm, + errors, + Arrays.asList("-source", "7"), + null, + Arrays.asList(updatedFile)); + task2.parse(); + + boolean found = false; + + for (Diagnostic d : errors.getDiagnostics()) { + if (d.getKind() == Diagnostic.Kind.ERROR && EXPECTED_ERRORS.contains(d.getCode())) { + if (found) { + throw new IllegalStateException("More than one expected error found."); + } + found = true; + } + } + + if (!found) + throw new IllegalStateException("Did not produce proper errors for: " + updated); + } + } + + static final Set EXPECTED_ERRORS = new HashSet<>(Arrays.asList( + "compiler.err.type.annotations.not.supported.in.source", + "compiler.err.annotations.after.type.params.not.supported.in.source" + )); + + class TestFO extends SimpleJavaFileObject { + private final String content; + public TestFO(URI uri, String content) { + super(uri, Kind.SOURCE); + this.content = content; + } + + @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return content; + } + + @Override public boolean isNameCompatible(String simpleName, Kind kind) { + return true; + } + } +} + +//data on which the source level check is verified: +class CheckErrorsForSource7Data { + @Target(ElementType.TYPE_USE) + @interface TA { } + + Object n1 = new @TA ArrayList<@TA String>(); + Object n2 = new @TA Object() {}; + Object [] @TA [] arr @TA[]; + @TA int @TA[] ret(Object obj) @TA[] throws @TA Exception { + this.<@TA String>ret(null); + Object c1 = new @TA String[1]; + + int val = obj instanceof @TA String ? ((@TA String) obj).length() : 0; + List<@TA ?> l; + return null; + } + void vararg(String @TA ... args) { } + + abstract class C<@TA T extends @TA Number & @TA Runnable> + extends @TA ArrayList<@TA String> + implements java.util. @TA Comparator<@TA T> { } + + interface I extends java.util. @TA Comparator<@TA String> { } + +} diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out b/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out index 325094a615a..efb655727e1 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out @@ -1,5 +1,5 @@ +DeclarationAnnotation.java:13:21: compiler.err.annotation.type.not.applicable DeclarationAnnotation.java:10:21: compiler.err.annotation.type.not.applicable DeclarationAnnotation.java:11:21: compiler.err.annotation.type.not.applicable DeclarationAnnotation.java:12:21: compiler.err.annotation.type.not.applicable -DeclarationAnnotation.java:13:21: compiler.err.annotation.type.not.applicable 4 errors diff --git a/langtools/test/tools/javac/classreader/BadClass.java b/langtools/test/tools/javac/classreader/BadClass.java new file mode 100644 index 00000000000..929b4d689ba --- /dev/null +++ b/langtools/test/tools/javac/classreader/BadClass.java @@ -0,0 +1,76 @@ +/* + * 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 6898851 + * @summary Compiling against this corrupt class file causes a stacktrace from javac + */ + +import java.io.File; +import java.io.FileWriter; +import java.io.StringWriter; +import java.io.PrintWriter; +import java.io.IOException; + +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ClassWriter; +import com.sun.tools.javac.Main; + +public class BadClass { + // Create and compile file containing body; return compiler output + static String makeClass(String dir, String filename, String body) throws IOException { + File file = new File(dir, filename); + try (FileWriter fw = new FileWriter(file)) { + fw.write(body); + } + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + String args[] = { "-cp", dir, "-d", dir, "-XDrawDiagnostics", file.getPath() }; + Main.compile(args, pw); + pw.close(); + return sw.toString(); + } + + public static void main(String... args) throws Exception { + new File("d1").mkdir(); + new File("d2").mkdir(); + + // Step 1. build an empty class with an interface + makeClass("d1", "Empty.java", "abstract class Empty implements Readable {}"); + + // Step 2. Modify classfile to have invalid constant pool index + ClassFile cf = ClassFile.read(new File("d1","Empty.class")); + cf.interfaces[0] = cf.constant_pool.size() + 10; + ClassWriter cw = new ClassWriter(); + cw.write(cf, new File("d2","Empty.class")); + + // Step 3. Compile use of invalid class + String result = makeClass("d2", "EmptyUse.java", "class EmptyUse { Empty e; }"); + if (!result.contains("compiler.misc.bad.class.file")) { + System.out.println(result); + throw new Exception("test failed"); + } + } +} diff --git a/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java b/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java index ba69bd614aa..52f912b6ecb 100644 --- a/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java +++ b/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.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 @@ -26,6 +26,7 @@ * @bug 8005166 * @summary Add support for static interface methods * Smoke test for static interface method hiding + * @run main/timeout=600 InterfaceMethodHidingTest */ import com.sun.source.util.JavacTask; diff --git a/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java b/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java index 6c5ef038382..f8cab930697 100644 --- a/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java +++ b/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java @@ -1,5 +1,5 @@ /* - * 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 @@ -135,12 +135,7 @@ class ArgTypeCompilerFactory implements Example.Compiler.Factory { args.add(f.getPath()); Main main = new Main("javac", out); - Context c = new Context() { - @Override public void clear() { - ((JavacFileManager) get(JavaFileManager.class)).close(); - super.clear(); - } - }; + Context c = new Context(); JavacFileManager.preRegister(c); // can't create it until Log has been set up ArgTypeJavaCompiler.preRegister(c); ArgTypeMessages.preRegister(c); diff --git a/langtools/test/tools/javac/diags/examples.not-yet.txt b/langtools/test/tools/javac/diags/examples.not-yet.txt index 9f227708f46..fc60fb0091a 100644 --- a/langtools/test/tools/javac/diags/examples.not-yet.txt +++ b/langtools/test/tools/javac/diags/examples.not-yet.txt @@ -111,3 +111,5 @@ compiler.warn.unknown.enum.constant # in bad class file compiler.warn.unknown.enum.constant.reason # in bad class file compiler.warn.override.equals.but.not.hashcode # when a class overrides equals but not hashCode method from Object compiler.warn.file.from.future # warning for future modification times on files +compiler.err.cant.inherit.from.anon # error for subclass of anonymous class +compiler.misc.bad.class.file # class file is malformed diff --git a/langtools/test/tools/javac/diags/examples/AnnotationsAfterTypeParamsNotSupportedInSource.java b/langtools/test/tools/javac/diags/examples/AnnotationsAfterTypeParamsNotSupportedInSource.java new file mode 100644 index 00000000000..9efc4c3d15b --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/AnnotationsAfterTypeParamsNotSupportedInSource.java @@ -0,0 +1,34 @@ +/* + * 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: compiler.err.annotations.after.type.params.not.supported.in.source +// key: compiler.warn.source.no.bootclasspath +// options: -source 7 + +@interface Anno { } + +class AnnotationsAfterTypeParamsNotSupportedInSource { + @Anno int m() { + return 0; + } +} diff --git a/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java index 06db21564f6..8e50868f8a0 100644 --- a/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java +++ b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.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 @@ -30,7 +30,7 @@ * @author Maurizio Cimadamore * @library ../lib * @build JavacTestingAbstractThreadedTest - * @run main/othervm FunctionalInterfaceConversionTest + * @run main/timeout=600/othervm FunctionalInterfaceConversionTest */ // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) diff --git a/langtools/test/tools/javac/lib/ToolBox.java b/langtools/test/tools/javac/lib/ToolBox.java index 73db0a42d2f..b933ab54de0 100644 --- a/langtools/test/tools/javac/lib/ToolBox.java +++ b/langtools/test/tools/javac/lib/ToolBox.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 @@ -22,11 +22,14 @@ */ import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; +import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URI; @@ -40,15 +43,22 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import com.sun.source.util.JavacTask; @@ -453,6 +463,45 @@ public class ToolBox { throw new AssertionError("javac command has been invoked with less parameters than needed"); } + /** + * Run javac and return the resulting classfiles. + */ + public static Map compile(JavaToolArgs params) + throws CommandExecutionException, IOException { + if (params.hasMinParams()) { + if (params.argsArr != null) { + throw new AssertionError("setAllArgs is not supported for compile"); + } + + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); + MemoryFileManager mfm = new MemoryFileManager(fm); + StringWriter sw = null; + boolean rc; + + try (PrintWriter pw = (params.errOutput == null) ? + null : new PrintWriter(sw = new StringWriter())) { + JavacTask ct = (JavacTask)comp.getTask(pw, mfm, null, + params.args, null, params.sources); + rc = ct.call(); + } + + String out = (sw == null) ? null : sw.toString(); + + if (params.errOutput != null && (out != null) && !out.isEmpty()) { + params.errOutput.addAll(splitLines(out, lineSeparator)); + } + + if ( ( rc && params.whatToExpect == Expect.SUCCESS) || + (!rc && params.whatToExpect == Expect.FAIL) ) { + return mfm.classes; + } + + throw new CommandExecutionException(JavaCMD.JAVAC_API.getExceptionMsgContent(params), + params.whatToExpect); + } + throw new AssertionError("compile command has been invoked with less parameters than needed"); + } + /** * A javap calling method. */ @@ -964,4 +1013,66 @@ public class ToolBox { return source; } } + + /** + * A file manager for compiling strings to byte arrays. + * This file manager delegates to another file manager + * to lookup classes on boot class path. + */ + public static final class MemoryFileManager extends ForwardingJavaFileManager { + /** + * Maps binary class names to class files stored as byte arrays. + */ + private final Map classes; + + /** + * Construct a memory file manager which delegates to the specified + * file manager for unknown sources. + * @param fileManager a file manager used to look up class files on class path, etc. + */ + public MemoryFileManager(JavaFileManager fileManager) { + super(fileManager); + classes = new HashMap<>(); + } + + @java.lang.Override + public JavaFileObject getJavaFileForOutput(Location location, + String name, + Kind kind, + FileObject sibling) + throws UnsupportedOperationException + { + return new JavaClassInArray(name); + } + + /** + * A file object representing a Java class file stored in a byte array. + */ + private class JavaClassInArray extends SimpleJavaFileObject { + + private final String name; + + /** + * Constructs a JavaClassInArray object. + * @param name binary name of the class to be stored in this file object + */ + JavaClassInArray(String name) { + super(URI.create("mfm:///" + name.replace('.','/') + Kind.CLASS.extension), + Kind.CLASS); + this.name = name; + } + + public OutputStream openOutputStream() { + return new FilterOutputStream(new ByteArrayOutputStream()) { + public void close() throws IOException { + out.close(); + ByteArrayOutputStream bos = (ByteArrayOutputStream)out; + classes.put(name, bos.toByteArray()); + } + }; + } + } + + } + } diff --git a/langtools/test/tools/javac/processing/environment/ProcessingEnvAnnoDiscovery.java b/langtools/test/tools/javac/processing/environment/ProcessingEnvAnnoDiscovery.java new file mode 100644 index 00000000000..ef2721f83f5 --- /dev/null +++ b/langtools/test/tools/javac/processing/environment/ProcessingEnvAnnoDiscovery.java @@ -0,0 +1,78 @@ +/* + * 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 8038080 + * @summary make sure that all declaration annotations are discovered + * by the processing environment + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor ProcessingEnvAnnoDiscovery + * @compile/process -processor ProcessingEnvAnnoDiscovery ProcessingEnvAnnoDiscovery.java + */ + +import java.lang.annotation.*; +import java.util.Set; +import javax.annotation.processing.*; +import javax.lang.model.element.*; + +import com.sun.tools.javac.util.*; + +@ProcessingEnvAnnoDiscovery.Anno1 +public class ProcessingEnvAnnoDiscovery<@ProcessingEnvAnnoDiscovery.Anno4 T> + extends JavacTestingAbstractProcessor { + private int round = 0; + + public boolean process(Set annos, RoundEnvironment rEnv) { + if (round++ == 0) { + System.out.println(annos); + Assert.check(annos.contains(eltUtils.getTypeElement("java.lang.annotation.Target"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno1"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno2"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno3"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno4"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno5"))); + Assert.check(annos.size() == 6, "Found extra annotations"); //Anno1-5 + @Target + } + + return true; + } + + @Anno2 + public <@Anno5 K> K m(@Anno3 long foo) { + return null; + } + + @interface Anno1 {} + + @interface Anno2 {} + + @interface Anno3 {} + + @Target(ElementType.TYPE_PARAMETER) + @interface Anno4 {} + + @Target(ElementType.TYPE_PARAMETER) + @interface Anno5 {} + +} diff --git a/langtools/test/tools/javac/processing/environment/round/Anno.java b/langtools/test/tools/javac/processing/environment/round/Anno.java new file mode 100644 index 00000000000..366b489e07b --- /dev/null +++ b/langtools/test/tools/javac/processing/environment/round/Anno.java @@ -0,0 +1,28 @@ +/* + * 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.annotation.*; +import static java.lang.annotation.RetentionPolicy.*; + +@Retention(RUNTIME) +public @interface Anno {} diff --git a/langtools/test/tools/javac/processing/environment/round/ParameterAnnotations.java b/langtools/test/tools/javac/processing/environment/round/ParameterAnnotations.java new file mode 100644 index 00000000000..a4433e352e0 --- /dev/null +++ b/langtools/test/tools/javac/processing/environment/round/ParameterAnnotations.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * Class to hold annotations for ElementsAnnotatedWithTest. + */ + +@AnnotatedElementInfo(annotationName="Anno", + expectedSize=1, + names={"annotatedParameter"}) +public class ParameterAnnotations { + private void foo(@Anno Object annotatedParameter) {} +} diff --git a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java index 3a020060d22..398b2f530df 100644 --- a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java +++ b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 6911854 8030049 + * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 6911854 8030049 8038080 * @summary Tests that getElementsAnnotatedWith works properly. * @author Joseph D. Darcy * @library /tools/javac/lib @@ -31,12 +31,14 @@ * @compile TestElementsAnnotatedWith.java * @compile InheritedAnnotation.java * @compile TpAnno.java + * @compile Anno.java * @compile -processor TestElementsAnnotatedWith -proc:only SurfaceAnnotations.java * @compile -processor TestElementsAnnotatedWith -proc:only BuriedAnnotations.java * @compile -processor TestElementsAnnotatedWith -proc:only Part1.java Part2.java * @compile -processor TestElementsAnnotatedWith -proc:only C2.java * @compile -processor TestElementsAnnotatedWith -proc:only Foo.java * @compile -processor TestElementsAnnotatedWith -proc:only TypeParameterAnnotations.java + * @compile -processor TestElementsAnnotatedWith -proc:only ParameterAnnotations.java * @compile/fail/ref=ErroneousAnnotations.out -processor TestElementsAnnotatedWith -proc:only -XDrawDiagnostics ErroneousAnnotations.java * @compile Foo.java * @compile/process -processor TestElementsAnnotatedWith -proc:only Foo diff --git a/langtools/test/tools/javac/processing/errors/TestBadProcessor.java b/langtools/test/tools/javac/processing/errors/TestBadProcessor.java index 881b2d8b643..065c7bfbf7c 100644 --- a/langtools/test/tools/javac/processing/errors/TestBadProcessor.java +++ b/langtools/test/tools/javac/processing/errors/TestBadProcessor.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 @@ -73,8 +73,10 @@ public class TestBadProcessor { String expect = "error: Bad service configuration file, " + "or exception thrown while constructing Processor object: " + "javax.annotation.processing.Processor: " + - "Provider AnnoProc could not be instantiated: java.lang.Error"; - if (!out.trim().equals(expect)) { + "Provider AnnoProc could not be instantiated: java.lang.Error\n" + + "1 error"; + String lineSeparator = System.getProperty("line.separator"); + if (!out.trim().replace(lineSeparator, "\n").equals(expect)) { System.err.println("expected: " + expect); error("output not as expected"); } diff --git a/langtools/test/tools/javac/processing/model/trees/OnDemandAttribution.java b/langtools/test/tools/javac/processing/model/trees/OnDemandAttribution.java new file mode 100644 index 00000000000..e541deed822 --- /dev/null +++ b/langtools/test/tools/javac/processing/model/trees/OnDemandAttribution.java @@ -0,0 +1,78 @@ +/* + * 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 8038455 + * @summary Verify that in-method ClassSymbols from one round do not affect ClassSymbols in + * following rounds. + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor OnDemandAttribution + * @compile/process -processor OnDemandAttribution OnDemandAttribution.java + */ + +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import static javax.lang.model.util.ElementFilter.*; +import com.sun.source.tree.*; +import com.sun.source.util.*; + +public class OnDemandAttribution extends JavacTestingAbstractProcessor { + + public OnDemandAttribution() { + class Local { } + new Object() { }; + } + + public boolean process(Set annos,RoundEnvironment rEnv) { + TypeElement currentClass = elements.getTypeElement("OnDemandAttribution"); + ExecutableElement constr = constructorsIn(currentClass.getEnclosedElements()).get(0); + Trees trees = Trees.instance(processingEnv); + TreePath path = trees.getPath(constr); + + new TreePathScanner() { + @Override public Void visitClass(ClassTree node, Void p) { + if (node.getSimpleName().contentEquals("Local")) { + //will also attribute the body on demand: + Element el = trees.getElement(getCurrentPath()); + Name binaryName = elements.getBinaryName((TypeElement) el); + if (!binaryName.contentEquals("OnDemandAttribution$1Local")) { + throw new IllegalStateException("Incorrect binary name=" + binaryName); + } + } + return super.visitClass(node, p); + } + @Override public Void visitNewClass(NewClassTree node, Void p) { + Element el = trees.getElement(getCurrentPath()); + Name binaryName = elements.getBinaryName((TypeElement) el.getEnclosingElement()); + if (!binaryName.contentEquals("OnDemandAttribution$1")) { + throw new IllegalStateException("Incorrect binary name=" + binaryName); + } + return super.visitNewClass(node, p); + } + }.scan(path, null); + + return true; + } +} diff --git a/langtools/test/tools/javac/processing/model/util/DirectSuperOfInt.java b/langtools/test/tools/javac/processing/model/util/DirectSuperOfInt.java new file mode 100644 index 00000000000..08483ea9a11 --- /dev/null +++ b/langtools/test/tools/javac/processing/model/util/DirectSuperOfInt.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 + * @bug 8034933 + * @summary Types.directSupertypes should return Object as the super type of interfaces + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor DirectSuperOfInt + * @compile -processor DirectSuperOfInt -proc:only DirectSuperOfInt.java + */ + +import java.util.Set; +import java.util.List; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import static javax.lang.model.util.ElementFilter.*; + +public class DirectSuperOfInt extends JavacTestingAbstractProcessor { + public boolean process(Set tes, + RoundEnvironment round) { + if (round.processingOver()) + return true; + + boolean tested = false; + for (TypeElement te : typesIn(round.getRootElements())) { + if (!te.getSimpleName().contentEquals("DirectSuperOfIntI")) + continue; + + tested = true; + List supers = types.directSupertypes(te.asType()); + if (supers.size() != 1) + throw new AssertionError("test failed"); + + if (!elements.getTypeElement("java.lang.Object").asType().equals((supers.get(0)))) + throw new AssertionError("test failed"); + } + if (!tested) + throw new AssertionError("test failed"); + return true; + } +} + +interface DirectSuperOfIntI {} diff --git a/langtools/test/tools/javac/processing/rounds/BaseClassesNotReRead.java b/langtools/test/tools/javac/processing/rounds/BaseClassesNotReRead.java new file mode 100644 index 00000000000..ebdc9c809e3 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/BaseClassesNotReRead.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 + * @bug 8038455 + * @summary Check that classfiles are read only once in common cases despite several rounds of + * annotation processing. + * @clean * + * @run main BaseClassesNotReRead + */ + +import java.io.*; +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.tools.*; +import javax.tools.JavaFileObject.Kind; +import com.sun.source.util.JavacTask; + + +@SupportedAnnotationTypes("*") +public class BaseClassesNotReRead extends AbstractProcessor { + public static void main(String... args) throws IOException { + new BaseClassesNotReRead().run(); + } + + void run() throws IOException { + File sources = new File(System.getProperty("test.src")); + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null); + Iterable files = + fm.getJavaFileObjects(new File(sources, "BaseClassesNotReReadSource.java")); + DiagnosticListener noErrors = new DiagnosticListener() { + @Override + public void report(Diagnostic diagnostic) { + throw new IllegalStateException(diagnostic.toString()); + } + }; + JavaFileManager manager = new OnlyOneReadFileManager(fm); + Iterable options = Arrays.asList("-processor", "BaseClassesNotReRead"); + JavacTask task = (JavacTask) compiler.getTask(null, manager, noErrors, options, null, files); + task.analyze(); + } + + int round = 1; + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + if (round++ == 1) { + for (int c = 1; c <= 6; c++) { + generateSource("GenClass" + c, + "public class GenClass" + c + " { public void test() { } }"); + } + for (int c = 1; c <= 3; c++) { + generateSource("GenIntf" + c, + "public interface GenIntf" + c + " { public void test(); }"); + } + generateSource("GenAnnotation", + "public @interface GenAnnotation { }"); + generateSource("GenException", + "public class GenException extends Exception { }"); + } + + return false; + } + + private void generateSource(String name, String code) { + Filer filer = processingEnv.getFiler(); + try (Writer out = filer.createSourceFile(name).openWriter()) { + out.write(code); + out.close(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.toString()); + } + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + final class OnlyOneReadFileManager extends ForwardingJavaFileManager { + + public OnlyOneReadFileManager(JavaFileManager fileManager) { + super(fileManager); + } + + @Override + public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) + throws IOException { + return new OnlyOneReadJavaFileObject(super.getJavaFileForInput(location, className, kind)); + } + + @Override + public Iterable list(Location location, String packageName, Set kinds, + boolean recurse) throws IOException { + List result = new ArrayList<>(); + for (JavaFileObject jfo : super.list(location, packageName, kinds, recurse)) { + result.add(new OnlyOneReadJavaFileObject(jfo)); + } + return result; + } + + @Override + public String inferBinaryName(Location location, JavaFileObject file) { + return super.inferBinaryName(location, + ((OnlyOneReadJavaFileObject) file).getFileObject()); + } + + } + + final class OnlyOneReadJavaFileObject extends ForwardingJavaFileObject { + + public OnlyOneReadJavaFileObject(JavaFileObject fileObject) { + super(fileObject); + } + + boolean used; + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + if (used) throw new IllegalStateException("Already read."); + used = true; + return super.getCharContent(ignoreEncodingErrors); + } + + @Override + public InputStream openInputStream() throws IOException { + if (used) throw new IllegalStateException("Already read."); + used = true; + return super.openInputStream(); + } + + @Override + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { + if (used) throw new IllegalStateException("Already read."); + used = true; + return super.openReader(ignoreEncodingErrors); + } + + public JavaFileObject getFileObject() { + return fileObject; + } + } +} diff --git a/langtools/test/tools/javac/processing/rounds/BaseClassesNotReReadSource.java b/langtools/test/tools/javac/processing/rounds/BaseClassesNotReReadSource.java new file mode 100644 index 00000000000..feaaa251134 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/BaseClassesNotReReadSource.java @@ -0,0 +1,40 @@ +/* + * 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.util.List; + +public class BaseClassesNotReReadSource extends GenClass2 + implements GenIntf2 { + public GenClass3 f; + @GenAnnotation + public GenClass4 get(GenClass5 i, List l) throws GenException { + return null; + } + @Override + public void test() { + } + @FunctionalInterface + interface FI extends GenIntf3 { + + } +} diff --git a/langtools/test/tools/javac/processing/rounds/ClassDependingOnGenerated.java b/langtools/test/tools/javac/processing/rounds/ClassDependingOnGenerated.java new file mode 100644 index 00000000000..e5f1c437275 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/ClassDependingOnGenerated.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 + * @bug 8038455 + * @summary Verify situation when a classfile depends on another type, which is missing and + * generated by an annotation processor, is handled properly + * @library /tools/javac/lib/ + * @clean * + * @build ClassWithSuperType ClassDependingOnGenerated JavacTestingAbstractProcessor + * @clean SuperClass + * @compile -processor ClassDependingOnGenerated ClassDependingOnGeneratedSource.java + */ + +import java.io.*; +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.*; +import com.sun.tools.javac.code.Symbol.CompletionFailure; + +public class ClassDependingOnGenerated extends JavacTestingAbstractProcessor { + int round = 1; + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + + try { + processingEnv.getElementUtils().getTypeElement("SuperClass"); + } catch (CompletionFailure cf) { + cf.printStackTrace(); + } + if (round++ == 1) { + try (Writer out = filer.createSourceFile("SuperClass").openWriter()) { + String code = "class SuperClass { public int get() { return 0; } }"; + out.write(code); + out.close(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.toString()); + } + } + + return false; + } + +} diff --git a/langtools/test/tools/javac/processing/rounds/ClassDependingOnGeneratedSource.java b/langtools/test/tools/javac/processing/rounds/ClassDependingOnGeneratedSource.java new file mode 100644 index 00000000000..a7dbc386324 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/ClassDependingOnGeneratedSource.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +public abstract class ClassDependingOnGeneratedSource { + ClassWithSuperType f; + public int get() { + return f.get(); + } +} diff --git a/langtools/test/tools/javac/processing/rounds/ClassWithSuperType.java b/langtools/test/tools/javac/processing/rounds/ClassWithSuperType.java new file mode 100644 index 00000000000..bd46b52a54e --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/ClassWithSuperType.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +public class ClassWithSuperType extends SuperClass { +} +class SuperClass {} diff --git a/langtools/test/tools/javac/processing/rounds/CompleteOnClosed.java b/langtools/test/tools/javac/processing/rounds/CompleteOnClosed.java new file mode 100644 index 00000000000..5de980774ee --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/CompleteOnClosed.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 + * @bug 8038455 + * @summary Ensure that formatting diagnostics with an already closed JavaCompiler won't crash + * the compiler. + * @library /tools/javac/lib + * @build CompleteOnClosed ToolBox JavacTestingAbstractProcessor + * @run main CompleteOnClosed + */ + +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileObject; +import javax.tools.ToolProvider; + +public class CompleteOnClosed extends JavacTestingAbstractProcessor { + public static void main(String... args) { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + DiagnosticCollector collector = new DiagnosticCollector<>(); + String source = "class Test extends CompleteOnClosedOther {" + + " class Inner extends Undefined { }" + + "}"; + Iterable files = Arrays.asList(new ToolBox.JavaSource(source)); + Iterable options = Arrays.asList("-processor", "CompleteOnClosed"); + CompilationTask task = compiler.getTask(null, null, collector, options, null, files); + task.call(); + for (Diagnostic d : collector.getDiagnostics()) { + System.out.println(d.toString()); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } +} diff --git a/langtools/test/tools/javac/processing/rounds/CompleteOnClosedOther.java b/langtools/test/tools/javac/processing/rounds/CompleteOnClosedOther.java new file mode 100644 index 00000000000..836eb29778a --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/CompleteOnClosedOther.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +class CompleteOnClosedOther { + Undefined2 undef; +} diff --git a/langtools/test/tools/javac/processing/rounds/MethodsDroppedBetweenRounds.java b/langtools/test/tools/javac/processing/rounds/MethodsDroppedBetweenRounds.java new file mode 100644 index 00000000000..668d05cef17 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/MethodsDroppedBetweenRounds.java @@ -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. + */ + +/* + * @test + * @bug 8038455 + * @summary Ensure that Symbols for members (methods and fields) are dropped across annotation + * processing rounds. ClassSymbols need to be kept. + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor MethodsDroppedBetweenRounds + * @compile/process -processor MethodsDroppedBetweenRounds MethodsDroppedBetweenRounds.java + */ + +import java.lang.ref.WeakReference; +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.util.ElementFilter; + +public class MethodsDroppedBetweenRounds extends JavacTestingAbstractProcessor { + private static TypeElement currentClassSymbol; + private static WeakReference keptMethod = null; + public boolean process(Set annos,RoundEnvironment rEnv) { + if (keptMethod != null) { + //force GC: + List hold = new ArrayList<>(); + try { + while (true) + hold.add(new byte[1024 * 1024 * 1024]); + } catch (OutOfMemoryError err) { } + hold.clear(); + if (keptMethod.get() != null) { + throw new IllegalStateException("Holds method across rounds."); + } + } + + TypeElement currentClass = elements.getTypeElement("MethodsDroppedBetweenRounds"); + + if (currentClassSymbol != null && currentClassSymbol != currentClass) { + throw new IllegalStateException("Different ClassSymbols across rounds"); + } + + ExecutableElement method = ElementFilter.methodsIn(currentClass.getEnclosedElements()).get(0); + + keptMethod = new WeakReference<>(method); + + return true; + } +} diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java new file mode 100644 index 00000000000..e2bde26e5e1 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java @@ -0,0 +1,118 @@ +/* + * 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 8038455 + * @summary Verify that annotation processor can overwrite source and class files it generated + * during previous compilations, and that the Symbols are updated appropriatelly. + * @library /tools/javac/lib/ + * @clean * + * @build OverwriteBetweenCompilations ToolBox JavacTestingAbstractProcessor + * @compile/ref=OverwriteBetweenCompilations_1.out -processor OverwriteBetweenCompilations -Apass=1 -parameters -XDrawDiagnostics OverwriteBetweenCompilationsSource.java + * @compile/ref=OverwriteBetweenCompilations_2.out -processor OverwriteBetweenCompilations -Apass=2 -parameters -XDrawDiagnostics OverwriteBetweenCompilationsSource.java + * @compile/ref=OverwriteBetweenCompilations_3.out -processor OverwriteBetweenCompilations -Apass=3 -parameters -XDrawDiagnostics OverwriteBetweenCompilationsSource.java + */ + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.*; + +import com.sun.tools.javac.processing.JavacProcessingEnvironment; +import com.sun.tools.javac.processing.PrintingProcessor.PrintingElementVisitor; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Log.WriterKind; + +@SupportedOptions("pass") +public class OverwriteBetweenCompilations extends JavacTestingAbstractProcessor { + int round = 1; + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + Log log = Log.instance(((JavacProcessingEnvironment) processingEnv).getContext()); + PrintWriter pw = log.getWriter(WriterKind.NOTICE); + + pw.println("round: " + round); + + TypeElement generatedSource = + processingEnv.getElementUtils().getTypeElement("GeneratedSource"); + + if (generatedSource != null) { + new PrintingElementVisitor(pw, processingEnv.getElementUtils()).visit(generatedSource); + pw.flush(); + } + + TypeElement generatedClass = + processingEnv.getElementUtils().getTypeElement("GeneratedClass"); + + if (generatedClass != null) { + new PrintingElementVisitor(pw, processingEnv.getElementUtils()).visit(generatedClass); + pw.flush(); + } + + int pass = Integer.parseInt(processingEnv.getOptions().get("pass")); + + if (round++ == 1) { + try (Writer out = filer.createSourceFile("GeneratedSource").openWriter()) { + String code = pass != 2 ? GENERATED_INIT : GENERATED_UPDATE; + code = code.replace("NAME", "GeneratedSource"); + out.write(code); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.toString()); + } + try (OutputStream out = filer.createClassFile("GeneratedClass").openOutputStream()) { + String code = pass != 2 ? GENERATED_INIT : GENERATED_UPDATE; + code = code.replace("NAME", "GeneratedClass"); + ToolBox.JavaToolArgs args = + new ToolBox.JavaToolArgs().appendArgs("-parameters").setSources(code); + Map codeMap = ToolBox.compile(args); + out.write(codeMap.get("GeneratedClass")); + } catch (IOException | ToolBox.CommandExecutionException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.toString()); + } + } + + return false; + } + + //the initial generated class - "NAME" will be replaced with either "GeneratedSource" or + //"GeneratedClass" while generating the class: + private static final String GENERATED_INIT = + "@Deprecated\n" + + "public class NAME extends java.util.ArrayList\n" + + " implements Runnable {\n" + + " public void test(int a) { }\n" + + " public void run() { }\n" + + "}"; + + //generated class update- "NAME" will be replaced with either "GeneratedSource" or + //"GeneratedClass" while generating the class: + private static final String GENERATED_UPDATE = + "@javax.annotation.processing.SupportedAnnotationTypes(\"*\")\n" + + "public abstract class NAME extends java.util.LinkedList" + + " implements Runnable, CharSequence {\n" + + " public void test(long a) { }\n" + + "}"; +} diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilationsSource.java b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilationsSource.java new file mode 100644 index 00000000000..6d07007f334 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilationsSource.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +public abstract class OverwriteBetweenCompilationsSource extends GeneratedSource { +} diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out new file mode 100644 index 00000000000..1840ca9205e --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out @@ -0,0 +1,45 @@ +round: 1 +round: 2 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +round: 3 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +- compiler.note.deprecated.filename: OverwriteBetweenCompilationsSource.java +- compiler.note.deprecated.recompile diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out new file mode 100644 index 00000000000..d1bf374bb74 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out @@ -0,0 +1,57 @@ +round: 1 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +round: 2 + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedSource(); + + public void test(long a); +} + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedClass extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedClass(); + + public void test(long a); +} +round: 3 + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedSource(); + + public void test(long a); +} + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedClass extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedClass(); + + public void test(long a); +} +- compiler.note.deprecated.filename: OverwriteBetweenCompilationsSource.java +- compiler.note.deprecated.recompile diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out new file mode 100644 index 00000000000..39b044ec78a --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out @@ -0,0 +1,61 @@ +round: 1 + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedSource(); + + public void test(long a); +} + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedClass extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedClass(); + + public void test(long a); +} +round: 2 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +round: 3 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +- compiler.note.deprecated.filename: OverwriteBetweenCompilationsSource.java +- compiler.note.deprecated.recompile diff --git a/langtools/test/tools/javac/processing/rounds/TypesCachesCleared.java b/langtools/test/tools/javac/processing/rounds/TypesCachesCleared.java new file mode 100644 index 00000000000..743f6762848 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/TypesCachesCleared.java @@ -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. + */ + +/* + * @test + * @bug 8038455 + * @summary Verify that Types caches (in particular MembersClosureCache) get cleared between rounds. + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor TypesCachesCleared + * @compile/process -processor TypesCachesCleared TypesCachesCleared.java + */ + +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import static javax.lang.model.util.ElementFilter.constructorsIn; +import javax.lang.model.util.Elements; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.util.TreePath; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; + +public class TypesCachesCleared extends JavacTestingAbstractProcessor { + int round = 1; + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + new TestPathScanner() { + @Override + public void visit(Void t) { + } + }; + TypeElement currentClass = elements.getTypeElement("TypesCachesCleared"); + Trees trees = Trees.instance(processingEnv); + TreePath path = trees.getPath(currentClass); + new TreePathScanner() { + @Override public Void visitClass(ClassTree node, Void p) { + trees.getElement(getCurrentPath()); + return super.visitClass(node, p); + } + }.scan(path, null); + return false; + } + + public TypesCachesCleared() { + class Local { } + new Object() { }; + } + + public boolean process(Elements elements) { + TypeElement currentClass = elements.getTypeElement("OnDemandAttribution"); + ExecutableElement constr = constructorsIn(currentClass.getEnclosedElements()).get(0); + Trees trees = Trees.instance(processingEnv); + TreePath path = trees.getPath(constr); + + new TreePathScanner() { + @Override public Void visitClass(ClassTree node, Void p) { + if (node.getSimpleName().contentEquals("Local")) { + //will also attribute the body on demand: + Element el = trees.getElement(getCurrentPath()); + Name binaryName = elements.getBinaryName((TypeElement) el); + if (!binaryName.contentEquals("OnDemandAttribution$1Local")) { + throw new IllegalStateException("Incorrect binary name=" + binaryName); + } + } + return super.visitClass(node, p); + } + @Override public Void visitNewClass(NewClassTree node, Void p) { + Element el = trees.getElement(getCurrentPath()); + Name binaryName = elements.getBinaryName((TypeElement) el.getEnclosingElement()); + if (!binaryName.contentEquals("OnDemandAttribution$1")) { + throw new IllegalStateException("Incorrect binary name=" + binaryName); + } + return super.visitNewClass(node, p); + } + }.scan(path, null); + + return true; + } + public static interface TestVisitor { + public void visit(T t); + } + + public static class TestScanner implements TestVisitor { + public void visit(T t) { } + } + + public static class TestPathScanner extends TestScanner { + public void visit(T t) { } + } +} diff --git a/langtools/test/tools/javac/processing/warnings/gold_unsp_warn.out b/langtools/test/tools/javac/processing/warnings/gold_unsp_warn.out index bd1f2766ea0..f76a3c011a1 100644 --- a/langtools/test/tools/javac/processing/warnings/gold_unsp_warn.out +++ b/langtools/test/tools/javac/processing/warnings/gold_unsp_warn.out @@ -1 +1,2 @@ - compiler.warn.proc.unmatched.processor.options: [unsupported] +1 warning diff --git a/langtools/test/tools/javac/util/context/T7021650.java b/langtools/test/tools/javac/util/context/T7021650.java index 5801b03b2f5..4bc314b2089 100644 --- a/langtools/test/tools/javac/util/context/T7021650.java +++ b/langtools/test/tools/javac/util/context/T7021650.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 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 @@ -56,7 +56,7 @@ public class T7021650 extends JavacTestingAbstractProcessor { * and verify that corresponding objects are created in each round. */ void run() throws Exception { - Counter demoCounter = new Counter(); + Counter myDemoCounter = new Counter(); Counter myAttrCounter = new Counter(); Context context = new Context(); @@ -76,7 +76,7 @@ public class T7021650 extends JavacTestingAbstractProcessor { } }); - Demo.preRegister(context, demoCounter); + MyDemo.preRegister(context, myDemoCounter); MyAttr.preRegister(context, myAttrCounter); String[] args = { @@ -88,13 +88,9 @@ public class T7021650 extends JavacTestingAbstractProcessor { compile(context, args); - // Expect to create Demo for initial round, then MAX_ROUNDS in which - // GenX files are generated, then standard final round of processing. - checkEqual("demoCounter", demoCounter.count, MAX_ROUNDS + 2); - - // Expect to create MyAttr for same processing rounds as for Demo, - // plus additional context for final compilation. - checkEqual("myAttrCounter", myAttrCounter.count, MAX_ROUNDS + 3); + // the services should only be created once in the current scheme: + checkEqual("demoCounter", myDemoCounter.count, 1); + checkEqual("myAttrCounter", myAttrCounter.count, 1); } void compile(Context context, String... args) throws Exception { @@ -123,15 +119,6 @@ public class T7021650 extends JavacTestingAbstractProcessor { * A custom class unknown to javac but nonetheless registered in the context. */ static class Demo { - static void preRegister(Context context, final Counter counter) { - context.put(Demo.class, new Context.Factory() { - public Demo make(Context c) { - counter.count++; - return new Demo(c); - } - }); - } - Demo(Context c) { c.put(Demo.class, this); } @@ -141,6 +128,21 @@ public class T7021650 extends JavacTestingAbstractProcessor { } } + static class MyDemo extends Demo { + static void preRegister(Context context, final Counter counter) { + context.put(Demo.class, new Context.Factory() { + public Demo make(Context c) { + counter.count++; + return new MyDemo(c); + } + }); + } + + MyDemo(Context c) { + super(c); + } + } + /** * A custom version of a standard javac component. */ @@ -174,7 +176,7 @@ public class T7021650 extends JavacTestingAbstractProcessor { Context context = ((JavacProcessingEnvironment) processingEnv).getContext(); // verify items in context as expected - check("Demo", Demo.instance(context), Demo.class); + check("Demo", Demo.instance(context), MyDemo.class); check("Attr", Attr.instance(context), MyAttr.class); // For a few rounds, generate new source files, so that we can check whether diff --git a/langtools/test/tools/javap/T4975569.java b/langtools/test/tools/javap/T4975569.java index b4a55492f31..df35b7ffd50 100644 --- a/langtools/test/tools/javap/T4975569.java +++ b/langtools/test/tools/javap/T4975569.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 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 @@ -40,10 +40,10 @@ public class T4975569 verify("T4975569$Anno", "flags: ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION"); verify("T4975569$E", "flags: ACC_FINAL, ACC_SUPER, ACC_ENUM"); verify("T4975569$S", "flags: ACC_BRIDGE, ACC_SYNTHETIC", - "InnerClasses:\n static"); + "InnerClasses:\n static"); verify("T4975569$V", "void m(java.lang.String...)", "flags: ACC_VARARGS"); - verify("T4975569$Prot", "InnerClasses:\n protected"); + verify("T4975569$Prot", "InnerClasses:\n protected"); //verify("T4975569$Priv", "InnerClasses"); if (errors > 0) throw new Error(errors + " found."); diff --git a/langtools/test/tools/javap/T8035104.java b/langtools/test/tools/javap/T8035104.java new file mode 100644 index 00000000000..37ef8fc015b --- /dev/null +++ b/langtools/test/tools/javap/T8035104.java @@ -0,0 +1,67 @@ +/* + * 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 8035104 + * @summary reorder class file attributes in javap listing + */ + +import java.io.*; + +public class T8035104 { + public static void main(String[] args) throws Exception { + new T8035104().run(); + } + + public void run() throws Exception { + String[] lines = javap("-v", T8035104.class.getName()).split("[\r\n]+"); + int minor = -1; + int SourceFile = -1; + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + if (line.matches(" *minor version: [0-9.]+")) + minor = i; + if (line.matches(" *SourceFile: .+")) + SourceFile = i; + } + if (minor == -1) + throw new Exception("minor version not found"); + if (SourceFile == -1) + throw new Exception("SourceFile not found"); + if (SourceFile < minor) + throw new Exception("unexpected order of output"); + + System.out.println("output OK"); + } + + String javap(String... args) { + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + int rc = com.sun.tools.javap.Main.run(args, out); + out.close(); + System.out.println(sw.toString()); + System.out.println("javap exited, rc=" + rc); + return sw.toString(); + } +} diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 361ea8d4c13..1b513ad7ce2 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -369,6 +369,10 @@ define SetupNativeCompilation $$(error Unknown value for OPTIMIZATION: $$($1_OPTIMIZATION)) endif + # Add sys root specific cflags last + $1_EXTRA_CFLAGS += $(SYSROOT_CFLAGS) + $1_EXTRA_CXXFLAGS += $(SYSROOT_CFLAGS) + # Now call add_native_source for each source file we are going to compile. $$(foreach p,$$($1_SRCS), \ $$(eval $$(call add_native_source,$1,$$p,$$($1_OBJECT_DIR), \ @@ -414,6 +418,8 @@ define SetupNativeCompilation $1_EXTRA_LDFLAGS += $(call SET_SHARED_LIBRARY_MAPFILE,$$($1_REAL_MAPFILE)) endif + $1_EXTRA_LDFLAGS += $(SYSROOT_LDFLAGS) + # Need to make sure TARGET is first on list $1 := $$($1_TARGET) ifeq ($$($1_STATIC_LIBRARY),) @@ -476,7 +482,7 @@ define SetupNativeCompilation # to be rebuilt properly. $$($1_DEBUGINFO_ZIP): $$($1_DEBUGINFO_FILES) $$($1_TARGET) $(CD) $$($1_OBJECT_DIR) \ - && $(ZIP) -q $$@ $$($1_DEBUGINFO_FILES) + && $(ZIP) -q $$@ $$(notdir $$($1_DEBUGINFO_FILES)) else $1 += $$(subst $$($1_OBJECT_DIR),$$($1_OUTPUT_DIR),$$($1_DEBUGINFO_FILES)) diff --git a/make/devkit/Makefile b/make/devkit/Makefile index a6a5ca9e9ae..0776f54b488 100644 --- a/make/devkit/Makefile +++ b/make/devkit/Makefile @@ -75,7 +75,7 @@ ifeq (,$(SKIP_ME)) $(foreach p,$(filter-out $(me),$(platforms)),$(eval $(p) : $$(me))) endif -OUTPUT_ROOT = $(abspath ../../../build/devkit) +OUTPUT_ROOT = $(abspath ../../build/devkit) RESULT = $(OUTPUT_ROOT)/result submakevars = HOST=$@ BUILD=$(me) \ diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index 457dacb8e9d..c2460105b7f 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -49,8 +49,8 @@ ARCH := $(word 1,$(subst -, ,$(TARGET))) # Define external dependencies # Latest that could be made to work. -gcc_ver := gcc-4.7.3 -binutils_ver := binutils-2.22 +gcc_ver := gcc-4.8.2 +binutils_ver := binutils-2.24 ccache_ver := ccache-3.1.9 mpfr_ver := mpfr-3.0.1 gmp_ver := gmp-4.3.2 @@ -64,6 +64,7 @@ GMP := http://ftp.gnu.org/pub/gnu/gmp/${gmp_ver}.tar.bz2 MPC := http://www.multiprecision.org/mpc/download/${mpc_ver}.tar.gz # RPMs in OEL5.5 +LINUX_VERSION := OEL5.5 RPM_LIST := \ kernel-headers \ glibc-2 glibc-headers glibc-devel \ @@ -121,7 +122,7 @@ RESULT := $(OUTPUT_ROOT)/result BUILDDIR := $(OUTPUT_ROOT)/$(HOST)/$(TARGET) PREFIX := $(RESULT)/$(HOST) TARGETDIR := $(PREFIX)/$(TARGET) -SYSROOT := $(TARGETDIR)/sys-root +SYSROOT := $(TARGETDIR)/sysroot DOWNLOAD := $(OUTPUT_ROOT)/download SRCDIR := $(OUTPUT_ROOT)/src @@ -184,7 +185,7 @@ $(foreach p,$(RPM_FILE_LIST),$(eval $(call unrpm,$(p)))) ########################################################################################## -# Note: MUST create a /usr/lib even if not really needed. +# Note: MUST create a /usr/lib even if not really needed. # gcc will use a path relative to it to resolve lib64. (x86_64). # we're creating multi-lib compiler with 32bit libc as well, so we should # have it anyway, but just to make sure... @@ -459,15 +460,31 @@ $(TARGETDIR)/%.done : $(BUILDDIR)/%/Makefile ########################################################################################## +$(PREFIX)/devkit.info: FRC + @echo 'Creating devkit.info in the root of the kit' + rm -f $@ + touch $@ + echo '# This file describes to configure how to interpret the contents of this' >> $@ + echo '# devkit' >> $@ + echo '' >> $@ + echo 'DEVKIT_NAME="$(gcc_ver) - $(LINUX_VERSION)"' >> $@ + echo 'DEVKIT_TOOLCHAIN_PATH="$$DEVKIT_ROOT/bin"' >> $@ + echo 'DEVKIT_SYSROOT="$$DEVKIT_ROOT/$$host/sysroot"' >> $@ + +########################################################################################## + bfdlib : $(bfdlib) binutils : $(binutils) rpms : $(rpms) libs : $(libs) sysroot : rpms libs gcc : sysroot $(gcc) $(gccpatch) -all : binutils gcc bfdlib +all : binutils gcc bfdlib $(PREFIX)/devkit.info # this is only built for host. so separate. ccache : $(ccache) +# Force target +FRC: + .PHONY : gcc all binutils bfdlib link_libs rpms libs sysroot diff --git a/nashorn/.hgtags b/nashorn/.hgtags index c7e5d51e490..34584cf61e4 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -240,3 +240,4 @@ b3517e51f40477f10db8bc30a557aa0ea712c274 jdk9-b02 3f6ef92cd7823372c45e79125adba4cbf1c9f7b2 jdk9-b04 2a1cac93c33317d828d4a5b81239204a9927cc4a jdk9-b05 1f75bcbe74e315470dc0b75b7d5bcd209e287c39 jdk9-b06 +9a34d2a0a5bdaf0bf0d81d6fe6324aa0cfb35bfe jdk9-b07 diff --git a/nashorn/README b/nashorn/README index 52b30919065..242d6077b67 100644 --- a/nashorn/README +++ b/nashorn/README @@ -81,13 +81,13 @@ TestNG library and placing its jar file into the lib subdirectory: After that, you can run the tests using: cd make - ant test + ant clean test You can also run the ECMA-262 test suite with Nashorn. In order to do that, you will need to get a copy of it and put it in test/script/external/test262 directory. A convenient way to do it is: - hg clone http://hg.ecmascript.org/tests/test262/ test/script/external/test262 + git clone https://github.com/tc39/test262 test/script/external/test262 Alternatively, you can check it out elsewhere and make test/script/external/test262 a symbolic link to that directory. After @@ -95,6 +95,11 @@ you've done this, you can run the ECMA-262 tests using: cd nashorn~jdk8/nashorn/make ant test262 + +Ant target to get/update external test suites: + + ant externals + ant update-externals These tests take time, so we have a parallelized runner for them that takes advantage of all processor cores on the computer: diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java index c43bdf52512..e47f8b160ad 100644 --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java @@ -22,40 +22,62 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.nashorn.internal.tools.nasgen; import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.STRING_DESC; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Type; import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.runtime.ScriptObject; /** * Details about a Java method or field annotated with any of the field/method * annotations from the jdk.nashorn.internal.objects.annotations package. */ public final class MemberInfo implements Cloneable { + // class loader of this class + private static ClassLoader myLoader = MemberInfo.class.getClassLoader(); + /** * The different kinds of available class annotations */ public static enum Kind { - /** This is a script class */ + + /** + * This is a script class + */ SCRIPT_CLASS, - /** This is a constructor */ + /** + * This is a constructor + */ CONSTRUCTOR, - /** This is a function */ + /** + * This is a function + */ FUNCTION, - /** This is a getter */ + /** + * This is a getter + */ GETTER, - /** This is a setter */ + /** + * This is a setter + */ SETTER, - /** This is a property */ + /** + * This is a property + */ PROPERTY, - /** This is a specialized version of a function */ + /** + * This is a specialized version of a function + */ SPECIALIZED_FUNCTION, - /** This is a specialized version of a constructor */ + /** + * This is a specialized version of a constructor + */ SPECIALIZED_CONSTRUCTOR } @@ -194,6 +216,7 @@ public final class MemberInfo implements Cloneable { /** * Check whether this MemberInfo is a getter that resides in the instance + * * @return true if instance setter */ boolean isInstanceSetter() { @@ -245,92 +268,201 @@ public final class MemberInfo implements Cloneable { } void verify() { - if (kind == Kind.CONSTRUCTOR) { - final Type returnType = Type.getReturnType(javaDesc); - if (! returnType.toString().equals(OBJECT_DESC)) { - error("return value should be of Object type, found" + returnType); - } - final Type[] argTypes = Type.getArgumentTypes(javaDesc); - if (argTypes.length < 2) { - error("constructor methods should have at least 2 args"); - } - if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) { - error("first argument should be of boolean type, found" + argTypes[0]); - } - if (! argTypes[1].toString().equals(OBJECT_DESC)) { - error("second argument should be of Object type, found" + argTypes[0]); - } + switch (kind) { + case CONSTRUCTOR: { + final Type returnType = Type.getReturnType(javaDesc); + if (!isJSObjectType(returnType)) { + error("return value of a @Constructor method should be of Object type, found " + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length < 2) { + error("@Constructor methods should have at least 2 args"); + } + if (!argTypes[0].equals(Type.BOOLEAN_TYPE)) { + error("first argument of a @Constructor method should be of boolean type, found " + argTypes[0]); + } + if (!isJavaLangObject(argTypes[1])) { + error("second argument of a @Constructor method should be of Object type, found " + argTypes[0]); + } - if (argTypes.length > 2) { - for (int i = 2; i < argTypes.length - 1; i++) { - if (! argTypes[i].toString().equals(OBJECT_DESC)) { - error(i + "'th argument should be of Object type, found " + argTypes[i]); + if (argTypes.length > 2) { + for (int i = 2; i < argTypes.length - 1; i++) { + if (!isJavaLangObject(argTypes[i])) { + error(i + "'th argument of a @Constructor method should be of Object type, found " + argTypes[i]); + } + } + + final String lastArgTypeDesc = argTypes[argTypes.length - 1].getDescriptor(); + final boolean isVarArg = lastArgTypeDesc.equals(OBJECT_ARRAY_DESC); + if (!lastArgTypeDesc.equals(OBJECT_DESC) && !isVarArg) { + error("last argument of a @Constructor method is neither Object nor Object[] type: " + lastArgTypeDesc); + } + + if (isVarArg && argTypes.length > 3) { + error("vararg of a @Constructor method has more than 3 arguments"); } } - - final String lastArgType = argTypes[argTypes.length - 1].toString(); - final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); - if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { - error("last argument is neither Object nor Object[] type: " + lastArgType); + } + break; + case SPECIALIZED_CONSTRUCTOR: { + final Type returnType = Type.getReturnType(javaDesc); + if (!isJSObjectType(returnType)) { + error("return value of a @SpecializedConstructor method should be a valid JS type, found " + returnType); } - - if (isVarArg && argTypes.length > 3) { - error("vararg constructor has more than 3 arguments"); - } - } - } else if (kind == Kind.FUNCTION) { - final Type[] argTypes = Type.getArgumentTypes(javaDesc); - if (argTypes.length < 1) { - error("function methods should have at least 1 arg"); - } - if (! argTypes[0].toString().equals(OBJECT_DESC)) { - error("first argument should be of Object type, found" + argTypes[0]); - } - - if (argTypes.length > 1) { - for (int i = 1; i < argTypes.length - 1; i++) { - if (! argTypes[i].toString().equals(OBJECT_DESC)) { - error(i + "'th argument should be of Object type, found " + argTypes[i]); + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + for (int i = 0; i < argTypes.length; i++) { + if (!isValidJSType(argTypes[i])) { + error(i + "'th argument of a @SpecializedConstructor method is not valid JS type, found " + argTypes[i]); } } - - final String lastArgType = argTypes[argTypes.length - 1].toString(); - final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); - if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { - error("last argument is neither Object nor Object[] type: " + lastArgType); + } + break; + case FUNCTION: { + final Type returnType = Type.getReturnType(javaDesc); + if (!isValidJSType(returnType)) { + error("return value of a @Function method should be a valid JS type, found " + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length < 1) { + error("@Function methods should have at least 1 arg"); + } + if (!isJavaLangObject(argTypes[0])) { + error("first argument of a @Function method should be of Object type, found " + argTypes[0]); } - if (isVarArg && argTypes.length > 2) { - error("vararg function has more than 2 arguments"); + if (argTypes.length > 1) { + for (int i = 1; i < argTypes.length - 1; i++) { + if (!isJavaLangObject(argTypes[i])) { + error(i + "'th argument of a @Function method should be of Object type, found " + argTypes[i]); + } + } + + final String lastArgTypeDesc = argTypes[argTypes.length - 1].getDescriptor(); + final boolean isVarArg = lastArgTypeDesc.equals(OBJECT_ARRAY_DESC); + if (!lastArgTypeDesc.equals(OBJECT_DESC) && !isVarArg) { + error("last argument of a @Function method is neither Object nor Object[] type: " + lastArgTypeDesc); + } + + if (isVarArg && argTypes.length > 2) { + error("vararg @Function method has more than 2 arguments"); + } } } - } else if (kind == Kind.GETTER) { - final Type[] argTypes = Type.getArgumentTypes(javaDesc); - if (argTypes.length != 1) { - error("getter methods should have one argument"); + break; + case SPECIALIZED_FUNCTION: { + final Type returnType = Type.getReturnType(javaDesc); + if (!isValidJSType(returnType)) { + error("return value of a @SpecializedFunction method should be a valid JS type, found " + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + for (int i = 0; i < argTypes.length; i++) { + if (!isValidJSType(argTypes[i])) { + error(i + "'th argument of a @SpecializedFunction method is not valid JS type, found " + argTypes[i]); + } + } } - if (! argTypes[0].toString().equals(OBJECT_DESC)) { - error("first argument of getter should be of Object type, found: " + argTypes[0]); + break; + case GETTER: { + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length != 1) { + error("@Getter methods should have one argument"); + } + if (!isJavaLangObject(argTypes[0])) { + error("first argument of a @Getter method should be of Object type, found: " + argTypes[0]); + } + + final Type returnType = Type.getReturnType(javaDesc); + if (!isJavaLangObject(returnType)) { + error("return type of a @Getter method should be Object, found: " + javaDesc); + } } - if (Type.getReturnType(javaDesc).equals(Type.VOID_TYPE)) { - error("return type of getter should not be void"); + break; + case SETTER: { + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length != 2) { + error("@Setter methods should have two arguments"); + } + if (!isJavaLangObject(argTypes[0])) { + error("first argument of a @Setter method should be of Object type, found: " + argTypes[0]); + } + if (!Type.getReturnType(javaDesc).toString().equals("V")) { + error("return type of of a @Setter method should be void, found: " + Type.getReturnType(javaDesc)); + } } - } else if (kind == Kind.SETTER) { - final Type[] argTypes = Type.getArgumentTypes(javaDesc); - if (argTypes.length != 2) { - error("setter methods should have two arguments"); - } - if (! argTypes[0].toString().equals(OBJECT_DESC)) { - error("first argument of setter should be of Object type, found: " + argTypes[0]); - } - if (!Type.getReturnType(javaDesc).toString().equals("V")) { - error("return type of setter should be void, found: " + Type.getReturnType(javaDesc)); + break; + case PROPERTY: { + if (where == Where.CONSTRUCTOR) { + if (isStatic()) { + if (!isFinal()) { + error("static Where.CONSTRUCTOR @Property should be final"); + } + + if (!isJSPrimitiveType(Type.getType(javaDesc))) { + error("static Where.CONSTRUCTOR @Property should be a JS primitive"); + } + } + } else if (where == Where.PROTOTYPE) { + if (isStatic()) { + if (!isFinal()) { + error("static Where.PROTOTYPE @Property should be final"); + } + + if (!isJSPrimitiveType(Type.getType(javaDesc))) { + error("static Where.PROTOTYPE @Property should be a JS primitive"); + } + } + } } } } + private static boolean isValidJSType(final Type type) { + return isJSPrimitiveType(type) || isJSObjectType(type); + } + + private static boolean isJSPrimitiveType(final Type type) { + switch (type.getSort()) { + case Type.BOOLEAN: + case Type.INT: + case Type.LONG: + case Type.DOUBLE: + return true; + default: + return false; + } + } + + private static boolean isJSObjectType(final Type type) { + return isJavaLangObject(type) || isJavaLangString(type) || isScriptObject(type); + } + + private static boolean isJavaLangObject(final Type type) { + return type.getDescriptor().equals(OBJECT_DESC); + } + + private static boolean isJavaLangString(final Type type) { + return type.getDescriptor().equals(STRING_DESC); + } + + private static boolean isScriptObject(final Type type) { + if (type.getDescriptor().equals(SCRIPTOBJECT_DESC)) { + return true; + } + + if (type.getSort() == Type.OBJECT) { + try { + final Class clazz = Class.forName(type.getClassName(), false, myLoader); + return ScriptObject.class.isAssignableFrom(clazz); + } catch (final ClassNotFoundException cnfe) { + return false; + } + } + + return false; + } + private void error(final String msg) { - throw new RuntimeException(javaName + javaDesc + " : " + msg); + throw new RuntimeException(javaName + " of type " + javaDesc + " : " + msg); } /** diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java index dd947033d34..1d724187dbe 100644 --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java @@ -61,6 +61,8 @@ public interface StringConstants { static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName(); static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName(); static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor(); + static final String STRING_TYPE = TYPE_STRING.getInternalName(); + static final String STRING_DESC = TYPE_STRING.getDescriptor(); static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class); static final String ARRAYLIST_TYPE = TYPE_ARRAYLIST.getInternalName(); static final String COLLECTION_TYPE = TYPE_COLLECTION.getInternalName(); @@ -129,6 +131,7 @@ public interface StringConstants { // ScriptObject static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName(); + static final String SCRIPTOBJECT_DESC = TYPE_SCRIPTOBJECT.getDescriptor(); static final String SCRIPTOBJECT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_PROPERTYMAP); static final String GETTER_PREFIX = "G$"; diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index 74eae86a588..3c1954a2afd 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -42,6 +42,9 @@ + + + @@ -503,18 +506,17 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { - - + + - + - - + + - diff --git a/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java b/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java index 519036b37cc..d0ad96bad21 100644 --- a/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java +++ b/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java @@ -113,6 +113,8 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL // explicit property is beneficial for them. // REVISIT: is it maybe a code smell that "dyn:getLength" is not needed? setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY); + } else if(List.class.isAssignableFrom(clazz)) { + setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF); } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index e0ca67a4a92..9cf0adb949f 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -3228,7 +3228,7 @@ final class CodeGenerator extends NodeOperatorVisitor install(final String className, final byte[] code) { - LOG.fine("Installing class ", className); - - final Class clazz = installer.install(Compiler.binaryName(className), code); - - try { - final Object[] constants = getConstantData().toArray(); - // Need doPrivileged because these fields are private - AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public Void run() throws Exception { - //use reflection to write source and constants table to installed classes - final Field sourceField = clazz.getDeclaredField(SOURCE.symbolName()); - final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName()); - sourceField.setAccessible(true); - constantsField.setAccessible(true); - sourceField.set(null, source); - constantsField.set(null, constants); - return null; - } - }); - } catch (final PrivilegedActionException e) { - throw new RuntimeException(e); - } - - return clazz; + private Class install(final String className, final byte[] code, final Object[] constants) { + return installer.install(className, code, source, constants); } /** @@ -444,10 +420,15 @@ public final class Compiler { assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed"; final Map> installedClasses = new HashMap<>(); + final Object[] constants = getConstantData().toArray(); final String rootClassName = firstCompileUnitName(); final byte[] rootByteCode = bytecode.get(rootClassName); - final Class rootClass = install(rootClassName, rootByteCode); + final Class rootClass = install(rootClassName, rootByteCode, constants); + + if (!isLazy()) { + installer.storeCompiledScript(source, rootClassName, bytecode, constants); + } int length = rootByteCode.length; @@ -461,7 +442,7 @@ public final class Compiler { final byte[] code = entry.getValue(); length += code.length; - installedClasses.put(className, install(className, code)); + installedClasses.put(className, install(className, code, constants)); } for (final CompileUnit unit : compileUnits) { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java index 8012adf5065..436622bd7ff 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java @@ -83,7 +83,7 @@ public class MapCreator { } } - return PropertyMap.newMap(properties, fieldCount, fieldMaximum, 0); + return PropertyMap.newMap(properties, structure.getName(), fieldCount, fieldMaximum, 0); } PropertyMap makeSpillMap(final boolean hasArguments) { @@ -100,7 +100,7 @@ public class MapCreator { } } - return PropertyMap.newMap(properties, 0, 0, spillIndex); + return PropertyMap.newMap(properties, structure.getName(), 0, 0, spillIndex); } /** diff --git a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java index 7bd1d2f91dd..c29af8515c9 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java @@ -382,7 +382,7 @@ abstract class ArrayBufferView extends ScriptObject { return (int) (length & Integer.MAX_VALUE); } - protected static Object subarrayImpl(final Object self, final Object begin0, final Object end0) { + protected static ScriptObject subarrayImpl(final Object self, final Object begin0, final Object end0) { final ArrayBufferView arrayView = ((ArrayBufferView)self); final int elementLength = arrayView.elementLength(); final int begin = NativeArrayBuffer.adjustIndex(JSType.toInt32(begin0), elementLength); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java index 168a2f8a9ec..6f07cb9dbc4 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java @@ -31,6 +31,7 @@ import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE; import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE; import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator; import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator; +import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; import java.lang.invoke.MethodHandle; import java.util.ArrayList; @@ -349,6 +350,27 @@ public final class NativeArray extends ScriptObject { return super.defineOwnProperty(key, desc, reject); } + /** + * Spec. mentions use of [[DefineOwnProperty]] for indexed properties in + * certain places (eg. Array.prototype.map, filter). We can not use ScriptObject.set + * method in such cases. This is because set method uses inherited setters (if any) + * from any object in proto chain such as Array.prototype, Object.prototype. + * This method directly sets a particular element value in the current object. + * + * @param index key for property + * @param value value to define + */ + @Override + public final void defineOwnProperty(final int index, final Object value) { + assert isValidArrayIndex(index) : "invalid array index"; + final long longIndex = ArrayIndex.toLongIndex(index); + if (longIndex >= getArray().length()) { + // make array big enough to hold.. + setArray(getArray().ensure(longIndex)); + } + setArray(getArray().set(index, value, false)); + } + /** * Return the array contents upcasted as an ObjectArray, regardless of * representation @@ -367,7 +389,7 @@ public final class NativeArray extends ScriptObject { * @return true if argument is an array */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isArray(final Object self, final Object arg) { + public static boolean isArray(final Object self, final Object arg) { return isArray(arg) || (arg instanceof JSObject && ((JSObject)arg).isArray()); } @@ -466,7 +488,7 @@ public final class NativeArray extends ScriptObject { * @return locale specific string representation for array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleString(final Object self) { + public static String toLocaleString(final Object self) { final StringBuilder sb = new StringBuilder(); final Iterator iter = arrayLikeIterator(self, true); @@ -512,7 +534,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @Constructor(arity = 1) - public static Object construct(final boolean newObj, final Object self, final Object... args) { + public static NativeArray construct(final boolean newObj, final Object self, final Object... args) { switch (args.length) { case 0: return new NativeArray(0); @@ -565,7 +587,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @SpecializedConstructor - public static Object construct(final boolean newObj, final Object self) { + public static NativeArray construct(final boolean newObj, final Object self) { return new NativeArray(0); } @@ -580,7 +602,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @SpecializedConstructor - public static Object construct(final boolean newObj, final Object self, final int length) { + public static NativeArray construct(final boolean newObj, final Object self, final int length) { if (length >= 0) { return new NativeArray(length); } @@ -599,7 +621,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @SpecializedConstructor - public static Object construct(final boolean newObj, final Object self, final long length) { + public static NativeArray construct(final boolean newObj, final Object self, final long length) { if (length >= 0L && length <= JSType.MAX_UINT) { return new NativeArray(length); } @@ -618,7 +640,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @SpecializedConstructor - public static Object construct(final boolean newObj, final Object self, final double length) { + public static NativeArray construct(final boolean newObj, final Object self, final double length) { final long uint32length = JSType.toUint32(length); if (uint32length == length) { @@ -636,7 +658,7 @@ public final class NativeArray extends ScriptObject { * @return resulting NativeArray */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object concat(final Object self, final Object... args) { + public static NativeArray concat(final Object self, final Object... args) { final ArrayList list = new ArrayList<>(); concatToList(list, Global.toObject(self)); @@ -683,7 +705,7 @@ public final class NativeArray extends ScriptObject { * @return string representation after join */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object join(final Object self, final Object separator) { + public static String join(final Object self, final Object separator) { final StringBuilder sb = new StringBuilder(); final Iterator iter = arrayLikeIterator(self, true); final String sep = separator == ScriptRuntime.UNDEFINED ? "," : JSType.toString(separator); @@ -951,7 +973,7 @@ public final class NativeArray extends ScriptObject { * @return sorted array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object sort(final Object self, final Object comparefn) { + public static ScriptObject sort(final Object self, final Object comparefn) { try { final ScriptObject sobj = (ScriptObject) self; final long len = JSType.toUint32(sobj.getLength()); @@ -1155,7 +1177,7 @@ public final class NativeArray extends ScriptObject { * @return index of element, or -1 if not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object indexOf(final Object self, final Object searchElement, final Object fromIndex) { + public static long indexOf(final Object self, final Object searchElement, final Object fromIndex) { try { final ScriptObject sobj = (ScriptObject)Global.toObject(self); final long len = JSType.toUint32(sobj.getLength()); @@ -1191,7 +1213,7 @@ public final class NativeArray extends ScriptObject { * @return index of element, or -1 if not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object lastIndexOf(final Object self, final Object... args) { + public static long lastIndexOf(final Object self, final Object... args) { try { final ScriptObject sobj = (ScriptObject)Global.toObject(self); final long len = JSType.toUint32(sobj.getLength()); @@ -1226,7 +1248,7 @@ public final class NativeArray extends ScriptObject { * @return true if callback function return true for every element in the array, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object every(final Object self, final Object callbackfn, final Object thisArg) { + public static boolean every(final Object self, final Object callbackfn, final Object thisArg) { return applyEvery(Global.toObject(self), callbackfn, thisArg); } @@ -1250,7 +1272,7 @@ public final class NativeArray extends ScriptObject { * @return true if callback function returned true for any element in the array, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object some(final Object self, final Object callbackfn, final Object thisArg) { + public static boolean some(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, false) { private final MethodHandle someInvoker = getSOME_CALLBACK_INVOKER(); @@ -1291,7 +1313,7 @@ public final class NativeArray extends ScriptObject { * @return array with elements transformed by map function */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object map(final Object self, final Object callbackfn, final Object thisArg) { + public static NativeArray map(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, null) { private final MethodHandle mapInvoker = getMAP_CALLBACK_INVOKER(); @@ -1320,7 +1342,7 @@ public final class NativeArray extends ScriptObject { * @return filtered array */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object filter(final Object self, final Object callbackfn, final Object thisArg) { + public static NativeArray filter(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, new NativeArray()) { private long to = 0; private final MethodHandle filterInvoker = getFILTER_CALLBACK_INVOKER(); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java index 49a61c96df3..70c97daf27b 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java @@ -45,7 +45,7 @@ final class NativeArrayBuffer extends ScriptObject { private static PropertyMap $nasgenmap$; @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { + public static NativeArrayBuffer constructor(final boolean newObj, final Object self, final Object... args) { if (args.length == 0) { throw new RuntimeException("missing length argument"); } @@ -81,7 +81,7 @@ final class NativeArrayBuffer extends ScriptObject { } @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object slice(final Object self, final Object begin0, final Object end0) { + public static NativeArrayBuffer slice(final Object self, final Object begin0, final Object end0) { final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self; int begin = JSType.toInt32(begin0); int end = end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : arrayBuffer.getByteLength(); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java index f737a6c898b..d645d6dd4e6 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java @@ -110,7 +110,7 @@ public final class NativeBoolean extends ScriptObject { * @return string representation of this boolean */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return getBoolean(self).toString(); } @@ -121,7 +121,7 @@ public final class NativeBoolean extends ScriptObject { * @return value of this boolean */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object valueOf(final Object self) { + public static boolean valueOf(final Object self) { return getBoolean(self); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java index 93b5f09f90c..414ff8ae5ce 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java @@ -131,7 +131,7 @@ public class NativeDataView extends ScriptObject { * @return newly constructed DataView object */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { + public static NativeDataView constructor(final boolean newObj, final Object self, final Object... args) { if (args.length == 0 || !(args[0] instanceof NativeArrayBuffer)) { throw typeError("not.an.arraybuffer.in.dataview"); } @@ -157,7 +157,7 @@ public class NativeDataView extends ScriptObject { * @return newly constructed DataView object */ @SpecializedConstructor - public static Object constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) { + public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) { if (!(arrBuf instanceof NativeArrayBuffer)) { throw typeError("not.an.arraybuffer.in.dataview"); } @@ -175,7 +175,7 @@ public class NativeDataView extends ScriptObject { * @return newly constructed DataView object */ @SpecializedConstructor - public static Object constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) { + public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) { if (!(arrBuf instanceof NativeArrayBuffer)) { throw typeError("not.an.arraybuffer.in.dataview"); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java index 34e27f173ac..b3661df7eb2 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java @@ -226,7 +226,7 @@ public final class NativeDate extends ScriptObject { * @return Date interpreted from the string, or NaN for illegal values */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object parse(final Object self, final Object string) { + public static double parse(final Object self, final Object string) { return parseDateString(JSType.toString(string)); } @@ -238,7 +238,7 @@ public final class NativeDate extends ScriptObject { * @return a time clip according to the ECMA specification */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 7, where = Where.CONSTRUCTOR) - public static Object UTC(final Object self, final Object... args) { + public static double UTC(final Object self, final Object... args) { final NativeDate nd = new NativeDate(0); final double[] d = convertCtorArgs(args); final double time = d == null ? Double.NaN : timeClip(makeDate(d)); @@ -253,8 +253,8 @@ public final class NativeDate extends ScriptObject { * @return a Date that points to the current moment in time */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object now(final Object self) { - return (double)System.currentTimeMillis(); + public static long now(final Object self) { + return System.currentTimeMillis(); } /** @@ -264,7 +264,7 @@ public final class NativeDate extends ScriptObject { * @return string value that represents the Date in the current time zone */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return toStringImpl(self, FORMAT_DATE_TIME); } @@ -275,7 +275,7 @@ public final class NativeDate extends ScriptObject { * @return string value with the "date" part of the Date in the current time zone */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toDateString(final Object self) { + public static String toDateString(final Object self) { return toStringImpl(self, FORMAT_DATE); } @@ -286,7 +286,7 @@ public final class NativeDate extends ScriptObject { * @return string value with "time" part of Date in the current time zone */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toTimeString(final Object self) { + public static String toTimeString(final Object self) { return toStringImpl(self, FORMAT_TIME); } @@ -297,7 +297,7 @@ public final class NativeDate extends ScriptObject { * @return string value that represents the Data in the current time zone and locale */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleString(final Object self) { + public static String toLocaleString(final Object self) { return toStringImpl(self, FORMAT_LOCAL_DATE_TIME); } @@ -308,7 +308,7 @@ public final class NativeDate extends ScriptObject { * @return string value with the "date" part of the Date in the current time zone and locale */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleDateString(final Object self) { + public static String toLocaleDateString(final Object self) { return toStringImpl(self, FORMAT_LOCAL_DATE); } @@ -319,7 +319,7 @@ public final class NativeDate extends ScriptObject { * @return string value with the "time" part of Date in the current time zone and locale */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleTimeString(final Object self) { + public static String toLocaleTimeString(final Object self) { return toStringImpl(self, FORMAT_LOCAL_TIME); } @@ -330,7 +330,7 @@ public final class NativeDate extends ScriptObject { * @return valueOf - a number which is this time value */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object valueOf(final Object self) { + public static double valueOf(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null) ? nd.getTime() : Double.NaN; } @@ -342,7 +342,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getTime(final Object self) { + public static double getTime(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null) ? nd.getTime() : Double.NaN; } @@ -365,7 +365,7 @@ public final class NativeDate extends ScriptObject { * @return UTC full year */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCFullYear(final Object self) { + public static double getUTCFullYear(final Object self) { return getUTCField(self, YEAR); } @@ -376,7 +376,7 @@ public final class NativeDate extends ScriptObject { * @return year */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getYear(final Object self) { + public static double getYear(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null && nd.isValidDate()) ? (yearFromTime(nd.getLocalTime()) - 1900) : Double.NaN; } @@ -388,7 +388,7 @@ public final class NativeDate extends ScriptObject { * @return month */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getMonth(final Object self) { + public static double getMonth(final Object self) { return getField(self, MONTH); } @@ -399,7 +399,7 @@ public final class NativeDate extends ScriptObject { * @return UTC month */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCMonth(final Object self) { + public static double getUTCMonth(final Object self) { return getUTCField(self, MONTH); } @@ -410,7 +410,7 @@ public final class NativeDate extends ScriptObject { * @return date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getDate(final Object self) { + public static double getDate(final Object self) { return getField(self, DAY); } @@ -421,7 +421,7 @@ public final class NativeDate extends ScriptObject { * @return UTC Date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCDate(final Object self) { + public static double getUTCDate(final Object self) { return getUTCField(self, DAY); } @@ -432,7 +432,7 @@ public final class NativeDate extends ScriptObject { * @return day */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getDay(final Object self) { + public static double getDay(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null && nd.isValidDate()) ? weekDay(nd.getLocalTime()) : Double.NaN; } @@ -444,7 +444,7 @@ public final class NativeDate extends ScriptObject { * @return UTC day */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCDay(final Object self) { + public static double getUTCDay(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null && nd.isValidDate()) ? weekDay(nd.getTime()) : Double.NaN; } @@ -456,7 +456,7 @@ public final class NativeDate extends ScriptObject { * @return hours */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getHours(final Object self) { + public static double getHours(final Object self) { return getField(self, HOUR); } @@ -467,7 +467,7 @@ public final class NativeDate extends ScriptObject { * @return UTC hours */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCHours(final Object self) { + public static double getUTCHours(final Object self) { return getUTCField(self, HOUR); } @@ -478,7 +478,7 @@ public final class NativeDate extends ScriptObject { * @return minutes */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getMinutes(final Object self) { + public static double getMinutes(final Object self) { return getField(self, MINUTE); } @@ -489,7 +489,7 @@ public final class NativeDate extends ScriptObject { * @return UTC minutes */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCMinutes(final Object self) { + public static double getUTCMinutes(final Object self) { return getUTCField(self, MINUTE); } @@ -500,7 +500,7 @@ public final class NativeDate extends ScriptObject { * @return seconds */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getSeconds(final Object self) { + public static double getSeconds(final Object self) { return getField(self, SECOND); } @@ -511,7 +511,7 @@ public final class NativeDate extends ScriptObject { * @return UTC seconds */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCSeconds(final Object self) { + public static double getUTCSeconds(final Object self) { return getUTCField(self, SECOND); } @@ -522,7 +522,7 @@ public final class NativeDate extends ScriptObject { * @return milliseconds */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getMilliseconds(final Object self) { + public static double getMilliseconds(final Object self) { return getField(self, MILLISECOND); } @@ -533,7 +533,7 @@ public final class NativeDate extends ScriptObject { * @return UTC milliseconds */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCMilliseconds(final Object self) { + public static double getUTCMilliseconds(final Object self) { return getUTCField(self, MILLISECOND); } @@ -544,7 +544,7 @@ public final class NativeDate extends ScriptObject { * @return time zone offset or NaN if N/A */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getTimezoneOffset(final Object self) { + public static double getTimezoneOffset(final Object self) { final NativeDate nd = getNativeDate(self); if (nd != null && nd.isValidDate()) { final long msec = (long) nd.getTime(); @@ -561,7 +561,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object setTime(final Object self, final Object time) { + public static double setTime(final Object self, final Object time) { final NativeDate nd = getNativeDate(self); final double num = timeClip(JSType.toNumber(time)); nd.setTime(num); @@ -576,7 +576,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object setMilliseconds(final Object self, final Object... args) { + public static double setMilliseconds(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MILLISECOND, args, true); return nd.getTime(); @@ -590,7 +590,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object setUTCMilliseconds(final Object self, final Object... args) { + public static double setUTCMilliseconds(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MILLISECOND, args, false); return nd.getTime(); @@ -604,7 +604,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) - public static Object setSeconds(final Object self, final Object... args) { + public static double setSeconds(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, SECOND, args, true); return nd.getTime(); @@ -618,7 +618,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) - public static Object setUTCSeconds(final Object self, final Object... args) { + public static double setUTCSeconds(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, SECOND, args, false); return nd.getTime(); @@ -632,7 +632,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) - public static Object setMinutes(final Object self, final Object... args) { + public static double setMinutes(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MINUTE, args, true); return nd.getTime(); @@ -646,7 +646,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) - public static Object setUTCMinutes(final Object self, final Object... args) { + public static double setUTCMinutes(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MINUTE, args, false); return nd.getTime(); @@ -660,7 +660,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4) - public static Object setHours(final Object self, final Object... args) { + public static double setHours(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, HOUR, args, true); return nd.getTime(); @@ -674,7 +674,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4) - public static Object setUTCHours(final Object self, final Object... args) { + public static double setUTCHours(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, HOUR, args, false); return nd.getTime(); @@ -688,7 +688,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object setDate(final Object self, final Object... args) { + public static double setDate(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, DAY, args, true); return nd.getTime(); @@ -702,7 +702,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object setUTCDate(final Object self, final Object... args) { + public static double setUTCDate(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, DAY, args, false); return nd.getTime(); @@ -716,7 +716,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) - public static Object setMonth(final Object self, final Object... args) { + public static double setMonth(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MONTH, args, true); return nd.getTime(); @@ -730,7 +730,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) - public static Object setUTCMonth(final Object self, final Object... args) { + public static double setUTCMonth(final Object self, final Object... args) { final NativeDate nd = ensureNativeDate(self); setFields(nd, MONTH, args, false); return nd.getTime(); @@ -744,7 +744,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) - public static Object setFullYear(final Object self, final Object... args) { + public static double setFullYear(final Object self, final Object... args) { final NativeDate nd = ensureNativeDate(self); if (nd.isValidDate()) { setFields(nd, YEAR, args, true); @@ -767,7 +767,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) - public static Object setUTCFullYear(final Object self, final Object... args) { + public static double setUTCFullYear(final Object self, final Object... args) { final NativeDate nd = ensureNativeDate(self); if (nd.isValidDate()) { setFields(nd, YEAR, args, false); @@ -786,7 +786,7 @@ public final class NativeDate extends ScriptObject { * @return NativeDate */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object setYear(final Object self, final Object year) { + public static double setYear(final Object self, final Object year) { final NativeDate nd = getNativeDate(self); if (isNaN(nd.getTime())) { nd.setTime(utc(0, nd.getTimeZone())); @@ -813,7 +813,7 @@ public final class NativeDate extends ScriptObject { * @return string representation of date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toUTCString(final Object self) { + public static String toUTCString(final Object self) { return toGMTStringImpl(self); } @@ -826,7 +826,7 @@ public final class NativeDate extends ScriptObject { * @return string representation of date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toGMTString(final Object self) { + public static String toGMTString(final Object self) { return toGMTStringImpl(self); } @@ -837,7 +837,7 @@ public final class NativeDate extends ScriptObject { * @return string representation of date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toISOString(final Object self) { + public static String toISOString(final Object self) { return toISOStringImpl(self); } @@ -1282,14 +1282,14 @@ public final class NativeDate extends ScriptObject { } } - private static Object getField(final Object self, final int field) { + private static double getField(final Object self, final int field) { final NativeDate nd = getNativeDate(self); - return (nd != null && nd.isValidDate()) ? valueFromTime(field, nd.getLocalTime()) : Double.NaN; + return (nd != null && nd.isValidDate()) ? (double)valueFromTime(field, nd.getLocalTime()) : Double.NaN; } - private static Object getUTCField(final Object self, final int field) { + private static double getUTCField(final Object self, final int field) { final NativeDate nd = getNativeDate(self); - return (nd != null && nd.isValidDate()) ? valueFromTime(field, nd.getTime()) : Double.NaN; + return (nd != null && nd.isValidDate()) ? (double)valueFromTime(field, nd.getTime()) : Double.NaN; } private static void setFields(final NativeDate nd, final int fieldId, final Object[] args, final boolean local) { @@ -1344,5 +1344,4 @@ public final class NativeDate extends ScriptObject { private TimeZone getTimeZone() { return timezone; } - } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java index 59b7b2fe379..5d80c37b06b 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java @@ -116,7 +116,7 @@ public final class NativeDebug extends ScriptObject { * @return true if reference identity */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object identical(final Object self, final Object obj1, final Object obj2) { + public static boolean identical(final Object self, final Object obj1, final Object obj2) { return obj1 == obj2; } @@ -144,7 +144,7 @@ public final class NativeDebug extends ScriptObject { * @return return {@link Object#equals(Object)} for objects. */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object equals(final Object self, final Object obj1, final Object obj2) { + public static boolean equals(final Object self, final Object obj1, final Object obj2) { return Objects.equals(obj1, obj2); } @@ -156,7 +156,7 @@ public final class NativeDebug extends ScriptObject { * @return Java string representation of {@code obj} */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object toJavaString(final Object self, final Object obj) { + public static String toJavaString(final Object self, final Object obj) { return Objects.toString(obj); } @@ -168,7 +168,7 @@ public final class NativeDebug extends ScriptObject { * @return string representation */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object toIdentString(final Object self, final Object obj) { + public static String toIdentString(final Object self, final Object obj) { if (obj == null) { return "null"; } @@ -185,7 +185,7 @@ public final class NativeDebug extends ScriptObject { * @return listener count */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object getListenerCount(final Object self, final Object obj) { + public static int getListenerCount(final Object self, final Object obj) { return (obj instanceof ScriptObject) ? PropertyListeners.getListenerCount((ScriptObject) obj) : 0; } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java index 3dea27288b0..1b6b809412f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java @@ -126,7 +126,7 @@ public final class NativeError extends ScriptObject { * @return NativeError instance */ @Constructor - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeError(msg); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java index 2b343ede673..586c7cffb31 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java @@ -98,7 +98,7 @@ public final class NativeEvalError extends ScriptObject { * @return new EvalError */ @Constructor(name = "EvalError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeEvalError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeEvalError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java index b96c81c96f9..a9dfb7a4c6f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java @@ -136,8 +136,8 @@ public final class NativeFloat32Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeFloat32Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeFloat32Array)constructorImpl(args, FACTORY); } NativeFloat32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -192,8 +192,8 @@ public final class NativeFloat32Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeFloat32Array subarray(final Object self, final Object begin, final Object end) { + return (NativeFloat32Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java index af9251f44e1..61b58807f8f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java @@ -146,8 +146,8 @@ public final class NativeFloat64Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeFloat64Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeFloat64Array)constructorImpl(args, FACTORY); } NativeFloat64Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -202,8 +202,8 @@ public final class NativeFloat64Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeFloat64Array subarray(final Object self, final Object begin, final Object end) { + return (NativeFloat64Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java index d092cfb6bcb..3d45cc1f48a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java @@ -71,7 +71,7 @@ public final class NativeFunction { * @return string representation of Function */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { if (!(self instanceof ScriptFunction)) { throw typeError("not.a.function", ScriptRuntime.safeToString(self)); } @@ -174,7 +174,7 @@ public final class NativeFunction { * @return function with bound arguments */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object bind(final Object self, final Object... args) { + public static ScriptFunction bind(final Object self, final Object... args) { if (!(self instanceof ScriptFunction)) { throw typeError("not.a.function", ScriptRuntime.safeToString(self)); } @@ -199,7 +199,7 @@ public final class NativeFunction { * @return source for function */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toSource(final Object self) { + public static String toSource(final Object self) { if (!(self instanceof ScriptFunction)) { throw typeError("not.a.function", ScriptRuntime.safeToString(self)); } @@ -217,7 +217,7 @@ public final class NativeFunction { * @return new NativeFunction */ @Constructor(arity = 1) - public static Object function(final boolean newObj, final Object self, final Object... args) { + public static ScriptFunction function(final boolean newObj, final Object self, final Object... args) { final StringBuilder sb = new StringBuilder(); sb.append("(function ("); @@ -253,7 +253,7 @@ public final class NativeFunction { final Global global = Global.instance(); - return Global.directEval(global, sb.toString(), global, "", global.isStrictContext()); + return (ScriptFunction)Global.directEval(global, sb.toString(), global, "", global.isStrictContext()); } private static void checkFunctionParameters(final String params) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java index e24691afd38..f6aa2054a36 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java @@ -100,8 +100,8 @@ public final class NativeInt16Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeInt16Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeInt16Array)constructorImpl(args, FACTORY); } NativeInt16Array(final NativeArrayBuffer buffer, final int byteOffset, final int byteLength) { @@ -151,8 +151,8 @@ public final class NativeInt16Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeInt16Array subarray(final Object self, final Object begin, final Object end) { + return (NativeInt16Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java index b25f84951d2..643bd81699f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java @@ -103,8 +103,8 @@ public final class NativeInt32Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeInt32Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeInt32Array)constructorImpl(args, FACTORY); } NativeInt32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -154,8 +154,8 @@ public final class NativeInt32Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeInt32Array subarray(final Object self, final Object begin, final Object end) { + return (NativeInt32Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java index e50691076b2..5822c6d5017 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java @@ -93,8 +93,8 @@ public final class NativeInt8Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeInt8Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeInt8Array)constructorImpl(args, FACTORY); } NativeInt8Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -144,8 +144,8 @@ public final class NativeInt8Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeInt8Array subarray(final Object self, final Object begin, final Object end) { + return (NativeInt8Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java index b71b4276cd8..84036a328f9 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java @@ -536,7 +536,7 @@ public final class NativeJSAdapter extends ScriptObject { * @return new NativeJSAdapter */ @Constructor - public static Object construct(final boolean isNew, final Object self, final Object... args) { + public static NativeJSAdapter construct(final boolean isNew, final Object self, final Object... args) { Object proto = UNDEFINED; Object overrides = UNDEFINED; Object adaptee; diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java index b863e24f2a5..7879bab4f4b 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java @@ -75,7 +75,7 @@ public final class NativeJava { * @see #type(Object, Object) */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isType(final Object self, final Object type) { + public static boolean isType(final Object self, final Object type) { return type instanceof StaticClass; } @@ -338,7 +338,7 @@ public final class NativeJava { * null. */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object from(final Object self, final Object objArray) { + public static NativeArray from(final Object self, final Object objArray) { if (objArray == null) { return null; } else if (objArray instanceof Collection) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java index 49be8a7c473..40ecbffca9a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java @@ -86,7 +86,7 @@ public final class NativeJavaImporter extends ScriptObject { * @return NativeJavaImporter instance */ @Constructor(arity = 1) - public static Object constructor(final boolean isNew, final Object self, final Object... args) { + public static NativeJavaImporter constructor(final boolean isNew, final Object self, final Object... args) { return new NativeJavaImporter(args); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java index 4181d205051..a95587efddb 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java @@ -185,7 +185,7 @@ public final class NativeNumber extends ScriptObject { * @return number in decimal fixed point notation */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toFixed(final Object self, final Object fractionDigits) { + public static String toFixed(final Object self, final Object fractionDigits) { final int f = JSType.toInteger(fractionDigits); if (f < 0 || f > 20) { throw rangeError("invalid.fraction.digits", "toFixed"); @@ -217,7 +217,7 @@ public final class NativeNumber extends ScriptObject { * @return number in decimal exponential notation */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toExponential(final Object self, final Object fractionDigits) { + public static String toExponential(final Object self, final Object fractionDigits) { final double x = getNumberValue(self); final boolean trimZeros = fractionDigits == UNDEFINED; final int f = trimZeros ? 16 : JSType.toInteger(fractionDigits); @@ -245,7 +245,7 @@ public final class NativeNumber extends ScriptObject { * @return number in decimal exponentiation notation or decimal fixed notation depending on {@code precision} */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toPrecision(final Object self, final Object precision) { + public static String toPrecision(final Object self, final Object precision) { final double x = getNumberValue(self); if (precision == UNDEFINED) { return JSType.toString(x); @@ -278,7 +278,7 @@ public final class NativeNumber extends ScriptObject { * @return string representation of this Number in the given radix */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self, final Object radix) { + public static String toString(final Object self, final Object radix) { if (radix != UNDEFINED) { final int intRadix = JSType.toInteger(radix); if (intRadix != 10) { @@ -299,7 +299,7 @@ public final class NativeNumber extends ScriptObject { * @return localized string for this Number */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleString(final Object self) { + public static String toLocaleString(final Object self) { return JSType.toString(getNumberValue(self)); } @@ -308,10 +308,10 @@ public final class NativeNumber extends ScriptObject { * ECMA 15.7.4.4 Number.prototype.valueOf ( ) * * @param self self reference - * @return boxed number value for this Number + * @return number value for this Number */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object valueOf(final Object self) { + public static double valueOf(final Object self) { return getNumberValue(self); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java index 26335f631e8..9cde4faf417 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java @@ -111,7 +111,7 @@ public final class NativeObject { * @return the 'obj' object */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object setIndexedPropertiesToExternalArrayData(final Object self, final Object obj, final Object buf) { + public static ScriptObject setIndexedPropertiesToExternalArrayData(final Object self, final Object obj, final Object buf) { Global.checkObject(obj); final ScriptObject sobj = (ScriptObject)obj; if (buf instanceof ByteBuffer) { @@ -203,7 +203,7 @@ public final class NativeObject { * @return array of property names */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object getOwnPropertyNames(final Object self, final Object obj) { + public static ScriptObject getOwnPropertyNames(final Object self, final Object obj) { if (obj instanceof ScriptObject) { return new NativeArray(((ScriptObject)obj).getOwnKeys(true)); } else if (obj instanceof ScriptObjectMirror) { @@ -222,7 +222,7 @@ public final class NativeObject { * @return object created */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object create(final Object self, final Object proto, final Object props) { + public static ScriptObject create(final Object self, final Object proto, final Object props) { if (proto != null) { Global.checkObject(proto); } @@ -248,10 +248,11 @@ public final class NativeObject { * @return object */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object defineProperty(final Object self, final Object obj, final Object prop, final Object attr) { + public static ScriptObject defineProperty(final Object self, final Object obj, final Object prop, final Object attr) { Global.checkObject(obj); - ((ScriptObject)obj).defineOwnProperty(JSType.toString(prop), attr, true); - return obj; + final ScriptObject sobj = (ScriptObject)obj; + sobj.defineOwnProperty(JSType.toString(prop), attr, true); + return sobj; } /** @@ -263,7 +264,7 @@ public final class NativeObject { * @return object */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object defineProperties(final Object self, final Object obj, final Object props) { + public static ScriptObject defineProperties(final Object self, final Object obj, final Object props) { Global.checkObject(obj); final ScriptObject sobj = (ScriptObject)obj; @@ -342,7 +343,7 @@ public final class NativeObject { * @return true if sealed, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isSealed(final Object self, final Object obj) { + public static boolean isSealed(final Object self, final Object obj) { if (obj instanceof ScriptObject) { return ((ScriptObject)obj).isSealed(); } else if (obj instanceof ScriptObjectMirror) { @@ -360,7 +361,7 @@ public final class NativeObject { * @return true if object is frozen, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isFrozen(final Object self, final Object obj) { + public static boolean isFrozen(final Object self, final Object obj) { if (obj instanceof ScriptObject) { return ((ScriptObject)obj).isFrozen(); } else if (obj instanceof ScriptObjectMirror) { @@ -378,7 +379,7 @@ public final class NativeObject { * @return true if object is extensible, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isExtensible(final Object self, final Object obj) { + public static boolean isExtensible(final Object self, final Object obj) { if (obj instanceof ScriptObject) { return ((ScriptObject)obj).isExtensible(); } else if (obj instanceof ScriptObjectMirror) { @@ -396,7 +397,7 @@ public final class NativeObject { * @return array of keys in object */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object keys(final Object self, final Object obj) { + public static ScriptObject keys(final Object self, final Object obj) { if (obj instanceof ScriptObject) { final ScriptObject sobj = (ScriptObject)obj; return new NativeArray(sobj.getOwnKeys(false)); @@ -453,7 +454,7 @@ public final class NativeObject { * @return ToString of object */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return ScriptRuntime.builtinObjectToString(self); } @@ -506,7 +507,7 @@ public final class NativeObject { * @return true if property exists in object */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object hasOwnProperty(final Object self, final Object v) { + public static boolean hasOwnProperty(final Object self, final Object v) { // Convert ScriptObjects to primitive with String.class hint // but no need to convert other primitives to string. final Object key = JSType.toPrimitive(v, String.class); @@ -523,7 +524,7 @@ public final class NativeObject { * @return true if object is prototype of v */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object isPrototypeOf(final Object self, final Object v) { + public static boolean isPrototypeOf(final Object self, final Object v) { if (!(v instanceof ScriptObject)) { return false; } @@ -549,7 +550,7 @@ public final class NativeObject { * @return true if property is enumerable */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object propertyIsEnumerable(final Object self, final Object v) { + public static boolean propertyIsEnumerable(final Object self, final Object v) { final String str = JSType.toString(v); final Object obj = Global.toObject(self); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java index 4b2bebcfd2d..ff3ac7b77c0 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java @@ -98,7 +98,7 @@ public final class NativeRangeError extends ScriptObject { * @return new RangeError */ @Constructor(name = "RangeError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeRangeError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeRangeError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java index 504f16ecd6c..741901796b0 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java @@ -98,7 +98,7 @@ public final class NativeReferenceError extends ScriptObject { * @return new ReferenceError */ @Constructor(name = "ReferenceError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeReferenceError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeReferenceError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java index 04b828bfc21..89a9a828455 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java @@ -122,7 +122,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @Constructor(arity = 2) - public static Object constructor(final boolean isNew, final Object self, final Object... args) { + public static NativeRegExp constructor(final boolean isNew, final Object self, final Object... args) { if (args.length > 1) { return newRegExp(args[0], args[1]); } else if (args.length > 0) { @@ -142,7 +142,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @SpecializedConstructor - public static Object constructor(final boolean isNew, final Object self) { + public static NativeRegExp constructor(final boolean isNew, final Object self) { return new NativeRegExp("", ""); } @@ -157,7 +157,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @SpecializedConstructor - public static Object constructor(final boolean isNew, final Object self, final Object pattern) { + public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern) { return newRegExp(pattern, UNDEFINED); } @@ -173,7 +173,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @SpecializedConstructor - public static Object constructor(final boolean isNew, final Object self, final Object pattern, final Object flags) { + public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern, final Object flags) { return newRegExp(pattern, flags); } @@ -283,7 +283,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object compile(final Object self, final Object pattern, final Object flags) { + public static ScriptObject compile(final Object self, final Object pattern, final Object flags) { final NativeRegExp regExp = checkRegExp(self); final NativeRegExp compiled = newRegExp(pattern, flags); // copy over regexp to 'self' @@ -302,7 +302,7 @@ public final class NativeRegExp extends ScriptObject { * @return array containing the matches or {@code null} if no match */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object exec(final Object self, final Object string) { + public static ScriptObject exec(final Object self, final Object string) { return checkRegExp(self).exec(JSType.toString(string)); } @@ -314,7 +314,7 @@ public final class NativeRegExp extends ScriptObject { * @return true if matches found, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object test(final Object self, final Object string) { + public static boolean test(final Object self, final Object string) { return checkRegExp(self).test(JSType.toString(string)); } @@ -325,7 +325,7 @@ public final class NativeRegExp extends ScriptObject { * @return string version of regexp */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return checkRegExp(self).toString(); } @@ -618,7 +618,7 @@ public final class NativeRegExp extends ScriptObject { * @param string String to match. * @return NativeArray of matches, string or null. */ - public Object exec(final String string) { + public NativeRegExpExecResult exec(final String string) { final RegExpResult match = execInner(string); if (match == null) { @@ -635,7 +635,7 @@ public final class NativeRegExp extends ScriptObject { * @param string String to match. * @return True if a match is found. */ - public Object test(final String string) { + public boolean test(final String string) { return execInner(string) != null; } @@ -649,7 +649,7 @@ public final class NativeRegExp extends ScriptObject { * @param replacement Replacement string. * @return String with substitutions. */ - Object replace(final String string, final String replacement, final ScriptFunction function) { + String replace(final String string, final String replacement, final ScriptFunction function) { final RegExpMatcher matcher = regexp.match(string); if (matcher == null) { @@ -804,7 +804,7 @@ public final class NativeRegExp extends ScriptObject { * @param limit Split limit. * @return Array of substrings. */ - Object split(final String string, final long limit) { + NativeArray split(final String string, final long limit) { if (limit == 0L) { return new NativeArray(); } @@ -867,7 +867,7 @@ public final class NativeRegExp extends ScriptObject { * @param string String to match. * @return Index of match. */ - Object search(final String string) { + int search(final String string) { final RegExpResult match = execInner(string); if (match == null) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java index c75b2b00362..51edf75a44f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java @@ -425,7 +425,7 @@ public final class NativeString extends ScriptObject { * @return string with arguments translated to charcodes */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1, where = Where.CONSTRUCTOR) - public static Object fromCharCode(final Object self, final Object... args) { + public static String fromCharCode(final Object self, final Object... args) { final char[] buf = new char[args.length]; int index = 0; for (final Object arg : args) { @@ -441,7 +441,7 @@ public final class NativeString extends ScriptObject { * @return string with one charcode */ @SpecializedFunction - public static Object fromCharCode(final Object self, final Object value) { + public static String fromCharCode(final Object self, final Object value) { try { return "" + (char)JSType.toUint16(((Number)value).doubleValue()); } catch (final ClassCastException e) { @@ -456,7 +456,7 @@ public final class NativeString extends ScriptObject { * @return string with one charcode */ @SpecializedFunction - public static Object fromCharCode(final Object self, final int value) { + public static String fromCharCode(final Object self, final int value) { return "" + (char)(value & 0xffff); } @@ -467,7 +467,7 @@ public final class NativeString extends ScriptObject { * @return string with one charcode */ @SpecializedFunction - public static Object fromCharCode(final Object self, final long value) { + public static String fromCharCode(final Object self, final long value) { return "" + (char)((int)value & 0xffff); } @@ -478,7 +478,7 @@ public final class NativeString extends ScriptObject { * @return string with one charcode */ @SpecializedFunction - public static Object fromCharCode(final Object self, final double value) { + public static String fromCharCode(final Object self, final double value) { return "" + (char)JSType.toUint16(value); } @@ -488,7 +488,7 @@ public final class NativeString extends ScriptObject { * @return self as string */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return getString(self); } @@ -498,7 +498,7 @@ public final class NativeString extends ScriptObject { * @return self as string */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object valueOf(final Object self) { + public static String valueOf(final Object self) { return getString(self); } @@ -509,7 +509,7 @@ public final class NativeString extends ScriptObject { * @return string representing the char at the given position */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object charAt(final Object self, final Object pos) { + public static String charAt(final Object self, final Object pos) { return charAtImpl(checkObjectToString(self), JSType.toInteger(pos)); } @@ -546,7 +546,7 @@ public final class NativeString extends ScriptObject { * @return number representing charcode at position */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object charCodeAt(final Object self, final Object pos) { + public static double charCodeAt(final Object self, final Object pos) { return charCodeAtImpl(checkObjectToString(self), JSType.toInteger(pos)); } @@ -601,7 +601,7 @@ public final class NativeString extends ScriptObject { * @return position of first match or -1 */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object indexOf(final Object self, final Object search, final Object pos) { + public static int indexOf(final Object self, final Object search, final Object pos) { final String str = checkObjectToString(self); return str.indexOf(JSType.toString(search), JSType.toInteger(pos)); } @@ -649,7 +649,7 @@ public final class NativeString extends ScriptObject { * @return last position of match or -1 */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object lastIndexOf(final Object self, final Object search, final Object pos) { + public static int lastIndexOf(final Object self, final Object search, final Object pos) { final String str = checkObjectToString(self); final String searchStr = JSType.toString(search); @@ -680,7 +680,7 @@ public final class NativeString extends ScriptObject { * @return result of locale sensitive comparison operation between {@code self} and {@code that} */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object localeCompare(final Object self, final Object that) { + public static double localeCompare(final Object self, final Object that) { final String str = checkObjectToString(self); final Collator collator = Collator.getInstance(Global.getEnv()._locale); @@ -698,7 +698,7 @@ public final class NativeString extends ScriptObject { * @return array of regexp matches */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object match(final Object self, final Object regexp) { + public static ScriptObject match(final Object self, final Object regexp) { final String str = checkObjectToString(self); @@ -745,7 +745,7 @@ public final class NativeString extends ScriptObject { * @return string after replacement */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object replace(final Object self, final Object string, final Object replacement) { + public static String replace(final Object self, final Object string, final Object replacement) { final String str = checkObjectToString(self); @@ -771,7 +771,7 @@ public final class NativeString extends ScriptObject { * @return offset where match occurred */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object search(final Object self, final Object string) { + public static int search(final Object self, final Object string) { final String str = checkObjectToString(self); final NativeRegExp nativeRegExp = Global.toRegExp(string == UNDEFINED ? "" : string); @@ -788,7 +788,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object slice(final Object self, final Object start, final Object end) { + public static String slice(final Object self, final Object start, final Object end) { final String str = checkObjectToString(self); if (end == UNDEFINED) { @@ -805,7 +805,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @SpecializedFunction - public static Object slice(final Object self, final int start) { + public static String slice(final Object self, final int start) { final String str = checkObjectToString(self); final int from = (start < 0) ? Math.max(str.length() + start, 0) : Math.min(start, str.length()); @@ -820,7 +820,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @SpecializedFunction - public static Object slice(final Object self, final double start) { + public static String slice(final Object self, final double start) { return slice(self, (int)start); } @@ -833,7 +833,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @SpecializedFunction - public static Object slice(final Object self, final int start, final int end) { + public static String slice(final Object self, final int start, final int end) { final String str = checkObjectToString(self); final int len = str.length(); @@ -853,7 +853,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @SpecializedFunction - public static Object slice(final Object self, final double start, final double end) { + public static String slice(final Object self, final double start, final double end) { return slice(self, (int)start, (int)end); } @@ -866,7 +866,7 @@ public final class NativeString extends ScriptObject { * @return array object in which splits have been placed */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object split(final Object self, final Object separator, final Object limit) { + public static ScriptObject split(final Object self, final Object separator, final Object limit) { final String str = checkObjectToString(self); final long lim = (limit == UNDEFINED) ? JSType.MAX_UINT : JSType.toUint32(limit); @@ -882,7 +882,7 @@ public final class NativeString extends ScriptObject { return splitString(str, JSType.toString(separator), lim); } - private static Object splitString(String str, String separator, long limit) { + private static ScriptObject splitString(String str, String separator, long limit) { if (separator.isEmpty()) { final int length = (int) Math.min(str.length(), limit); final Object[] array = new Object[length]; @@ -923,7 +923,7 @@ public final class NativeString extends ScriptObject { * @return substring given start and length of section */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object substr(final Object self, final Object start, final Object length) { + public static String substr(final Object self, final Object start, final Object length) { final String str = JSType.toString(self); final int strLength = str.length(); @@ -946,7 +946,7 @@ public final class NativeString extends ScriptObject { * @return substring given start and end indexes */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object substring(final Object self, final Object start, final Object end) { + public static String substring(final Object self, final Object start, final Object end) { final String str = checkObjectToString(self); if (end == UNDEFINED) { @@ -1026,7 +1026,7 @@ public final class NativeString extends ScriptObject { * @return string to lower case */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLowerCase(final Object self) { + public static String toLowerCase(final Object self) { return checkObjectToString(self).toLowerCase(Locale.ROOT); } @@ -1036,7 +1036,7 @@ public final class NativeString extends ScriptObject { * @return string to locale sensitive lower case */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleLowerCase(final Object self) { + public static String toLocaleLowerCase(final Object self) { return checkObjectToString(self).toLowerCase(Global.getEnv()._locale); } @@ -1046,7 +1046,7 @@ public final class NativeString extends ScriptObject { * @return string to upper case */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toUpperCase(final Object self) { + public static String toUpperCase(final Object self) { return checkObjectToString(self).toUpperCase(Locale.ROOT); } @@ -1056,7 +1056,7 @@ public final class NativeString extends ScriptObject { * @return string to locale sensitive upper case */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleUpperCase(final Object self) { + public static String toLocaleUpperCase(final Object self) { return checkObjectToString(self).toUpperCase(Global.getEnv()._locale); } @@ -1066,7 +1066,7 @@ public final class NativeString extends ScriptObject { * @return string trimmed from whitespace */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object trim(final Object self) { + public static String trim(final Object self) { final String str = checkObjectToString(self); int start = 0; @@ -1088,7 +1088,7 @@ public final class NativeString extends ScriptObject { * @return string trimmed left from whitespace */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object trimLeft(final Object self) { + public static String trimLeft(final Object self) { final String str = checkObjectToString(self); int start = 0; @@ -1107,7 +1107,7 @@ public final class NativeString extends ScriptObject { * @return string trimmed right from whitespace */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object trimRight(final Object self) { + public static String trimRight(final Object self) { final String str = checkObjectToString(self); int start = 0; @@ -1120,7 +1120,7 @@ public final class NativeString extends ScriptObject { return str.substring(start, end + 1); } - private static Object newObj(final Object self, final CharSequence str) { + private static ScriptObject newObj(final Object self, final CharSequence str) { return new NativeString(str); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java index 6515f3cc2e6..db7debb0151 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java @@ -94,7 +94,7 @@ public final class NativeSyntaxError extends ScriptObject { * @return new SyntaxError */ @Constructor(name = "SyntaxError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeSyntaxError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeSyntaxError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java index f799b1767d0..6e5a4934f2c 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java @@ -94,7 +94,7 @@ public final class NativeTypeError extends ScriptObject { * @return new TypeError */ @Constructor(name = "TypeError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeTypeError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeTypeError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java index fd59bc8a209..cf5fdaa041c 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java @@ -93,7 +93,7 @@ public final class NativeURIError extends ScriptObject { * @return new URIError */ @Constructor(name = "URIError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeURIError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeURIError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java index ee91aef3b35..8aa3d628308 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java @@ -99,8 +99,8 @@ public final class NativeUint16Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeUint16Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeUint16Array)constructorImpl(args, FACTORY); } NativeUint16Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -150,8 +150,8 @@ public final class NativeUint16Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeUint16Array subarray(final Object self, final Object begin, final Object end) { + return (NativeUint16Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java index 58909dbaf52..738122466d8 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java @@ -118,8 +118,8 @@ public final class NativeUint32Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeUint32Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeUint32Array)constructorImpl(args, FACTORY); } NativeUint32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -169,8 +169,8 @@ public final class NativeUint32Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeUint32Array subarray(final Object self, final Object begin, final Object end) { + return (NativeUint32Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java index 0db1bee6f8d..1f30456350a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java @@ -92,8 +92,8 @@ public final class NativeUint8Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeUint8Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeUint8Array)constructorImpl(args, FACTORY); } NativeUint8Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -143,8 +143,8 @@ public final class NativeUint8Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeUint8Array subarray(final Object self, final Object begin, final Object end) { + return (NativeUint8Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java index f0db743cb21..d757ee3ab1d 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java @@ -109,8 +109,8 @@ public final class NativeUint8ClampedArray extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeUint8ClampedArray constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeUint8ClampedArray)constructorImpl(args, FACTORY); } NativeUint8ClampedArray(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -160,8 +160,8 @@ public final class NativeUint8ClampedArray extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeUint8ClampedArray subarray(final Object self, final Object begin, final Object end) { + return (NativeUint8ClampedArray)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java index f6b962a93e1..08ff725a175 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java @@ -1700,9 +1700,11 @@ loop: // ECMA 12.4.1 strict mode restrictions verifyStrictIdent(exception, "catch argument"); - // Check for conditional catch. + // Nashorn extension: catch clause can have optional + // condition. So, a single try can have more than one + // catch clause each with it's own condition. final Expression ifExpression; - if (type == IF) { + if (!env._no_syntax_extensions && type == IF) { next(); // Get the exception condition. ifExpression = expression(); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java index d22a956760b..e8ff153da5e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -39,6 +39,9 @@ import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getNumberOfAcces import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.lookup.MethodHandleFactory.stripName; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -51,11 +54,12 @@ import jdk.nashorn.internal.lookup.MethodHandleFactory; * An AccessorProperty is the most generic property type. An AccessorProperty is * represented as fields in a ScriptObject class. */ -public final class AccessorProperty extends Property { +public final class AccessorProperty extends Property implements Serializable { private static final MethodHandles.Lookup lookup = MethodHandles.lookup(); private static final MethodHandle REPLACE_MAP = findOwnMH("replaceMap", Object.class, Object.class, PropertyMap.class, String.class, Class.class, Class.class); private static final int NOOF_TYPES = getNumberOfAccessorTypes(); + private static final long serialVersionUID = 3371720170182154920L; /** * Properties in different maps for the same structure class will share their field getters and setters. This could @@ -71,7 +75,7 @@ public final class AccessorProperty extends Property { }; /** Property getter cache */ - private MethodHandle[] getters = new MethodHandle[NOOF_TYPES]; + private transient MethodHandle[] getters = new MethodHandle[NOOF_TYPES]; private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES]; private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES]; @@ -122,16 +126,16 @@ public final class AccessorProperty extends Property { } /** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */ - private MethodHandle primitiveGetter; + private transient MethodHandle primitiveGetter; /** Seed setter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */ - private MethodHandle primitiveSetter; + private transient MethodHandle primitiveSetter; /** Seed getter for the Object version of this field */ - private MethodHandle objectGetter; + private transient MethodHandle objectGetter; /** Seed setter for the Object version of this field */ - private MethodHandle objectSetter; + private transient MethodHandle objectSetter; /** * Current type of this object, in object only mode, this is an Object.class. In dual-fields mode @@ -243,6 +247,12 @@ public final class AccessorProperty extends Property { public AccessorProperty(final String key, final int flags, final Class structure, final int slot) { super(key, flags, slot); + initGetterSetter(structure); + } + + private void initGetterSetter(final Class structure) { + final int slot = getSlot(); + final String key = getKey(); /* * primitiveGetter and primitiveSetter are only used in dual fields mode. Setting them to null also * works in dual field mode, it only means that the property never has a primitive @@ -305,6 +315,12 @@ public final class AccessorProperty extends Property { setCurrentType(property.getCurrentType()); } + private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException { + s.defaultReadObject(); + // Restore getters array + getters = new MethodHandle[NOOF_TYPES]; + } + private static MethodHandle bindTo(final MethodHandle mh, final Object receiver) { if (mh == null) { return null; @@ -363,6 +379,16 @@ public final class AccessorProperty extends Property { return objectSetter; } + @Override + void initMethodHandles(final Class structure) { + if (!ScriptObject.class.isAssignableFrom(structure) || !StructureLoader.isStructureClass(structure.getName())) { + throw new IllegalArgumentException(); + } + if (!isSpill()) { + initGetterSetter(structure); + } + } + @Override public MethodHandle getGetter(final Class type) { final int i = getAccessorTypeIndex(type); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java index 28c9630ea54..579b6f3efbf 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java @@ -25,6 +25,7 @@ package jdk.nashorn.internal.runtime; +import java.util.Map; import jdk.nashorn.internal.codegen.ClassEmitter; /** @@ -52,7 +53,7 @@ public interface CodeInstaller { * @param bytecode bytecode * @return the installed class */ - public Class install(final String className, final byte[] bytecode); + public Class install(final String className, final byte[] bytecode, final Source source, final Object[] constants); /** * Verify generated bytecode before emission. This is called back from the @@ -74,4 +75,13 @@ public interface CodeInstaller { * @return unique eval id */ public long getUniqueEvalId(); + + /** + * Store a compiled script for later reuse + * @param source the script source + * @param mainClassName the main class name + * @param classBytes map of class names to class bytes + * @param constants constants array + */ + public void storeCompiledScript(Source source, String mainClassName, Map classBytes, Object[] constants); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java b/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java new file mode 100644 index 00000000000..8f5959993cf --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java @@ -0,0 +1,179 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.runtime; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Base64; +import java.util.Map; + +/** + * A code cache for persistent caching of compiled scripts. + */ +final class CodeStore { + + private final File dir; + private final int minSize; + + // Message digest to file name encoder + private final static Base64.Encoder BASE64 = Base64.getUrlEncoder().withoutPadding(); + + // Default minimum size for storing a compiled script class + private final static int DEFAULT_MIN_SIZE = 1000; + + /** + * Constructor + * @param path directory to store code in + * @throws IOException + */ + public CodeStore(final String path) throws IOException { + this(path, DEFAULT_MIN_SIZE); + } + + /** + * Constructor + * @param path directory to store code in + * @param minSize minimum file size for caching scripts + * @throws IOException + */ + public CodeStore(final String path, final int minSize) throws IOException { + this.dir = checkDirectory(path); + this.minSize = minSize; + } + + private static File checkDirectory(final String path) throws IOException { + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public File run() throws IOException { + final File dir = new File(path).getAbsoluteFile(); + if (!dir.exists() && !dir.mkdirs()) { + throw new IOException("Could not create directory: " + dir); + } else if (!dir.isDirectory()) { + throw new IOException("Not a directory: " + dir); + } else if (!dir.canRead() || !dir.canWrite()) { + throw new IOException("Directory not readable or writable: " + dir); + } + return dir; + } + }); + } catch (PrivilegedActionException e) { + throw (IOException) e.getException(); + } + } + + /** + * Return a compiled script from the cache, or null if it isn't found. + * + * @param source the source + * @return the compiled script or null + * @throws IOException + * @throws ClassNotFoundException + */ + public CompiledScript getScript(final Source source) throws IOException, ClassNotFoundException { + if (source.getLength() < minSize) { + return null; + } + + final String digest = BASE64.encodeToString(source.getDigest()); + final File file = new File(dir, digest); + + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public CompiledScript run() throws IOException, ClassNotFoundException { + if (!file.exists()) { + return null; + } + try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) { + CompiledScript compiledScript = (CompiledScript) in.readObject(); + compiledScript.setSource(source); + return compiledScript; + } + } + }); + } catch (PrivilegedActionException e) { + final Exception ex = e.getException(); + if (ex instanceof IOException) { + throw (IOException) ex; + } else if (ex instanceof ClassNotFoundException) { + throw (ClassNotFoundException) ex; + } + throw (new RuntimeException(ex)); + } + } + + /** + * Store a compiled script in the cache. + * + * @param source the source + * @param mainClassName the main class name + * @param classBytes a map of class bytes + * @param constants the constants array + * @throws IOException + */ + public void putScript(final Source source, final String mainClassName, final Map classBytes, final Object[] constants) + throws IOException { + if (source.getLength() < minSize) { + return; + } + for (final Object constant : constants) { + // Make sure all constant data is serializable + if (! (constant instanceof Serializable)) { + return; + } + } + + final String digest = BASE64.encodeToString(source.getDigest()); + final File file = new File(dir, digest); + final CompiledScript script = new CompiledScript(source, mainClassName, classBytes, constants); + + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Void run() throws IOException { + try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { + out.writeObject(script); + } + return null; + } + }); + } catch (PrivilegedActionException e) { + throw (IOException) e.getException(); + } + } +} + diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CompiledScript.java b/nashorn/src/jdk/nashorn/internal/runtime/CompiledScript.java new file mode 100644 index 00000000000..6bb8e9a0f37 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/CompiledScript.java @@ -0,0 +1,127 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.runtime; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Map; + +/** + * Class representing a compiled script. + */ +final class CompiledScript implements Serializable { + + /** Main class name. */ + private final String mainClassName; + + /** Map of class names to class bytes. */ + private final Map classBytes; + + /** Constants array. */ + private final Object[] constants; + + /** The source */ + private transient Source source; + + private static final long serialVersionUID = 2958227232195298340L; + + /** + * Constructor. + * + * @param mainClassName main class name + * @param classBytes map of class names to class bytes + * @param constants constants array + */ + CompiledScript(final Source source, final String mainClassName, final Map classBytes, final Object[] constants) { + this.source = source; + this.mainClassName = mainClassName; + this.classBytes = classBytes; + this.constants = constants; + } + + /** + * Returns the main class name. + * @return the main class name + */ + public String getMainClassName() { + return mainClassName; + } + + /** + * Returns a map of class names to class bytes. + * @return map of class bytes + */ + public Map getClassBytes() { + return classBytes; + } + + /** + * Returns the constants array. + * @return constants array + */ + public Object[] getConstants() { + return constants; + } + + /** + * Returns the source of this cached script. + * @return the source + */ + public Source getSource() { + return source; + } + + /** + * Sets the source of this cached script. + * @param source the source + */ + void setSource(final Source source) { + this.source = source; + } + + @Override + public int hashCode() { + int hash = mainClassName.hashCode(); + hash = 31 * hash + classBytes.hashCode(); + hash = 31 * hash + Arrays.hashCode(constants); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof CompiledScript)) { + return false; + } + + final CompiledScript cs = (CompiledScript) obj; + return mainClassName.equals(cs.mainClassName) + && classBytes.equals(cs.classBytes) + && Arrays.equals(constants, cs.constants); + } +} diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index f3ec08757d1..19c5c5c1036 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -25,7 +25,9 @@ package jdk.nashorn.internal.runtime; +import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT; +import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; @@ -38,6 +40,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; +import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; @@ -47,7 +50,10 @@ import java.security.CodeSigner; import java.security.CodeSource; import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; @@ -133,8 +139,32 @@ public final class Context { } @Override - public Class install(final String className, final byte[] bytecode) { - return loader.installClass(className, bytecode, codeSource); + public Class install(final String className, final byte[] bytecode, final Source source, final Object[] constants) { + Compiler.LOG.fine("Installing class ", className); + + final String binaryName = Compiler.binaryName(className); + final Class clazz = loader.installClass(binaryName, bytecode, codeSource); + + try { + // Need doPrivileged because these fields are private + AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Void run() throws Exception { + //use reflection to write source and constants table to installed classes + final Field sourceField = clazz.getDeclaredField(SOURCE.symbolName()); + final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName()); + sourceField.setAccessible(true); + constantsField.setAccessible(true); + sourceField.set(null, source); + constantsField.set(null, constants); + return null; + } + }); + } catch (final PrivilegedActionException e) { + throw new RuntimeException(e); + } + + return clazz; } @Override @@ -151,6 +181,18 @@ public final class Context { public long getUniqueEvalId() { return context.getUniqueEvalId(); } + + @Override + public void storeCompiledScript(final Source source, final String mainClassName, + final Map classBytes, final Object[] constants) { + if (context.codeStore != null) { + try { + context.codeStore.putScript(source, mainClassName, classBytes, constants); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + } } /** Is Context global debug mode enabled ? */ @@ -158,9 +200,12 @@ public final class Context { private static final ThreadLocal currentGlobal = new ThreadLocal<>(); - // class cache + // in-memory cache for loaded classes private ClassCache classCache; + // persistent code store + private CodeStore codeStore; + /** * Get the current global scope * @return the current global scope @@ -368,6 +413,19 @@ public final class Context { classCache = new ClassCache(cacheSize); } + if (env._persistent_cache) { + if (env._lazy_compilation || env._specialize_calls != null) { + getErr().println("Can not use persistent class caching with lazy compilation or call specialization."); + } else { + try { + final String cacheDir = Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"); + codeStore = new CodeStore(cacheDir); + } catch (IOException e) { + throw new RuntimeException("Error initializing code cache", e); + } + } + } + // print version info if asked. if (env._version) { getErr().println("nashorn " + Version.version()); @@ -932,17 +990,32 @@ public final class Context { return script; } - final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse(); - if (errors.hasErrors()) { - return null; + CompiledScript compiledScript = null; + FunctionNode functionNode = null; + + if (!env._parse_only && codeStore != null) { + try { + compiledScript = codeStore.getScript(source); + } catch (IOException | ClassNotFoundException e) { + Compiler.LOG.warning("Error loading ", source, " from cache: ", e); + // Fall back to normal compilation + } } - if (env._print_ast) { - getErr().println(new ASTWriter(functionNode)); - } + if (compiledScript == null) { + functionNode = new Parser(env, source, errMan, strict).parse(); - if (env._print_parse) { - getErr().println(new PrintVisitor(functionNode)); + if (errors.hasErrors()) { + return null; + } + + if (env._print_ast) { + getErr().println(new ASTWriter(functionNode)); + } + + if (env._print_parse) { + getErr().println(new PrintVisitor(functionNode)); + } } if (env._parse_only) { @@ -954,12 +1027,15 @@ public final class Context { final CodeSource cs = new CodeSource(url, (CodeSigner[])null); final CodeInstaller installer = new ContextCodeInstaller(this, loader, cs); - final Compiler compiler = new Compiler(installer, strict); + if (functionNode != null) { + final Compiler compiler = new Compiler(installer, strict); + final FunctionNode newFunctionNode = compiler.compile(functionNode); + script = compiler.install(newFunctionNode); + } else { + script = install(compiledScript, installer); + } - final FunctionNode newFunctionNode = compiler.compile(functionNode); - script = compiler.install(newFunctionNode); cacheClass(source, script); - return script; } @@ -981,6 +1057,42 @@ public final class Context { return uniqueScriptId.getAndIncrement(); } + + /** + * Install a previously compiled class from the code cache. + * + * @param compiledScript cached script containing class bytes and constants + * @return main script class + */ + private Class install(final CompiledScript compiledScript, final CodeInstaller installer) { + + final Map> installedClasses = new HashMap<>(); + final Source source = compiledScript.getSource(); + final Object[] constants = compiledScript.getConstants(); + final String rootClassName = compiledScript.getMainClassName(); + final byte[] rootByteCode = compiledScript.getClassBytes().get(rootClassName); + final Class rootClass = installer.install(rootClassName, rootByteCode, source, constants); + + installedClasses.put(rootClassName, rootClass); + + for (final Map.Entry entry : compiledScript.getClassBytes().entrySet()) { + final String className = entry.getKey(); + if (className.equals(rootClassName)) { + continue; + } + final byte[] code = entry.getValue(); + + installedClasses.put(className, installer.install(className, code, source, constants)); + } + for (Object constant : constants) { + if (constant instanceof RecompilableScriptFunctionData) { + ((RecompilableScriptFunctionData) constant).setCodeAndSource(installedClasses, source); + } + } + + return rootClass; + } + /** * Cache for compiled script classes. */ diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java index 64863184759..f12945fee52 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java @@ -101,7 +101,6 @@ public final class JSONFunctions { // apply 'reviver' function if available private static Object applyReviver(final Global global, final Object unfiltered, final Object reviver) { if (reviver instanceof ScriptFunction) { - assert global instanceof Global; final ScriptObject root = global.newObject(); root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered); return walk(root, "", (ScriptFunction)reviver); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Property.java b/nashorn/src/jdk/nashorn/internal/runtime/Property.java index 885fa712a13..b3f1e0af48d 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java @@ -29,6 +29,7 @@ import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE; import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE; import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.util.Objects; import jdk.nashorn.internal.codegen.ObjectClassGenerator; @@ -43,7 +44,7 @@ import jdk.nashorn.internal.codegen.types.Type; * @see AccessorProperty * @see UserAccessorProperty */ -public abstract class Property { +public abstract class Property implements Serializable { /* * ECMA 8.6.1 Property Attributes * @@ -100,6 +101,8 @@ public abstract class Property { /** Property field number or spill slot. */ private final int slot; + private static final long serialVersionUID = 2099814273074501176L; + /** * Constructor * @@ -357,6 +360,13 @@ public abstract class Property { */ public abstract MethodHandle getGetter(final Class type); + /** + * Hook to initialize method handles after deserialization. + * + * @param structure the structure class + */ + abstract void initMethodHandles(final Class structure); + /** * Get the key for this property. This key is an ordinary string. The "name". * @return key for property diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java index 77bcc83fea3..e2e07fdf2fc 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -29,6 +29,10 @@ import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_HASHMAP; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.lang.invoke.SwitchPoint; import java.lang.ref.SoftReference; import java.util.Arrays; @@ -37,6 +41,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.WeakHashMap; +import jdk.nashorn.internal.scripts.JO; /** * Map of object properties. The PropertyMap is the "template" for JavaScript object @@ -47,7 +52,7 @@ import java.util.WeakHashMap; * All property maps are immutable. If a property is added, modified or removed, the mutator * will return a new map. */ -public final class PropertyMap implements Iterable { +public final class PropertyMap implements Iterable, Serializable { /** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */ public static final int NOT_EXTENSIBLE = 0b0000_0001; /** Does this map contain valid array keys? */ @@ -57,7 +62,7 @@ public final class PropertyMap implements Iterable { private int flags; /** Map of properties. */ - private final PropertyHashMap properties; + private transient PropertyHashMap properties; /** Number of fields in use. */ private int fieldCount; @@ -68,17 +73,22 @@ public final class PropertyMap implements Iterable { /** Length of spill in use. */ private int spillLength; + /** Structure class name */ + private String className; + /** {@link SwitchPoint}s for gets on inherited properties. */ - private HashMap protoGetSwitches; + private transient HashMap protoGetSwitches; /** History of maps, used to limit map duplication. */ - private WeakHashMap> history; + private transient WeakHashMap> history; /** History of prototypes, used to limit map duplication. */ - private WeakHashMap> protoHistory; + private transient WeakHashMap> protoHistory; /** property listeners */ - private PropertyListeners listeners; + private transient PropertyListeners listeners; + + private static final long serialVersionUID = -7041836752008732533L; /** * Constructor. @@ -89,8 +99,10 @@ public final class PropertyMap implements Iterable { * @param spillLength Number of spill slots used. * @param containsArrayKeys True if properties contain numeric keys */ - private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) { + private PropertyMap(final PropertyHashMap properties, final String className, final int fieldCount, + final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) { this.properties = properties; + this.className = className; this.fieldCount = fieldCount; this.fieldMaximum = fieldMaximum; this.spillLength = spillLength; @@ -145,7 +157,25 @@ public final class PropertyMap implements Iterable { if (Context.DEBUG) { duplicatedCount++; } - return new PropertyMap(this.properties, 0, 0, 0, containsArrayKeys()); + return new PropertyMap(this.properties, this.className, 0, 0, 0, containsArrayKeys()); + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(properties.getProperties()); + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + + final Property[] props = (Property[]) in.readObject(); + this.properties = EMPTY_HASHMAP.immutableAdd(props); + + assert className != null; + final Class structure = Context.forStructureClass(className); + for (Property prop : props) { + prop.initMethodHandles(structure); + } } /** @@ -160,9 +190,9 @@ public final class PropertyMap implements Iterable { * @param spillLength Number of used spill slots. * @return New {@link PropertyMap}. */ - public static PropertyMap newMap(final Collection properties, final int fieldCount, final int fieldMaximum, final int spillLength) { + public static PropertyMap newMap(final Collection properties, final String className, final int fieldCount, final int fieldMaximum, final int spillLength) { PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties); - return new PropertyMap(newProperties, fieldCount, fieldMaximum, spillLength, false); + return new PropertyMap(newProperties, className, fieldCount, fieldMaximum, spillLength, false); } /** @@ -175,7 +205,7 @@ public final class PropertyMap implements Iterable { * @return New {@link PropertyMap}. */ public static PropertyMap newMap(final Collection properties) { - return (properties == null || properties.isEmpty())? newMap() : newMap(properties, 0, 0, 0); + return (properties == null || properties.isEmpty())? newMap() : newMap(properties, JO.class.getName(), 0, 0, 0); } /** @@ -184,7 +214,7 @@ public final class PropertyMap implements Iterable { * @return New empty {@link PropertyMap}. */ public static PropertyMap newMap() { - return new PropertyMap(EMPTY_HASHMAP, 0, 0, 0, false); + return new PropertyMap(EMPTY_HASHMAP, JO.class.getName(), 0, 0, 0, false); } /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 7e1a516aa6d..9088544454a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -27,14 +27,15 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.lookup.Lookup.MH; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; +import java.util.Map; import jdk.internal.dynalink.support.NameCodec; - import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.FunctionSignature; @@ -43,6 +44,7 @@ import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.scripts.JS; /** * This is a subclass that represents a script function that may be regenerated, @@ -50,13 +52,19 @@ import jdk.nashorn.internal.parser.TokenType; * The common denominator is that it can get new invokers during its lifespan, * unlike {@code FinalScriptFunctionData} */ -public final class RecompilableScriptFunctionData extends ScriptFunctionData { +public final class RecompilableScriptFunctionData extends ScriptFunctionData implements Serializable { /** FunctionNode with the code for this ScriptFunction */ - private FunctionNode functionNode; + private transient FunctionNode functionNode; /** Source from which FunctionNode was parsed. */ - private final Source source; + private transient Source source; + + /** The line number where this function begins. */ + private final int lineNumber; + + /** Allows us to retrieve the method handle for this function once the code is compiled */ + private MethodLocator methodLocator; /** Token of this function within the source. */ private final long token; @@ -65,13 +73,13 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { private final PropertyMap allocatorMap; /** Code installer used for all further recompilation/specialization of this ScriptFunction */ - private CodeInstaller installer; + private transient CodeInstaller installer; /** Name of class where allocator function resides */ private final String allocatorClassName; /** lazily generated allocator */ - private MethodHandle allocator; + private transient MethodHandle allocator; private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); @@ -79,7 +87,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { * Used for specialization based on runtime arguments. Whenever we specialize on * callsite parameter types at runtime, we need to use a parameter type guard to * ensure that the specialized version of the script function continues to be - * applicable for a particular callsite * + * applicable for a particular callsite. */ private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Object[].class); @@ -88,10 +96,12 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { * (or java.lang.Number instance) to specialize the parameter to an integer, if the * parameter in question can be represented as one. The double typically only exists * because the compiler doesn't know any better than "a number type" and conservatively - * picks doubles when it can't prove that an integer addition wouldn't overflow + * picks doubles when it can't prove that an integer addition wouldn't overflow. */ private static final MethodHandle ENSURE_INT = findOwnMH("ensureInt", int.class, Object.class); + private static final long serialVersionUID = 4914839316174633726L; + /** * Constructor - public as scripts use it * @@ -104,13 +114,16 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { super(functionName(functionNode), functionNode.getParameters().size(), getFlags(functionNode)); - this.functionNode = functionNode; this.source = functionNode.getSource(); + this.lineNumber = functionNode.getLineNumber(); this.token = tokenFor(functionNode); this.installer = installer; this.allocatorClassName = allocatorClassName; this.allocatorMap = allocatorMap; + if (!functionNode.isLazy()) { + methodLocator = new MethodLocator(functionNode); + } } @Override @@ -122,16 +135,19 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { return "function " + (name == null ? "" : name) + "() { [native code] }"; } + public void setCodeAndSource(final Map> code, final Source source) { + this.source = source; + if (methodLocator != null) { + methodLocator.setClass(code.get(methodLocator.getClassName())); + } + } + @Override public String toString() { final StringBuilder sb = new StringBuilder(); if (source != null) { - sb.append(source.getName()); - if (functionNode != null) { - sb.append(':').append(functionNode.getLineNumber()); - } - sb.append(' '); + sb.append(source.getName()).append(':').append(lineNumber).append(' '); } return sb.toString() + super.toString(); @@ -204,8 +220,13 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { functionNode = compiler.compile(functionNode); assert !functionNode.isLazy(); compiler.install(functionNode); + methodLocator = new MethodLocator(functionNode); flags = getFlags(functionNode); } + + if (functionNode != null) { + methodLocator.setClass(functionNode.getCompileUnit().getCode()); + } } @Override @@ -221,12 +242,13 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { * eager compilation or from running a lazy compile on the lines above */ - assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode); + assert functionNode == null || functionNode.hasState(CompilationState.EMITTED) : + functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode); // code exists - look it up and add it into the automatically sorted invoker list addCode(functionNode); - if (! functionNode.canSpecialize()) { + if (functionNode != null && !functionNode.canSpecialize()) { // allow GC to claim IR stuff that is not needed anymore functionNode = null; installer = null; @@ -238,13 +260,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { } private MethodHandle addCode(final FunctionNode fn, final MethodType runtimeType, final MethodHandle guard, final MethodHandle fallback) { - final MethodType targetType = new FunctionSignature(fn).getMethodType(); - MethodHandle target = - MH.findStatic( - LOOKUP, - fn.getCompileUnit().getCode(), - fn.getName(), - targetType); + assert methodLocator != null; + MethodHandle target = methodLocator.getMethodHandle(); + final MethodType targetType = methodLocator.getMethodType(); /* * For any integer argument. a double that is representable as an integer is OK. @@ -424,7 +442,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { Compiler.LOG.info("Callsite specialized ", name, " runtimeType=", runtimeType, " parameters=", snapshot.getParameters(), " args=", Arrays.asList(args)); - assert snapshot != null; assert snapshot != functionNode; final Compiler compiler = new Compiler(installer); @@ -450,5 +467,45 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types)); } + /** + * Helper class that allows us to retrieve the method handle for this function once it has been generated. + */ + private static class MethodLocator implements Serializable { + private transient Class clazz; + private final String className; + private final String methodName; + private final MethodType methodType; + + private static final long serialVersionUID = -5420835725902966692L; + + MethodLocator(final FunctionNode functionNode) { + this.className = functionNode.getCompileUnit().getUnitClassName(); + this.methodName = functionNode.getName(); + this.methodType = new FunctionSignature(functionNode).getMethodType(); + + assert className != null; + assert methodName != null; + } + + void setClass(final Class clazz) { + if (!JS.class.isAssignableFrom(clazz)) { + throw new IllegalArgumentException(); + } + this.clazz = clazz; + } + + String getClassName() { + return className; + } + + MethodType getMethodType() { + return methodType; + } + + MethodHandle getMethodHandle() { + return MH.findStatic(LOOKUP, clazz, methodName, methodType); + } + } + } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java index 5327471051a..96982011dbe 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java @@ -134,6 +134,9 @@ public final class ScriptEnvironment { /** Only parse the source code, do not compile */ public final boolean _parse_only; + /** Enable disk cache for compiled scripts */ + public final boolean _persistent_cache; + /** Print the AST before lowering */ public final boolean _print_ast; @@ -218,6 +221,7 @@ public final class ScriptEnvironment { _no_syntax_extensions = options.getBoolean("no.syntax.extensions"); _no_typed_arrays = options.getBoolean("no.typed.arrays"); _parse_only = options.getBoolean("parse.only"); + _persistent_cache = options.getBoolean("persistent.code.cache"); _print_ast = options.getBoolean("print.ast"); _print_lower_ast = options.getBoolean("print.lower.ast"); _print_code = options.getBoolean("print.code"); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index aee367d65ba..ad40d622d7e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -29,10 +29,10 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; /** @@ -40,7 +40,7 @@ import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; * Instances of this class are created during codegen and stored in script classes' * constants array to reduce function instantiation overhead during runtime. */ -public abstract class ScriptFunctionData { +public abstract class ScriptFunctionData implements Serializable { /** Name of the function or "" for anonynous functions */ protected final String name; @@ -74,6 +74,8 @@ public abstract class ScriptFunctionData { /** Flag for strict constructors */ public static final int IS_STRICT_CONSTRUCTOR = IS_STRICT | IS_CONSTRUCTOR; + private static final long serialVersionUID = 4252901245508769114L; + /** * Constructor * diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 05e236e3bd6..1519024a70b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -593,23 +593,16 @@ public abstract class ScriptObject implements PropertyAccess { } /** - * Spec. mentions use of [[DefineOwnProperty]] for indexed properties in - * certain places (eg. Array.prototype.map, filter). We can not use ScriptObject.set - * method in such cases. This is because set method uses inherited setters (if any) - * from any object in proto chain such as Array.prototype, Object.prototype. - * This method directly sets a particular element value in the current object. + * Almost like defineOwnProperty(int,Object) for arrays this one does + * not add 'gap' elements (like the array one does). * * @param index key for property * @param value value to define */ - public final void defineOwnProperty(final int index, final Object value) { + public void defineOwnProperty(final int index, final Object value) { assert isValidArrayIndex(index) : "invalid array index"; final long longIndex = ArrayIndex.toLongIndex(index); - if (longIndex >= getArray().length()) { - // make array big enough to hold.. - setArray(getArray().ensure(longIndex)); - } - setArray(getArray().set(index, value, false)); + setValueAtArrayIndex(longIndex, index, value, false); } private void checkIntegerKey(final String key) { @@ -2747,9 +2740,7 @@ public abstract class ScriptObject implements PropertyAccess { * @param strict are we in strict mode */ private void doesNotHave(final int index, final Object value, final boolean strict) { - final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); - if (getMap().containsArrayKeys()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); @@ -2760,6 +2751,18 @@ public abstract class ScriptObject implements PropertyAccess { } } + setValueAtArrayIndex(longIndex, index, value, strict); + } + + /** + * Handle when an array doesn't have a slot - possibly grow and/or convert array. + * + * @param index key as index + * @param value element value + * @param strict are we in strict mode + */ + private void setValueAtArrayIndex(final long longIndex, final int index, final Object value, final boolean strict) { + final long oldLength = getArray().length(); if (longIndex >= oldLength) { if (!isExtensible()) { if (strict) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Source.java b/nashorn/src/jdk/nashorn/internal/runtime/Source.java index 0455a86c6d2..f57874bc18f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Source.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Source.java @@ -39,6 +39,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Objects; import jdk.nashorn.internal.parser.Token; @@ -71,6 +73,9 @@ public final class Source { /** Cached hash code */ private int hash; + /** Message digest */ + private byte[] digest; + /** Source URL if available */ private final URL url; @@ -416,6 +421,40 @@ public final class Source { return readFully(url.openStream(), cs); } + /** + * Get a message digest for this source. + * + * @return a message digest for this source + */ + public synchronized byte[] getDigest() { + if (digest == null) { + + final byte[] bytes = new byte[content.length * 2]; + + for (int i = 0; i < content.length; i++) { + bytes[i * 2] = (byte) (content[i] & 0x00ff); + bytes[i * 2 + 1] = (byte) ((content[i] & 0xff00) >> 8); + } + + try { + final MessageDigest md = MessageDigest.getInstance("SHA-1"); + if (name != null) { + md.update(name.getBytes(StandardCharsets.UTF_8)); + } + if (base != null) { + md.update(base.getBytes(StandardCharsets.UTF_8)); + } + if (url != null) { + md.update(url.toString().getBytes(StandardCharsets.UTF_8)); + } + digest = md.digest(bytes); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + return digest; + } + /** * Get the base url. This is currently used for testing only * @param url a URL diff --git a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java index a69de45ca3d..5b21f6eea91 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java @@ -186,6 +186,11 @@ public final class UserAccessorProperty extends Property { return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type); } + @Override + void initMethodHandles(final Class structure) { + throw new UnsupportedOperationException(); + } + @Override public ScriptFunction getGetterFunction(final ScriptObject obj) { final Object value = obj.getSpill(getterSlot); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties index 2726211151a..033fcc2546e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties @@ -230,6 +230,14 @@ nashorn.option.parse.only = { \ desc="Parse without compiling." \ } +nashorn.option.persistent.code.cache = { \ + name="--persistent-code-cache", \ + short_name="-pcc", \ + desc="Enable disk cache for compiled scripts.", \ + is_undocumented=true, \ + default=false \ +} + nashorn.option.profile.callsites = { \ name="--profile-callsites", \ short_name="-pcs", \ diff --git a/nashorn/test/script/basic/JDK-8037562.js b/nashorn/test/script/basic/JDK-8037562.js new file mode 100644 index 00000000000..7534a0dab12 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8037562.js @@ -0,0 +1,41 @@ +/* + * 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. + */ + + +/** + * JDK-8037562: Nashorn: JSON.parse comes up with nonexistent entries if there are gaps between the keys + * + * @test + * @run + */ + +var strs = [ + '{ "0":0, "2":2 }', + '{ "0":"", "2":"" }', + '{ "0":0, "5":"hello" }', + '{ "0":"", "15":3234 }', +] + +for (var i in strs) { + print(JSON.stringify(JSON.parse(strs[i]))); +} diff --git a/nashorn/test/script/basic/JDK-8037562.js.EXPECTED b/nashorn/test/script/basic/JDK-8037562.js.EXPECTED new file mode 100644 index 00000000000..ea671713c4e --- /dev/null +++ b/nashorn/test/script/basic/JDK-8037562.js.EXPECTED @@ -0,0 +1,4 @@ +{"0":0,"2":2} +{"0":"","2":""} +{"0":0,"5":"hello"} +{"0":"","15":3234} diff --git a/nashorn/test/script/basic/JDK-8039387.js b/nashorn/test/script/basic/JDK-8039387.js new file mode 100644 index 00000000000..8f903c1af96 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8039387.js @@ -0,0 +1,39 @@ +/* + * 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. + */ + +/** + * JDK-8039387: Nashorn supports indexed access of List elements, but length property is not supported + * + * @test + * @run + */ + +var ArrayList = Java.type("java.util.ArrayList") +var list = new ArrayList(3) +list.add("nashorn") +list.add("js") +list.add("ecmascript") +var len = list.length +print("length = " + len) +for (var i = 0; i < len; i++) + print(list[i]) diff --git a/nashorn/test/script/basic/JDK-8039387.js.EXPECTED b/nashorn/test/script/basic/JDK-8039387.js.EXPECTED new file mode 100644 index 00000000000..5b9ce56d56b --- /dev/null +++ b/nashorn/test/script/basic/JDK-8039387.js.EXPECTED @@ -0,0 +1,4 @@ +length = 3 +nashorn +js +ecmascript diff --git a/nashorn/test/script/basic/list.js b/nashorn/test/script/basic/list.js index 72ae0be7617..59136c0b2ee 100644 --- a/nashorn/test/script/basic/list.js +++ b/nashorn/test/script/basic/list.js @@ -33,7 +33,7 @@ print("l.class.name=" + Java.typeName(l.class)) // Has "class" property like any l.add("foo") l.add("bar") -print("l.length=" + l.length) // doesn't work, returns undefined +print("l.length=" + l.length) // works, maps to l.size() print("l.size()=" + l.size()) // this will work print("l[0]=" + l[0]) diff --git a/nashorn/test/script/basic/list.js.EXPECTED b/nashorn/test/script/basic/list.js.EXPECTED index 18feade2b4e..47f3bd4fec1 100644 --- a/nashorn/test/script/basic/list.js.EXPECTED +++ b/nashorn/test/script/basic/list.js.EXPECTED @@ -1,5 +1,5 @@ l.class.name=java.util.ArrayList -l.length=undefined +l.length=2 l.size()=2 l[0]=foo l[1]=bar diff --git a/nashorn/test/script/error/JDK-8039047.js b/nashorn/test/script/error/JDK-8039047.js new file mode 100644 index 00000000000..8cbd51fdf5e --- /dev/null +++ b/nashorn/test/script/error/JDK-8039047.js @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/** + * JDK-8039047: Parser accepts conditional catch clauses even when --no-syntax-extensions / -nse option is passed + * + * @option --no-syntax-extensions + * @test/compile-error + */ + +try { + func() +} catch (e if e instanceof ReferenceError) { + print("Got ReferenceError " + e); +} diff --git a/nashorn/test/script/error/JDK-8039047.js.EXPECTED b/nashorn/test/script/error/JDK-8039047.js.EXPECTED new file mode 100644 index 00000000000..b1d2f1705b0 --- /dev/null +++ b/nashorn/test/script/error/JDK-8039047.js.EXPECTED @@ -0,0 +1,6 @@ +test/script/error/JDK-8039047.js:33:11 Expected ) but found if +} catch (e if e instanceof ReferenceError) { + ^ +test/script/error/JDK-8039047.js:35:0 Expected eof but found } +} +^ diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java new file mode 100644 index 00000000000..a2d72ebfd99 --- /dev/null +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.nashorn.internal.runtime; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.DirectoryStream; +import java.nio.file.Path; +import java.nio.file.FileSystems; +import javax.script.ScriptException; +import org.testng.annotations.Test; +import javax.script.ScriptEngine; +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertEquals; + +/** + * @test + * @bug 8039185 8039403 + * @summary Test for persistent code cache and path handling + * @run testng jdk.nashorn.internal.runtime.CodeStoreAndPathTest + */ + +public class CodeStoreAndPathTest { + + final String code1 = "var code1; var x = 'Hello Script'; var x1 = 'Hello Script'; " + + "var x2 = 'Hello Script'; var x3 = 'Hello Script'; " + + "var x4 = 'Hello Script'; var x5 = 'Hello Script';" + + "var x6 = 'Hello Script'; var x7 = 'Hello Script'; " + + "var x8 = 'Hello Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';" + + "function f() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function g() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function h() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function i() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}"; + final String code2 = "var code2; var x = 'Hello Script'; var x1 = 'Hello Script'; " + + "var x2 = 'Hello Script'; var x3 = 'Hello Script'; " + + "var x4 = 'Hello Script'; var x5 = 'Hello Script';" + + "var x6 = 'Hello Script'; var x7 = 'Hello Script'; " + + "var x8 = 'Hello Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';" + + "function f() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function g() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function h() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function i() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}"; + // Script size < Default minimum size for storing a compiled script class + final String code3 = "var code3; var x = 'Hello Script'; var x1 = 'Hello Script'; "; + final String codeCache = "build/nashorn_code_cache"; + final String oldUserDir = System.getProperty("user.dir"); + + public void checkCompiledScripts(DirectoryStream stream, int numberOfScripts) throws IOException { + for (Path file : stream) { + numberOfScripts--; + } + stream.close(); + assertEquals(numberOfScripts,0); + } + + @Test + public void pathHandlingTest() throws ScriptException, IOException { + System.setProperty("nashorn.persistent.code.cache", codeCache); + String[] options = new String[]{"--persistent-code-cache"}; + NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + ScriptEngine e = fac.getScriptEngine(options); + Path expectedCodeCachePath = FileSystems.getDefault().getPath(oldUserDir + File.separator + codeCache); + Path actualCodeCachePath = FileSystems.getDefault().getPath(System.getProperty( + "nashorn.persistent.code.cache")).toAbsolutePath(); + // Check that nashorn code cache is created in current working directory + assertEquals(actualCodeCachePath, expectedCodeCachePath); + // Check that code cache dir exists and it's not empty + File file = new File(actualCodeCachePath.toUri()); + assertFalse(!file.isDirectory(), "No code cache directory was created!"); + assertFalse(file.list().length == 0, "Code cache directory is empty!"); + } + + @Test + public void changeUserDirTest() throws ScriptException, IOException { + System.setProperty("nashorn.persistent.code.cache", codeCache); + String[] options = new String[]{"--persistent-code-cache"}; + NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + ScriptEngine e = fac.getScriptEngine(options); + Path codeCachePath = FileSystems.getDefault().getPath(System.getProperty( + "nashorn.persistent.code.cache")).toAbsolutePath(); + String newUserDir = "build/newUserDir"; + // Now changing current working directory + System.setProperty("user.dir", System.getProperty("user.dir") + File.separator + newUserDir); + // Check that a new compiled script is stored in exisitng code cache + e.eval(code1); + DirectoryStream stream = Files.newDirectoryStream(codeCachePath); + // Already one compiled script has been stored in the cache during initialization + checkCompiledScripts(stream, 2); + // Setting to default current working dir + System.setProperty("user.dir", oldUserDir); + } + + @Test + public void codeCacheTest() throws ScriptException, IOException { + System.setProperty("nashorn.persistent.code.cache", codeCache); + String[] options = new String[]{"--persistent-code-cache"}; + NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + ScriptEngine e = fac.getScriptEngine(options); + Path codeCachePath = FileSystems.getDefault().getPath(System.getProperty( + "nashorn.persistent.code.cache")).toAbsolutePath(); + e.eval(code1); + e.eval(code2); + e.eval(code3);// less than minimum size for storing + // Already one compiled script has been stored in the cache during initialization + // adding code1 and code2. + DirectoryStream stream = Files.newDirectoryStream(codeCachePath); + checkCompiledScripts(stream, 3); + } +} diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java index aefa828b470..7b84f5a7af3 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java @@ -37,6 +37,8 @@ import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import javax.script.SimpleScriptContext; import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; /** * @test @@ -50,8 +52,8 @@ public class NoPersistenceCachingTest { private ScriptContext context1, context2, context3; private ByteArrayOutputStream stderr; private PrintStream prevStderr; - private final String script = "print('Hello')"; + @BeforeTest public void setupTest() { stderr = new ByteArrayOutputStream(); prevStderr = System.err; @@ -69,33 +71,33 @@ public class NoPersistenceCachingTest { } String[] options = new String[]{"--log=compiler:finest"}; engine = nashornFactory.getScriptEngine(options); + context1 = engine.getContext(); + context2 = new SimpleScriptContext(); + context2.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); + context3 = new SimpleScriptContext(); + context3.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); } + @AfterTest public void setErrTest() { System.setErr(prevStderr); } public void runTest(int numberOfContext, String expectedOutputPattern, int expectedPatternOccurrence) { - setupTest(); + try { switch (numberOfContext) { case 2: - context1 = engine.getContext(); - context2 = new SimpleScriptContext(); - context2.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); - engine.eval(script, context1); - engine.eval(script, context2); + String scriptTwoContexts = "print('HelloTwoContexts')"; + engine.eval(scriptTwoContexts, context1); + engine.eval(scriptTwoContexts, context2); break; case 3: - context1 = engine.getContext(); - context2 = new SimpleScriptContext(); - context2.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); - context3 = new SimpleScriptContext(); - context3.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); - engine.eval(script, context1); - engine.eval(script, context2); - engine.eval(script, context3); + String scriptThreeContexts = "print('HelloThreeContexts')"; + engine.eval(scriptThreeContexts, context1); + engine.eval(scriptThreeContexts, context2); + engine.eval(scriptThreeContexts, context3); break; } } catch (final Exception se) { @@ -113,7 +115,7 @@ public class NoPersistenceCachingTest { + expectedPatternOccurrence + " and found: " + matches + "\n" + stderr); } - setErrTest(); + stderr.reset(); } private static String getCodeCachePattern() {