diff --git a/.hgtags b/.hgtags index 49424e043a0..82b9404a86c 100644 --- a/.hgtags +++ b/.hgtags @@ -246,3 +246,5 @@ a1ee9743f4ee165eae59389a020f2552f895dac8 jdk8-b120 f130ca87de6637acae7d99fcd7a8573eea1cbaed jdk9-b01 b32e2219736e42baaf45daf0ad67ed34f6033799 jdk9-b02 7f655f31f9bcee618cf832f08176ad8c1ed3fdd3 jdk9-b03 +099891b1d86f3719e116ac717ffdafc90d037fb7 jdk9-b04 +dd311791ad6895a3989020dd6c6c46db87972ab8 jdk9-b05 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 45398d20075..4119c1cfd65 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -246,3 +246,5 @@ cd3825b2983045784d6fc6d1729c799b08215752 jdk8-b120 50669e45cec4491de0d921d3118a3fe2e767020a jdk9-b01 135f0c7af57ebace31383d8877f47e32172759ff jdk9-b02 fd8d51bdf9aadf7ae83e65e8655c53581017c363 jdk9-b03 +cb4c3440bc2748101923e2488506e61009ab1bf5 jdk9-b04 +8c63f0b6ada282f27e3a80125e53c3be603f9af7 jdk9-b05 diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4 index 170049731dc..edd6cec4ffb 100644 --- a/common/autoconf/boot-jdk.m4 +++ b/common/autoconf/boot-jdk.m4 @@ -350,8 +350,23 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], AC_MSG_CHECKING([flags for boot jdk java command] ) + # Disable special log output when a debug build is used as Boot JDK... + ADD_JVM_ARG_IF_OK([-XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput],boot_jdk_jvmargs,[$JAVA]) + + # Apply user provided options. + ADD_JVM_ARG_IF_OK([$with_boot_jdk_jvmargs],boot_jdk_jvmargs,[$JAVA]) + + AC_MSG_RESULT([$boot_jdk_jvmargs]) + + # For now, general JAVA_FLAGS are the same as the boot jdk jvmargs + JAVA_FLAGS=$boot_jdk_jvmargs + AC_SUBST(JAVA_FLAGS) + + + AC_MSG_CHECKING([flags for boot jdk java command for big workloads]) + # Starting amount of heap memory. - ADD_JVM_ARG_IF_OK([-Xms64M],boot_jdk_jvmargs,[$JAVA]) + ADD_JVM_ARG_IF_OK([-Xms64M],boot_jdk_jvmargs_big,[$JAVA]) # Maximum amount of heap memory. # Maximum stack size. @@ -366,20 +381,24 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], JVM_MAX_HEAP=1600M STACK_SIZE=1536 fi - ADD_JVM_ARG_IF_OK([-Xmx$JVM_MAX_HEAP],boot_jdk_jvmargs,[$JAVA]) - ADD_JVM_ARG_IF_OK([-XX:ThreadStackSize=$STACK_SIZE],boot_jdk_jvmargs,[$JAVA]) + ADD_JVM_ARG_IF_OK([-Xmx$JVM_MAX_HEAP],boot_jdk_jvmargs_big,[$JAVA]) + ADD_JVM_ARG_IF_OK([-XX:ThreadStackSize=$STACK_SIZE],boot_jdk_jvmargs_big,[$JAVA]) - # Disable special log output when a debug build is used as Boot JDK... - ADD_JVM_ARG_IF_OK([-XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput],boot_jdk_jvmargs,[$JAVA]) + AC_MSG_RESULT([$boot_jdk_jvmargs_big]) - # Apply user provided options. - ADD_JVM_ARG_IF_OK([$with_boot_jdk_jvmargs],boot_jdk_jvmargs,[$JAVA]) + JAVA_FLAGS_BIG=$boot_jdk_jvmargs_big + AC_SUBST(JAVA_FLAGS_BIG) - AC_MSG_RESULT([$boot_jdk_jvmargs]) - # For now, general JAVA_FLAGS are the same as the boot jdk jvmargs - JAVA_FLAGS=$boot_jdk_jvmargs + AC_MSG_CHECKING([flags for boot jdk java command for small workloads]) - AC_SUBST(BOOT_JDK_JVMARGS, $boot_jdk_jvmargs) - AC_SUBST(JAVA_FLAGS, $JAVA_FLAGS) + # Use serial gc for small short lived tools if possible + ADD_JVM_ARG_IF_OK([-XX:+UseSerialGC],boot_jdk_jvmargs_small,[$JAVA]) + ADD_JVM_ARG_IF_OK([-Xms32M],boot_jdk_jvmargs_small,[$JAVA]) + ADD_JVM_ARG_IF_OK([-Xmx512M],boot_jdk_jvmargs_small,[$JAVA]) + + AC_MSG_RESULT([$boot_jdk_jvmargs_small]) + + JAVA_FLAGS_SMALL=$boot_jdk_jvmargs_small + AC_SUBST(JAVA_FLAGS_SMALL) ]) diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index 613afc319a1..bcfa1777bcf 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -133,6 +133,26 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], C_FLAG_REORDER='' CXX_FLAG_REORDER='' + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + # Linking is different on MacOSX + SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG" + SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker @loader_path/.' + SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN" + SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/[$]1' + SET_SHARED_LIBRARY_MAPFILE='' + else + # Default works for linux, might work on other platforms as well. + SHARED_LIBRARY_FLAGS='-shared' + SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker \$$$$ORIGIN[$]1' + SET_SHARED_LIBRARY_ORIGIN="-Xlinker -z -Xlinker origin $SET_EXECUTABLE_ORIGIN" + SET_SHARED_LIBRARY_NAME='-Xlinker -soname=[$]1' + SET_SHARED_LIBRARY_MAPFILE='-Xlinker -version-script=[$]1' + fi + elif test "x$TOOLCHAIN_TYPE" = xclang; then + PICFLAG='' + C_FLAG_REORDER='' + CXX_FLAG_REORDER='' + if test "x$OPENJDK_TARGET_OS" = xmacosx; then # Linking is different on MacOSX SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG" @@ -242,6 +262,8 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], # Generate make dependency files if test "x$TOOLCHAIN_TYPE" = xgcc; then C_FLAG_DEPS="-MMD -MF" + elif test "x$TOOLCHAIN_TYPE" = xclang; then + C_FLAG_DEPS="-MMD -MF" elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then C_FLAG_DEPS="-xMMD -xMF" elif test "x$TOOLCHAIN_TYPE" = xxlc; then @@ -260,6 +282,9 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], CFLAGS_DEBUG_SYMBOLS="-g" CXXFLAGS_DEBUG_SYMBOLS="-g" fi + elif test "x$TOOLCHAIN_TYPE" = xclang; then + CFLAGS_DEBUG_SYMBOLS="-g" + CXXFLAGS_DEBUG_SYMBOLS="-g" elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then CFLAGS_DEBUG_SYMBOLS="-g -xs" CXXFLAGS_DEBUG_SYMBOLS="-g0 -xs" @@ -315,6 +340,20 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], C_O_FLAG_NORM="-O2" C_O_FLAG_NONE="-O0" fi + elif test "x$TOOLCHAIN_TYPE" = xclang; then + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + # On MacOSX we optimize for size, something + # we should do for all platforms? + C_O_FLAG_HIGHEST="-Os" + C_O_FLAG_HI="-Os" + C_O_FLAG_NORM="-Os" + C_O_FLAG_NONE="" + else + C_O_FLAG_HIGHEST="-O3" + C_O_FLAG_HI="-O3" + C_O_FLAG_NORM="-O2" + C_O_FLAG_NONE="-O0" + fi elif test "x$TOOLCHAIN_TYPE" = xxlc; then C_O_FLAG_HIGHEST="-O3" C_O_FLAG_HI="-O3 -qstrict" diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 7473edb634f..b3d823b29ed 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -653,6 +653,9 @@ LIBDL LIBM LIBZIP_CAN_USE_MMAP USE_EXTERNAL_LIBZ +USE_EXTERNAL_LIBPNG +PNG_LIBS +PNG_CFLAGS USE_EXTERNAL_LIBGIF USE_EXTERNAL_LIBJPEG ALSA_LIBS @@ -793,8 +796,9 @@ JAXWS_TOPDIR JAXP_TOPDIR CORBA_TOPDIR LANGTOOLS_TOPDIR +JAVA_FLAGS_SMALL +JAVA_FLAGS_BIG JAVA_FLAGS -BOOT_JDK_JVMARGS JAVAC_FLAGS BOOT_JDK_SOURCETARGET JARSIGNER @@ -1071,6 +1075,7 @@ with_alsa with_alsa_include with_alsa_lib with_giflib +with_libpng with_zlib with_stdc__lib with_msvcr_dll @@ -1183,6 +1188,8 @@ FREETYPE_CFLAGS FREETYPE_LIBS ALSA_CFLAGS ALSA_LIBS +PNG_CFLAGS +PNG_LIBS LIBFFI_CFLAGS LIBFFI_LIBS CCACHE' @@ -1921,6 +1928,8 @@ Optional Packages: --with-alsa-lib specify directory for the alsa library --with-giflib use giflib from build system or OpenJDK source (system, bundled) [bundled] + --with-libpng use libpng from build system or OpenJDK source + (system, bundled) [bundled] --with-zlib use zlib from build system or OpenJDK source (system, bundled) [bundled] --with-stdc++lib=,, @@ -2045,6 +2054,8 @@ Some influential environment variables: linker flags for FREETYPE, overriding pkg-config ALSA_CFLAGS C compiler flags for ALSA, overriding pkg-config ALSA_LIBS linker flags for ALSA, overriding pkg-config + PNG_CFLAGS C compiler flags for PNG, overriding pkg-config + PNG_LIBS linker flags for PNG, overriding pkg-config LIBFFI_CFLAGS C compiler flags for LIBFFI, overriding pkg-config LIBFFI_LIBS linker flags for LIBFFI, overriding pkg-config @@ -4221,7 +4232,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=1394011255 +DATE_WHEN_GENERATED=1394794899 ############################################################################### # @@ -25856,67 +25867,6 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command " >&5 $as_echo_n "checking flags for boot jdk java command ... " >&6; } - # Starting amount of heap memory. - - $ECHO "Check if jvm arg is ok: -Xms64M" >&5 - $ECHO "Command: $JAVA -Xms64M -version" >&5 - OUTPUT=`$JAVA -Xms64M -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs="$boot_jdk_jvmargs -Xms64M" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - # Maximum amount of heap memory. - # Maximum stack size. - if test "x$BUILD_NUM_BITS" = x32; then - JVM_MAX_HEAP=1100M - STACK_SIZE=768 - else - # Running Javac on a JVM on a 64-bit machine, takes more space since 64-bit - # pointers are used. Apparently, we need to increase the heap and stack - # space for the jvm. More specifically, when running javac to build huge - # jdk batch - JVM_MAX_HEAP=1600M - STACK_SIZE=1536 - fi - - $ECHO "Check if jvm arg is ok: -Xmx$JVM_MAX_HEAP" >&5 - $ECHO "Command: $JAVA -Xmx$JVM_MAX_HEAP -version" >&5 - OUTPUT=`$JAVA -Xmx$JVM_MAX_HEAP -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs="$boot_jdk_jvmargs -Xmx$JVM_MAX_HEAP" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - - $ECHO "Check if jvm arg is ok: -XX:ThreadStackSize=$STACK_SIZE" >&5 - $ECHO "Command: $JAVA -XX:ThreadStackSize=$STACK_SIZE -version" >&5 - OUTPUT=`$JAVA -XX:ThreadStackSize=$STACK_SIZE -version 2>&1` - FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` - FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` - if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then - boot_jdk_jvmargs="$boot_jdk_jvmargs -XX:ThreadStackSize=$STACK_SIZE" - JVM_ARG_OK=true - else - $ECHO "Arg failed:" >&5 - $ECHO "$OUTPUT" >&5 - JVM_ARG_OK=false - fi - - # Disable special log output when a debug build is used as Boot JDK... $ECHO "Check if jvm arg is ok: -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput" >&5 @@ -25957,9 +25907,133 @@ $as_echo "$boot_jdk_jvmargs" >&6; } # For now, general JAVA_FLAGS are the same as the boot jdk jvmargs JAVA_FLAGS=$boot_jdk_jvmargs - BOOT_JDK_JVMARGS=$boot_jdk_jvmargs - JAVA_FLAGS=$JAVA_FLAGS + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command for big workloads" >&5 +$as_echo_n "checking flags for boot jdk java command for big workloads... " >&6; } + + # Starting amount of heap memory. + + $ECHO "Check if jvm arg is ok: -Xms64M" >&5 + $ECHO "Command: $JAVA -Xms64M -version" >&5 + OUTPUT=`$JAVA -Xms64M -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -Xms64M" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + # Maximum amount of heap memory. + # Maximum stack size. + if test "x$BUILD_NUM_BITS" = x32; then + JVM_MAX_HEAP=1100M + STACK_SIZE=768 + else + # Running Javac on a JVM on a 64-bit machine, takes more space since 64-bit + # pointers are used. Apparently, we need to increase the heap and stack + # space for the jvm. More specifically, when running javac to build huge + # jdk batch + JVM_MAX_HEAP=1600M + STACK_SIZE=1536 + fi + + $ECHO "Check if jvm arg is ok: -Xmx$JVM_MAX_HEAP" >&5 + $ECHO "Command: $JAVA -Xmx$JVM_MAX_HEAP -version" >&5 + OUTPUT=`$JAVA -Xmx$JVM_MAX_HEAP -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -Xmx$JVM_MAX_HEAP" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + $ECHO "Check if jvm arg is ok: -XX:ThreadStackSize=$STACK_SIZE" >&5 + $ECHO "Command: $JAVA -XX:ThreadStackSize=$STACK_SIZE -version" >&5 + OUTPUT=`$JAVA -XX:ThreadStackSize=$STACK_SIZE -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -XX:ThreadStackSize=$STACK_SIZE" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_big" >&5 +$as_echo "$boot_jdk_jvmargs_big" >&6; } + + JAVA_FLAGS_BIG=$boot_jdk_jvmargs_big + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command for small workloads" >&5 +$as_echo_n "checking flags for boot jdk java command for small workloads... " >&6; } + + # Use serial gc for small short lived tools if possible + + $ECHO "Check if jvm arg is ok: -XX:+UseSerialGC" >&5 + $ECHO "Command: $JAVA -XX:+UseSerialGC -version" >&5 + OUTPUT=`$JAVA -XX:+UseSerialGC -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -XX:+UseSerialGC" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + $ECHO "Check if jvm arg is ok: -Xms32M" >&5 + $ECHO "Command: $JAVA -Xms32M -version" >&5 + OUTPUT=`$JAVA -Xms32M -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -Xms32M" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + $ECHO "Check if jvm arg is ok: -Xmx512M" >&5 + $ECHO "Command: $JAVA -Xmx512M -version" >&5 + OUTPUT=`$JAVA -Xmx512M -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -Xmx512M" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_small" >&5 +$as_echo "$boot_jdk_jvmargs_small" >&6; } + + JAVA_FLAGS_SMALL=$boot_jdk_jvmargs_small @@ -26297,8 +26371,28 @@ fi # Use indirect variable referencing toolchain_var_name=VALID_TOOLCHAINS_$OPENJDK_BUILD_OS VALID_TOOLCHAINS=${!toolchain_var_name} - # First toolchain type in the list is the default - DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *} + + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + # On Mac OS X, default toolchain to clang after Xcode 5 + XCODE_VERSION_OUTPUT=`xcodebuild -version 2>&1 | $HEAD -n 1` + $ECHO "$XCODE_VERSION_OUTPUT" | $GREP "Xcode " > /dev/null + if test $? -ne 0; then + as_fn_error $? "Failed to determine Xcode version." "$LINENO" 5 + fi + XCODE_MAJOR_VERSION=`$ECHO $XCODE_VERSION_OUTPUT | \ + $SED -e 's/^Xcode \([1-9][0-9.]*\)/\1/' | \ + $CUT -f 1 -d .` + { $as_echo "$as_me:${as_lineno-$LINENO}: Xcode major version: $XCODE_MAJOR_VERSION" >&5 +$as_echo "$as_me: Xcode major version: $XCODE_MAJOR_VERSION" >&6;} + if test $XCODE_MAJOR_VERSION -ge 5; then + DEFAULT_TOOLCHAIN="clang" + else + DEFAULT_TOOLCHAIN="gcc" + fi + else + # First toolchain type in the list is the default + DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *} + fi if test "x$with_toolchain_type" = xlist; then # List all toolchains @@ -41221,6 +41315,26 @@ $as_echo "$ac_cv_c_bigendian" >&6; } C_FLAG_REORDER='' CXX_FLAG_REORDER='' + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + # Linking is different on MacOSX + SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG" + SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker @loader_path/.' + SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN" + SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/$1' + SET_SHARED_LIBRARY_MAPFILE='' + else + # Default works for linux, might work on other platforms as well. + SHARED_LIBRARY_FLAGS='-shared' + SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker \$$$$ORIGIN$1' + SET_SHARED_LIBRARY_ORIGIN="-Xlinker -z -Xlinker origin $SET_EXECUTABLE_ORIGIN" + SET_SHARED_LIBRARY_NAME='-Xlinker -soname=$1' + SET_SHARED_LIBRARY_MAPFILE='-Xlinker -version-script=$1' + fi + elif test "x$TOOLCHAIN_TYPE" = xclang; then + PICFLAG='' + C_FLAG_REORDER='' + CXX_FLAG_REORDER='' + if test "x$OPENJDK_TARGET_OS" = xmacosx; then # Linking is different on MacOSX SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG" @@ -41297,6 +41411,8 @@ $as_echo "$ac_cv_c_bigendian" >&6; } # Generate make dependency files if test "x$TOOLCHAIN_TYPE" = xgcc; then C_FLAG_DEPS="-MMD -MF" + elif test "x$TOOLCHAIN_TYPE" = xclang; then + C_FLAG_DEPS="-MMD -MF" elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then C_FLAG_DEPS="-xMMD -xMF" elif test "x$TOOLCHAIN_TYPE" = xxlc; then @@ -41315,6 +41431,9 @@ $as_echo "$ac_cv_c_bigendian" >&6; } CFLAGS_DEBUG_SYMBOLS="-g" CXXFLAGS_DEBUG_SYMBOLS="-g" fi + elif test "x$TOOLCHAIN_TYPE" = xclang; then + CFLAGS_DEBUG_SYMBOLS="-g" + CXXFLAGS_DEBUG_SYMBOLS="-g" elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then CFLAGS_DEBUG_SYMBOLS="-g -xs" CXXFLAGS_DEBUG_SYMBOLS="-g0 -xs" @@ -41370,6 +41489,20 @@ $as_echo "$ac_cv_c_bigendian" >&6; } C_O_FLAG_NORM="-O2" C_O_FLAG_NONE="-O0" fi + elif test "x$TOOLCHAIN_TYPE" = xclang; then + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + # On MacOSX we optimize for size, something + # we should do for all platforms? + C_O_FLAG_HIGHEST="-Os" + C_O_FLAG_HI="-Os" + C_O_FLAG_NORM="-Os" + C_O_FLAG_NONE="" + else + C_O_FLAG_HIGHEST="-O3" + C_O_FLAG_HI="-O3" + C_O_FLAG_NORM="-O2" + C_O_FLAG_NONE="-O0" + fi elif test "x$TOOLCHAIN_TYPE" = xxlc; then C_O_FLAG_HIGHEST="-O3" C_O_FLAG_HI="-O3 -qstrict" @@ -46789,6 +46922,118 @@ fi fi + ############################################################################### + # + # Check for the png library + # + + +# Check whether --with-libpng was given. +if test "${with_libpng+set}" = set; then : + withval=$with_libpng; +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for which libpng to use" >&5 +$as_echo_n "checking for which libpng to use... " >&6; } + + # default is bundled + DEFAULT_LIBPNG=bundled + + # + # if user didn't specify, use DEFAULT_LIBPNG + # + if test "x${with_libpng}" = "x"; then + with_libpng=${DEFAULT_LIBPNG} + fi + + if test "x${with_libpng}" = "xbundled"; then + USE_EXTERNAL_LIBPNG=false + { $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5 +$as_echo "bundled" >&6; } + elif test "x${with_libpng}" = "xsystem"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PNG" >&5 +$as_echo_n "checking for PNG... " >&6; } + +if test -n "$PNG_CFLAGS"; then + pkg_cv_PNG_CFLAGS="$PNG_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpng\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libpng") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PNG_CFLAGS=`$PKG_CONFIG --cflags "libpng" 2>/dev/null` +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PNG_LIBS"; then + pkg_cv_PNG_LIBS="$PNG_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpng\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libpng") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PNG_LIBS=`$PKG_CONFIG --libs "libpng" 2>/dev/null` +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PNG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libpng" 2>&1` + else + PNG_PKG_ERRORS=`$PKG_CONFIG --print-errors "libpng" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PNG_PKG_ERRORS" >&5 + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + LIBPNG_FOUND=no +elif test $pkg_failed = untried; then + LIBPNG_FOUND=no +else + PNG_CFLAGS=$pkg_cv_PNG_CFLAGS + PNG_LIBS=$pkg_cv_PNG_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + LIBPNG_FOUND=yes +fi + if test "x${LIBPNG_FOUND}" = "xyes"; then + USE_EXTERNAL_LIBPNG=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: system" >&5 +$as_echo "system" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: system not found" >&5 +$as_echo "system not found" >&6; } + as_fn_error $? "--with-libpng=system specified, but no libpng found!" "$LINENO" 5 + fi + else + as_fn_error $? "Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled'" "$LINENO" 5 + fi + + ############################################################################### # # Check for the zlib library diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4 index 685e9a903c6..6dca4aad3c6 100644 --- a/common/autoconf/libraries.m4 +++ b/common/autoconf/libraries.m4 @@ -652,6 +652,46 @@ AC_DEFUN_ONCE([LIB_SETUP_MISC_LIBS], fi AC_SUBST(USE_EXTERNAL_LIBGIF) + ############################################################################### + # + # Check for the png library + # + + AC_ARG_WITH(libpng, [AS_HELP_STRING([--with-libpng], + [use libpng from build system or OpenJDK source (system, bundled) @<:@bundled@:>@])]) + + + AC_MSG_CHECKING([for which libpng to use]) + + # default is bundled + DEFAULT_LIBPNG=bundled + + # + # if user didn't specify, use DEFAULT_LIBPNG + # + if test "x${with_libpng}" = "x"; then + with_libpng=${DEFAULT_LIBPNG} + fi + + if test "x${with_libpng}" = "xbundled"; then + USE_EXTERNAL_LIBPNG=false + AC_MSG_RESULT([bundled]) + elif test "x${with_libpng}" = "xsystem"; then + PKG_CHECK_MODULES(PNG, libpng, + [ LIBPNG_FOUND=yes ], + [ LIBPNG_FOUND=no ]) + if test "x${LIBPNG_FOUND}" = "xyes"; then + USE_EXTERNAL_LIBPNG=true + AC_MSG_RESULT([system]) + else + AC_MSG_RESULT([system not found]) + AC_MSG_ERROR([--with-libpng=system specified, but no libpng found!]) + fi + else + AC_MSG_ERROR([Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled']) + fi + AC_SUBST(USE_EXTERNAL_LIBPNG) + ############################################################################### # # Check for the zlib library diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 81dc5a99a81..fe5fb1be8d8 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -254,7 +254,6 @@ BUILD_HOTSPOT=@BUILD_HOTSPOT@ # The boot jdk to use BOOT_JDK:=@BOOT_JDK@ -BOOT_JDK_JVMARGS:=@BOOT_JDK_JVMARGS@ BOOT_RTJAR:=@BOOT_RTJAR@ BOOT_TOOLSJAR=$(BOOT_JDK)/lib/tools.jar @@ -442,8 +441,11 @@ POST_STRIP_CMD:=@POST_STRIP_CMD@ POST_MCS_CMD:=@POST_MCS_CMD@ JAVA_FLAGS:=@JAVA_FLAGS@ +JAVA_FLAGS_BIG:=@JAVA_FLAGS_BIG@ +JAVA_FLAGS_SMALL:=@JAVA_FLAGS_SMALL@ -JAVA=@FIXPATH@ @JAVA@ $(JAVA_FLAGS) +JAVA=@FIXPATH@ @JAVA@ $(JAVA_FLAGS_BIG) $(JAVA_FLAGS) +JAVA_SMALL=@FIXPATH@ @JAVA@ $(JAVA_FLAGS_SMALL) $(JAVA_FLAGS) JAVAC:=@FIXPATH@ @JAVAC@ # Hotspot sets this variable before reading the SPEC when compiling sa-jdi.jar. Avoid @@ -454,7 +456,7 @@ JAVAH:=@FIXPATH@ @JAVAH@ JAR:=@FIXPATH@ @JAR@ -NATIVE2ASCII:=@FIXPATH@ @NATIVE2ASCII@ +NATIVE2ASCII:=@FIXPATH@ @NATIVE2ASCII@ $(addprefix -J, $(JAVA_FLAGS_SMALL)) JARSIGNER:=@FIXPATH@ @JARSIGNER@ @@ -645,6 +647,15 @@ INSTALL_SHAREDSTATEDIR=@sharedstatedir@ # Read-only single-machine data INSTALL_SYSCONFDIR=@sysconfdir@ +#################################################### +# +# Libraries +# + +USE_EXTERNAL_LIBPNG:=@USE_EXTERNAL_LIBPNG@ +PNG_LIBS:=@PNG_LIBS@ +PNG_CFLAGS:=@PNG_CFLAGS@ + #################################################### # diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index 7110d783205..ba57a850219 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -96,8 +96,27 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE], # Use indirect variable referencing toolchain_var_name=VALID_TOOLCHAINS_$OPENJDK_BUILD_OS VALID_TOOLCHAINS=${!toolchain_var_name} - # First toolchain type in the list is the default - DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *} + + if test "x$OPENJDK_TARGET_OS" = xmacosx; then + # On Mac OS X, default toolchain to clang after Xcode 5 + XCODE_VERSION_OUTPUT=`xcodebuild -version 2>&1 | $HEAD -n 1` + $ECHO "$XCODE_VERSION_OUTPUT" | $GREP "Xcode " > /dev/null + if test $? -ne 0; then + AC_MSG_ERROR([Failed to determine Xcode version.]) + fi + XCODE_MAJOR_VERSION=`$ECHO $XCODE_VERSION_OUTPUT | \ + $SED -e 's/^Xcode \(@<:@1-9@:>@@<:@0-9.@:>@*\)/\1/' | \ + $CUT -f 1 -d .` + AC_MSG_NOTICE([Xcode major version: $XCODE_MAJOR_VERSION]) + if test $XCODE_MAJOR_VERSION -ge 5; then + DEFAULT_TOOLCHAIN="clang" + else + DEFAULT_TOOLCHAIN="gcc" + fi + else + # First toolchain type in the list is the default + DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *} + fi if test "x$with_toolchain_type" = xlist; then # List all toolchains diff --git a/corba/.hgtags b/corba/.hgtags index 13a64cfd8b1..ab5e3f09588 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -246,3 +246,5 @@ a7d3638deb2f4e33217b1ecf889479e90f9e5b50 jdk9-b00 79a8136b18c1c6848f500088f5a4b39f262f082d jdk9-b01 8394993063135a42b63a94473280399fb2a13aa7 jdk9-b02 d338b892a13db19b093f85cf5f949a4504e4d31f jdk9-b03 +1ed19de263e1e0772da0269118cdd9deeb9fff04 jdk9-b04 +167c39eb44731a5d66770d0f00e231164653a2ff jdk9-b05 diff --git a/corba/make/CompileCorba.gmk b/corba/make/CompileCorba.gmk index f50d4ca4687..225258c2080 100644 --- a/corba/make/CompileCorba.gmk +++ b/corba/make/CompileCorba.gmk @@ -45,16 +45,18 @@ $(eval $(call SetupJavaCompilation,BUILD_CORBA, \ org/omg/PortableInterceptor/UNKNOWN.java \ com/sun/tools/corba/se/idl/ResourceBundleUtil.java \ com/sun/corba/se/impl/presentation/rmi/jndi.properties, \ - COPY := .prp LogStrings.properties, \ + COPY := .prp, \ + CLEAN := .properties, \ BIN := $(CORBA_OUTPUTDIR)/classes, \ JAR := $(CORBA_OUTPUTDIR)/dist/lib/classes.jar)) +# For the interim version, don't bother cleaning the properties. $(eval $(call SetupJavaCompilation,BUILD_INTERIM_CORBA, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := $(BUILD_CORBA_SRC), \ EXCLUDES := $(BUILD_CORBA_EXCLUDES), \ EXCLUDE_FILES := $(BUILD_CORBA_EXCLUDE_FILES), \ - COPY := $(BUILD_CORBA_COPY), \ + COPY := $(BUILD_CORBA_COPY) $(BUILD_CORBA_CLEAN), \ BIN := $(CORBA_OUTPUTDIR)/interim_classes, \ JAR := $(INTERIM_CORBA_JAR))) @@ -63,7 +65,6 @@ $(eval $(call SetupJavaCompilation,BUILD_INTERIM_CORBA, \ $(eval $(call SetupZipArchive,ARCHIVE_CORBA_SRC, \ SRC := $(CORBA_TOPDIR)/src/share/classes $(CORBA_OUTPUTDIR)/gensrc, \ ZIP := $(CORBA_OUTPUTDIR)/dist/lib/src.zip)) - JAR := $(CORBA_OUTPUTDIR)/dist/lib/classes.jar)) ################################################################################ # Create bin.zip containing the corba specific binaries: orb.idl, ir.idl @@ -81,6 +82,5 @@ $(CORBA_OUTPUTDIR)/dist/lib/bin.zip: $(BIN_FILES) ################################################################################ - all: $(BUILD_CORBA) $(BUILD_INTERIM_CORBA) $(ARCHIVE_CORBA_SRC) \ $(CORBA_OUTPUTDIR)/dist/lib/bin.zip diff --git a/corba/make/GensrcCorba.gmk b/corba/make/GensrcCorba.gmk index 8dbf5102eda..4d078a56bb2 100644 --- a/corba/make/GensrcCorba.gmk +++ b/corba/make/GensrcCorba.gmk @@ -39,9 +39,6 @@ $(eval $(call SetupJavaCompilation,BUILD_TOOLS, \ SRC := $(CORBA_TOPDIR)/make/src/classes, \ BIN := $(CORBA_OUTPUTDIR)/tools_classes)) -TOOL_STRIPPROP_CMD := $(JAVA) -cp $(CORBA_OUTPUTDIR)/tools_classes \ - build.tools.stripproperties.StripPropertiesCorba - TOOL_LOGUTIL_CMD := $(JAVA) -cp $(CORBA_OUTPUTDIR)/tools_classes \ build.tools.logutil.MC @@ -230,27 +227,14 @@ $(eval $(call SetupIdlCompilation,BUILD_IDLS, \ $(BUILD_IDLS): $(BUILD_IDLJ) ################################################################################ -# Run stripproperties on all sunorb resource files. +# zh_HK is just a copy of zh_TW -STRIP_PROP_SRC_FILES := $(shell $(FIND) $(CORBA_TOPDIR)/src/share/classes -name "sunorb*.properties") -STRIP_PROP_FILES := $(patsubst $(CORBA_TOPDIR)/src/share/classes/%, $(CORBA_OUTPUTDIR)/classes/%, \ - $(STRIP_PROP_SRC_FILES)) -# Simple delivery of zh_HK properties files just copies zh_TW properties files -STRIP_PROP_SRC_FILE_ZH_TW := $(shell $(FIND) $(CORBA_TOPDIR)/src/share/classes -name "sunorb_zh_TW.properties") -STRIP_PROP_SRC_FILES += $(STRIP_PROP_SRC_FILE_ZH_TW) -STRIP_PROP_FILES += $(patsubst $(CORBA_TOPDIR)/src/share/classes/%_zh_TW.properties, \ - $(CORBA_OUTPUTDIR)/classes/%_zh_HK.properties, $(STRIP_PROP_SRC_FILE_ZH_TW)) -STRIP_PROP_CMDLINE := $(subst _SPACE_, $(SPACE), \ - $(join $(addprefix -clean_SPACE_, $(STRIP_PROP_SRC_FILES)), \ - $(addprefix _SPACE_, $(STRIP_PROP_FILES)))) - -$(CORBA_OUTPUTDIR)/_the.stripped_properties: $(STRIP_PROP_SRC_FILES) \ - $(BUILD_TOOLS) - $(MKDIR) -p $(sort $(dir $(STRIP_PROP_FILES))) - $(call ListPathsSafely,STRIP_PROP_CMDLINE,\n, >> $(CORBA_OUTPUTDIR)/_the.strip_prop.cmdline) - $(TOOL_STRIPPROP_CMD) @$(CORBA_OUTPUTDIR)/_the.strip_prop.cmdline - $(TOUCH) $@ +$(CORBA_OUTPUTDIR)/gensrc/com/sun/corba/se/impl/orbutil/resources/sunorb_zh_HK.properties: \ + $(CORBA_TOPDIR)/src/share/classes/com/sun/corba/se/impl/orbutil/resources/sunorb_zh_TW.properties + $(install-file) ################################################################################ -all: $(BUILD_IDLS) $(CORBA_OUTPUTDIR)/_the.stripped_properties $(LOGWRAPPER_TARGETS) +all: $(BUILD_IDLS) $(LOGWRAPPER_TARGETS) \ + $(CORBA_OUTPUTDIR)/gensrc/com/sun/corba/se/impl/orbutil/resources/sunorb_zh_HK.properties + diff --git a/corba/make/src/classes/build/tools/stripproperties/StripPropertiesCorba.java b/corba/make/src/classes/build/tools/stripproperties/StripPropertiesCorba.java deleted file mode 100644 index b5c7ecb253b..00000000000 --- a/corba/make/src/classes/build/tools/stripproperties/StripPropertiesCorba.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2001, 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 build.tools.stripproperties; - -import java.io.BufferedInputStream; -import java.io.BufferedWriter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.Properties; - -/** - * Reads a properties file from standard input and writes an equivalent - * properties file without comments to standard output. - */ -public class StripPropertiesCorba { - - private static void error(String msg, Exception e) { - System.err.println("ERROR: stripproperties: " + msg); - if ( e != null ) { - System.err.println("EXCEPTION: " + e.toString()); - e.printStackTrace(); - } - } - - private static List infiles = new ArrayList(); - private static List outfiles = new ArrayList(); - - private static boolean parseOptions(String args[]) { - boolean ok = true; - - for ( int i = 0; i < args.length ; i++ ) { - if ( "-clean".equals(args[i]) && i+2 < args.length ) { - infiles.add(args[++i]); - outfiles.add(args[++i]); - } else if ( args[i].charAt(0)=='@') { - String filename = args[i].substring(1); - FileInputStream finput = null; - byte contents[] = null; - try { - finput = new FileInputStream(filename); - int byteCount = finput.available(); - if ( byteCount <= 0 ) { - error("The @file is empty", null); - ok = false; - } else { - contents = new byte[byteCount]; - int bytesRead = finput.read(contents); - if ( byteCount != bytesRead ) { - error("Cannot read all of @file", null); - ok = false; - } - } - } catch ( IOException e ) { - error("cannot open " + filename, e); - ok = false; - } - if ( finput != null ) { - try { - finput.close(); - } catch ( IOException e ) { - ok = false; - error("cannot close " + filename, e); - } - } - if ( ok && contents != null ) { - String tokens[] = (new String(contents)).split("\\s+"); - if ( tokens.length > 0 ) { - ok = parseOptions(tokens); - } - } - if ( !ok ) { - break; - } - } else { - infiles.add(args[i]); - outfiles.add(args[i]); - } - } - return ok; - } - - private static boolean stripFiles(List infiles, List outfiles) { - boolean ok = true; - Iterator inIter = infiles.iterator(); - Iterator outIter = outfiles.iterator(); - - for (; inIter.hasNext(); ) { - String infile = inIter.next(); - String outfile = outIter.next(); - - Properties prop = new Properties(); - InputStream in = null; - try { - in = new BufferedInputStream(new FileInputStream(infile)); - prop.load(in); - } catch ( FileNotFoundException e ) { - error("Cannot access file " + infile, e); - ok = false; - } catch ( IOException e ) { - error("IO exception processing file " + infile, e); - ok = false; - } - if ( in != null ) { - try { - in.close(); - } catch ( IOException e ) { - error("IO exception closing file " + infile, e); - ok = false; - } - } - if ( !ok ) { - break; - } - - OutputStream out = null; - try { - out = new FileOutputStream(outfile); - storeProperties(prop, out); - out.flush(); - } catch ( IOException e ) { - error("IO exception processing file " + outfile, e); - ok = false; - } - if ( out != null ) { - try { - out.close(); - } catch ( IOException e ) { - error("IO exception closing file " + outfile, e); - ok = false; - } - } - if ( !ok ) { - break; - } - - } - return ok; - } - - /** - * Strip the properties filenames supplied, replacing their contents. - * @param args Names of properties files to process and replace contents - */ - public static void main(String args[]) { - boolean ok = parseOptions(args); - if ( !ok || !stripFiles(infiles, outfiles) ) { - System.exit(1); - } - } - - // --- code below here is adapted from java.util.Properties --- - - private static final String specialSaveChars = "=: \t\r\n\f#!"; - - /* - * Converts unicodes to encoded \uxxxx - * and writes out any of the characters in specialSaveChars - * with a preceding slash - */ - private static String saveConvert(String theString, boolean escapeSpace) { - int len = theString.length(); - StringBuffer outBuffer = new StringBuffer(len*2); - - for(int x=0; x 0x00ff)) { - outBuffer.append('\\'); - outBuffer.append('u'); - outBuffer.append(toHex((aChar >> 12) & 0xF)); - outBuffer.append(toHex((aChar >> 8) & 0xF)); - outBuffer.append(toHex((aChar >> 4) & 0xF)); - outBuffer.append(toHex( aChar & 0xF)); - } else { - if (specialSaveChars.indexOf(aChar) != -1) { - outBuffer.append('\\'); - } - outBuffer.append(aChar); - } - } - } - return outBuffer.toString(); - } - - /** - * Writes the content of properties to out. - * The format is that of Properties.store with the following modifications: - *
    - *
  • No header or date is written - *
  • Latin-1 characters are written as single bytes, not escape sequences - *
  • Line breaks are indicated by a single \n independent of platform - *
      - */ - private static void storeProperties(Properties properties, OutputStream out) - throws IOException { - BufferedWriter awriter; - awriter = new BufferedWriter(new OutputStreamWriter(out, "8859_1")); - for (Enumeration e = properties.keys(); e.hasMoreElements();) { - String key = (String)e.nextElement(); - String val = (String)properties.get(key); - key = saveConvert(key, true); - - /* No need to escape embedded and trailing spaces for value, hence - * pass false to flag. - */ - val = saveConvert(val, false); - writeln(awriter, key + "=" + val); - } - awriter.flush(); - } - - private static void writeln(BufferedWriter bw, String s) throws IOException { - bw.write(s); - bw.write("\n"); - } - - /** - * Convert a nibble to a hex character - * @param nibble the nibble to convert. - */ - private static char toHex(int nibble) { - return hexDigit[(nibble & 0xF)]; - } - - /** A table of hex digits */ - private static final char[] hexDigit = { - '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' - }; -} diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 71ad9311d10..880948aef94 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -406,3 +406,5 @@ ce2d7e46f3c7e41241f3b407705a4071323a11ab jdk9-b00 050a626a88951140df874f7b163e304d07b6c296 jdk9-b01 b188446de75bda5fc52d102cddf242c3ef5ecbdf jdk9-b02 b2fee789d23f3cdabb3db4e51af43038e5692d3a jdk9-b03 +3812c088b9456ee22c933e88aee1ece71f4e783a jdk9-b04 +bdc5311e1db7598589b77015119b821bf8c828bd jdk9-b05 diff --git a/hotspot/make/aix/Makefile b/hotspot/make/aix/Makefile index 19bab5494bc..79bcf7880ac 100644 --- a/hotspot/make/aix/Makefile +++ b/hotspot/make/aix/Makefile @@ -70,6 +70,10 @@ ifndef CC_INTERP FORCE_TIERED=1 endif endif +# C1 is not ported on ppc64(le), so we cannot build a tiered VM: +ifneq (,$(filter $(ARCH),ppc64 pp64le)) + FORCE_TIERED=0 +endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","") diff --git a/hotspot/make/aix/makefiles/adjust-mflags.sh b/hotspot/make/aix/makefiles/adjust-mflags.sh index df1aa625b77..6c06819fb74 100644 --- a/hotspot/make/aix/makefiles/adjust-mflags.sh +++ b/hotspot/make/aix/makefiles/adjust-mflags.sh @@ -1,6 +1,6 @@ #! /bin/sh # -# 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 @@ -64,7 +64,7 @@ MFLAGS=` echo "$MFLAGS" \ | sed ' s/^-/ -/ - s/ -\([^ ][^ ]*\)j/ -\1 -j/ + s/ -\([^ I][^ I]*\)j/ -\1 -j/ s/ -j[0-9][0-9]*/ -j/ s/ -j\([^ ]\)/ -j -\1/ s/ -j/ -j'${HOTSPOT_BUILD_JOBS:-${default_build_jobs}}'/ diff --git a/hotspot/make/bsd/makefiles/gcc.make b/hotspot/make/bsd/makefiles/gcc.make index 9c9cef07f82..2a0eab17ef9 100644 --- a/hotspot/make/bsd/makefiles/gcc.make +++ b/hotspot/make/bsd/makefiles/gcc.make @@ -260,7 +260,7 @@ ifeq ($(USE_CLANG), true) WARNINGS_ARE_ERRORS += -Wno-empty-body endif -WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wformat=2 -Wno-error=format-nonliteral +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wformat=2 ifeq ($(USE_CLANG),) # Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index 0820c254612..8321f8e15db 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -66,6 +66,10 @@ ifndef CC_INTERP FORCE_TIERED=1 endif endif +# C1 is not ported on ppc64(le), so we cannot build a tiered VM: +ifneq (,$(filter $(ARCH),ppc64 pp64le)) + FORCE_TIERED=0 +endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","") diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index 071c36e5876..87ef16faed8 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -215,7 +215,7 @@ ifeq ($(USE_CLANG), true) WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body endif -WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wunused-value -Wformat=2 -Wno-error=format-nonliteral +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wunused-value -Wformat=2 ifeq ($(USE_CLANG),) # Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit diff --git a/hotspot/make/linux/makefiles/zeroshark.make b/hotspot/make/linux/makefiles/zeroshark.make index 890a0910e7f..3c10770d42a 100644 --- a/hotspot/make/linux/makefiles/zeroshark.make +++ b/hotspot/make/linux/makefiles/zeroshark.make @@ -25,6 +25,9 @@ # Setup common to Zero (non-Shark) and Shark versions of VM +# override this from the main file because some version of llvm do not like -Wundef +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wunused-function -Wunused-value + # The copied fdlibm routines in sharedRuntimeTrig.o must not be optimized OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT) # The copied fdlibm routines in sharedRuntimeTrans.o must not be optimized diff --git a/hotspot/make/solaris/makefiles/gcc.make b/hotspot/make/solaris/makefiles/gcc.make index 627691c78f3..94778592ece 100644 --- a/hotspot/make/solaris/makefiles/gcc.make +++ b/hotspot/make/solaris/makefiles/gcc.make @@ -118,7 +118,7 @@ endif # Compiler warnings are treated as errors WARNINGS_ARE_ERRORS = -Werror # Enable these warnings. See 'info gcc' about details on these options -WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef -Wformat=2 -Wno-error=format-nonliteral +WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef -Wformat=2 CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp index b0519a63b08..56b0b92db73 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp @@ -124,6 +124,7 @@ class Argument VALUE_OBJ_CLASS_SPEC { } }; +#if !defined(ABI_ELFv2) // A ppc64 function descriptor. struct FunctionDescriptor VALUE_OBJ_CLASS_SPEC { private: @@ -161,6 +162,7 @@ struct FunctionDescriptor VALUE_OBJ_CLASS_SPEC { _env = (address) 0xbad; } }; +#endif class Assembler : public AbstractAssembler { protected: @@ -1067,6 +1069,7 @@ class Assembler : public AbstractAssembler { // Emit an address. inline address emit_addr(const address addr = NULL); +#if !defined(ABI_ELFv2) // Emit a function descriptor with the specified entry point, TOC, // and ENV. If the entry point is NULL, the descriptor will point // just past the descriptor. @@ -1074,6 +1077,7 @@ class Assembler : public AbstractAssembler { inline address emit_fd(address entry = NULL, address toc = (address) FunctionDescriptor::friend_toc, address env = (address) FunctionDescriptor::friend_env); +#endif ///////////////////////////////////////////////////////////////////////////////////// // PPC instructions diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp index 200aaf11aed..d96d9204dbc 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp @@ -55,6 +55,7 @@ inline address Assembler::emit_addr(const address addr) { return start; } +#if !defined(ABI_ELFv2) // Emit a function descriptor with the specified entry point, TOC, and // ENV. If the entry point is NULL, the descriptor will point just // past the descriptor. @@ -73,6 +74,7 @@ inline address Assembler::emit_fd(address entry, address toc, address env) { return (address)fd; } +#endif // Issue an illegal instruction. 0 is guaranteed to be an illegal instruction. inline void Assembler::illtrap() { Assembler::emit_int32(0); } diff --git a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp index c9853c589cc..5cf5a6a6573 100644 --- a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp @@ -1136,7 +1136,9 @@ address CppInterpreterGenerator::generate_native_entry(void) { // (outgoing C args), R3_ARG1 to R10_ARG8, and F1_ARG1 to // F13_ARG13. __ mr(R3_ARG1, R18_locals); +#if !defined(ABI_ELFv2) __ ld(signature_handler_fd, 0, signature_handler_fd); +#endif __ call_stub(signature_handler_fd); // reload method __ ld(R19_method, state_(_method)); @@ -1295,8 +1297,13 @@ address CppInterpreterGenerator::generate_native_entry(void) { // native result acrosss the call. No oop is present __ mr(R3_ARG1, R16_thread); +#if defined(ABI_ELFv2) + __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), + relocInfo::none); +#else __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans), relocInfo::none); +#endif __ bind(sync_check_done); //============================================================================= @@ -1346,9 +1353,9 @@ address CppInterpreterGenerator::generate_native_entry(void) { // notify here, we'll drop it on the floor. __ notify_method_exit(true/*native method*/, - ilgl /*illegal state (not used for native methods)*/); - - + ilgl /*illegal state (not used for native methods)*/, + InterpreterMacroAssembler::NotifyJVMTI, + false /*check_exceptions*/); //============================================================================= // Handle exceptions @@ -1413,7 +1420,7 @@ address CppInterpreterGenerator::generate_native_entry(void) { // First, pop to caller's frame. __ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2); - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // Get the address of the exception handler. __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, @@ -2545,7 +2552,7 @@ address CppInterpreterGenerator::generate_normal_entry(void) { __ mr(R4_ARG2, R3_ARG1); // ARG2 := ARG1 // Find the address of the "catch_exception" stub. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, R4_ARG2); diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp index 1cd2c6a0a5b..6df316d1b87 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2000, 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 @@ -42,10 +42,6 @@ #include "runtime/vframeArray.hpp" #endif -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC64" -#endif - #ifdef ASSERT void RegisterMap::check_location_valid() { } @@ -89,7 +85,10 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const { frame frame::sender_for_interpreter_frame(RegisterMap *map) const { // Pass callers initial_caller_sp as unextended_sp. - return frame(sender_sp(), sender_pc(), (intptr_t*)((parent_ijava_frame_abi *)callers_abi())->initial_caller_sp); + return frame(sender_sp(), sender_pc(), + CC_INTERP_ONLY((intptr_t*)((parent_ijava_frame_abi *)callers_abi())->initial_caller_sp) + NOT_CC_INTERP((intptr_t*)get_ijava_state()->sender_sp) + ); } frame frame::sender_for_compiled_frame(RegisterMap *map) const { @@ -183,6 +182,9 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) interpreterState istate = get_interpreterState(); address lresult = (address)istate + in_bytes(BytecodeInterpreter::native_lresult_offset()); address fresult = (address)istate + in_bytes(BytecodeInterpreter::native_fresult_offset()); +#else + address lresult = (address)&(get_ijava_state()->lresult); + address fresult = (address)&(get_ijava_state()->fresult); #endif switch (method->result_type()) { @@ -259,7 +261,21 @@ void frame::describe_pd(FrameValues& values, int frame_no) { values.describe(frame_no, (intptr_t*)&(istate->_native_fresult), " native_fresult"); values.describe(frame_no, (intptr_t*)&(istate->_native_lresult), " native_lresult"); #else - Unimplemented(); +#define DESCRIBE_ADDRESS(name) \ + values.describe(frame_no, (intptr_t*)&(get_ijava_state()->name), #name); + + DESCRIBE_ADDRESS(method); + DESCRIBE_ADDRESS(locals); + DESCRIBE_ADDRESS(monitors); + DESCRIBE_ADDRESS(cpoolCache); + DESCRIBE_ADDRESS(bcp); + DESCRIBE_ADDRESS(esp); + DESCRIBE_ADDRESS(mdx); + DESCRIBE_ADDRESS(top_frame_sp); + DESCRIBE_ADDRESS(sender_sp); + DESCRIBE_ADDRESS(oop_tmp); + DESCRIBE_ADDRESS(lresult); + DESCRIBE_ADDRESS(fresult); #endif } } diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp index 26321baeb89..f327d2ce424 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 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 @@ -29,10 +29,6 @@ #include "runtime/synchronizer.hpp" #include "utilities/top.hpp" -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC64" -#endif - // C frame layout on PPC-64. // // In this figure the stack grows upwards, while memory grows @@ -50,7 +46,7 @@ // [C_FRAME] // // C_FRAME: - // 0 [ABI_112] + // 0 [ABI_REG_ARGS] // 112 CARG_9: outgoing arg 9 (arg_1 ... arg_8 via gpr_3 ... gpr_{10}) // ... // 40+M*8 CARG_M: outgoing arg M (M is the maximum of outgoing args taken over all call sites in the procedure) @@ -77,7 +73,7 @@ // 32 reserved // 40 space for TOC (=R2) register for next call // - // ABI_112: + // ABI_REG_ARGS: // 0 [ABI_48] // 48 CARG_1: spill slot for outgoing arg 1. used by next callee. // ... ... @@ -95,23 +91,25 @@ log_2_of_alignment_in_bits = 7 }; - // ABI_48: - struct abi_48 { + // ABI_MINFRAME: + struct abi_minframe { uint64_t callers_sp; uint64_t cr; //_16 uint64_t lr; +#if !defined(ABI_ELFv2) uint64_t reserved1; //_16 uint64_t reserved2; +#endif uint64_t toc; //_16 // nothing to add here! // aligned to frame::alignment_in_bytes (16) }; enum { - abi_48_size = sizeof(abi_48) + abi_minframe_size = sizeof(abi_minframe) }; - struct abi_112 : abi_48 { + struct abi_reg_args : abi_minframe { uint64_t carg_1; uint64_t carg_2; //_16 uint64_t carg_3; @@ -124,13 +122,13 @@ }; enum { - abi_112_size = sizeof(abi_112) + abi_reg_args_size = sizeof(abi_reg_args) }; #define _abi(_component) \ - (offset_of(frame::abi_112, _component)) + (offset_of(frame::abi_reg_args, _component)) - struct abi_112_spill : abi_112 { + struct abi_reg_args_spill : abi_reg_args { // additional spill slots uint64_t spill_ret; uint64_t spill_fret; //_16 @@ -138,11 +136,11 @@ }; enum { - abi_112_spill_size = sizeof(abi_112_spill) + abi_reg_args_spill_size = sizeof(abi_reg_args_spill) }; - #define _abi_112_spill(_component) \ - (offset_of(frame::abi_112_spill, _component)) + #define _abi_reg_args_spill(_component) \ + (offset_of(frame::abi_reg_args_spill, _component)) // non-volatile GPRs: @@ -195,7 +193,85 @@ #define _spill_nonvolatiles_neg(_component) \ (int)(-frame::spill_nonvolatiles_size + offset_of(frame::spill_nonvolatiles, _component)) - // Frame layout for the Java interpreter on PPC64. + + +#ifndef CC_INTERP + // Frame layout for the Java template interpreter on PPC64. + // + // Diffs to the CC_INTERP are marked with 'X'. + // + // TOP_IJAVA_FRAME: + // + // 0 [TOP_IJAVA_FRAME_ABI] + // alignment (optional) + // [operand stack] + // [monitors] (optional) + // X[IJAVA_STATE] + // note: own locals are located in the caller frame. + // + // PARENT_IJAVA_FRAME: + // + // 0 [PARENT_IJAVA_FRAME_ABI] + // alignment (optional) + // [callee's Java result] + // [callee's locals w/o arguments] + // [outgoing arguments] + // [used part of operand stack w/o arguments] + // [monitors] (optional) + // X[IJAVA_STATE] + // + + struct parent_ijava_frame_abi : abi_minframe { + }; + + enum { + parent_ijava_frame_abi_size = sizeof(parent_ijava_frame_abi) + }; + +#define _parent_ijava_frame_abi(_component) \ + (offset_of(frame::parent_ijava_frame_abi, _component)) + + struct top_ijava_frame_abi : abi_reg_args { + }; + + enum { + top_ijava_frame_abi_size = sizeof(top_ijava_frame_abi) + }; + +#define _top_ijava_frame_abi(_component) \ + (offset_of(frame::top_ijava_frame_abi, _component)) + + struct ijava_state { +#ifdef ASSERT + uint64_t ijava_reserved; // Used for assertion. + uint64_t ijava_reserved2; // Inserted for alignment. +#endif + uint64_t method; + uint64_t locals; + uint64_t monitors; + uint64_t cpoolCache; + uint64_t bcp; + uint64_t esp; + uint64_t mdx; + uint64_t top_frame_sp; // Maybe define parent_frame_abi and move there. + uint64_t sender_sp; + // Slots only needed for native calls. Maybe better to move elsewhere. + uint64_t oop_tmp; + uint64_t lresult; + uint64_t fresult; + // Aligned to frame::alignment_in_bytes (16). + }; + + enum { + ijava_state_size = sizeof(ijava_state) + }; + +#define _ijava_state_neg(_component) \ + (int) (-frame::ijava_state_size + offset_of(frame::ijava_state, _component)) + +#else // CC_INTERP: + + // Frame layout for the Java C++ interpreter on PPC64. // // This frame layout provides a C-like frame for every Java frame. // @@ -242,7 +318,7 @@ // [ENTRY_FRAME_LOCALS] // // PARENT_IJAVA_FRAME_ABI: - // 0 [ABI_48] + // 0 [ABI_MINFRAME] // top_frame_sp // initial_caller_sp // @@ -258,7 +334,7 @@ // PARENT_IJAVA_FRAME_ABI - struct parent_ijava_frame_abi : abi_48 { + struct parent_ijava_frame_abi : abi_minframe { // SOE registers. // C2i adapters spill their top-frame stack-pointer here. uint64_t top_frame_sp; // carg_1 @@ -285,7 +361,7 @@ uint64_t carg_6_unused; //_16 carg_6 uint64_t carg_7_unused; // carg_7 // Use arg8 for storing frame_manager_lr. The size of - // top_ijava_frame_abi must match abi_112. + // top_ijava_frame_abi must match abi_reg_args. uint64_t frame_manager_lr; //_16 carg_8 // nothing to add here! // aligned to frame::alignment_in_bytes (16) @@ -298,6 +374,8 @@ #define _top_ijava_frame_abi(_component) \ (offset_of(frame::top_ijava_frame_abi, _component)) +#endif // CC_INTERP + // ENTRY_FRAME struct entry_frame_locals { @@ -395,8 +473,8 @@ intptr_t* fp() const { return _fp; } // Accessors for ABIs - inline abi_48* own_abi() const { return (abi_48*) _sp; } - inline abi_48* callers_abi() const { return (abi_48*) _fp; } + inline abi_minframe* own_abi() const { return (abi_minframe*) _sp; } + inline abi_minframe* callers_abi() const { return (abi_minframe*) _fp; } private: @@ -421,6 +499,14 @@ #ifdef CC_INTERP // Additional interface for interpreter frames: inline interpreterState get_interpreterState() const; +#else + inline ijava_state* get_ijava_state() const; + // Some convenient register frame setters/getters for deoptimization. + inline intptr_t* interpreter_frame_esp() const; + inline void interpreter_frame_set_cpcache(ConstantPoolCache* cp); + inline void interpreter_frame_set_esp(intptr_t* esp); + inline void interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp); + inline void interpreter_frame_set_sender_sp(intptr_t* sender_sp); #endif // CC_INTERP // Size of a monitor in bytes. diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp index 2dadd6c69eb..8e46363eac9 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.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 @@ -26,10 +26,6 @@ #ifndef CPU_PPC_VM_FRAME_PPC_INLINE_HPP #define CPU_PPC_VM_FRAME_PPC_INLINE_HPP -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC64" -#endif - // Inline functions for ppc64 frames: // Find codeblob and set deopt_state. @@ -199,6 +195,75 @@ inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const { interpreterState istate = get_interpreterState(); return &istate->_constants; } + +#else // !CC_INTERP + +// Template Interpreter frame value accessors. + +inline frame::ijava_state* frame::get_ijava_state() const { + return (ijava_state*) ((uintptr_t)fp() - ijava_state_size); +} + +inline intptr_t** frame::interpreter_frame_locals_addr() const { + return (intptr_t**) &(get_ijava_state()->locals); +} +inline intptr_t* frame::interpreter_frame_bcx_addr() const { + return (intptr_t*) &(get_ijava_state()->bcp); +} +inline intptr_t* frame::interpreter_frame_mdx_addr() const { + return (intptr_t*) &(get_ijava_state()->mdx); +} +// Pointer beyond the "oldest/deepest" BasicObjectLock on stack. +inline BasicObjectLock* frame::interpreter_frame_monitor_end() const { + return (BasicObjectLock *) get_ijava_state()->monitors; +} + +inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const { + return (BasicObjectLock *) get_ijava_state(); +} + +// SAPJVM ASc 2012-11-21. Return register stack slot addr at which currently interpreted method is found +inline Method** frame::interpreter_frame_method_addr() const { + return (Method**) &(get_ijava_state()->method); +} +inline ConstantPoolCache** frame::interpreter_frame_cpoolcache_addr() const { + return (ConstantPoolCache**) &(get_ijava_state()->cpoolCache); +} +inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const { + return (ConstantPoolCache**) &(get_ijava_state()->cpoolCache); +} + +inline oop* frame::interpreter_frame_temp_oop_addr() const { + return (oop *) &(get_ijava_state()->oop_tmp); +} +inline intptr_t* frame::interpreter_frame_esp() const { + return (intptr_t*) get_ijava_state()->esp; +} + +// Convenient setters +inline void frame::interpreter_frame_set_monitor_end(BasicObjectLock* end) { get_ijava_state()->monitors = (intptr_t) end;} +inline void frame::interpreter_frame_set_cpcache(ConstantPoolCache* cp) { *frame::interpreter_frame_cpoolcache_addr() = cp; } +inline void frame::interpreter_frame_set_esp(intptr_t* esp) { get_ijava_state()->esp = (intptr_t) esp; } +inline void frame::interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp) { get_ijava_state()->top_frame_sp = (intptr_t) top_frame_sp; } +inline void frame::interpreter_frame_set_sender_sp(intptr_t* sender_sp) { get_ijava_state()->sender_sp = (intptr_t) sender_sp; } + +inline intptr_t* frame::interpreter_frame_expression_stack() const { + return (intptr_t*)interpreter_frame_monitor_end() - 1; +} + +inline jint frame::interpreter_frame_expression_stack_direction() { + return -1; +} + +// top of expression stack +inline intptr_t* frame::interpreter_frame_tos_address() const { + return ((intptr_t*) get_ijava_state()->esp) + Interpreter::stackElementWords; +} + +inline intptr_t* frame::interpreter_frame_tos_at(jint offset) const { + return &interpreter_frame_tos_address()[offset]; +} + #endif // CC_INTERP inline int frame::interpreter_frame_monitor_size() { diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp index 5d135199b7e..f71acaca095 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 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 @@ -29,6 +29,7 @@ #include "asm/macroAssembler.inline.hpp" #include "interp_masm_ppc_64.hpp" #include "interpreter/interpreterRuntime.hpp" +#include "prims/jvmtiThreadState.hpp" #ifdef PRODUCT #define BLOCK_COMMENT(str) // nothing @@ -45,6 +46,691 @@ void InterpreterMacroAssembler::null_check_throw(Register a, int offset, Registe MacroAssembler::null_check_throw(a, offset, temp_reg, exception_entry); } +void InterpreterMacroAssembler::branch_to_entry(address entry, Register Rscratch) { + assert(entry, "Entry must have been generated by now"); + if (is_within_range_of_b(entry, pc())) { + b(entry); + } else { + load_const_optimized(Rscratch, entry, R0); + mtctr(Rscratch); + bctr(); + } +} + +#ifndef CC_INTERP + +void InterpreterMacroAssembler::dispatch_next(TosState state, int bcp_incr) { + Register bytecode = R12_scratch2; + if (bcp_incr != 0) { + lbzu(bytecode, bcp_incr, R14_bcp); + } else { + lbz(bytecode, 0, R14_bcp); + } + + dispatch_Lbyte_code(state, bytecode, Interpreter::dispatch_table(state)); +} + +void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { + // Load current bytecode. + Register bytecode = R12_scratch2; + lbz(bytecode, 0, R14_bcp); + dispatch_Lbyte_code(state, bytecode, table); +} + +// Dispatch code executed in the prolog of a bytecode which does not do it's +// own dispatch. The dispatch address is computed and placed in R24_dispatch_addr. +void InterpreterMacroAssembler::dispatch_prolog(TosState state, int bcp_incr) { + Register bytecode = R12_scratch2; + lbz(bytecode, bcp_incr, R14_bcp); + + load_dispatch_table(R24_dispatch_addr, Interpreter::dispatch_table(state)); + + sldi(bytecode, bytecode, LogBytesPerWord); + ldx(R24_dispatch_addr, R24_dispatch_addr, bytecode); +} + +// Dispatch code executed in the epilog of a bytecode which does not do it's +// own dispatch. The dispatch address in R24_dispatch_addr is used for the +// dispatch. +void InterpreterMacroAssembler::dispatch_epilog(TosState state, int bcp_incr) { + mtctr(R24_dispatch_addr); + addi(R14_bcp, R14_bcp, bcp_incr); + bctr(); +} + +void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) { + assert(scratch_reg != R0, "can't use R0 as scratch_reg here"); + if (JvmtiExport::can_pop_frame()) { + Label L; + + // Check the "pending popframe condition" flag in the current thread. + lwz(scratch_reg, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + + // Initiate popframe handling only if it is not already being + // processed. If the flag has the popframe_processing bit set, it + // means that this code is called *during* popframe handling - we + // don't want to reenter. + andi_(R0, scratch_reg, JavaThread::popframe_pending_bit); + beq(CCR0, L); + + andi_(R0, scratch_reg, JavaThread::popframe_processing_bit); + bne(CCR0, L); + + // Call the Interpreter::remove_activation_preserving_args_entry() + // func to get the address of the same-named entrypoint in the + // generated interpreter code. + call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, + Interpreter::remove_activation_preserving_args_entry), + relocInfo::none); + + // Jump to Interpreter::_remove_activation_preserving_args_entry. + mtctr(R3_RET); + bctr(); + + align(32, 12); + bind(L); + } +} + +void InterpreterMacroAssembler::check_and_handle_earlyret(Register scratch_reg) { + const Register Rthr_state_addr = scratch_reg; + if (JvmtiExport::can_force_early_return()) { + Label Lno_early_ret; + ld(Rthr_state_addr, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread); + cmpdi(CCR0, Rthr_state_addr, 0); + beq(CCR0, Lno_early_ret); + + lwz(R0, in_bytes(JvmtiThreadState::earlyret_state_offset()), Rthr_state_addr); + cmpwi(CCR0, R0, JvmtiThreadState::earlyret_pending); + bne(CCR0, Lno_early_ret); + + // Jump to Interpreter::_earlyret_entry. + lwz(R3_ARG1, in_bytes(JvmtiThreadState::earlyret_tos_offset()), Rthr_state_addr); + call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry)); + mtlr(R3_RET); + blr(); + + align(32, 12); + bind(Lno_early_ret); + } +} + +void InterpreterMacroAssembler::load_earlyret_value(TosState state, Register Rscratch1) { + const Register RjvmtiState = Rscratch1; + const Register Rscratch2 = R0; + + ld(RjvmtiState, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread); + li(Rscratch2, 0); + + switch (state) { + case atos: ld(R17_tos, in_bytes(JvmtiThreadState::earlyret_oop_offset()), RjvmtiState); + std(Rscratch2, in_bytes(JvmtiThreadState::earlyret_oop_offset()), RjvmtiState); + break; + case ltos: ld(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + break; + case btos: // fall through + case ctos: // fall through + case stos: // fall through + case itos: lwz(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + break; + case ftos: lfs(F15_ftos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + break; + case dtos: lfd(F15_ftos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + break; + case vtos: break; + default : ShouldNotReachHere(); + } + + // Clean up tos value in the jvmti thread state. + std(Rscratch2, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + // Set tos state field to illegal value. + li(Rscratch2, ilgl); + stw(Rscratch2, in_bytes(JvmtiThreadState::earlyret_tos_offset()), RjvmtiState); +} + +// Common code to dispatch and dispatch_only. +// Dispatch value in Lbyte_code and increment Lbcp. + +void InterpreterMacroAssembler::load_dispatch_table(Register dst, address* table) { + address table_base = (address)Interpreter::dispatch_table((TosState)0); + intptr_t table_offs = (intptr_t)table - (intptr_t)table_base; + if (is_simm16(table_offs)) { + addi(dst, R25_templateTableBase, (int)table_offs); + } else { + load_const_optimized(dst, table, R0); + } +} + +void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, Register bytecode, address* table, bool verify) { + if (verify) { + unimplemented("dispatch_Lbyte_code: verify"); // See Sparc Implementation to implement this + } + +#ifdef FAST_DISPATCH + unimplemented("dispatch_Lbyte_code FAST_DISPATCH"); +#else + assert_different_registers(bytecode, R11_scratch1); + + // Calc dispatch table address. + load_dispatch_table(R11_scratch1, table); + + sldi(R12_scratch2, bytecode, LogBytesPerWord); + ldx(R11_scratch1, R11_scratch1, R12_scratch2); + + // Jump off! + mtctr(R11_scratch1); + bctr(); +#endif +} + +void InterpreterMacroAssembler::load_receiver(Register Rparam_count, Register Rrecv_dst) { + sldi(Rrecv_dst, Rparam_count, Interpreter::logStackElementSize); + ldx(Rrecv_dst, Rrecv_dst, R15_esp); +} + +// helpers for expression stack + +void InterpreterMacroAssembler::pop_i(Register r) { + lwzu(r, Interpreter::stackElementSize, R15_esp); +} + +void InterpreterMacroAssembler::pop_ptr(Register r) { + ldu(r, Interpreter::stackElementSize, R15_esp); +} + +void InterpreterMacroAssembler::pop_l(Register r) { + ld(r, Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, 2 * Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::pop_f(FloatRegister f) { + lfsu(f, Interpreter::stackElementSize, R15_esp); +} + +void InterpreterMacroAssembler::pop_d(FloatRegister f) { + lfd(f, Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, 2 * Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::push_i(Register r) { + stw(r, 0, R15_esp); + addi(R15_esp, R15_esp, - Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_ptr(Register r) { + std(r, 0, R15_esp); + addi(R15_esp, R15_esp, - Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_l(Register r) { + std(r, - Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, - 2 * Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_f(FloatRegister f) { + stfs(f, 0, R15_esp); + addi(R15_esp, R15_esp, - Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_d(FloatRegister f) { + stfd(f, - Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, - 2 * Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_2ptrs(Register first, Register second) { + std(first, 0, R15_esp); + std(second, -Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, - 2 * Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_l_pop_d(Register l, FloatRegister d) { + std(l, 0, R15_esp); + lfd(d, 0, R15_esp); +} + +void InterpreterMacroAssembler::push_d_pop_l(FloatRegister d, Register l) { + stfd(d, 0, R15_esp); + ld(l, 0, R15_esp); +} + +void InterpreterMacroAssembler::push(TosState state) { + switch (state) { + case atos: push_ptr(); break; + case btos: + case ctos: + case stos: + case itos: push_i(); break; + case ltos: push_l(); break; + case ftos: push_f(); break; + case dtos: push_d(); break; + case vtos: /* nothing to do */ break; + default : ShouldNotReachHere(); + } +} + +void InterpreterMacroAssembler::pop(TosState state) { + switch (state) { + case atos: pop_ptr(); break; + case btos: + case ctos: + case stos: + case itos: pop_i(); break; + case ltos: pop_l(); break; + case ftos: pop_f(); break; + case dtos: pop_d(); break; + case vtos: /* nothing to do */ break; + default : ShouldNotReachHere(); + } + verify_oop(R17_tos, state); +} + +void InterpreterMacroAssembler::empty_expression_stack() { + addi(R15_esp, R26_monitor, - Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::get_2_byte_integer_at_bcp(int bcp_offset, + Register Rdst, + signedOrNot is_signed) { + // Read Java big endian format. + if (is_signed == Signed) { + lha(Rdst, bcp_offset, R14_bcp); + } else { + lhz(Rdst, bcp_offset, R14_bcp); + } +#if 0 + assert(Rtmp != Rdst, "need separate temp register"); + Register Rfirst = Rtmp; + lbz(Rfirst, bcp_offset, R14_bcp); // first byte + lbz(Rdst, bcp_offset+1, R14_bcp); // second byte + + // Rdst = ((Rfirst<<8) & 0xFF00) | (Rdst &~ 0xFF00) + rldimi(/*RA=*/Rdst, /*RS=*/Rfirst, /*sh=*/8, /*mb=*/48); + if (is_signed == Signed) { + extsh(Rdst, Rdst); + } +#endif +} + +void InterpreterMacroAssembler::get_4_byte_integer_at_bcp(int bcp_offset, + Register Rdst, + signedOrNot is_signed) { + // Read Java big endian format. + if (bcp_offset & 3) { // Offset unaligned? + load_const_optimized(Rdst, bcp_offset); + if (is_signed == Signed) { + lwax(Rdst, R14_bcp, Rdst); + } else { + lwzx(Rdst, R14_bcp, Rdst); + } + } else { + if (is_signed == Signed) { + lwa(Rdst, bcp_offset, R14_bcp); + } else { + lwz(Rdst, bcp_offset, R14_bcp); + } + } +} + +// Load the constant pool cache index from the bytecode stream. +// +// Kills / writes: +// - Rdst, Rscratch +void InterpreterMacroAssembler::get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size) { + assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); + if (index_size == sizeof(u2)) { + get_2_byte_integer_at_bcp(bcp_offset, Rdst, Unsigned); + } else if (index_size == sizeof(u4)) { + assert(EnableInvokeDynamic, "giant index used only for JSR 292"); + get_4_byte_integer_at_bcp(bcp_offset, Rdst, Signed); + assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); + nand(Rdst, Rdst, Rdst); // convert to plain index + } else if (index_size == sizeof(u1)) { + lbz(Rdst, bcp_offset, R14_bcp); + } else { + ShouldNotReachHere(); + } + // Rdst now contains cp cache index. +} + +void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size) { + get_cache_index_at_bcp(cache, bcp_offset, index_size); + sldi(cache, cache, exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord)); + add(cache, R27_constPoolCache, cache); +} + +// Load object from cpool->resolved_references(index). +void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result, Register index) { + assert_different_registers(result, index); + get_constant_pool(result); + + // Convert from field index to resolved_references() index and from + // word index to byte offset. Since this is a java object, it can be compressed. + Register tmp = index; // reuse + sldi(tmp, index, LogBytesPerHeapOop); + // Load pointer for resolved_references[] objArray. + ld(result, ConstantPool::resolved_references_offset_in_bytes(), result); + // JNIHandles::resolve(result) + ld(result, 0, result); +#ifdef ASSERT + Label index_ok; + lwa(R0, arrayOopDesc::length_offset_in_bytes(), result); + sldi(R0, R0, LogBytesPerHeapOop); + cmpd(CCR0, tmp, R0); + blt(CCR0, index_ok); + stop("resolved reference index out of bounds", 0x09256); + bind(index_ok); +#endif + // Add in the index. + add(result, tmp, result); + load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result); +} + +// Generate a subtype check: branch to ok_is_subtype if sub_klass is +// a subtype of super_klass. Blows registers Rsub_klass, tmp1, tmp2. +void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Register Rsuper_klass, Register Rtmp1, + Register Rtmp2, Register Rtmp3, Label &ok_is_subtype) { + // Profile the not-null value's klass. + profile_typecheck(Rsub_klass, Rtmp1, Rtmp2); + check_klass_subtype(Rsub_klass, Rsuper_klass, Rtmp1, Rtmp2, ok_is_subtype); + profile_typecheck_failed(Rtmp1, Rtmp2); +} + +void InterpreterMacroAssembler::generate_stack_overflow_check_with_compare_and_throw(Register Rmem_frame_size, Register Rscratch1) { + Label done; + sub(Rmem_frame_size, R1_SP, Rmem_frame_size); + ld(Rscratch1, thread_(stack_overflow_limit)); + cmpld(CCR0/*is_stack_overflow*/, Rmem_frame_size, Rscratch1); + bgt(CCR0/*is_stack_overflow*/, done); + + // Load target address of the runtime stub. + assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "generated in wrong order"); + load_const_optimized(Rscratch1, (StubRoutines::throw_StackOverflowError_entry()), R0); + mtctr(Rscratch1); + // Restore caller_sp. +#ifdef ASSERT + ld(Rscratch1, 0, R1_SP); + ld(R0, 0, R21_sender_SP); + cmpd(CCR0, R0, Rscratch1); + asm_assert_eq("backlink", 0x547); +#endif // ASSERT + mr(R1_SP, R21_sender_SP); + bctr(); + + align(32, 12); + bind(done); +} + +// Separate these two to allow for delay slot in middle. +// These are used to do a test and full jump to exception-throwing code. + +// Check that index is in range for array, then shift index by index_shift, +// and put arrayOop + shifted_index into res. +// Note: res is still shy of address by array offset into object. + +void InterpreterMacroAssembler::index_check_without_pop(Register Rarray, Register Rindex, int index_shift, Register Rtmp, Register Rres) { + // Check that index is in range for array, then shift index by index_shift, + // and put arrayOop + shifted_index into res. + // Note: res is still shy of address by array offset into object. + // Kills: + // - Rindex + // Writes: + // - Rres: Address that corresponds to the array index if check was successful. + verify_oop(Rarray); + const Register Rlength = R0; + const Register RsxtIndex = Rtmp; + Label LisNull, LnotOOR; + + // Array nullcheck + if (!ImplicitNullChecks) { + cmpdi(CCR0, Rarray, 0); + beq(CCR0, LisNull); + } else { + null_check_throw(Rarray, arrayOopDesc::length_offset_in_bytes(), /*temp*/RsxtIndex); + } + + // Rindex might contain garbage in upper bits (remember that we don't sign extend + // during integer arithmetic operations). So kill them and put value into same register + // where ArrayIndexOutOfBounds would expect the index in. + rldicl(RsxtIndex, Rindex, 0, 32); // zero extend 32 bit -> 64 bit + + // Index check + lwz(Rlength, arrayOopDesc::length_offset_in_bytes(), Rarray); + cmplw(CCR0, Rindex, Rlength); + sldi(RsxtIndex, RsxtIndex, index_shift); + blt(CCR0, LnotOOR); + load_dispatch_table(Rtmp, (address*)Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); + mtctr(Rtmp); + bctr(); + + if (!ImplicitNullChecks) { + bind(LisNull); + load_dispatch_table(Rtmp, (address*)Interpreter::_throw_NullPointerException_entry); + mtctr(Rtmp); + bctr(); + } + + align(32, 16); + bind(LnotOOR); + + // Calc address + add(Rres, RsxtIndex, Rarray); +} + +void InterpreterMacroAssembler::index_check(Register array, Register index, int index_shift, Register tmp, Register res) { + // pop array + pop_ptr(array); + + // check array + index_check_without_pop(array, index, index_shift, tmp, res); +} + +void InterpreterMacroAssembler::get_const(Register Rdst) { + ld(Rdst, in_bytes(Method::const_offset()), R19_method); +} + +void InterpreterMacroAssembler::get_constant_pool(Register Rdst) { + get_const(Rdst); + ld(Rdst, in_bytes(ConstMethod::constants_offset()), Rdst); +} + +void InterpreterMacroAssembler::get_constant_pool_cache(Register Rdst) { + get_constant_pool(Rdst); + ld(Rdst, ConstantPool::cache_offset_in_bytes(), Rdst); +} + +void InterpreterMacroAssembler::get_cpool_and_tags(Register Rcpool, Register Rtags) { + get_constant_pool(Rcpool); + ld(Rtags, ConstantPool::tags_offset_in_bytes(), Rcpool); +} + +// Unlock if synchronized method. +// +// Unlock the receiver if this is a synchronized method. +// Unlock any Java monitors from synchronized blocks. +// +// If there are locked Java monitors +// If throw_monitor_exception +// throws IllegalMonitorStateException +// Else if install_monitor_exception +// installs IllegalMonitorStateException +// Else +// no error processing +void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state, + bool throw_monitor_exception, + bool install_monitor_exception) { + Label Lunlocked, Lno_unlock; + { + Register Rdo_not_unlock_flag = R11_scratch1; + Register Raccess_flags = R12_scratch2; + + // Check if synchronized method or unlocking prevented by + // JavaThread::do_not_unlock_if_synchronized flag. + lbz(Rdo_not_unlock_flag, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + lwz(Raccess_flags, in_bytes(Method::access_flags_offset()), R19_method); + li(R0, 0); + stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); // reset flag + + push(state); + + // Skip if we don't have to unlock. + rldicl_(R0, Raccess_flags, 64-JVM_ACC_SYNCHRONIZED_BIT, 63); // Extract bit and compare to 0. + beq(CCR0, Lunlocked); + + cmpwi(CCR0, Rdo_not_unlock_flag, 0); + bne(CCR0, Lno_unlock); + } + + // Unlock + { + Register Rmonitor_base = R11_scratch1; + + Label Lunlock; + // If it's still locked, everything is ok, unlock it. + ld(Rmonitor_base, 0, R1_SP); + addi(Rmonitor_base, Rmonitor_base, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes())); // Monitor base + + ld(R0, BasicObjectLock::obj_offset_in_bytes(), Rmonitor_base); + cmpdi(CCR0, R0, 0); + bne(CCR0, Lunlock); + + // If it's already unlocked, throw exception. + if (throw_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); + should_not_reach_here(); + } else { + if (install_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception)); + b(Lunlocked); + } + } + + bind(Lunlock); + unlock_object(Rmonitor_base); + } + + // Check that all other monitors are unlocked. Throw IllegelMonitorState exception if not. + bind(Lunlocked); + { + Label Lexception, Lrestart; + Register Rcurrent_obj_addr = R11_scratch1; + const int delta = frame::interpreter_frame_monitor_size_in_bytes(); + assert((delta & LongAlignmentMask) == 0, "sizeof BasicObjectLock must be even number of doublewords"); + + bind(Lrestart); + // Set up search loop: Calc num of iterations. + { + Register Riterations = R12_scratch2; + Register Rmonitor_base = Rcurrent_obj_addr; + ld(Rmonitor_base, 0, R1_SP); + addi(Rmonitor_base, Rmonitor_base, - frame::ijava_state_size); // Monitor base + + subf_(Riterations, R26_monitor, Rmonitor_base); + ble(CCR0, Lno_unlock); + + addi(Rcurrent_obj_addr, Rmonitor_base, BasicObjectLock::obj_offset_in_bytes() - frame::interpreter_frame_monitor_size_in_bytes()); + // Check if any monitor is on stack, bail out if not + srdi(Riterations, Riterations, exact_log2(delta)); + mtctr(Riterations); + } + + // The search loop: Look for locked monitors. + { + const Register Rcurrent_obj = R0; + Label Lloop; + + ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + addi(Rcurrent_obj_addr, Rcurrent_obj_addr, -delta); + bind(Lloop); + + // Check if current entry is used. + cmpdi(CCR0, Rcurrent_obj, 0); + bne(CCR0, Lexception); + // Preload next iteration's compare value. + ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + addi(Rcurrent_obj_addr, Rcurrent_obj_addr, -delta); + bdnz(Lloop); + } + // Fell through: Everything's unlocked => finish. + b(Lno_unlock); + + // An object is still locked => need to throw exception. + bind(Lexception); + if (throw_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); + should_not_reach_here(); + } else { + // Stack unrolling. Unlock object and if requested, install illegal_monitor_exception. + // Unlock does not block, so don't have to worry about the frame. + Register Rmonitor_addr = R11_scratch1; + addi(Rmonitor_addr, Rcurrent_obj_addr, -BasicObjectLock::obj_offset_in_bytes() + delta); + unlock_object(Rmonitor_addr); + if (install_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception)); + } + b(Lrestart); + } + } + + align(32, 12); + bind(Lno_unlock); + pop(state); +} + +// Support function for remove_activation & Co. +void InterpreterMacroAssembler::merge_frames(Register Rsender_sp, Register return_pc, Register Rscratch1, Register Rscratch2) { + // Pop interpreter frame. + ld(Rscratch1, 0, R1_SP); // *SP + ld(Rsender_sp, _ijava_state_neg(sender_sp), Rscratch1); // top_frame_sp + ld(Rscratch2, 0, Rscratch1); // **SP +#ifdef ASSERT + { + Label Lok; + ld(R0, _ijava_state_neg(ijava_reserved), Rscratch1); + cmpdi(CCR0, R0, 0x5afe); + beq(CCR0, Lok); + stop("frame corrupted (remove activation)", 0x5afe); + bind(Lok); + } +#endif + if (return_pc!=noreg) { + ld(return_pc, _abi(lr), Rscratch1); // LR + } + + // Merge top frames. + subf(Rscratch1, R1_SP, Rsender_sp); // top_frame_sp - SP + stdux(Rscratch2, R1_SP, Rscratch1); // atomically set *(SP = top_frame_sp) = **SP +} + +// Remove activation. +// +// Unlock the receiver if this is a synchronized method. +// Unlock any Java monitors from synchronized blocks. +// Remove the activation from the stack. +// +// If there are locked Java monitors +// If throw_monitor_exception +// throws IllegalMonitorStateException +// Else if install_monitor_exception +// installs IllegalMonitorStateException +// Else +// no error processing +void InterpreterMacroAssembler::remove_activation(TosState state, + bool throw_monitor_exception, + bool install_monitor_exception) { + unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception); + + // Save result (push state before jvmti call and pop it afterwards) and notify jvmti. + notify_method_exit(false, state, NotifyJVMTI, true); + + verify_oop(R17_tos, state); + verify_thread(); + + merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + mtlr(R0); +} + +#endif // !CC_INTERP + // Lock object // // Registers alive @@ -81,7 +767,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { assert_different_registers(displaced_header, object_mark_addr, current_header, tmp); - // markOop displaced_header = obj->mark().set_unlocked(); // Load markOop from object into displaced_header. @@ -94,7 +779,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // Set displaced_header to be (markOop of object | UNLOCK_VALUE). ori(displaced_header, displaced_header, markOopDesc::unlocked_value); - // monitor->lock()->set_displaced_header(displaced_header); // Initialize the box (Must happen before we update the object mark!). @@ -147,7 +831,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { BasicLock::displaced_header_offset_in_bytes(), monitor); b(done); - // } else { // // Slow path. // InterpreterRuntime::monitorenter(THREAD, monitor); @@ -158,7 +841,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor, /*check_for_exceptions=*/true CC_INTERP_ONLY(&& false)); // } - + align(32, 12); bind(done); } } @@ -173,13 +856,13 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_exceptions) { if (UseHeavyMonitors) { call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), - monitor, /*check_for_exceptions=*/false); + monitor, check_for_exceptions CC_INTERP_ONLY(&& false)); } else { // template code: // // if ((displaced_header = monitor->displaced_header()) == NULL) { - // // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL. + // // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL. // monitor->set_obj(NULL); // } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) { // // We swapped the unlocked mark in displaced_header into the object's mark word. @@ -221,7 +904,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e // If we still have a lightweight lock, unlock the object and be done. // The object address from the monitor is in object. - if (!UseBiasedLocking) ld(object, BasicObjectLock::obj_offset_in_bytes(), monitor); + if (!UseBiasedLocking) { ld(object, BasicObjectLock::obj_offset_in_bytes(), monitor); } addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes()); // We have the displaced header in displaced_header. If the lock is still @@ -261,6 +944,959 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e } } +#ifndef CC_INTERP + +// Load compiled (i2c) or interpreter entry when calling from interpreted and +// do the call. Centralized so that all interpreter calls will do the same actions. +// If jvmti single stepping is on for a thread we must not call compiled code. +// +// Input: +// - Rtarget_method: method to call +// - Rret_addr: return address +// - 2 scratch regs +// +void InterpreterMacroAssembler::call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2) { + assert_different_registers(Rscratch1, Rscratch2, Rtarget_method, Rret_addr); + // Assume we want to go compiled if available. + const Register Rtarget_addr = Rscratch1; + const Register Rinterp_only = Rscratch2; + + ld(Rtarget_addr, in_bytes(Method::from_interpreted_offset()), Rtarget_method); + + if (JvmtiExport::can_post_interpreter_events()) { + lwz(Rinterp_only, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread); + + // JVMTI events, such as single-stepping, are implemented partly by avoiding running + // compiled code in threads for which the event is enabled. Check here for + // interp_only_mode if these events CAN be enabled. + Label done; + verify_thread(); + cmpwi(CCR0, Rinterp_only, 0); + beq(CCR0, done); + ld(Rtarget_addr, in_bytes(Method::interpreter_entry_offset()), Rtarget_method); + align(32, 12); + bind(done); + } + +#ifdef ASSERT + { + Label Lok; + cmpdi(CCR0, Rtarget_addr, 0); + bne(CCR0, Lok); + stop("null entry point"); + bind(Lok); + } +#endif // ASSERT + + mr(R21_sender_SP, R1_SP); + + // Calc a precise SP for the call. The SP value we calculated in + // generate_fixed_frame() is based on the max_stack() value, so we would waste stack space + // if esp is not max. Also, the i2c adapter extends the stack space without restoring + // our pre-calced value, so repeating calls via i2c would result in stack overflow. + // Since esp already points to an empty slot, we just have to sub 1 additional slot + // to meet the abi scratch requirements. + // The max_stack pointer will get restored by means of the GR_Lmax_stack local in + // the return entry of the interpreter. + addi(Rscratch2, R15_esp, Interpreter::stackElementSize - frame::abi_reg_args_size); + clrrdi(Rscratch2, Rscratch2, exact_log2(frame::alignment_in_bytes)); // round towards smaller address + resize_frame_absolute(Rscratch2, Rscratch2, R0); + + mr_if_needed(R19_method, Rtarget_method); + mtctr(Rtarget_addr); + mtlr(Rret_addr); + + save_interpreter_state(Rscratch2); +#ifdef ASSERT + ld(Rscratch1, _ijava_state_neg(top_frame_sp), Rscratch2); // Rscratch2 contains fp + cmpd(CCR0, R21_sender_SP, Rscratch1); + asm_assert_eq("top_frame_sp incorrect", 0x951); +#endif + + bctr(); +} + +// Set the method data pointer for the current bcp. +void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { + assert(ProfileInterpreter, "must be profiling interpreter"); + Label get_continue; + ld(R28_mdx, in_bytes(Method::method_data_offset()), R19_method); + test_method_data_pointer(get_continue); + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), R19_method, R14_bcp); + + addi(R28_mdx, R28_mdx, in_bytes(MethodData::data_offset())); + add(R28_mdx, R28_mdx, R3_RET); + bind(get_continue); +} + +// Test ImethodDataPtr. If it is null, continue at the specified label. +void InterpreterMacroAssembler::test_method_data_pointer(Label& zero_continue) { + assert(ProfileInterpreter, "must be profiling interpreter"); + cmpdi(CCR0, R28_mdx, 0); + beq(CCR0, zero_continue); +} + +void InterpreterMacroAssembler::verify_method_data_pointer() { + assert(ProfileInterpreter, "must be profiling interpreter"); +#ifdef ASSERT + Label verify_continue; + test_method_data_pointer(verify_continue); + + // If the mdp is valid, it will point to a DataLayout header which is + // consistent with the bcp. The converse is highly probable also. + lhz(R11_scratch1, in_bytes(DataLayout::bci_offset()), R28_mdx); + ld(R12_scratch2, in_bytes(Method::const_offset()), R19_method); + addi(R11_scratch1, R11_scratch1, in_bytes(ConstMethod::codes_offset())); + add(R11_scratch1, R12_scratch2, R12_scratch2); + cmpd(CCR0, R11_scratch1, R14_bcp); + beq(CCR0, verify_continue); + + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp ), R19_method, R14_bcp, R28_mdx); + + bind(verify_continue); +#endif +} + +void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, + Register Rscratch, + Label &profile_continue) { + assert(ProfileInterpreter, "must be profiling interpreter"); + // Control will flow to "profile_continue" if the counter is less than the + // limit or if we call profile_method(). + Label done; + + // If no method data exists, and the counter is high enough, make one. + int ipl_offs = load_const_optimized(Rscratch, &InvocationCounter::InterpreterProfileLimit, R0, true); + lwz(Rscratch, ipl_offs, Rscratch); + + cmpdi(CCR0, R28_mdx, 0); + // Test to see if we should create a method data oop. + cmpd(CCR1, Rscratch /* InterpreterProfileLimit */, invocation_count); + bne(CCR0, done); + bge(CCR1, profile_continue); + + // Build it now. + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); + set_method_data_pointer_for_bcp(); + b(profile_continue); + + align(32, 12); + bind(done); +} + +void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp) { + assert_different_registers(backedge_count, Rtmp, branch_bcp); + assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr"); + + Label did_not_overflow; + Label overflow_with_error; + + int ibbl_offs = load_const_optimized(Rtmp, &InvocationCounter::InterpreterBackwardBranchLimit, R0, true); + lwz(Rtmp, ibbl_offs, Rtmp); + cmpw(CCR0, backedge_count, Rtmp); + + blt(CCR0, did_not_overflow); + + // When ProfileInterpreter is on, the backedge_count comes from the + // methodDataOop, which value does not get reset on the call to + // frequency_counter_overflow(). To avoid excessive calls to the overflow + // routine while the method is being compiled, add a second test to make sure + // the overflow function is called only once every overflow_frequency. + if (ProfileInterpreter) { + const int overflow_frequency = 1024; + li(Rtmp, overflow_frequency-1); + andr(Rtmp, Rtmp, backedge_count); + cmpwi(CCR0, Rtmp, 0); + bne(CCR0, did_not_overflow); + } + + // Overflow in loop, pass branch bytecode. + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), branch_bcp, true); + + // Was an OSR adapter generated? + // O0 = osr nmethod + cmpdi(CCR0, R3_RET, 0); + beq(CCR0, overflow_with_error); + + // Has the nmethod been invalidated already? + lwz(Rtmp, nmethod::entry_bci_offset(), R3_RET); + cmpwi(CCR0, Rtmp, InvalidOSREntryBci); + beq(CCR0, overflow_with_error); + + // Migrate the interpreter frame off of the stack. + // We can use all registers because we will not return to interpreter from this point. + + // Save nmethod. + const Register osr_nmethod = R31; + mr(osr_nmethod, R3_RET); + set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R11_scratch1); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), R16_thread); + reset_last_Java_frame(); + // OSR buffer is in ARG1 + + // Remove the interpreter frame. + merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + + // Jump to the osr code. + ld(R11_scratch1, nmethod::osr_entry_point_offset(), osr_nmethod); + mtlr(R0); + mtctr(R11_scratch1); + bctr(); + + align(32, 12); + bind(overflow_with_error); + bind(did_not_overflow); +} + +// Store a value at some constant offset from the method data pointer. +void InterpreterMacroAssembler::set_mdp_data_at(int constant, Register value) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + std(value, constant, R28_mdx); +} + +// Increment the value at some constant offset from the method data pointer. +void InterpreterMacroAssembler::increment_mdp_data_at(int constant, + Register counter_addr, + Register Rbumped_count, + bool decrement) { + // Locate the counter at a fixed offset from the mdp: + addi(counter_addr, R28_mdx, constant); + increment_mdp_data_at(counter_addr, Rbumped_count, decrement); +} + +// Increment the value at some non-fixed (reg + constant) offset from +// the method data pointer. +void InterpreterMacroAssembler::increment_mdp_data_at(Register reg, + int constant, + Register scratch, + Register Rbumped_count, + bool decrement) { + // Add the constant to reg to get the offset. + add(scratch, R28_mdx, reg); + // Then calculate the counter address. + addi(scratch, scratch, constant); + increment_mdp_data_at(scratch, Rbumped_count, decrement); +} + +void InterpreterMacroAssembler::increment_mdp_data_at(Register counter_addr, + Register Rbumped_count, + bool decrement) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + // Load the counter. + ld(Rbumped_count, 0, counter_addr); + + if (decrement) { + // Decrement the register. Set condition codes. + addi(Rbumped_count, Rbumped_count, - DataLayout::counter_increment); + // Store the decremented counter, if it is still negative. + std(Rbumped_count, 0, counter_addr); + // Note: add/sub overflow check are not ported, since 64 bit + // calculation should never overflow. + } else { + // Increment the register. Set carry flag. + addi(Rbumped_count, Rbumped_count, DataLayout::counter_increment); + // Store the incremented counter. + std(Rbumped_count, 0, counter_addr); + } +} + +// Set a flag value at the current method data pointer position. +void InterpreterMacroAssembler::set_mdp_flag_at(int flag_constant, + Register scratch) { + assert(ProfileInterpreter, "must be profiling interpreter"); + // Load the data header. + lbz(scratch, in_bytes(DataLayout::flags_offset()), R28_mdx); + // Set the flag. + ori(scratch, scratch, flag_constant); + // Store the modified header. + stb(scratch, in_bytes(DataLayout::flags_offset()), R28_mdx); +} + +// Test the location at some offset from the method data pointer. +// If it is not equal to value, branch to the not_equal_continue Label. +void InterpreterMacroAssembler::test_mdp_data_at(int offset, + Register value, + Label& not_equal_continue, + Register test_out) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + ld(test_out, offset, R28_mdx); + cmpd(CCR0, value, test_out); + bne(CCR0, not_equal_continue); +} + +// Update the method data pointer by the displacement located at some fixed +// offset from the method data pointer. +void InterpreterMacroAssembler::update_mdp_by_offset(int offset_of_disp, + Register scratch) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + ld(scratch, offset_of_disp, R28_mdx); + add(R28_mdx, scratch, R28_mdx); +} + +// Update the method data pointer by the displacement located at the +// offset (reg + offset_of_disp). +void InterpreterMacroAssembler::update_mdp_by_offset(Register reg, + int offset_of_disp, + Register scratch) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + add(scratch, reg, R28_mdx); + ld(scratch, offset_of_disp, scratch); + add(R28_mdx, scratch, R28_mdx); +} + +// Update the method data pointer by a simple constant displacement. +void InterpreterMacroAssembler::update_mdp_by_constant(int constant) { + assert(ProfileInterpreter, "must be profiling interpreter"); + addi(R28_mdx, R28_mdx, constant); +} + +// Update the method data pointer for a _ret bytecode whose target +// was not among our cached targets. +void InterpreterMacroAssembler::update_mdp_for_ret(TosState state, + Register return_bci) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + push(state); + assert(return_bci->is_nonvolatile(), "need to protect return_bci"); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), return_bci); + pop(state); +} + +// Increments the backedge counter. +// Returns backedge counter + invocation counter in Rdst. +void InterpreterMacroAssembler::increment_backedge_counter(const Register Rcounters, const Register Rdst, + const Register Rtmp1, Register Rscratch) { + assert(UseCompiler, "incrementing must be useful"); + assert_different_registers(Rdst, Rtmp1); + const Register invocation_counter = Rtmp1; + const Register counter = Rdst; + // TODO ppc port assert(4 == InvocationCounter::sz_counter(), "unexpected field size."); + + // Load backedge counter. + lwz(counter, in_bytes(MethodCounters::backedge_counter_offset()) + + in_bytes(InvocationCounter::counter_offset()), Rcounters); + // Load invocation counter. + lwz(invocation_counter, in_bytes(MethodCounters::invocation_counter_offset()) + + in_bytes(InvocationCounter::counter_offset()), Rcounters); + + // Add the delta to the backedge counter. + addi(counter, counter, InvocationCounter::count_increment); + + // Mask the invocation counter. + li(Rscratch, InvocationCounter::count_mask_value); + andr(invocation_counter, invocation_counter, Rscratch); + + // Store new counter value. + stw(counter, in_bytes(MethodCounters::backedge_counter_offset()) + + in_bytes(InvocationCounter::counter_offset()), Rcounters); + // Return invocation counter + backedge counter. + add(counter, counter, invocation_counter); +} + +// Count a taken branch in the bytecodes. +void InterpreterMacroAssembler::profile_taken_branch(Register scratch, Register bumped_count) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // We are taking a branch. Increment the taken count. + increment_mdp_data_at(in_bytes(JumpData::taken_offset()), scratch, bumped_count); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_offset(in_bytes(JumpData::displacement_offset()), scratch); + bind (profile_continue); + } +} + +// Count a not-taken branch in the bytecodes. +void InterpreterMacroAssembler::profile_not_taken_branch(Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // We are taking a branch. Increment the not taken count. + increment_mdp_data_at(in_bytes(BranchData::not_taken_offset()), scratch1, scratch2); + + // The method data pointer needs to be updated to correspond to the + // next bytecode. + update_mdp_by_constant(in_bytes(BranchData::branch_data_size())); + bind (profile_continue); + } +} + +// Count a non-virtual call in the bytecodes. +void InterpreterMacroAssembler::profile_call(Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // We are making a call. Increment the count. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(in_bytes(CounterData::counter_data_size())); + bind (profile_continue); + } +} + +// Count a final call in the bytecodes. +void InterpreterMacroAssembler::profile_final_call(Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // We are making a call. Increment the count. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + bind (profile_continue); + } +} + +// Count a virtual call in the bytecodes. +void InterpreterMacroAssembler::profile_virtual_call(Register Rreceiver, + Register Rscratch1, + Register Rscratch2, + bool receiver_can_be_null) { + if (!ProfileInterpreter) { return; } + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + Label skip_receiver_profile; + if (receiver_can_be_null) { + Label not_null; + cmpdi(CCR0, Rreceiver, 0); + bne(CCR0, not_null); + // We are making a call. Increment the count for null receiver. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), Rscratch1, Rscratch2); + b(skip_receiver_profile); + bind(not_null); + } + + // Record the receiver type. + record_klass_in_profile(Rreceiver, Rscratch1, Rscratch2, true); + bind(skip_receiver_profile); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + bind (profile_continue); +} + +void InterpreterMacroAssembler::profile_typecheck(Register Rklass, Register Rscratch1, Register Rscratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + int mdp_delta = in_bytes(BitData::bit_data_size()); + if (TypeProfileCasts) { + mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + + // Record the object type. + record_klass_in_profile(Rklass, Rscratch1, Rscratch2, false); + } + + // The method data pointer needs to be updated. + update_mdp_by_constant(mdp_delta); + + bind (profile_continue); + } +} + +void InterpreterMacroAssembler::profile_typecheck_failed(Register Rscratch1, Register Rscratch2) { + if (ProfileInterpreter && TypeProfileCasts) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + int count_offset = in_bytes(CounterData::count_offset()); + // Back up the address, since we have already bumped the mdp. + count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); + + // *Decrement* the counter. We expect to see zero or small negatives. + increment_mdp_data_at(count_offset, Rscratch1, Rscratch2, true); + + bind (profile_continue); + } +} + +// Count a ret in the bytecodes. +void InterpreterMacroAssembler::profile_ret(TosState state, Register return_bci, Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + uint row; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // Update the total ret count. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2 ); + + for (row = 0; row < RetData::row_limit(); row++) { + Label next_test; + + // See if return_bci is equal to bci[n]: + test_mdp_data_at(in_bytes(RetData::bci_offset(row)), return_bci, next_test, scratch1); + + // return_bci is equal to bci[n]. Increment the count. + increment_mdp_data_at(in_bytes(RetData::bci_count_offset(row)), scratch1, scratch2); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_offset(in_bytes(RetData::bci_displacement_offset(row)), scratch1); + b(profile_continue); + bind(next_test); + } + + update_mdp_for_ret(state, return_bci); + + bind (profile_continue); + } +} + +// Count the default case of a switch construct. +void InterpreterMacroAssembler::profile_switch_default(Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // Update the default case count + increment_mdp_data_at(in_bytes(MultiBranchData::default_count_offset()), + scratch1, scratch2); + + // The method data pointer needs to be updated. + update_mdp_by_offset(in_bytes(MultiBranchData::default_displacement_offset()), + scratch1); + + bind (profile_continue); + } +} + +// Count the index'th case of a switch construct. +void InterpreterMacroAssembler::profile_switch_case(Register index, + Register scratch1, + Register scratch2, + Register scratch3) { + if (ProfileInterpreter) { + assert_different_registers(index, scratch1, scratch2, scratch3); + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // Build the base (index * per_case_size_in_bytes()) + case_array_offset_in_bytes(). + li(scratch3, in_bytes(MultiBranchData::case_array_offset())); + + assert (in_bytes(MultiBranchData::per_case_size()) == 16, "so that shladd works"); + sldi(scratch1, index, exact_log2(in_bytes(MultiBranchData::per_case_size()))); + add(scratch1, scratch1, scratch3); + + // Update the case count. + increment_mdp_data_at(scratch1, in_bytes(MultiBranchData::relative_count_offset()), scratch2, scratch3); + + // The method data pointer needs to be updated. + update_mdp_by_offset(scratch1, in_bytes(MultiBranchData::relative_displacement_offset()), scratch2); + + bind (profile_continue); + } +} + +void InterpreterMacroAssembler::profile_null_seen(Register Rscratch1, Register Rscratch2) { + if (ProfileInterpreter) { + assert_different_registers(Rscratch1, Rscratch2); + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + set_mdp_flag_at(BitData::null_seen_byte_constant(), Rscratch1); + + // The method data pointer needs to be updated. + int mdp_delta = in_bytes(BitData::bit_data_size()); + if (TypeProfileCasts) { + mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + } + update_mdp_by_constant(mdp_delta); + + bind (profile_continue); + } +} + +void InterpreterMacroAssembler::record_klass_in_profile(Register Rreceiver, + Register Rscratch1, Register Rscratch2, + bool is_virtual_call) { + assert(ProfileInterpreter, "must be profiling"); + assert_different_registers(Rreceiver, Rscratch1, Rscratch2); + + Label done; + record_klass_in_profile_helper(Rreceiver, Rscratch1, Rscratch2, 0, done, is_virtual_call); + bind (done); +} + +void InterpreterMacroAssembler::record_klass_in_profile_helper( + Register receiver, Register scratch1, Register scratch2, + int start_row, Label& done, bool is_virtual_call) { + if (TypeProfileWidth == 0) { + if (is_virtual_call) { + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); + } + return; + } + + int last_row = VirtualCallData::row_limit() - 1; + assert(start_row <= last_row, "must be work left to do"); + // Test this row for both the receiver and for null. + // Take any of three different outcomes: + // 1. found receiver => increment count and goto done + // 2. found null => keep looking for case 1, maybe allocate this cell + // 3. found something else => keep looking for cases 1 and 2 + // Case 3 is handled by a recursive call. + for (int row = start_row; row <= last_row; row++) { + Label next_test; + bool test_for_null_also = (row == start_row); + + // See if the receiver is receiver[n]. + int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); + test_mdp_data_at(recvr_offset, receiver, next_test, scratch1); + // delayed()->tst(scratch); + + // The receiver is receiver[n]. Increment count[n]. + int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + increment_mdp_data_at(count_offset, scratch1, scratch2); + b(done); + bind(next_test); + + if (test_for_null_also) { + Label found_null; + // Failed the equality check on receiver[n]... Test for null. + if (start_row == last_row) { + // The only thing left to do is handle the null case. + if (is_virtual_call) { + // Scratch1 contains test_out from test_mdp_data_at. + cmpdi(CCR0, scratch1, 0); + beq(CCR0, found_null); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polymorphic case. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); + b(done); + bind(found_null); + } else { + cmpdi(CCR0, scratch1, 0); + bne(CCR0, done); + } + break; + } + // Since null is rare, make it be the branch-taken case. + cmpdi(CCR0, scratch1, 0); + beq(CCR0, found_null); + + // Put all the "Case 3" tests here. + record_klass_in_profile_helper(receiver, scratch1, scratch2, start_row + 1, done, is_virtual_call); + + // Found a null. Keep searching for a matching receiver, + // but remember that this is an empty (unused) slot. + bind(found_null); + } + } + + // In the fall-through case, we found no matching receiver, but we + // observed the receiver[start_row] is NULL. + + // Fill in the receiver field and increment the count. + int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); + set_mdp_data_at(recvr_offset, receiver); + int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + li(scratch1, DataLayout::counter_increment); + set_mdp_data_at(count_offset, scratch1); + if (start_row > 0) { + b(done); + } +} + +// Add a InterpMonitorElem to stack (see frame_sparc.hpp). +void InterpreterMacroAssembler::add_monitor_to_stack(bool stack_is_empty, Register Rtemp1, Register Rtemp2) { + + // Very-local scratch registers. + const Register esp = Rtemp1; + const Register slot = Rtemp2; + + // Extracted monitor_size. + int monitor_size = frame::interpreter_frame_monitor_size_in_bytes(); + assert(Assembler::is_aligned((unsigned int)monitor_size, + (unsigned int)frame::alignment_in_bytes), + "size of a monitor must respect alignment of SP"); + + resize_frame(-monitor_size, /*temp*/esp); // Allocate space for new monitor + std(R1_SP, _ijava_state_neg(top_frame_sp), esp); // esp contains fp + + // Shuffle expression stack down. Recall that stack_base points + // just above the new expression stack bottom. Old_tos and new_tos + // are used to scan thru the old and new expression stacks. + if (!stack_is_empty) { + Label copy_slot, copy_slot_finished; + const Register n_slots = slot; + + addi(esp, R15_esp, Interpreter::stackElementSize); // Point to first element (pre-pushed stack). + subf(n_slots, esp, R26_monitor); + srdi_(n_slots, n_slots, LogBytesPerWord); // Compute number of slots to copy. + assert(LogBytesPerWord == 3, "conflicts assembler instructions"); + beq(CCR0, copy_slot_finished); // Nothing to copy. + + mtctr(n_slots); + + // loop + bind(copy_slot); + ld(slot, 0, esp); // Move expression stack down. + std(slot, -monitor_size, esp); // distance = monitor_size + addi(esp, esp, BytesPerWord); + bdnz(copy_slot); + + bind(copy_slot_finished); + } + + addi(R15_esp, R15_esp, -monitor_size); + addi(R26_monitor, R26_monitor, -monitor_size); + + // Restart interpreter +} + +// ============================================================================ +// Java locals access + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_int(Register Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + lwz(Rdst_value, 0, Rdst_address); +} + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_long(Register Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + ld(Rdst_value, -8, Rdst_address); +} + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Input: +// - Rindex: slot nr of local variable +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_ptr(Register Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + ld(Rdst_value, 0, Rdst_address); +} + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_float(FloatRegister Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + lfs(Rdst_value, 0, Rdst_address); +} + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_double(FloatRegister Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + lfd(Rdst_value, -8, Rdst_address); +} + +// Store an int value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_int(Register Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + stw(Rvalue, 0, Rindex); +} + +// Store a long value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_long(Register Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + std(Rvalue, -8, Rindex); +} + +// Store an oop value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_ptr(Register Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + std(Rvalue, 0, Rindex); +} + +// Store an int value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_float(FloatRegister Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + stfs(Rvalue, 0, Rindex); +} + +// Store an int value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_double(FloatRegister Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + stfd(Rvalue, -8, Rindex); +} + +// Read pending exception from thread and jump to interpreter. +// Throw exception entry if one if pending. Fall through otherwise. +void InterpreterMacroAssembler::check_and_forward_exception(Register Rscratch1, Register Rscratch2) { + assert_different_registers(Rscratch1, Rscratch2, R3); + Register Rexception = Rscratch1; + Register Rtmp = Rscratch2; + Label Ldone; + // Get pending exception oop. + ld(Rexception, thread_(pending_exception)); + cmpdi(CCR0, Rexception, 0); + beq(CCR0, Ldone); + li(Rtmp, 0); + mr_if_needed(R3, Rexception); + std(Rtmp, thread_(pending_exception)); // Clear exception in thread + if (Interpreter::rethrow_exception_entry() != NULL) { + // Already got entry address. + load_dispatch_table(Rtmp, (address*)Interpreter::rethrow_exception_entry()); + } else { + // Dynamically load entry address. + int simm16_rest = load_const_optimized(Rtmp, &Interpreter::_rethrow_exception_entry, R0, true); + ld(Rtmp, simm16_rest, Rtmp); + } + mtctr(Rtmp); + save_interpreter_state(Rtmp); + bctr(); + + align(32, 12); + bind(Ldone); +} + +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, bool check_exceptions) { + save_interpreter_state(R11_scratch1); + + MacroAssembler::call_VM(oop_result, entry_point, false); + + restore_interpreter_state(R11_scratch1, /*bcp_and_mdx_only*/ true); + + check_and_handle_popframe(R11_scratch1); + check_and_handle_earlyret(R11_scratch1); + // Now check exceptions manually. + if (check_exceptions) { + check_and_forward_exception(R11_scratch1, R12_scratch2); + } +} + +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions) { + // ARG1 is reserved for the thread. + mr_if_needed(R4_ARG2, arg_1); + call_VM(oop_result, entry_point, check_exceptions); +} + +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) { + // ARG1 is reserved for the thread. + mr_if_needed(R4_ARG2, arg_1); + assert(arg_2 != R4_ARG2, "smashed argument"); + mr_if_needed(R5_ARG3, arg_2); + call_VM(oop_result, entry_point, check_exceptions); +} + +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) { + // ARG1 is reserved for the thread. + mr_if_needed(R4_ARG2, arg_1); + assert(arg_2 != R4_ARG2, "smashed argument"); + mr_if_needed(R5_ARG3, arg_2); + assert(arg_3 != R4_ARG2 && arg_3 != R5_ARG3, "smashed argument"); + mr_if_needed(R6_ARG4, arg_3); + call_VM(oop_result, entry_point, check_exceptions); +} + +void InterpreterMacroAssembler::save_interpreter_state(Register scratch) { + ld(scratch, 0, R1_SP); + std(R15_esp, _ijava_state_neg(esp), scratch); + std(R14_bcp, _ijava_state_neg(bcp), scratch); + std(R26_monitor, _ijava_state_neg(monitors), scratch); + if (ProfileInterpreter) { std(R28_mdx, _ijava_state_neg(mdx), scratch); } + // Other entries should be unchanged. +} + +void InterpreterMacroAssembler::restore_interpreter_state(Register scratch, bool bcp_and_mdx_only) { + ld(scratch, 0, R1_SP); + ld(R14_bcp, _ijava_state_neg(bcp), scratch); // Changed by VM code (exception). + if (ProfileInterpreter) { ld(R28_mdx, _ijava_state_neg(mdx), scratch); } // Changed by VM code. + if (!bcp_and_mdx_only) { + // Following ones are Metadata. + ld(R19_method, _ijava_state_neg(method), scratch); + ld(R27_constPoolCache, _ijava_state_neg(cpoolCache), scratch); + // Following ones are stack addresses and don't require reload. + ld(R15_esp, _ijava_state_neg(esp), scratch); + ld(R18_locals, _ijava_state_neg(locals), scratch); + ld(R26_monitor, _ijava_state_neg(monitors), scratch); + } +#ifdef ASSERT + { + Label Lok; + subf(R0, R1_SP, scratch); + cmpdi(CCR0, R0, frame::abi_reg_args_size + frame::ijava_state_size); + bge(CCR0, Lok); + stop("frame too small (restore istate)", 0x5432); + bind(Lok); + } + { + Label Lok; + ld(R0, _ijava_state_neg(ijava_reserved), scratch); + cmpdi(CCR0, R0, 0x5afe); + beq(CCR0, Lok); + stop("frame corrupted (restore istate)", 0x5afe); + bind(Lok); + } +#endif +} + +#endif // !CC_INTERP + void InterpreterMacroAssembler::get_method_counters(Register method, Register Rcounters, Label& skip) { @@ -321,6 +1957,66 @@ void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { if (state == atos) { MacroAssembler::verify_oop(reg); } } +#ifndef CC_INTERP +// Local helper function for the verify_oop_or_return_address macro. +static bool verify_return_address(Method* m, int bci) { +#ifndef PRODUCT + address pc = (address)(m->constMethod()) + in_bytes(ConstMethod::codes_offset()) + bci; + // Assume it is a valid return address if it is inside m and is preceded by a jsr. + if (!m->contains(pc)) return false; + address jsr_pc; + jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr); + if (*jsr_pc == Bytecodes::_jsr && jsr_pc >= m->code_base()) return true; + jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr_w); + if (*jsr_pc == Bytecodes::_jsr_w && jsr_pc >= m->code_base()) return true; +#endif // PRODUCT + return false; +} + +void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { + if (VerifyFPU) { + unimplemented("verfiyFPU"); + } +} + +void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Register Rtmp) { + if (!VerifyOops) return; + + // The VM documentation for the astore[_wide] bytecode allows + // the TOS to be not only an oop but also a return address. + Label test; + Label skip; + // See if it is an address (in the current method): + + const int log2_bytecode_size_limit = 16; + srdi_(Rtmp, reg, log2_bytecode_size_limit); + bne(CCR0, test); + + address fd = CAST_FROM_FN_PTR(address, verify_return_address); + unsigned int nbytes_save = 10*8; // 10 volatile gprs + + save_LR_CR(Rtmp); + push_frame_reg_args(nbytes_save, Rtmp); + save_volatile_gprs(R1_SP, 112); // except R0 + + load_const_optimized(Rtmp, fd, R0); + mr_if_needed(R4_ARG2, reg); + mr(R3_ARG1, R19_method); + call_c(Rtmp); // call C + + restore_volatile_gprs(R1_SP, 112); // except R0 + pop_frame(); + restore_LR_CR(Rtmp); + b(skip); + + // Perform a more elaborate out-of-line call. + // Not an address; verify it: + bind(test); + verify_oop(reg); + bind(skip); +} +#endif // !CC_INTERP + // Inline assembly for: // // if (thread is in interp_only_mode) { @@ -343,13 +2039,12 @@ void InterpreterMacroAssembler::notify_method_entry() { cmpwi(CCR0, R0, 0); beq(CCR0, jvmti_post_done); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry), - /*check_exceptions=*/false); + /*check_exceptions=*/true CC_INTERP_ONLY(&& false)); bind(jvmti_post_done); } } - // Inline assembly for: // // if (thread is in interp_only_mode) { @@ -365,26 +2060,33 @@ void InterpreterMacroAssembler::notify_method_entry() { // // Native methods have their result stored in d_tmp and l_tmp. // Java methods have their result stored in the expression stack. -void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosState state) { +void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosState state, + NotifyMethodExitMode mode, bool check_exceptions) { // JVMTI // Whenever JVMTI puts a thread in interp_only_mode, method // entry/exit events are sent for that thread to track stack // depth. If it is possible to enter interp_only_mode we add // the code to check if the event should be sent. - if (JvmtiExport::can_post_interpreter_events()) { + if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { Label jvmti_post_done; lwz(R0, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread); cmpwi(CCR0, R0, 0); beq(CCR0, jvmti_post_done); + CC_INTERP_ONLY(assert(is_native_method && !check_exceptions, "must not push state")); + if (!is_native_method) push(state); // Expose tos to GC. call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit), - /*check_exceptions=*/false); + /*check_exceptions=*/check_exceptions); + if (!is_native_method) pop(state); align(32, 12); bind(jvmti_post_done); } + + // Dtrace support not implemented. } +#ifdef CC_INTERP // Convert the current TOP_IJAVA_FRAME into a PARENT_IJAVA_FRAME // (using parent_frame_resize) and push a new interpreter // TOP_IJAVA_FRAME (using frame_size). @@ -442,7 +2144,6 @@ void InterpreterMacroAssembler::pop_interpreter_frame(Register tmp1, Register tm std(R1_SP, _top_ijava_frame_abi(top_frame_sp), R1_SP); } -#ifdef CC_INTERP // Turn state's interpreter frame into the current TOP_IJAVA_FRAME. void InterpreterMacroAssembler::pop_interpreter_frame_to_state(Register state, Register tmp1, Register tmp2, Register tmp3) { assert_different_registers(R14_state, R15_prev_state, tmp1, tmp2, tmp3); @@ -471,7 +2172,6 @@ void InterpreterMacroAssembler::pop_interpreter_frame_to_state(Register state, R // Used for non-initial callers by unextended_sp(). std(R1_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP); } -#endif // CC_INTERP // Set SP to initial caller's sp, but before fix the back chain. void InterpreterMacroAssembler::resize_frame_to_initial_caller(Register tmp1, Register tmp2) { @@ -481,7 +2181,6 @@ void InterpreterMacroAssembler::resize_frame_to_initial_caller(Register tmp1, Re mr(R1_SP, tmp1); // ... and resize to initial caller. } -#ifdef CC_INTERP // Pop the current interpreter state (without popping the correspoding // frame) and restore R14_state and R15_prev_state accordingly. // Use prev_state_may_be_0 to indicate whether prev_state may be 0 diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp index a189e30043c..9846bb5113e 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.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 @@ -29,7 +29,7 @@ #include "assembler_ppc.inline.hpp" #include "interpreter/invocationCounter.hpp" -// This file specializes the assembler with interpreter-specific macros +// This file specializes the assembler with interpreter-specific macros. class InterpreterMacroAssembler: public MacroAssembler { @@ -39,15 +39,176 @@ class InterpreterMacroAssembler: public MacroAssembler { void null_check_throw(Register a, int offset, Register temp_reg); - // Handy address generation macros + void branch_to_entry(address entry, Register Rscratch); + + // Handy address generation macros. #define thread_(field_name) in_bytes(JavaThread::field_name ## _offset()), R16_thread #define method_(field_name) in_bytes(Method::field_name ## _offset()), R19_method #ifdef CC_INTERP #define state_(field_name) in_bytes(byte_offset_of(BytecodeInterpreter, field_name)), R14_state #define prev_state_(field_name) in_bytes(byte_offset_of(BytecodeInterpreter, field_name)), R15_prev_state + void pop (TosState state) {}; // Not needed. + void push(TosState state) {}; // Not needed. #endif +#ifndef CC_INTERP + virtual void check_and_handle_popframe(Register java_thread); + virtual void check_and_handle_earlyret(Register java_thread); + + // Base routine for all dispatches. + void dispatch_base(TosState state, address* table); + + void load_earlyret_value(TosState state, Register Rscratch1); + + static const Address l_tmp; + static const Address d_tmp; + + // dispatch routines + void dispatch_next(TosState state, int step = 0); + void dispatch_via (TosState state, address* table); + void load_dispatch_table(Register dst, address* table); + void dispatch_Lbyte_code(TosState state, Register bytecode, address* table, bool verify = false); + + // Called by shared interpreter generator. + void dispatch_prolog(TosState state, int step = 0); + void dispatch_epilog(TosState state, int step = 0); + + // Super call_VM calls - correspond to MacroAssembler::call_VM(_leaf) calls. + void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1); + void super_call_VM(Register thread_cache, Register oop_result, Register last_java_sp, + address entry_point, Register arg_1, Register arg_2, bool check_exception = true); + + // Generate a subtype check: branch to ok_is_subtype if sub_klass is + // a subtype of super_klass. Blows registers tmp1, tmp2 and tmp3. + void gen_subtype_check(Register sub_klass, Register super_klass, + Register tmp1, Register tmp2, Register tmp3, Label &ok_is_subtype); + + // Load object from cpool->resolved_references(index). + void load_resolved_reference_at_index(Register result, Register index); + + void generate_stack_overflow_check_with_compare_and_throw(Register Rmem_frame_size, Register Rscratch1); + void load_receiver(Register Rparam_count, Register Rrecv_dst); + + // helpers for expression stack + void pop_i( Register r = R17_tos); + void pop_ptr( Register r = R17_tos); + void pop_l( Register r = R17_tos); + void pop_f(FloatRegister f = F15_ftos); + void pop_d(FloatRegister f = F15_ftos ); + + void push_i( Register r = R17_tos); + void push_ptr( Register r = R17_tos); + void push_l( Register r = R17_tos); + void push_f(FloatRegister f = F15_ftos ); + void push_d(FloatRegister f = F15_ftos); + + void push_2ptrs(Register first, Register second); + + void push_l_pop_d(Register l = R17_tos, FloatRegister d = F15_ftos); + void push_d_pop_l(FloatRegister d = F15_ftos, Register l = R17_tos); + + void pop (TosState state); // transition vtos -> state + void push(TosState state); // transition state -> vtos + void empty_expression_stack(); // Resets both Lesp and SP. + + public: + // Load values from bytecode stream: + + enum signedOrNot { Signed, Unsigned }; + enum setCCOrNot { set_CC, dont_set_CC }; + + void get_2_byte_integer_at_bcp(int bcp_offset, + Register Rdst, + signedOrNot is_signed); + + void get_4_byte_integer_at_bcp(int bcp_offset, + Register Rdst, + signedOrNot is_signed = Unsigned); + + void get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size); + + void get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size = sizeof(u2)); + + + // common code + + void field_offset_at(int n, Register tmp, Register dest, Register base); + int field_offset_at(Register object, address bcp, int offset); + void fast_iaaccess(int n, address bcp); + void fast_iagetfield(address bcp); + void fast_iaputfield(address bcp, bool do_store_check); + + void index_check(Register array, Register index, int index_shift, Register tmp, Register res); + void index_check_without_pop(Register array, Register index, int index_shift, Register tmp, Register res); + + void get_const(Register Rdst); + void get_constant_pool(Register Rdst); + void get_constant_pool_cache(Register Rdst); + void get_cpool_and_tags(Register Rcpool, Register Rtags); + void is_a(Label& L); + + // Java Call Helpers + void call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2); + + // -------------------------------------------------- + + void unlock_if_synchronized_method(TosState state, bool throw_monitor_exception = true, + bool install_monitor_exception = true); + + // Removes the current activation (incl. unlocking of monitors). + // Additionally this code is used for earlyReturn in which case we + // want to skip throwing an exception and installing an exception. + void remove_activation(TosState state, + bool throw_monitor_exception = true, + bool install_monitor_exception = true); + void merge_frames(Register Rtop_frame_sp, Register return_pc, Register Rscratch1, Register Rscratch2); // merge top frames + + void add_monitor_to_stack(bool stack_is_empty, Register Rtemp1, Register Rtemp2); + + // Local variable access helpers + void load_local_int(Register Rdst_value, Register Rdst_address, Register Rindex); + void load_local_long(Register Rdst_value, Register Rdst_address, Register Rindex); + void load_local_ptr(Register Rdst_value, Register Rdst_address, Register Rindex); + void load_local_float(FloatRegister Rdst_value, Register Rdst_address, Register Rindex); + void load_local_double(FloatRegister Rdst_value, Register Rdst_address, Register Rindex); + void store_local_int(Register Rvalue, Register Rindex); + void store_local_long(Register Rvalue, Register Rindex); + void store_local_ptr(Register Rvalue, Register Rindex); + void store_local_float(FloatRegister Rvalue, Register Rindex); + void store_local_double(FloatRegister Rvalue, Register Rindex); + + // Call VM for std frames + // Special call VM versions that check for exceptions and forward exception + // via short cut (not via expensive forward exception stub). + void check_and_forward_exception(Register Rscratch1, Register Rscratch2); + void call_VM(Register oop_result, address entry_point, bool check_exceptions = true); + void call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions = true); + void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true); + void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true); + // Should not be used: + void call_VM(Register oop_result, Register last_java_sp, address entry_point, bool check_exceptions = true) {ShouldNotReachHere();} + void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true) {ShouldNotReachHere();} + void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true) {ShouldNotReachHere();} + void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true) {ShouldNotReachHere();} + + Address first_local_in_stack(); + + enum LoadOrStore { load, store }; + void static_iload_or_store(int which_local, LoadOrStore direction, Register Rtmp); + void static_aload_or_store(int which_local, LoadOrStore direction, Register Rtmp); + void static_dload_or_store(int which_local, LoadOrStore direction); + + void save_interpreter_state(Register scratch); + void restore_interpreter_state(Register scratch, bool bcp_and_mdx_only = false); + + void increment_backedge_counter(const Register Rcounters, Register Rtmp, Register Rtmp2, Register Rscratch); + void test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp); + + void record_static_call_in_profile(Register Rentry, Register Rtmp); + void record_receiver_call_in_profile(Register Rklass, Register Rentry, Register Rtmp); +#endif // !CC_INTERP + void get_method_counters(Register method, Register Rcounters, Label& skip); void increment_invocation_counter(Register iv_be_count, Register Rtmp1, Register Rtmp2_r0); @@ -55,12 +216,59 @@ class InterpreterMacroAssembler: public MacroAssembler { void lock_object (Register lock_reg, Register obj_reg); void unlock_object(Register lock_reg, bool check_for_exceptions = true); +#ifndef CC_INTERP + + // Interpreter profiling operations + void set_method_data_pointer_for_bcp(); + void test_method_data_pointer(Label& zero_continue); + void verify_method_data_pointer(); + void test_invocation_counter_for_mdp(Register invocation_count, Register Rscratch, Label &profile_continue); + + void set_mdp_data_at(int constant, Register value); + + void increment_mdp_data_at(int constant, Register counter_addr, Register Rbumped_count, bool decrement = false); + + void increment_mdp_data_at(Register counter_addr, Register Rbumped_count, bool decrement = false); + void increment_mdp_data_at(Register reg, int constant, Register scratch, Register Rbumped_count, bool decrement = false); + + void set_mdp_flag_at(int flag_constant, Register scratch); + void test_mdp_data_at(int offset, Register value, Label& not_equal_continue, Register test_out); + + void update_mdp_by_offset(int offset_of_disp, Register scratch); + void update_mdp_by_offset(Register reg, int offset_of_disp, + Register scratch); + void update_mdp_by_constant(int constant); + void update_mdp_for_ret(TosState state, Register return_bci); + + void profile_taken_branch(Register scratch, Register bumped_count); + void profile_not_taken_branch(Register scratch1, Register scratch2); + void profile_call(Register scratch1, Register scratch2); + void profile_final_call(Register scratch1, Register scratch2); + void profile_virtual_call(Register Rreceiver, Register Rscratch1, Register Rscratch2, bool receiver_can_be_null); + void profile_typecheck(Register Rklass, Register Rscratch1, Register Rscratch2); + void profile_typecheck_failed(Register Rscratch1, Register Rscratch2); + void profile_ret(TosState state, Register return_bci, Register scratch1, Register scratch2); + void profile_switch_default(Register scratch1, Register scratch2); + void profile_switch_case(Register index, Register scratch1,Register scratch2, Register scratch3); + void profile_null_seen(Register Rscratch1, Register Rscratch2); + void record_klass_in_profile(Register receiver, Register scratch1, Register scratch2, bool is_virtual_call); + void record_klass_in_profile_helper(Register receiver, Register scratch1, Register scratch2, int start_row, Label& done, bool is_virtual_call); + +#endif // !CC_INTERP + // Debugging void verify_oop(Register reg, TosState state = atos); // only if +VerifyOops && state == atos +#ifndef CC_INTERP + void verify_oop_or_return_address(Register reg, Register rtmp); // for astore + void verify_FPU(int stack_depth, TosState state = ftos); +#endif // !CC_INTERP - // support for jvmdi/jvmpi + typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; + + // Support for jvmdi/jvmpi. void notify_method_entry(); - void notify_method_exit(bool is_native_method, TosState state); + void notify_method_exit(bool is_native_method, TosState state, + NotifyMethodExitMode mode, bool check_exceptions); #ifdef CC_INTERP // Convert the current TOP_IJAVA_FRAME into a PARENT_IJAVA_FRAME diff --git a/hotspot/src/cpu/ppc/vm/interpreterRT_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreterRT_ppc.cpp index 3a1389f413b..5d45d8bf82f 100644 --- a/hotspot/src/cpu/ppc/vm/interpreterRT_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/interpreterRT_ppc.cpp @@ -109,8 +109,10 @@ void InterpreterRuntime::SignatureHandlerGenerator::pass_object() { } void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) { +#if !defined(ABI_ELFv2) // Emit fd for current codebuffer. Needs patching! __ emit_fd(); +#endif // Generate code to handle arguments. iterate(fingerprint); @@ -127,11 +129,13 @@ void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprin // Implementation of SignatureHandlerLibrary void SignatureHandlerLibrary::pd_set_handler(address handler) { +#if !defined(ABI_ELFv2) // patch fd here. FunctionDescriptor* fd = (FunctionDescriptor*) handler; fd->set_entry(handler + (int)sizeof(FunctionDescriptor)); assert(fd->toc() == (address)0xcafe, "need to adjust TOC here"); +#endif } diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp index 3cc1b7f07e9..80bfc2d2918 100644 --- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/interpreter_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 (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,10 +51,6 @@ #include "c1/c1_Runtime1.hpp" #endif -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC" -#endif - #define __ _masm-> #ifdef PRODUCT @@ -128,13 +124,13 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { const Register target_sp = R28_tmp8; const FloatRegister floatSlot = F0; - address entry = __ emit_fd(); + address entry = __ function_entry(); __ save_LR_CR(R0); __ save_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14)); // We use target_sp for storing arguments in the C frame. __ mr(target_sp, R1_SP); - __ push_frame_abi112_nonvolatiles(0, R11_scratch1); + __ push_frame_reg_args_nonvolatiles(0, R11_scratch1); __ mr(arg_java, R3_ARG1); @@ -147,7 +143,8 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { #ifdef CC_INTERP __ ld(R19_method, state_(_method)); #else - __ unimplemented("slow signature handler 1"); + __ ld(R19_method, 0, target_sp); + __ ld(R19_method, _ijava_state_neg(method), R19_method); #endif // Get the result handler. @@ -157,7 +154,8 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { #ifdef CC_INTERP __ ld(R19_method, state_(_method)); #else - __ unimplemented("slow signature handler 2"); + __ ld(R19_method, 0, target_sp); + __ ld(R19_method, _ijava_state_neg(method), R19_method); #endif { @@ -453,7 +451,7 @@ address InterpreterGenerator::generate_abstract_entry(void) { // // Registers alive // R16_thread - JavaThread* - // R19_method - callee's methodOop (method to be invoked) + // R19_method - callee's method (method to be invoked) // R1_SP - SP prepared such that caller's outgoing args are near top // LR - return address to caller // @@ -474,7 +472,7 @@ address InterpreterGenerator::generate_abstract_entry(void) { // Push a new C frame and save LR. __ save_LR_CR(R0); - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // This is not a leaf but we have a JavaFrameAnchor now and we will // check (create) exceptions afterward so this is ok. @@ -491,7 +489,12 @@ address InterpreterGenerator::generate_abstract_entry(void) { // Return to frame manager, it will handle the pending exception. __ blr(); #else - Unimplemented(); + // We don't know our caller, so jump to the general forward exception stub, + // which will also pop our full frame off. Satisfy the interface of + // SharedRuntime::generate_forward_exception() + __ load_const_optimized(R11_scratch1, StubRoutines::forward_exception_entry(), R0); + __ mtctr(R11_scratch1); + __ bctr(); #endif return entry; @@ -500,8 +503,9 @@ address InterpreterGenerator::generate_abstract_entry(void) { // Call an accessor method (assuming it is resolved, otherwise drop into // vanilla (slow path) entry. address InterpreterGenerator::generate_accessor_entry(void) { - if(!UseFastAccessorMethods && (!FLAG_IS_ERGO(UseFastAccessorMethods))) + if (!UseFastAccessorMethods && (!FLAG_IS_ERGO(UseFastAccessorMethods))) { return NULL; + } Label Lslow_path, Lacquire; @@ -586,10 +590,14 @@ address InterpreterGenerator::generate_accessor_entry(void) { // Load from branch table and dispatch (volatile case: one instruction ahead) __ sldi(Rflags, Rflags, LogBytesPerWord); __ cmpwi(CCR6, Rscratch, 1); // volatile? - __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // volatile ? size of 1 instruction : 0 + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // volatile ? size of 1 instruction : 0 + } __ ldx(Rbtable, Rbtable, Rflags); - __ subf(Rbtable, Rscratch, Rbtable); // point to volatile/non-volatile entry point + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ subf(Rbtable, Rscratch, Rbtable); // point to volatile/non-volatile entry point + } __ mtctr(Rbtable); __ bctr(); @@ -605,7 +613,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { } assert(all_uninitialized != all_initialized, "consistency"); // either or - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) if (branch_table[vtos] == 0) branch_table[vtos] = __ pc(); // non-volatile_entry point if (branch_table[dtos] == 0) branch_table[dtos] = __ pc(); // non-volatile_entry point if (branch_table[ftos] == 0) branch_table[ftos] = __ pc(); // non-volatile_entry point @@ -614,7 +622,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { if (branch_table[itos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[itos] = __ pc(); // non-volatile_entry point __ lwax(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); @@ -623,7 +631,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { if (branch_table[ltos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[ltos] = __ pc(); // non-volatile_entry point __ ldx(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); @@ -632,7 +640,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { if (branch_table[btos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[btos] = __ pc(); // non-volatile_entry point __ lbzx(R3_RET, Rclass_or_obj, Roffset); __ extsb(R3_RET, R3_RET); @@ -642,7 +650,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { if (branch_table[ctos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[ctos] = __ pc(); // non-volatile_entry point __ lhzx(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); @@ -651,7 +659,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { if (branch_table[stos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[stos] = __ pc(); // non-volatile_entry point __ lhax(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); @@ -660,7 +668,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { if (branch_table[atos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[atos] = __ pc(); // non-volatile_entry point __ load_heap_oop(R3_RET, (RegisterOrConstant)Roffset, Rclass_or_obj); __ verify_oop(R3_RET); @@ -683,10 +691,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { #endif __ bind(Lslow_path); - assert(Interpreter::entry_for_kind(Interpreter::zerolocals), "Normal entry must have been generated by now"); - __ load_const_optimized(Rscratch, Interpreter::entry_for_kind(Interpreter::zerolocals), R0); - __ mtctr(Rscratch); - __ bctr(); + __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), Rscratch); __ flush(); return entry; @@ -773,10 +778,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // Generate regular method entry. __ bind(slow_path); - assert(Interpreter::entry_for_kind(Interpreter::zerolocals), "Normal entry must have been generated by now"); - __ load_const_optimized(R11_scratch1, Interpreter::entry_for_kind(Interpreter::zerolocals), R0); - __ mtctr(R11_scratch1); - __ bctr(); + __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1); __ flush(); return entry; diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp index 37bf8e9fe6b..48864ae7213 100644 --- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 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,15 +28,23 @@ public: - // Stack index relative to tos (which points at value) + // Stack index relative to tos (which points at value). static int expr_index_at(int i) { return stackElementWords * i; } - // Already negated by c++ interpreter + // Already negated by c++ interpreter. static int local_index_at(int i) { assert(i <= 0, "local direction already negated"); return stackElementWords * i; } +#ifndef CC_INTERP + // The offset in bytes to access a expression stack slot + // relative to the esp pointer. + static int expr_offset_in_bytes(int slot) { + return stackElementSize * slot + wordSize; + } +#endif + #endif // CPU_PPC_VM_INTERPRETER_PPC_PP diff --git a/hotspot/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp b/hotspot/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp index f12df9cbe76..26ca0dbf181 100644 --- a/hotspot/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 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 @@ -26,10 +26,6 @@ #ifndef CPU_PPC_VM_JAVAFRAMEANCHOR_PPC_HPP #define CPU_PPC_VM_JAVAFRAMEANCHOR_PPC_HPP -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC64" -#endif - public: // Each arch must define reset, save, restore // These are used by objects that only care about: diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index dfe97adadb5..2d3d9cf9713 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -594,7 +594,13 @@ void MacroAssembler::bxx64_patchable(address dest, relocInfo::relocType rt, bool "can't identify emitted call"); } else { // variant 1: - +#if defined(ABI_ELFv2) + nop(); + calculate_address_from_global_toc(R12, dest, true, true, false); + mtctr(R12); + nop(); + nop(); +#else mr(R0, R11); // spill R11 -> R0. // Load the destination address into CTR, @@ -604,6 +610,7 @@ void MacroAssembler::bxx64_patchable(address dest, relocInfo::relocType rt, bool mtctr(R11); mr(R11, R0); // spill R11 <- R0. nop(); +#endif // do the call/jump if (link) { @@ -912,16 +919,16 @@ void MacroAssembler::push_frame(unsigned int bytes, Register tmp) { } } -// Push a frame of size `bytes' plus abi112 on top. -void MacroAssembler::push_frame_abi112(unsigned int bytes, Register tmp) { - push_frame(bytes + frame::abi_112_size, tmp); +// Push a frame of size `bytes' plus abi_reg_args on top. +void MacroAssembler::push_frame_reg_args(unsigned int bytes, Register tmp) { + push_frame(bytes + frame::abi_reg_args_size, tmp); } // Setup up a new C frame with a spill area for non-volatile GPRs and // additional space for local variables. -void MacroAssembler::push_frame_abi112_nonvolatiles(unsigned int bytes, - Register tmp) { - push_frame(bytes + frame::abi_112_size + frame::spill_nonvolatiles_size, tmp); +void MacroAssembler::push_frame_reg_args_nonvolatiles(unsigned int bytes, + Register tmp) { + push_frame(bytes + frame::abi_reg_args_size + frame::spill_nonvolatiles_size, tmp); } // Pop current C frame. @@ -929,6 +936,42 @@ void MacroAssembler::pop_frame() { ld(R1_SP, _abi(callers_sp), R1_SP); } +#if defined(ABI_ELFv2) +address MacroAssembler::branch_to(Register r_function_entry, bool and_link) { + // TODO(asmundak): make sure the caller uses R12 as function descriptor + // most of the times. + if (R12 != r_function_entry) { + mr(R12, r_function_entry); + } + mtctr(R12); + // Do a call or a branch. + if (and_link) { + bctrl(); + } else { + bctr(); + } + _last_calls_return_pc = pc(); + + return _last_calls_return_pc; +} + +// Call a C function via a function descriptor and use full C +// calling conventions. Updates and returns _last_calls_return_pc. +address MacroAssembler::call_c(Register r_function_entry) { + return branch_to(r_function_entry, /*and_link=*/true); +} + +// For tail calls: only branch, don't link, so callee returns to caller of this function. +address MacroAssembler::call_c_and_return_to_caller(Register r_function_entry) { + return branch_to(r_function_entry, /*and_link=*/false); +} + +address MacroAssembler::call_c(address function_entry, relocInfo::relocType rt) { + load_const(R12, function_entry, R0); + return branch_to(R12, /*and_link=*/true); +} + +#else // Generic version of a call to C function via a function descriptor // with variable support for C calling conventions (TOC, ENV, etc.). // Updates and returns _last_calls_return_pc. @@ -1077,6 +1120,7 @@ address MacroAssembler::call_c_using_toc(const FunctionDescriptor* fd, } return _last_calls_return_pc; } +#endif void MacroAssembler::call_VM_base(Register oop_result, Register last_java_sp, @@ -1091,8 +1135,11 @@ void MacroAssembler::call_VM_base(Register oop_result, // ARG1 must hold thread address. mr(R3_ARG1, R16_thread); - +#if defined(ABI_ELFv2) + address return_pc = call_c(entry_point, relocInfo::none); +#else address return_pc = call_c((FunctionDescriptor*)entry_point, relocInfo::none); +#endif reset_last_Java_frame(); @@ -1113,7 +1160,11 @@ void MacroAssembler::call_VM_base(Register oop_result, void MacroAssembler::call_VM_leaf_base(address entry_point) { BLOCK_COMMENT("call_VM_leaf {"); +#if defined(ABI_ELFv2) + call_c(entry_point, relocInfo::none); +#else call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::none); +#endif BLOCK_COMMENT("} call_VM_leaf"); } @@ -2227,7 +2278,7 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs // VM call need frame to access(write) O register. if (needs_frame) { save_LR_CR(Rtmp1); - push_frame_abi112(0, Rtmp2); + push_frame_reg_args(0, Rtmp2); } if (Rpre_val->is_volatile() && Robj == noreg) mr(R31, Rpre_val); // Save pre_val across C call if it was preloaded. @@ -2361,7 +2412,8 @@ void MacroAssembler::set_top_ijava_frame_at_SP_as_last_Java_frame(Register sp, R #ifdef CC_INTERP ld(tmp1/*pc*/, _top_ijava_frame_abi(frame_manager_lr), sp); #else - Unimplemented(); + address entry = pc(); + load_const_optimized(tmp1, entry); #endif set_last_Java_frame(/*sp=*/sp, /*pc=*/tmp1); @@ -2421,6 +2473,16 @@ void MacroAssembler::store_klass(Register dst_oop, Register klass, Register ck) } } +void MacroAssembler::store_klass_gap(Register dst_oop, Register val) { + if (UseCompressedClassPointers) { + if (val == noreg) { + val = R0; + li(val, 0); + } + stw(val, oopDesc::klass_gap_offset_in_bytes(), dst_oop); // klass gap if compressed + } +} + int MacroAssembler::instr_size_for_decode_klass_not_null() { if (!UseCompressedClassPointers) return 0; int num_instrs = 1; // shift or move @@ -3006,13 +3068,13 @@ void MacroAssembler::verify_oop(Register oop, const char* msg) { mr(R0, tmp); // kill tmp save_LR_CR(tmp); - push_frame_abi112(nbytes_save, tmp); + push_frame_reg_args(nbytes_save, tmp); // restore tmp mr(tmp, R0); save_volatile_gprs(R1_SP, 112); // except R0 - // load FunctionDescriptor** + // load FunctionDescriptor** / entry_address * load_const(tmp, fd); - // load FunctionDescriptor* + // load FunctionDescriptor* / entry_address ld(tmp, 0, tmp); mr(R4_ARG2, oop); load_const(R3_ARG1, (address)msg); @@ -3092,3 +3154,15 @@ void MacroAssembler::zap_from_to(Register low, int before, Register high, int af } #endif // !PRODUCT + +SkipIfEqualZero::SkipIfEqualZero(MacroAssembler* masm, Register temp, const bool* flag_addr) : _masm(masm), _label() { + int simm16_offset = masm->load_const_optimized(temp, (address)flag_addr, R0, true); + assert(sizeof(bool) == 1, "PowerPC ABI"); + masm->lbz(temp, simm16_offset, temp); + masm->cmpwi(CCR0, temp, 0); + masm->beq(CCR0, _label); +} + +SkipIfEqualZero::~SkipIfEqualZero() { + _masm->bind(_label); +} diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index e3ba572c67f..a6576a4c472 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 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 @@ -279,12 +279,12 @@ class MacroAssembler: public Assembler { // Push a frame of size `bytes'. No abi space provided. void push_frame(unsigned int bytes, Register tmp); - // Push a frame of size `bytes' plus abi112 on top. - void push_frame_abi112(unsigned int bytes, Register tmp); + // Push a frame of size `bytes' plus abi_reg_args on top. + void push_frame_reg_args(unsigned int bytes, Register tmp); // Setup up a new C frame with a spill area for non-volatile GPRs and additional // space for local variables - void push_frame_abi112_nonvolatiles(unsigned int bytes, Register tmp); + void push_frame_reg_args_nonvolatiles(unsigned int bytes, Register tmp); // pop current C frame void pop_frame(); @@ -296,17 +296,31 @@ class MacroAssembler: public Assembler { private: address _last_calls_return_pc; +#if defined(ABI_ELFv2) + // Generic version of a call to C function. + // Updates and returns _last_calls_return_pc. + address branch_to(Register function_entry, bool and_link); +#else // Generic version of a call to C function via a function descriptor // with variable support for C calling conventions (TOC, ENV, etc.). // updates and returns _last_calls_return_pc. address branch_to(Register function_descriptor, bool and_link, bool save_toc_before_call, bool restore_toc_after_call, bool load_toc_of_callee, bool load_env_of_callee); +#endif public: // Get the pc where the last call will return to. returns _last_calls_return_pc. inline address last_calls_return_pc(); +#if defined(ABI_ELFv2) + // Call a C function via a function descriptor and use full C + // calling conventions. Updates and returns _last_calls_return_pc. + address call_c(Register function_entry); + // For tail calls: only branch, don't link, so callee returns to caller of this function. + address call_c_and_return_to_caller(Register function_entry); + address call_c(address function_entry, relocInfo::relocType rt); +#else // Call a C function via a function descriptor and use full C // calling conventions. Updates and returns _last_calls_return_pc. address call_c(Register function_descriptor); @@ -315,6 +329,7 @@ class MacroAssembler: public Assembler { address call_c(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt); address call_c_using_toc(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt, Register toc); +#endif protected: @@ -551,12 +566,14 @@ class MacroAssembler: public Assembler { // Load heap oop and decompress. Loaded oop may not be null. inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg); + inline void store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, + /*specify if d must stay uncompressed*/ Register tmp = noreg); // Null allowed. inline void load_heap_oop(Register d, RegisterOrConstant offs, Register s1 = noreg); // Encode/decode heap oop. Oop may not be null, else en/decoding goes wrong. - inline void encode_heap_oop_not_null(Register d); + inline Register encode_heap_oop_not_null(Register d, Register src = noreg); inline void decode_heap_oop_not_null(Register d); // Null allowed. @@ -566,6 +583,7 @@ class MacroAssembler: public Assembler { void load_klass(Register dst, Register src); void load_klass_with_trap_null_check(Register dst, Register src); void store_klass(Register dst_oop, Register klass, Register tmp = R0); + void store_klass_gap(Register dst_oop, Register val = noreg); // Will store 0 if val not specified. static int instr_size_for_decode_klass_not_null(); void decode_klass_not_null(Register dst, Register src = noreg); void encode_klass_not_null(Register dst, Register src = noreg); @@ -649,6 +667,11 @@ class MacroAssembler: public Assembler { void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {} void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line) {} + // Convenience method returning function entry. For the ELFv1 case + // creates function descriptor at the current address and returs + // the pointer to it. For the ELFv2 case returns the current address. + inline address function_entry(); + #define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__) #define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__) @@ -673,4 +696,21 @@ class MacroAssembler: public Assembler { void zap_from_to(Register low, int before, Register high, int after, Register val, Register addr) PRODUCT_RETURN; }; +// class SkipIfEqualZero: +// +// Instantiating this class will result in assembly code being output that will +// jump around any code emitted between the creation of the instance and it's +// automatic destruction at the end of a scope block, depending on the value of +// the flag passed to the constructor, which will be checked at run-time. +class SkipIfEqualZero : public StackObj { + private: + MacroAssembler* _masm; + Label _label; + + public: + // 'Temp' is a temp register that this object can use (and trash). + explicit SkipIfEqualZero(MacroAssembler*, Register temp, const bool* flag_addr); + ~SkipIfEqualZero(); +}; + #endif // CPU_PPC_VM_MACROASSEMBLER_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp index 93f31a70f5e..84485d4f6af 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_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 @@ -321,6 +321,15 @@ inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstan } } +inline void MacroAssembler::store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) { + if (UseCompressedOops) { + Register compressedOop = encode_heap_oop_not_null((tmp != noreg) ? tmp : d, d); + stw(compressedOop, offs, s1); + } else { + std(d, offs, s1); + } +} + inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, Register s1) { if (UseCompressedOops) { lwz(d, offs, s1); @@ -330,13 +339,17 @@ inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, R } } -inline void MacroAssembler::encode_heap_oop_not_null(Register d) { +inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register src) { + Register current = (src!=noreg) ? src : d; // Compressed oop is in d if no src provided. if (Universe::narrow_oop_base() != NULL) { - sub(d, d, R30); + sub(d, current, R30); + current = d; } if (Universe::narrow_oop_shift() != 0) { - srdi(d, d, LogMinObjAlignmentInBytes); + srdi(d, current, LogMinObjAlignmentInBytes); + current = d; } + return current; // Encoded oop is in this register. } inline void MacroAssembler::decode_heap_oop_not_null(Register d) { @@ -385,4 +398,10 @@ inline void MacroAssembler::trap_range_check_ge(Register a, int si16) { twi(traptoEqual | traptoGreaterThanUnsigned, a/*reg a*/, si16); } +#if defined(ABI_ELFv2) +inline address MacroAssembler::function_entry() { return pc(); } +#else +inline address MacroAssembler::function_entry() { return emit_fd(); } +#endif + #endif // CPU_PPC_VM_MACROASSEMBLER_PPC_INLINE_HPP diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp index 6709c8ce680..26363754b09 100644 --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp @@ -453,11 +453,11 @@ void trace_method_handle_stub(const char* adaptername, if (Verbose) { tty->print_cr("Registers:"); - const int abi_offset = frame::abi_112_size / 8; + const int abi_offset = frame::abi_reg_args_size / 8; for (int i = R3->encoding(); i <= R12->encoding(); i++) { Register r = as_Register(i); int count = i - R3->encoding(); - // The registers are stored in reverse order on the stack (by save_volatile_gprs(R1_SP, abi_112_size)). + // The registers are stored in reverse order on the stack (by save_volatile_gprs(R1_SP, abi_reg_args_size)). tty->print("%3s=" PTR_FORMAT, r->name(), saved_regs[abi_offset + count]); if ((count + 1) % 4 == 0) { tty->cr(); @@ -524,9 +524,9 @@ void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adapt __ save_LR_CR(R0); __ mr(R0, R1_SP); // saved_sp assert(Assembler::is_simm(-nbytes_save, 16), "Overwriting R0"); - // push_frame_abi112 only uses R0 if nbytes_save is wider than 16 bit - __ push_frame_abi112(nbytes_save, R0); - __ save_volatile_gprs(R1_SP, frame::abi_112_size); // Except R0. + // Push_frame_reg_args only uses R0 if nbytes_save is wider than 16 bit. + __ push_frame_reg_args(nbytes_save, R0); + __ save_volatile_gprs(R1_SP, frame::abi_reg_args_size); // Except R0. __ load_const(R3_ARG1, (address)adaptername); __ mr(R4_ARG2, R23_method_handle); diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index 6006c1acaf6..c2854e68e16 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -1008,7 +1008,11 @@ int MachCallDynamicJavaNode::ret_addr_offset() { } int MachCallRuntimeNode::ret_addr_offset() { +#if defined(ABI_ELFv2) + return 28; +#else return 40; +#endif } //============================================================================= @@ -3674,6 +3678,10 @@ encode %{ MacroAssembler _masm(&cbuf); const address start_pc = __ pc(); +#if defined(ABI_ELFv2) + address entry= !($meth$$method) ? NULL : (address)$meth$$method; + __ call_c(entry, relocInfo::runtime_call_type); +#else // The function we're going to call. FunctionDescriptor fdtemp; const FunctionDescriptor* fd = !($meth$$method) ? &fdtemp : (FunctionDescriptor*)$meth$$method; @@ -3684,6 +3692,7 @@ encode %{ // Put entry, env, toc into the constant pool, this needs up to 3 constant // pool entries; call_c_using_toc will optimize the call. __ call_c_using_toc(fd, relocInfo::runtime_call_type, Rtoc); +#endif // Check the ret_addr_offset. assert(((MachCallRuntimeNode*)this)->ret_addr_offset() == __ last_calls_return_pc() - start_pc, @@ -3699,20 +3708,25 @@ encode %{ __ mtctr($src$$Register); %} - // postalloc expand emitter for runtime leaf calls. + // Postalloc expand emitter for runtime leaf calls. enc_class postalloc_expand_java_to_runtime_call(method meth, iRegLdst toc) %{ + loadConLNodesTuple loadConLNodes_Entry; +#if defined(ABI_ELFv2) + jlong entry_address = (jlong) this->entry_point(); + assert(entry_address, "need address here"); + loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper(entry_address), + OptoReg::Name(R12_H_num), OptoReg::Name(R12_num)); +#else // Get the struct that describes the function we are about to call. FunctionDescriptor* fd = (FunctionDescriptor*) this->entry_point(); assert(fd, "need fd here"); + jlong entry_address = (jlong) fd->entry(); // new nodes - loadConLNodesTuple loadConLNodes_Entry; loadConLNodesTuple loadConLNodes_Env; loadConLNodesTuple loadConLNodes_Toc; - MachNode *mtctr = NULL; - MachCallLeafNode *call = NULL; // Create nodes and operands for loading the entry point. - loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper((jlong) fd->entry()), + loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper(entry_address), OptoReg::Name(R12_H_num), OptoReg::Name(R12_num)); @@ -3733,8 +3747,9 @@ encode %{ // Create nodes and operands for loading the Toc point. loadConLNodes_Toc = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper((jlong) fd->toc()), OptoReg::Name(R2_H_num), OptoReg::Name(R2_num)); +#endif // ABI_ELFv2 // mtctr node - mtctr = new (C) CallLeafDirect_mtctrNode(); + MachNode *mtctr = new (C) CallLeafDirect_mtctrNode(); assert(loadConLNodes_Entry._last != NULL, "entry must exist"); mtctr->add_req(0, loadConLNodes_Entry._last); @@ -3743,10 +3758,10 @@ encode %{ mtctr->_opnds[1] = new (C) iRegLdstOper(); // call node - call = new (C) CallLeafDirectNode(); + MachCallLeafNode *call = new (C) CallLeafDirectNode(); call->_opnds[0] = _opnds[0]; - call->_opnds[1] = new (C) methodOper((intptr_t) fd->entry()); // may get set later + call->_opnds[1] = new (C) methodOper((intptr_t) entry_address); // May get set later. // Make the new call node look like the old one. call->_name = _name; @@ -3773,8 +3788,10 @@ encode %{ // These must be reqired edges, as the registers are live up to // the call. Else the constants are handled as kills. call->add_req(mtctr); +#if !defined(ABI_ELFv2) call->add_req(loadConLNodes_Env._last); call->add_req(loadConLNodes_Toc._last); +#endif // ...as well as prec for (uint i = req(); i < len(); ++i) { @@ -3787,10 +3804,12 @@ encode %{ // Insert the new nodes. if (loadConLNodes_Entry._large_hi) nodes->push(loadConLNodes_Entry._large_hi); if (loadConLNodes_Entry._last) nodes->push(loadConLNodes_Entry._last); +#if !defined(ABI_ELFv2) if (loadConLNodes_Env._large_hi) nodes->push(loadConLNodes_Env._large_hi); if (loadConLNodes_Env._last) nodes->push(loadConLNodes_Env._last); if (loadConLNodes_Toc._large_hi) nodes->push(loadConLNodes_Toc._large_hi); if (loadConLNodes_Toc._last) nodes->push(loadConLNodes_Toc._last); +#endif nodes->push(mtctr); nodes->push(call); %} @@ -3837,7 +3856,7 @@ frame %{ // out_preserve_stack_slots for calls to C. Supports the var-args // backing area for register parms. // - varargs_C_out_slots_killed(((frame::abi_112_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size)); + varargs_C_out_slots_killed(((frame::abi_reg_args_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size)); // The after-PROLOG location of the return address. Location of // return address specifies a type (REG or STACK) and a number diff --git a/hotspot/src/cpu/ppc/vm/register_ppc.hpp b/hotspot/src/cpu/ppc/vm/register_ppc.hpp index bc04d8d2c16..107c5bab8b8 100644 --- a/hotspot/src/cpu/ppc/vm/register_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/register_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 @@ -579,15 +579,27 @@ REGISTER_DECLARATION(FloatRegister, F13_ARG13, F13); // volatile // Register declarations to be used in frame manager assembly code. // Use only non-volatile registers in order to keep values across C-calls. +#ifdef CC_INTERP REGISTER_DECLARATION(Register, R14_state, R14); // address of new cInterpreter. REGISTER_DECLARATION(Register, R15_prev_state, R15); // address of old cInterpreter +#else // CC_INTERP +REGISTER_DECLARATION(Register, R14_bcp, R14); +REGISTER_DECLARATION(Register, R15_esp, R15); +REGISTER_DECLARATION(FloatRegister, F15_ftos, F15); +#endif // CC_INTERP REGISTER_DECLARATION(Register, R16_thread, R16); // address of current thread REGISTER_DECLARATION(Register, R17_tos, R17); // address of Java tos (prepushed). REGISTER_DECLARATION(Register, R18_locals, R18); // address of first param slot (receiver). REGISTER_DECLARATION(Register, R19_method, R19); // address of current method #ifndef DONT_USE_REGISTER_DEFINES +#ifdef CC_INTERP #define R14_state AS_REGISTER(Register, R14) #define R15_prev_state AS_REGISTER(Register, R15) +#else // CC_INTERP +#define R14_bcp AS_REGISTER(Register, R14) +#define R15_esp AS_REGISTER(Register, R15) +#define F15_ftos AS_REGISTER(FloatRegister, F15) +#endif // CC_INTERP #define R16_thread AS_REGISTER(Register, R16) #define R17_tos AS_REGISTER(Register, R17) #define R18_locals AS_REGISTER(Register, R18) @@ -608,6 +620,14 @@ REGISTER_DECLARATION(Register, R26_tmp6, R26); REGISTER_DECLARATION(Register, R27_tmp7, R27); REGISTER_DECLARATION(Register, R28_tmp8, R28); REGISTER_DECLARATION(Register, R29_tmp9, R29); +#ifndef CC_INTERP +REGISTER_DECLARATION(Register, R24_dispatch_addr, R24); +REGISTER_DECLARATION(Register, R25_templateTableBase, R25); +REGISTER_DECLARATION(Register, R26_monitor, R26); +REGISTER_DECLARATION(Register, R27_constPoolCache, R27); +REGISTER_DECLARATION(Register, R28_mdx, R28); +#endif // CC_INTERP + #ifndef DONT_USE_REGISTER_DEFINES #define R21_tmp1 AS_REGISTER(Register, R21) #define R22_tmp2 AS_REGISTER(Register, R22) @@ -618,6 +638,16 @@ REGISTER_DECLARATION(Register, R29_tmp9, R29); #define R27_tmp7 AS_REGISTER(Register, R27) #define R28_tmp8 AS_REGISTER(Register, R28) #define R29_tmp9 AS_REGISTER(Register, R29) +#ifndef CC_INTERP +// Lmonitors : monitor pointer +// LcpoolCache: constant pool cache +// mdx: method data index +#define R24_dispatch_addr AS_REGISTER(Register, R24) +#define R25_templateTableBase AS_REGISTER(Register, R25) +#define R26_monitor AS_REGISTER(Register, R26) +#define R27_constPoolCache AS_REGISTER(Register, R27) +#define R28_mdx AS_REGISTER(Register, R28) +#endif #define CCR4_is_synced AS_REGISTER(ConditionRegister, CCR4) #endif diff --git a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp index bc3432bb1e3..0e5898381c2 100644 --- a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp @@ -87,7 +87,7 @@ void OptoRuntime::generate_exception_blob() { address start = __ pc(); - int frame_size_in_bytes = frame::abi_112_size; + int frame_size_in_bytes = frame::abi_reg_args_size; OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); // Exception pc is 'return address' for stack walker. @@ -99,7 +99,7 @@ void OptoRuntime::generate_exception_blob() { // Save callee-saved registers. // Push a C frame for the exception blob. It is needed for the C call later on. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // This call does all the hard work. It checks if an exception handler // exists in the method. @@ -109,8 +109,12 @@ void OptoRuntime::generate_exception_blob() { __ set_last_Java_frame(/*sp=*/R1_SP, noreg); __ mr(R3_ARG1, R16_thread); +#if defined(ABI_ELFv2) + __ call_c((address) OptoRuntime::handle_exception_C, relocInfo::none); +#else __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, OptoRuntime::handle_exception_C), relocInfo::none); +#endif address calls_return_pc = __ last_calls_return_pc(); # ifdef ASSERT __ cmpdi(CCR0, R3_RET, 0); @@ -162,7 +166,11 @@ void OptoRuntime::generate_exception_blob() { __ bind(mh_callsite); __ mr(R31, R3_RET); // Save branch address. __ mr(R3_ARG1, R16_thread); +#if defined(ABI_ELFv2) + __ call_c((address) adjust_SP_for_methodhandle_callsite, relocInfo::none); +#else __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, adjust_SP_for_methodhandle_callsite), relocInfo::none); +#endif // Returns unextended_sp in R3_RET. __ mtctr(R31); // Move address of exception handler to SR_CTR. diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index 2d9b4900bce..d556d7009fa 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 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 @@ -67,7 +67,7 @@ class RegisterSaver { return_pc_is_thread_saved_exception_pc }; - static OopMap* push_frame_abi112_and_save_live_registers(MacroAssembler* masm, + static OopMap* push_frame_reg_args_and_save_live_registers(MacroAssembler* masm, int* out_frame_size_in_bytes, bool generate_oop_map, int return_pc_adjustment, @@ -200,12 +200,12 @@ static const RegisterSaver::LiveRegType RegisterSaver_LiveRegs[] = { RegisterSaver_LiveIntReg( R30 ), // r30 must be the last register }; -OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler* masm, +OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssembler* masm, int* out_frame_size_in_bytes, bool generate_oop_map, int return_pc_adjustment, ReturnPCLocation return_pc_location) { - // Push an abi112-frame and store all registers which may be live. + // Push an abi_reg_args-frame and store all registers which may be live. // If requested, create an OopMap: Record volatile registers as // callee-save values in an OopMap so their save locations will be // propagated to the RegisterMap of the caller frame during @@ -221,7 +221,7 @@ OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler* sizeof(RegisterSaver::LiveRegType); const int register_save_size = regstosave_num * reg_size; const int frame_size_in_bytes = round_to(register_save_size, frame::alignment_in_bytes) - + frame::abi_112_size; + + frame::abi_reg_args_size; *out_frame_size_in_bytes = frame_size_in_bytes; const int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); const int register_save_offset = frame_size_in_bytes - register_save_size; @@ -229,7 +229,7 @@ OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler* // OopMap frame size is in c2 stack slots (sizeof(jint)) not bytes or words. OopMap* map = generate_oop_map ? new OopMap(frame_size_in_slots, 0) : NULL; - BLOCK_COMMENT("push_frame_abi112_and_save_live_registers {"); + BLOCK_COMMENT("push_frame_reg_args_and_save_live_registers {"); // Save r30 in the last slot of the not yet pushed frame so that we // can use it as scratch reg. @@ -294,7 +294,7 @@ OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler* offset += reg_size; } - BLOCK_COMMENT("} push_frame_abi112_and_save_live_registers"); + BLOCK_COMMENT("} push_frame_reg_args_and_save_live_registers"); // And we're done. return map; @@ -699,15 +699,19 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt, int i; VMReg reg; - // Leave room for C-compatible ABI_112. - int stk = (frame::abi_112_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size; + // Leave room for C-compatible ABI_REG_ARGS. + int stk = (frame::abi_reg_args_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size; int arg = 0; int freg = 0; // Avoid passing C arguments in the wrong stack slots. +#if defined(ABI_ELFv2) + assert((SharedRuntime::out_preserve_stack_slots() + stk) * VMRegImpl::stack_slot_size == 96, + "passing C arguments in wrong stack slots"); +#else assert((SharedRuntime::out_preserve_stack_slots() + stk) * VMRegImpl::stack_slot_size == 112, "passing C arguments in wrong stack slots"); - +#endif // We fill-out regs AND regs2 if an argument must be passed in a // register AND in a stack slot. If regs2 is NULL in such a // situation, we bail-out with a fatal error. @@ -953,6 +957,9 @@ static address gen_c2i_adapter(MacroAssembler *masm, #ifdef CC_INTERP const Register tos = R17_tos; +#else + const Register tos = R15_esp; + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); #endif // load TOS @@ -971,7 +978,7 @@ static void gen_i2c_adapter(MacroAssembler *masm, const BasicType *sig_bt, const VMRegPair *regs) { - // Load method's entry-point from methodOop. + // Load method's entry-point from method. __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); @@ -992,7 +999,10 @@ static void gen_i2c_adapter(MacroAssembler *masm, #ifdef CC_INTERP const Register ld_ptr = R17_tos; +#else + const Register ld_ptr = R15_esp; #endif + const Register value_regs[] = { R22_tmp2, R23_tmp3, R24_tmp4, R25_tmp5, R26_tmp6 }; const int num_value_regs = sizeof(value_regs) / sizeof(Register); int value_regs_index = 0; @@ -1083,8 +1093,8 @@ static void gen_i2c_adapter(MacroAssembler *masm, } } - BLOCK_COMMENT("Store method oop"); - // Store method oop into thread->callee_target. + BLOCK_COMMENT("Store method"); + // Store method into thread->callee_target. // We might end up in handle_wrong_method if the callee is // deoptimized as we race thru here. If that happens we don't want // to take a safepoint because the caller frame will look @@ -1504,7 +1514,11 @@ static void check_needs_gc_for_critical_native(MacroAssembler* masm, __ block_comment("block_for_jni_critical"); address entry_point = CAST_FROM_FN_PTR(address, SharedRuntime::block_for_jni_critical); +#if defined(ABI_ELFv2) + __ call_c(entry_point, relocInfo::runtime_call_type); +#else __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::runtime_call_type); +#endif address start = __ pc() - __ offset(), calls_return_pc = __ last_calls_return_pc(); oop_maps->add_gc_map(calls_return_pc - start, map); @@ -1877,7 +1891,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Layout of the native wrapper frame: // (stack grows upwards, memory grows downwards) // - // NW [ABI_112] <-- 1) R1_SP + // NW [ABI_REG_ARGS] <-- 1) R1_SP // [outgoing arguments] <-- 2) R1_SP + out_arg_slot_offset // [oopHandle area] <-- 3) R1_SP + oop_handle_offset (save area for critical natives) // klass <-- 4) R1_SP + klass_offset @@ -2211,8 +2225,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // slow case of monitor enter. Inline a special case of call_VM that // disallows any pending_exception. - // Save argument registers and leave room for C-compatible ABI_112. - int frame_size = frame::abi_112_size + + // Save argument registers and leave room for C-compatible ABI_REG_ARGS. + int frame_size = frame::abi_reg_args_size + round_to(total_c_args * wordSize, frame::alignment_in_bytes); __ mr(R11_scratch1, R1_SP); RegisterSaver::push_frame_and_save_argument_registers(masm, R12_scratch2, frame_size, total_c_args, out_regs, out_regs2); @@ -2250,9 +2264,12 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // The JNI call // -------------------------------------------------------------------------- - +#if defined(ABI_ELFv2) + __ call_c(native_func, relocInfo::runtime_call_type); +#else FunctionDescriptor* fd_native_method = (FunctionDescriptor*) native_func; __ call_c(fd_native_method, relocInfo::runtime_call_type); +#endif // Now, we are back from the native code. @@ -2606,8 +2623,12 @@ static void push_skeleton_frame(MacroAssembler* masm, bool deopt, #ifdef CC_INTERP __ std(R1_SP, _parent_ijava_frame_abi(initial_caller_sp), R1_SP); #else - Unimplemented(); +#ifdef ASSERT + __ load_const_optimized(pc_reg, 0x5afe); + __ std(pc_reg, _ijava_state_neg(ijava_reserved), R1_SP); #endif + __ std(R1_SP, _ijava_state_neg(sender_sp), R1_SP); +#endif // CC_INTERP __ addi(number_of_frames_reg, number_of_frames_reg, -1); __ addi(frame_sizes_reg, frame_sizes_reg, wordSize); __ addi(pcs_reg, pcs_reg, wordSize); @@ -2679,7 +2700,15 @@ static void push_skeleton_frames(MacroAssembler* masm, bool deopt, __ std(R12_scratch2, _abi(lr), R1_SP); // Initialize initial_caller_sp. +#ifdef CC_INTERP __ std(frame_size_reg/*old_sp*/, _parent_ijava_frame_abi(initial_caller_sp), R1_SP); +#else +#ifdef ASSERT + __ load_const_optimized(pc_reg, 0x5afe); + __ std(pc_reg, _ijava_state_neg(ijava_reserved), R1_SP); +#endif + __ std(frame_size_reg, _ijava_state_neg(sender_sp), R1_SP); +#endif // CC_INTERP #ifdef ASSERT // Make sure that there is at least one entry in the array. @@ -2724,7 +2753,7 @@ void SharedRuntime::generate_deopt_blob() { OopMapSet *oop_maps = new OopMapSet(); // size of ABI112 plus spill slots for R3_RET and F1_RET. - const int frame_size_in_bytes = frame::abi_112_spill_size; + const int frame_size_in_bytes = frame::abi_reg_args_spill_size; const int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); int first_frame_size_in_bytes = 0; // frame size of "unpack frame" for call to fetch_unroll_info. @@ -2757,11 +2786,11 @@ void SharedRuntime::generate_deopt_blob() { // Push the "unpack frame" // Save everything in sight. - map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm, - &first_frame_size_in_bytes, - /*generate_oop_map=*/ true, - return_pc_adjustment_no_exception, - RegisterSaver::return_pc_is_lr); + map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &first_frame_size_in_bytes, + /*generate_oop_map=*/ true, + return_pc_adjustment_no_exception, + RegisterSaver::return_pc_is_lr); assert(map != NULL, "OopMap must have been created"); __ li(exec_mode_reg, Deoptimization::Unpack_deopt); @@ -2787,11 +2816,11 @@ void SharedRuntime::generate_deopt_blob() { // Push the "unpack frame". // Save everything in sight. assert(R4 == R4_ARG2, "exception pc must be in r4"); - RegisterSaver::push_frame_abi112_and_save_live_registers(masm, - &first_frame_size_in_bytes, - /*generate_oop_map=*/ false, - return_pc_adjustment_exception, - RegisterSaver::return_pc_is_r4); + RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &first_frame_size_in_bytes, + /*generate_oop_map=*/ false, + return_pc_adjustment_exception, + RegisterSaver::return_pc_is_r4); // Deopt during an exception. Save exec mode for unpack_frames. __ li(exec_mode_reg, Deoptimization::Unpack_exception); @@ -2876,8 +2905,8 @@ void SharedRuntime::generate_deopt_blob() { // ...). // Spill live volatile registers since we'll do a call. - __ std( R3_RET, _abi_112_spill(spill_ret), R1_SP); - __ stfd(F1_RET, _abi_112_spill(spill_fret), R1_SP); + __ std( R3_RET, _abi_reg_args_spill(spill_ret), R1_SP); + __ stfd(F1_RET, _abi_reg_args_spill(spill_fret), R1_SP); // Let the unpacker layout information in the skeletal frames just // allocated. @@ -2889,8 +2918,8 @@ void SharedRuntime::generate_deopt_blob() { __ reset_last_Java_frame(); // Restore the volatiles saved above. - __ ld( R3_RET, _abi_112_spill(spill_ret), R1_SP); - __ lfd(F1_RET, _abi_112_spill(spill_fret), R1_SP); + __ ld( R3_RET, _abi_reg_args_spill(spill_ret), R1_SP); + __ lfd(F1_RET, _abi_reg_args_spill(spill_fret), R1_SP); // Pop the unpack frame. __ pop_frame(); @@ -2900,10 +2929,16 @@ void SharedRuntime::generate_deopt_blob() { // optional c2i, caller of deoptee, ...). // Initialize R14_state. +#ifdef CC_INTERP __ ld(R14_state, 0, R1_SP); __ addi(R14_state, R14_state, -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); // Also inititialize R15_prev_state. __ restore_prev_state(); +#else + __ restore_interpreter_state(R11_scratch1); + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); +#endif // CC_INTERP + // Return to the interpreter entry point. __ blr(); @@ -2930,7 +2965,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { Register unc_trap_reg = R23_tmp3; OopMapSet* oop_maps = new OopMapSet(); - int frame_size_in_bytes = frame::abi_112_size; + int frame_size_in_bytes = frame::abi_reg_args_size; OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); // stack: (deoptee, optional i2c, caller_of_deoptee, ...). @@ -2943,7 +2978,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { __ save_LR_CR(R11_scratch1); // Push an "uncommon_trap" frame. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // stack: (unpack frame, deoptee, optional i2c, caller_of_deoptee, ...). @@ -2996,7 +3031,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { // interpreter frames just created. // Push a simple "unpack frame" here. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // stack: (unpack frame, skeletal interpreter frame, ..., optional // skeletal interpreter frame, optional c2i, caller of deoptee, @@ -3022,11 +3057,17 @@ void SharedRuntime::generate_uncommon_trap_blob() { // stack: (top interpreter frame, ..., optional interpreter frame, // optional c2i, caller of deoptee, ...). +#ifdef CC_INTERP // Initialize R14_state, ... __ ld(R11_scratch1, 0, R1_SP); __ addi(R14_state, R11_scratch1, -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); // also initialize R15_prev_state. __ restore_prev_state(); +#else + __ restore_interpreter_state(R11_scratch1); + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); +#endif // CC_INTERP + // Return to the interpreter entry point. __ blr(); @@ -3064,11 +3105,11 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t } // Save registers, fpu state, and flags. - map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm, - &frame_size_in_bytes, - /*generate_oop_map=*/ true, - /*return_pc_adjustment=*/0, - return_pc_location); + map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &frame_size_in_bytes, + /*generate_oop_map=*/ true, + /*return_pc_adjustment=*/0, + return_pc_location); // The following is basically a call_VM. However, we need the precise // address of the call in order to generate an oopmap. Hence, we do all the @@ -3104,7 +3145,6 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t frame_size_in_bytes, /*restore_ctr=*/true); - BLOCK_COMMENT(" Jump to forward_exception_entry."); // Jump to forward_exception_entry, with the issuing PC in LR // so it looks like the original nmethod called forward_exception_entry. @@ -3151,11 +3191,11 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha address start = __ pc(); - map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm, - &frame_size_in_bytes, - /*generate_oop_map*/ true, - /*return_pc_adjustment*/ 0, - RegisterSaver::return_pc_is_lr); + map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &frame_size_in_bytes, + /*generate_oop_map*/ true, + /*return_pc_adjustment*/ 0, + RegisterSaver::return_pc_is_lr); // Use noreg as last_Java_pc, the return pc will be reconstructed // from the physical frame. @@ -3189,7 +3229,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha RegisterSaver::restore_live_registers_and_pop_frame(masm, frame_size_in_bytes, /*restore_ctr*/ false); - // Get the returned methodOop. + // Get the returned method. __ get_vm_result_2(R19_method); __ bctr(); diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index 1cd4d295925..d452b27038c 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_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 @@ -39,15 +39,10 @@ #include "runtime/stubCodeGenerator.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/top.hpp" -#ifdef TARGET_OS_FAMILY_aix -# include "thread_aix.inline.hpp" -#endif -#ifdef TARGET_OS_FAMILY_linux -# include "thread_linux.inline.hpp" -#endif #ifdef COMPILER2 #include "opto/runtime.hpp" #endif +#include "runtime/thread.inline.hpp" #define __ _masm-> @@ -79,11 +74,11 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", "call_stub"); - address start = __ emit_fd(); + address start = __ function_entry(); // some sanity checks - assert((sizeof(frame::abi_48) % 16) == 0, "unaligned"); - assert((sizeof(frame::abi_112) % 16) == 0, "unaligned"); + assert((sizeof(frame::abi_minframe) % 16) == 0, "unaligned"); + assert((sizeof(frame::abi_reg_args) % 16) == 0, "unaligned"); assert((sizeof(frame::spill_nonvolatiles) % 16) == 0, "unaligned"); assert((sizeof(frame::parent_ijava_frame_abi) % 16) == 0, "unaligned"); assert((sizeof(frame::entry_frame_locals) % 16) == 0, "unaligned"); @@ -221,7 +216,7 @@ class StubGenerator: public StubCodeGenerator { { BLOCK_COMMENT("Call frame manager or native entry."); // Call frame manager or native entry. - Register r_new_arg_entry = R14_state; + Register r_new_arg_entry = R14; // PPC_state; assert_different_registers(r_new_arg_entry, r_top_of_arguments_addr, r_arg_method, r_arg_thread); @@ -234,7 +229,11 @@ class StubGenerator: public StubCodeGenerator { // R16_thread - JavaThread* // Tos must point to last argument - element_size. +#ifdef CC_INTERP const Register tos = R17_tos; +#else + const Register tos = R15_esp; +#endif __ addi(tos, r_top_of_arguments_addr, -Interpreter::stackElementSize); // initialize call_stub locals (step 2) @@ -248,8 +247,11 @@ class StubGenerator: public StubCodeGenerator { assert(tos != r_arg_thread && R19_method != r_arg_thread, "trashed r_arg_thread"); // Set R15_prev_state to 0 for simplifying checks in callee. +#ifdef CC_INTERP __ li(R15_prev_state, 0); - +#else + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); +#endif // Stack on entry to frame manager / native entry: // // F0 [TOP_IJAVA_FRAME_ABI] @@ -444,7 +446,7 @@ class StubGenerator: public StubCodeGenerator { // Save LR/CR and copy exception pc (LR) into R4_ARG2. __ save_LR_CR(R4_ARG2); - __ push_frame_abi112(0, R0); + __ push_frame_reg_args(0, R0); // Find exception handler. __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), @@ -519,7 +521,7 @@ class StubGenerator: public StubCodeGenerator { MacroAssembler* masm = new MacroAssembler(&code); OopMapSet* oop_maps = new OopMapSet(); - int frame_size_in_bytes = frame::abi_112_size; + int frame_size_in_bytes = frame::abi_reg_args_size; OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); StubCodeMark mark(this, "StubRoutines", "throw_exception"); @@ -529,7 +531,7 @@ class StubGenerator: public StubCodeGenerator { __ save_LR_CR(R11_scratch1); // Push a frame. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); address frame_complete_pc = __ pc(); @@ -551,8 +553,11 @@ class StubGenerator: public StubCodeGenerator { if (arg2 != noreg) { __ mr(R5_ARG3, arg2); } - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), - relocInfo::none); +#if defined(ABI_ELFv2) + __ call_c(runtime_entry, relocInfo::none); +#else + __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none); +#endif // Set an oopmap for the call site. oop_maps->add_gc_map((int)(gc_map_pc - start), map); @@ -614,7 +619,7 @@ class StubGenerator: public StubCodeGenerator { // With G1, don't generate the call if we statically know that the target in uninitialized if (!dest_uninitialized) { const int spill_slots = 4 * wordSize; - const int frame_size = frame::abi_112_size + spill_slots; + const int frame_size = frame::abi_reg_args_size + spill_slots; Label filtered; // Is marking active? @@ -628,7 +633,7 @@ class StubGenerator: public StubCodeGenerator { __ beq(CCR0, filtered); __ save_LR_CR(R0); - __ push_frame_abi112(spill_slots, R0); + __ push_frame_reg_args(spill_slots, R0); __ std(from, frame_size - 1 * wordSize, R1_SP); __ std(to, frame_size - 2 * wordSize, R1_SP); __ std(count, frame_size - 3 * wordSize, R1_SP); @@ -672,7 +677,7 @@ class StubGenerator: public StubCodeGenerator { if (branchToEnd) { __ save_LR_CR(R0); // We need this frame only to spill LR. - __ push_frame_abi112(0, R0); + __ push_frame_reg_args(0, R0); __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), addr, count); __ pop_frame(); __ restore_LR_CR(R0); @@ -742,7 +747,7 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", "zero_words_aligned8"); // Implemented as in ClearArray. - address start = __ emit_fd(); + address start = __ function_entry(); Register base_ptr_reg = R3_ARG1; // tohw (needs to be 8b aligned) Register cnt_dwords_reg = R4_ARG2; // count (in dwords) @@ -820,7 +825,7 @@ class StubGenerator: public StubCodeGenerator { // address generate_handler_for_unsafe_access() { StubCodeMark mark(this, "StubRoutines", "handler_for_unsafe_access"); - address start = __ emit_fd(); + address start = __ function_entry(); __ unimplemented("StubRoutines::handler_for_unsafe_access", 93); return start; } @@ -861,7 +866,7 @@ class StubGenerator: public StubCodeGenerator { // to read from the safepoint polling page. address generate_load_from_poll() { StubCodeMark mark(this, "StubRoutines", "generate_load_from_poll"); - address start = __ emit_fd(); + address start = __ function_entry(); __ unimplemented("StubRoutines::verify_oop", 95); // TODO PPC port return start; } @@ -885,7 +890,7 @@ class StubGenerator: public StubCodeGenerator { // address generate_fill(BasicType t, bool aligned, const char* name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); const Register to = R3_ARG1; // source array address const Register value = R4_ARG2; // fill value @@ -1123,7 +1128,7 @@ class StubGenerator: public StubCodeGenerator { // address generate_disjoint_byte_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); Register tmp1 = R6_ARG4; Register tmp2 = R7_ARG5; @@ -1254,15 +1259,21 @@ class StubGenerator: public StubCodeGenerator { // address generate_conjoint_byte_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); Register tmp1 = R6_ARG4; Register tmp2 = R7_ARG5; Register tmp3 = R8_ARG6; +#if defined(ABI_ELFv2) + address nooverlap_target = aligned ? + StubRoutines::arrayof_jbyte_disjoint_arraycopy() : + StubRoutines::jbyte_disjoint_arraycopy(); +#else address nooverlap_target = aligned ? ((FunctionDescriptor*)StubRoutines::arrayof_jbyte_disjoint_arraycopy())->entry() : ((FunctionDescriptor*)StubRoutines::jbyte_disjoint_arraycopy())->entry(); +#endif array_overlap_test(nooverlap_target, 0); // Do reverse copy. We assume the case of actual overlap is rare enough @@ -1345,7 +1356,7 @@ class StubGenerator: public StubCodeGenerator { Register tmp3 = R8_ARG6; Register tmp4 = R9_ARG7; - address start = __ emit_fd(); + address start = __ function_entry(); Label l_1, l_2, l_3, l_4, l_5, l_6, l_7, l_8; // don't try anything fancy if arrays don't have many elements @@ -1474,15 +1485,21 @@ class StubGenerator: public StubCodeGenerator { // address generate_conjoint_short_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); Register tmp1 = R6_ARG4; Register tmp2 = R7_ARG5; Register tmp3 = R8_ARG6; +#if defined(ABI_ELFv2) + address nooverlap_target = aligned ? + StubRoutines::arrayof_jshort_disjoint_arraycopy() : + StubRoutines::jshort_disjoint_arraycopy(); +#else address nooverlap_target = aligned ? ((FunctionDescriptor*)StubRoutines::arrayof_jshort_disjoint_arraycopy())->entry() : ((FunctionDescriptor*)StubRoutines::jshort_disjoint_arraycopy())->entry(); +#endif array_overlap_test(nooverlap_target, 1); @@ -1597,7 +1614,7 @@ class StubGenerator: public StubCodeGenerator { // address generate_disjoint_int_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); generate_disjoint_int_copy_core(aligned); __ blr(); return start; @@ -1681,11 +1698,17 @@ class StubGenerator: public StubCodeGenerator { // address generate_conjoint_int_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); +#if defined(ABI_ELFv2) + address nooverlap_target = aligned ? + StubRoutines::arrayof_jint_disjoint_arraycopy() : + StubRoutines::jint_disjoint_arraycopy(); +#else address nooverlap_target = aligned ? ((FunctionDescriptor*)StubRoutines::arrayof_jint_disjoint_arraycopy())->entry() : ((FunctionDescriptor*)StubRoutines::jint_disjoint_arraycopy())->entry(); +#endif array_overlap_test(nooverlap_target, 2); @@ -1767,7 +1790,7 @@ class StubGenerator: public StubCodeGenerator { // address generate_disjoint_long_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); generate_disjoint_long_copy_core(aligned); __ blr(); @@ -1849,11 +1872,17 @@ class StubGenerator: public StubCodeGenerator { // address generate_conjoint_long_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); +#if defined(ABI_ELFv2) + address nooverlap_target = aligned ? + StubRoutines::arrayof_jlong_disjoint_arraycopy() : + StubRoutines::jlong_disjoint_arraycopy(); +#else address nooverlap_target = aligned ? ((FunctionDescriptor*)StubRoutines::arrayof_jlong_disjoint_arraycopy())->entry() : ((FunctionDescriptor*)StubRoutines::jlong_disjoint_arraycopy())->entry(); +#endif array_overlap_test(nooverlap_target, 3); generate_conjoint_long_copy_core(aligned); @@ -1875,11 +1904,17 @@ class StubGenerator: public StubCodeGenerator { address generate_conjoint_oop_copy(bool aligned, const char * name, bool dest_uninitialized) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); +#if defined(ABI_ELFv2) + address nooverlap_target = aligned ? + StubRoutines::arrayof_oop_disjoint_arraycopy() : + StubRoutines::oop_disjoint_arraycopy(); +#else address nooverlap_target = aligned ? ((FunctionDescriptor*)StubRoutines::arrayof_oop_disjoint_arraycopy())->entry() : ((FunctionDescriptor*)StubRoutines::oop_disjoint_arraycopy())->entry(); +#endif gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7); @@ -1910,7 +1945,7 @@ class StubGenerator: public StubCodeGenerator { // address generate_disjoint_oop_copy(bool aligned, const char * name, bool dest_uninitialized) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7); @@ -1991,7 +2026,7 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); // Entry point, pc or function descriptor. - *entry = __ emit_fd(); + *entry = __ function_entry(); // Load *adr into R4_ARG2, may fault. *fault_pc = __ pc(); @@ -2056,7 +2091,7 @@ class StubGenerator: public StubCodeGenerator { guarantee(!UseAESIntrinsics, "not yet implemented."); } - // PPC uses stubs for safefetch. + // Safefetch stubs. generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, &StubRoutines::_safefetch32_fault_pc, &StubRoutines::_safefetch32_continuation_pc); diff --git a/langtools/test/tools/javac/annotations/neg/MixedSource.java b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp similarity index 50% rename from langtools/test/tools/javac/annotations/neg/MixedSource.java rename to hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp index 30df4391289..051ed26e728 100644 --- a/langtools/test/tools/javac/annotations/neg/MixedSource.java +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 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 @@ -19,17 +20,25 @@ * Please 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 5036565 - * @summary Annotations definitions are allowed using -source 1.4 but not annotations - * @author gafter * - * @compile/fail -source 1.4 MixedSource.java */ -package mixed.source; +#ifndef CPU_PPC_VM_TEMPLATEINTERPRETERGENERATOR_PPC_HPP +#define CPU_PPC_VM_TEMPLATEINTERPRETERGENERATOR_PPC_HPP -@interface foo {} + protected: + address generate_normal_entry(bool synchronized); + address generate_native_entry(bool synchronized); + address generate_math_entry(AbstractInterpreter::MethodKind kind); + address generate_empty_entry(void); + + void lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded=false); + void unlock_method(bool check_exceptions = true); + + void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); + void generate_counter_overflow(Label& continue_entry); + + void generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals); + void generate_stack_overflow_check(Register Rframe_size, Register Rscratch1); + +#endif // CPU_PPC_VM_TEMPLATEINTERPRETERGENERATOR_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp new file mode 100644 index 00000000000..2e19fca081d --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp @@ -0,0 +1,1813 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2014 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#ifndef CC_INTERP +#include "asm/macroAssembler.inline.hpp" +#include "interpreter/bytecodeHistogram.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterGenerator.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "interpreter/templateTable.hpp" +#include "oops/arrayOop.hpp" +#include "oops/methodData.hpp" +#include "oops/method.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/jvmtiThreadState.hpp" +#include "runtime/arguments.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/synchronizer.hpp" +#include "runtime/timer.hpp" +#include "runtime/vframeArray.hpp" +#include "utilities/debug.hpp" +#include "utilities/macros.hpp" + +#undef __ +#define __ _masm-> + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +//----------------------------------------------------------------------------- + +// Actually we should never reach here since we do stack overflow checks before pushing any frame. +address TemplateInterpreterGenerator::generate_StackOverflowError_handler() { + address entry = __ pc(); + __ unimplemented("generate_StackOverflowError_handler"); + return entry; +} + +address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) { + address entry = __ pc(); + __ empty_expression_stack(); + __ load_const_optimized(R4_ARG2, (address) name); + // Index is in R17_tos. + __ mr(R5_ARG3, R17_tos); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException)); + return entry; +} + +#if 0 +// Call special ClassCastException constructor taking object to cast +// and target class as arguments. +address TemplateInterpreterGenerator::generate_ClassCastException_verbose_handler(const char* name) { + address entry = __ pc(); + + // Target class oop is in register R6_ARG4 by convention! + + // Expression stack must be empty before entering the VM if an + // exception happened. + __ empty_expression_stack(); + // Setup parameters. + // Thread will be loaded to R3_ARG1. + __ load_const_optimized(R4_ARG2, (address) name); + __ mr(R5_ARG3, R17_tos); + // R6_ARG4 contains specified class. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException_verbose)); +#ifdef ASSERT + // Above call must not return here since exception pending. + __ should_not_reach_here(); +#endif + return entry; +} +#endif + +address TemplateInterpreterGenerator::generate_ClassCastException_handler() { + address entry = __ pc(); + // Expression stack must be empty before entering the VM if an + // exception happened. + __ empty_expression_stack(); + + // Load exception object. + // Thread will be loaded to R3_ARG1. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException), R17_tos); +#ifdef ASSERT + // Above call must not return here since exception pending. + __ should_not_reach_here(); +#endif + return entry; +} + +address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) { + address entry = __ pc(); + //__ untested("generate_exception_handler_common"); + Register Rexception = R17_tos; + + // Expression stack must be empty before entering the VM if an exception happened. + __ empty_expression_stack(); + + __ load_const_optimized(R4_ARG2, (address) name, R11_scratch1); + if (pass_oop) { + __ mr(R5_ARG3, Rexception); + __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), false); + } else { + __ load_const_optimized(R5_ARG3, (address) message, R11_scratch1); + __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), false); + } + + // Throw exception. + __ mr(R3_ARG1, Rexception); + __ load_const_optimized(R11_scratch1, Interpreter::throw_exception_entry(), R12_scratch2); + __ mtctr(R11_scratch1); + __ bctr(); + + return entry; +} + +address TemplateInterpreterGenerator::generate_continuation_for(TosState state) { + address entry = __ pc(); + __ unimplemented("generate_continuation_for"); + return entry; +} + +// This entry is returned to when a call returns to the interpreter. +// When we arrive here, we expect that the callee stack frame is already popped. +address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) { + address entry = __ pc(); + + // Move the value out of the return register back to the TOS cache of current frame. + switch (state) { + case ltos: + case btos: + case ctos: + case stos: + case atos: + case itos: __ mr(R17_tos, R3_RET); break; // RET -> TOS cache + case ftos: + case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET + case vtos: break; // Nothing to do, this was a void return. + default : ShouldNotReachHere(); + } + + __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp. + __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1); + __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0); + + // Compiled code destroys templateTableBase, reload. + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R12_scratch2); + + const Register cache = R11_scratch1; + const Register size = R12_scratch2; + __ get_cache_and_index_at_bcp(cache, 1, index_size); + + // Big Endian (get least significant byte of 64 bit value): + __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()) + 7, cache); + __ sldi(size, size, Interpreter::logStackElementSize); + __ add(R15_esp, R15_esp, size); + __ dispatch_next(state, step); + return entry; +} + +address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { + address entry = __ pc(); + // If state != vtos, we're returning from a native method, which put it's result + // into the result register. So move the value out of the return register back + // to the TOS cache of current frame. + + switch (state) { + case ltos: + case btos: + case ctos: + case stos: + case atos: + case itos: __ mr(R17_tos, R3_RET); break; // GR_RET -> TOS cache + case ftos: + case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET + case vtos: break; // Nothing to do, this was a void return. + default : ShouldNotReachHere(); + } + + // Load LcpoolCache @@@ should be already set! + __ get_constant_pool_cache(R27_constPoolCache); + + // Handle a pending exception, fall through if none. + __ check_and_forward_exception(R11_scratch1, R12_scratch2); + + // Start executing bytecodes. + __ dispatch_next(state, step); + + return entry; +} + +// A result handler converts the native result into java format. +// Use the shared code between c++ and template interpreter. +address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) { + return AbstractInterpreterGenerator::generate_result_handler_for(type); +} + +address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) { + address entry = __ pc(); + + __ push(state); + __ call_VM(noreg, runtime_entry); + __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos)); + + return entry; +} + +// Helpers for commoning out cases in the various type of method entries. + +// Increment invocation count & check for overflow. +// +// Note: checking for negative value instead of overflow +// so we have a 'sticky' overflow test. +// +void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { + // Note: In tiered we increment either counters in method or in MDO depending if we're profiling or not. + Register Rscratch1 = R11_scratch1; + Register Rscratch2 = R12_scratch2; + Register R3_counters = R3_ARG1; + Label done; + + if (TieredCompilation) { + const int increment = InvocationCounter::count_increment; + const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; + Label no_mdo; + if (ProfileInterpreter) { + const Register Rmdo = Rscratch1; + // If no method data exists, go to profile_continue. + __ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method); + __ cmpdi(CCR0, Rmdo, 0); + __ beq(CCR0, no_mdo); + + // Increment backedge counter in the MDO. + const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ lwz(Rscratch2, mdo_bc_offs, Rmdo); + __ addi(Rscratch2, Rscratch2, increment); + __ stw(Rscratch2, mdo_bc_offs, Rmdo); + __ load_const_optimized(Rscratch1, mask, R0); + __ and_(Rscratch1, Rscratch2, Rscratch1); + __ bne(CCR0, done); + __ b(*overflow); + } + + // Increment counter in MethodCounters*. + const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ bind(no_mdo); + __ get_method_counters(R19_method, R3_counters, done); + __ lwz(Rscratch2, mo_bc_offs, R3_counters); + __ addi(Rscratch2, Rscratch2, increment); + __ stw(Rscratch2, mo_bc_offs, R3_counters); + __ load_const_optimized(Rscratch1, mask, R0); + __ and_(Rscratch1, Rscratch2, Rscratch1); + __ beq(CCR0, *overflow); + + __ bind(done); + + } else { + + // Update standard invocation counters. + Register Rsum_ivc_bec = R4_ARG2; + __ get_method_counters(R19_method, R3_counters, done); + __ increment_invocation_counter(R3_counters, Rsum_ivc_bec, R12_scratch2); + // Increment interpreter invocation counter. + if (ProfileInterpreter) { // %%% Merge this into methodDataOop. + __ lwz(R12_scratch2, in_bytes(MethodCounters::interpreter_invocation_counter_offset()), R3_counters); + __ addi(R12_scratch2, R12_scratch2, 1); + __ stw(R12_scratch2, in_bytes(MethodCounters::interpreter_invocation_counter_offset()), R3_counters); + } + // Check if we must create a method data obj. + if (ProfileInterpreter && profile_method != NULL) { + const Register profile_limit = Rscratch1; + int pl_offs = __ load_const_optimized(profile_limit, &InvocationCounter::InterpreterProfileLimit, R0, true); + __ lwz(profile_limit, pl_offs, profile_limit); + // Test to see if we should create a method data oop. + __ cmpw(CCR0, Rsum_ivc_bec, profile_limit); + __ blt(CCR0, *profile_method_continue); + // If no method data exists, go to profile_method. + __ test_method_data_pointer(*profile_method); + } + // Finally check for counter overflow. + if (overflow) { + const Register invocation_limit = Rscratch1; + int il_offs = __ load_const_optimized(invocation_limit, &InvocationCounter::InterpreterInvocationLimit, R0, true); + __ lwz(invocation_limit, il_offs, invocation_limit); + assert(4 == sizeof(InvocationCounter::InterpreterInvocationLimit), "unexpected field size"); + __ cmpw(CCR0, Rsum_ivc_bec, invocation_limit); + __ bge(CCR0, *overflow); + } + + __ bind(done); + } +} + +// Generate code to initiate compilation on invocation counter overflow. +void TemplateInterpreterGenerator::generate_counter_overflow(Label& continue_entry) { + // Generate code to initiate compilation on the counter overflow. + + // InterpreterRuntime::frequency_counter_overflow takes one arguments, + // which indicates if the counter overflow occurs at a backwards branch (NULL bcp) + // We pass zero in. + // The call returns the address of the verified entry point for the method or NULL + // if the compilation did not complete (either went background or bailed out). + // + // Unlike the C++ interpreter above: Check exceptions! + // Assumption: Caller must set the flag "do_not_unlock_if_sychronized" if the monitor of a sync'ed + // method has not yet been created. Thus, no unlocking of a non-existing monitor can occur. + + __ li(R4_ARG2, 0); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true); + + // Returns verified_entry_point or NULL. + // We ignore it in any case. + __ b(continue_entry); +} + +void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rmem_frame_size, Register Rscratch1) { + assert_different_registers(Rmem_frame_size, Rscratch1); + __ generate_stack_overflow_check_with_compare_and_throw(Rmem_frame_size, Rscratch1); +} + +void TemplateInterpreterGenerator::unlock_method(bool check_exceptions) { + __ unlock_object(R26_monitor, check_exceptions); +} + +// Lock the current method, interpreter register window must be set up! +void TemplateInterpreterGenerator::lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded) { + const Register Robj_to_lock = Rscratch2; + + { + if (!flags_preloaded) { + __ lwz(Rflags, method_(access_flags)); + } + +#ifdef ASSERT + // Check if methods needs synchronization. + { + Label Lok; + __ testbitdi(CCR0, R0, Rflags, JVM_ACC_SYNCHRONIZED_BIT); + __ btrue(CCR0,Lok); + __ stop("method doesn't need synchronization"); + __ bind(Lok); + } +#endif // ASSERT + } + + // Get synchronization object to Rscratch2. + { + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + Label Lstatic; + Label Ldone; + + __ testbitdi(CCR0, R0, Rflags, JVM_ACC_STATIC_BIT); + __ btrue(CCR0, Lstatic); + + // Non-static case: load receiver obj from stack and we're done. + __ ld(Robj_to_lock, R18_locals); + __ b(Ldone); + + __ bind(Lstatic); // Static case: Lock the java mirror + __ ld(Robj_to_lock, in_bytes(Method::const_offset()), R19_method); + __ ld(Robj_to_lock, in_bytes(ConstMethod::constants_offset()), Robj_to_lock); + __ ld(Robj_to_lock, ConstantPool::pool_holder_offset_in_bytes(), Robj_to_lock); + __ ld(Robj_to_lock, mirror_offset, Robj_to_lock); + + __ bind(Ldone); + __ verify_oop(Robj_to_lock); + } + + // Got the oop to lock => execute! + __ add_monitor_to_stack(true, Rscratch1, R0); + + __ std(Robj_to_lock, BasicObjectLock::obj_offset_in_bytes(), R26_monitor); + __ lock_object(R26_monitor, Robj_to_lock); +} + +// Generate a fixed interpreter frame for pure interpreter +// and I2N native transition frames. +// +// Before (stack grows downwards): +// +// | ... | +// |------------- | +// | java arg0 | +// | ... | +// | java argn | +// | | <- R15_esp +// | | +// |--------------| +// | abi_112 | +// | | <- R1_SP +// |==============| +// +// +// After: +// +// | ... | +// | java arg0 |<- R18_locals +// | ... | +// | java argn | +// |--------------| +// | | +// | java locals | +// | | +// |--------------| +// | abi_48 | +// |==============| +// | | +// | istate | +// | | +// |--------------| +// | monitor |<- R26_monitor +// |--------------| +// | |<- R15_esp +// | expression | +// | stack | +// | | +// |--------------| +// | | +// | abi_112 |<- R1_SP +// |==============| +// +// The top most frame needs an abi space of 112 bytes. This space is needed, +// since we call to c. The c function may spill their arguments to the caller +// frame. When we call to java, we don't need these spill slots. In order to save +// space on the stack, we resize the caller. However, java local reside in +// the caller frame and the frame has to be increased. The frame_size for the +// current frame was calculated based on max_stack as size for the expression +// stack. At the call, just a part of the expression stack might be used. +// We don't want to waste this space and cut the frame back accordingly. +// The resulting amount for resizing is calculated as follows: +// resize = (number_of_locals - number_of_arguments) * slot_size +// + (R1_SP - R15_esp) + 48 +// +// The size for the callee frame is calculated: +// framesize = 112 + max_stack + monitor + state_size +// +// maxstack: Max number of slots on the expression stack, loaded from the method. +// monitor: We statically reserve room for one monitor object. +// state_size: We save the current state of the interpreter to this area. +// +void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals) { + Register parent_frame_resize = R6_ARG4, // Frame will grow by this number of bytes. + top_frame_size = R7_ARG5, + Rconst_method = R8_ARG6; + + assert_different_registers(Rsize_of_parameters, Rsize_of_locals, parent_frame_resize, top_frame_size); + + __ ld(Rconst_method, method_(const)); + __ lhz(Rsize_of_parameters /* number of params */, + in_bytes(ConstMethod::size_of_parameters_offset()), Rconst_method); + if (native_call) { + // If we're calling a native method, we reserve space for the worst-case signature + // handler varargs vector, which is max(Argument::n_register_parameters, parameter_count+2). + // We add two slots to the parameter_count, one for the jni + // environment and one for a possible native mirror. + Label skip_native_calculate_max_stack; + __ addi(top_frame_size, Rsize_of_parameters, 2); + __ cmpwi(CCR0, top_frame_size, Argument::n_register_parameters); + __ bge(CCR0, skip_native_calculate_max_stack); + __ li(top_frame_size, Argument::n_register_parameters); + __ bind(skip_native_calculate_max_stack); + __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize); + __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize); + __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize! + assert(Rsize_of_locals == noreg, "Rsize_of_locals not initialized"); // Only relevant value is Rsize_of_parameters. + } else { + __ lhz(Rsize_of_locals /* number of params */, in_bytes(ConstMethod::size_of_locals_offset()), Rconst_method); + __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize); + __ sldi(Rsize_of_locals, Rsize_of_locals, Interpreter::logStackElementSize); + __ lhz(top_frame_size, in_bytes(ConstMethod::max_stack_offset()), Rconst_method); + __ sub(R11_scratch1, Rsize_of_locals, Rsize_of_parameters); // >=0 + __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize! + __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize); + __ add(parent_frame_resize, parent_frame_resize, R11_scratch1); + } + + // Compute top frame size. + __ addi(top_frame_size, top_frame_size, frame::abi_reg_args_size + frame::ijava_state_size); + + // Cut back area between esp and max_stack. + __ addi(parent_frame_resize, parent_frame_resize, frame::abi_minframe_size - Interpreter::stackElementSize); + + __ round_to(top_frame_size, frame::alignment_in_bytes); + __ round_to(parent_frame_resize, frame::alignment_in_bytes); + // parent_frame_resize = (locals-parameters) - (ESP-SP-ABI48) Rounded to frame alignment size. + // Enlarge by locals-parameters (not in case of native_call), shrink by ESP-SP-ABI48. + + { + // -------------------------------------------------------------------------- + // Stack overflow check + + Label cont; + __ add(R11_scratch1, parent_frame_resize, top_frame_size); + generate_stack_overflow_check(R11_scratch1, R12_scratch2); + } + + // Set up interpreter state registers. + + __ add(R18_locals, R15_esp, Rsize_of_parameters); + __ ld(R27_constPoolCache, in_bytes(ConstMethod::constants_offset()), Rconst_method); + __ ld(R27_constPoolCache, ConstantPool::cache_offset_in_bytes(), R27_constPoolCache); + + // Set method data pointer. + if (ProfileInterpreter) { + Label zero_continue; + __ ld(R28_mdx, method_(method_data)); + __ cmpdi(CCR0, R28_mdx, 0); + __ beq(CCR0, zero_continue); + __ addi(R28_mdx, R28_mdx, in_bytes(MethodData::data_offset())); + __ bind(zero_continue); + } + + if (native_call) { + __ li(R14_bcp, 0); // Must initialize. + } else { + __ add(R14_bcp, in_bytes(ConstMethod::codes_offset()), Rconst_method); + } + + // Resize parent frame. + __ mflr(R12_scratch2); + __ neg(parent_frame_resize, parent_frame_resize); + __ resize_frame(parent_frame_resize, R11_scratch1); + __ std(R12_scratch2, _abi(lr), R1_SP); + + __ addi(R26_monitor, R1_SP, - frame::ijava_state_size); + __ addi(R15_esp, R26_monitor, - Interpreter::stackElementSize); + + // Store values. + // R15_esp, R14_bcp, R26_monitor, R28_mdx are saved at java calls + // in InterpreterMacroAssembler::call_from_interpreter. + __ std(R19_method, _ijava_state_neg(method), R1_SP); + __ std(R21_sender_SP, _ijava_state_neg(sender_sp), R1_SP); + __ std(R27_constPoolCache, _ijava_state_neg(cpoolCache), R1_SP); + __ std(R18_locals, _ijava_state_neg(locals), R1_SP); + + // Note: esp, bcp, monitor, mdx live in registers. Hence, the correct version can only + // be found in the frame after save_interpreter_state is done. This is always true + // for non-top frames. But when a signal occurs, dumping the top frame can go wrong, + // because e.g. frame::interpreter_frame_bcp() will not access the correct value + // (Enhanced Stack Trace). + // The signal handler does not save the interpreter state into the frame. + __ li(R0, 0); +#ifdef ASSERT + // Fill remaining slots with constants. + __ load_const_optimized(R11_scratch1, 0x5afe); + __ load_const_optimized(R12_scratch2, 0xdead); +#endif + // We have to initialize some frame slots for native calls (accessed by GC). + if (native_call) { + __ std(R26_monitor, _ijava_state_neg(monitors), R1_SP); + __ std(R14_bcp, _ijava_state_neg(bcp), R1_SP); + if (ProfileInterpreter) { __ std(R28_mdx, _ijava_state_neg(mdx), R1_SP); } + } +#ifdef ASSERT + else { + __ std(R12_scratch2, _ijava_state_neg(monitors), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(bcp), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(mdx), R1_SP); + } + __ std(R11_scratch1, _ijava_state_neg(ijava_reserved), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(esp), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(lresult), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(fresult), R1_SP); +#endif + __ subf(R12_scratch2, top_frame_size, R1_SP); + __ std(R0, _ijava_state_neg(oop_tmp), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(top_frame_sp), R1_SP); + + // Push top frame. + __ push_frame(top_frame_size, R11_scratch1); +} + +// End of helpers + +// ============================================================================ +// Various method entries +// + +// Empty method, generate a very fast return. We must skip this entry if +// someone's debugging, indicated by the flag +// "interp_mode" in the Thread obj. +// Note: empty methods are generated mostly methods that do assertions, which are +// disabled in the "java opt build". +address TemplateInterpreterGenerator::generate_empty_entry(void) { + if (!UseFastEmptyMethods) { + NOT_PRODUCT(__ should_not_reach_here();) + return Interpreter::entry_for_kind(Interpreter::zerolocals); + } + + Label Lslow_path; + const Register Rjvmti_mode = R11_scratch1; + address entry = __ pc(); + + __ lwz(Rjvmti_mode, thread_(interp_only_mode)); + __ cmpwi(CCR0, Rjvmti_mode, 0); + __ bne(CCR0, Lslow_path); // jvmti_mode!=0 + + // Noone's debuggin: Simply return. + // Pop c2i arguments (if any) off when we return. +#ifdef ASSERT + __ ld(R9_ARG7, 0, R1_SP); + __ ld(R10_ARG8, 0, R21_sender_SP); + __ cmpd(CCR0, R9_ARG7, R10_ARG8); + __ asm_assert_eq("backlink", 0x545); +#endif // ASSERT + __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started. + + // And we're done. + __ blr(); + + __ bind(Lslow_path); + __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1); + __ flush(); + + return entry; +} + +// Support abs and sqrt like in compiler. +// For others we can use a normal (native) entry. + +inline bool math_entry_available(AbstractInterpreter::MethodKind kind) { + // Provide math entry with debugging on demand. + // Note: Debugging changes which code will get executed: + // Debugging or disabled InlineIntrinsics: java method will get interpreted and performs a native call. + // Not debugging and enabled InlineIntrinics: processor instruction will get used. + // Result might differ slightly due to rounding etc. + if (!InlineIntrinsics && (!FLAG_IS_ERGO(InlineIntrinsics))) return false; // Generate a vanilla entry. + + return ((kind==Interpreter::java_lang_math_sqrt && VM_Version::has_fsqrt()) || + (kind==Interpreter::java_lang_math_abs)); +} + +address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { + if (!math_entry_available(kind)) { + NOT_PRODUCT(__ should_not_reach_here();) + return Interpreter::entry_for_kind(Interpreter::zerolocals); + } + + Label Lslow_path; + const Register Rjvmti_mode = R11_scratch1; + address entry = __ pc(); + + // Provide math entry with debugging on demand. + __ lwz(Rjvmti_mode, thread_(interp_only_mode)); + __ cmpwi(CCR0, Rjvmti_mode, 0); + __ bne(CCR0, Lslow_path); // jvmti_mode!=0 + + __ lfd(F1_RET, Interpreter::stackElementSize, R15_esp); + + // Pop c2i arguments (if any) off when we return. +#ifdef ASSERT + __ ld(R9_ARG7, 0, R1_SP); + __ ld(R10_ARG8, 0, R21_sender_SP); + __ cmpd(CCR0, R9_ARG7, R10_ARG8); + __ asm_assert_eq("backlink", 0x545); +#endif // ASSERT + __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started. + + if (kind == Interpreter::java_lang_math_sqrt) { + __ fsqrt(F1_RET, F1_RET); + } else if (kind == Interpreter::java_lang_math_abs) { + __ fabs(F1_RET, F1_RET); + } else { + ShouldNotReachHere(); + } + + // And we're done. + __ blr(); + + // Provide slow path for JVMTI case. + __ bind(Lslow_path); + __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R12_scratch2); + __ flush(); + + return entry; +} + +// Interpreter stub for calling a native method. (asm interpreter) +// This sets up a somewhat different looking stack for calling the +// native method than the typical interpreter frame setup. +// +// On entry: +// R19_method - method +// R16_thread - JavaThread* +// R15_esp - intptr_t* sender tos +// +// abstract stack (grows up) +// [ IJava (caller of JNI callee) ] <-- ASP +// ... +address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { + + address entry = __ pc(); + + const bool inc_counter = UseCompiler || CountCompiledCalls; + + // ----------------------------------------------------------------------------- + // Allocate a new frame that represents the native callee (i2n frame). + // This is not a full-blown interpreter frame, but in particular, the + // following registers are valid after this: + // - R19_method + // - R18_local (points to start of argumuments to native function) + // + // abstract stack (grows up) + // [ IJava (caller of JNI callee) ] <-- ASP + // ... + + const Register signature_handler_fd = R11_scratch1; + const Register pending_exception = R0; + const Register result_handler_addr = R31; + const Register native_method_fd = R11_scratch1; + const Register access_flags = R22_tmp2; + const Register active_handles = R11_scratch1; // R26_monitor saved to state. + const Register sync_state = R12_scratch2; + const Register sync_state_addr = sync_state; // Address is dead after use. + const Register suspend_flags = R11_scratch1; + + //============================================================================= + // Allocate new frame and initialize interpreter state. + + Label exception_return; + Label exception_return_sync_check; + Label stack_overflow_return; + + // Generate new interpreter state and jump to stack_overflow_return in case of + // a stack overflow. + //generate_compute_interpreter_state(stack_overflow_return); + + Register size_of_parameters = R22_tmp2; + + generate_fixed_frame(true, size_of_parameters, noreg /* unused */); + + //============================================================================= + // Increment invocation counter. On overflow, entry to JNI method + // will be compiled. + Label invocation_counter_overflow, continue_after_compile; + if (inc_counter) { + if (synchronized) { + // Since at this point in the method invocation the exception handler + // would try to exit the monitor of synchronized methods which hasn't + // been entered yet, we set the thread local variable + // _do_not_unlock_if_synchronized to true. If any exception was thrown by + // runtime, exception handling i.e. unlock_if_synchronized_method will + // check this thread local flag. + // This flag has two effects, one is to force an unwind in the topmost + // interpreter frame and not perform an unlock while doing so. + __ li(R0, 1); + __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + } + generate_counter_incr(&invocation_counter_overflow, NULL, NULL); + + __ BIND(continue_after_compile); + // Reset the _do_not_unlock_if_synchronized flag. + if (synchronized) { + __ li(R0, 0); + __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + } + } + + // access_flags = method->access_flags(); + // Load access flags. + assert(access_flags->is_nonvolatile(), + "access_flags must be in a non-volatile register"); + // Type check. + assert(4 == sizeof(AccessFlags), "unexpected field size"); + __ lwz(access_flags, method_(access_flags)); + + // We don't want to reload R19_method and access_flags after calls + // to some helper functions. + assert(R19_method->is_nonvolatile(), + "R19_method must be a non-volatile register"); + + // Check for synchronized methods. Must happen AFTER invocation counter + // check, so method is not locked if counter overflows. + + if (synchronized) { + lock_method(access_flags, R11_scratch1, R12_scratch2, true); + + // Update monitor in state. + __ ld(R11_scratch1, 0, R1_SP); + __ std(R26_monitor, _ijava_state_neg(monitors), R11_scratch1); + } + + // jvmti/jvmpi support + __ notify_method_entry(); + + //============================================================================= + // Get and call the signature handler. + + __ ld(signature_handler_fd, method_(signature_handler)); + Label call_signature_handler; + + __ cmpdi(CCR0, signature_handler_fd, 0); + __ bne(CCR0, call_signature_handler); + + // Method has never been called. Either generate a specialized + // handler or point to the slow one. + // + // Pass parameter 'false' to avoid exception check in call_VM. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), R19_method, false); + + // Check for an exception while looking up the target method. If we + // incurred one, bail. + __ ld(pending_exception, thread_(pending_exception)); + __ cmpdi(CCR0, pending_exception, 0); + __ bne(CCR0, exception_return_sync_check); // Has pending exception. + + // Reload signature handler, it may have been created/assigned in the meanwhile. + __ ld(signature_handler_fd, method_(signature_handler)); + __ twi_0(signature_handler_fd); // Order wrt. load of klass mirror and entry point (isync is below). + + __ BIND(call_signature_handler); + + // Before we call the signature handler we push a new frame to + // protect the interpreter frame volatile registers when we return + // from jni but before we can get back to Java. + + // First set the frame anchor while the SP/FP registers are + // convenient and the slow signature handler can use this same frame + // anchor. + + // We have a TOP_IJAVA_FRAME here, which belongs to us. + __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R12_scratch2/*tmp*/); + + // Now the interpreter frame (and its call chain) have been + // invalidated and flushed. We are now protected against eager + // being enabled in native code. Even if it goes eager the + // registers will be reloaded as clean and we will invalidate after + // the call so no spurious flush should be possible. + + // Call signature handler and pass locals address. + // + // Our signature handlers copy required arguments to the C stack + // (outgoing C args), R3_ARG1 to R10_ARG8, and FARG1 to FARG13. + __ mr(R3_ARG1, R18_locals); + __ ld(signature_handler_fd, 0, signature_handler_fd); + + __ call_stub(signature_handler_fd); + + // Remove the register parameter varargs slots we allocated in + // compute_interpreter_state. SP+16 ends up pointing to the ABI + // outgoing argument area. + // + // Not needed on PPC64. + //__ add(SP, SP, Argument::n_register_parameters*BytesPerWord); + + assert(result_handler_addr->is_nonvolatile(), "result_handler_addr must be in a non-volatile register"); + // Save across call to native method. + __ mr(result_handler_addr, R3_RET); + + __ isync(); // Acquire signature handler before trying to fetch the native entry point and klass mirror. + + // Set up fixed parameters and call the native method. + // If the method is static, get mirror into R4_ARG2. + { + Label method_is_not_static; + // Access_flags is non-volatile and still, no need to restore it. + + // Restore access flags. + __ testbitdi(CCR0, R0, access_flags, JVM_ACC_STATIC_BIT); + __ bfalse(CCR0, method_is_not_static); + + // constants = method->constants(); + __ ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method); + __ ld(R11_scratch1, in_bytes(ConstMethod::constants_offset()), R11_scratch1); + // pool_holder = method->constants()->pool_holder(); + __ ld(R11_scratch1/*pool_holder*/, ConstantPool::pool_holder_offset_in_bytes(), + R11_scratch1/*constants*/); + + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + + // mirror = pool_holder->klass_part()->java_mirror(); + __ ld(R0/*mirror*/, mirror_offset, R11_scratch1/*pool_holder*/); + // state->_native_mirror = mirror; + + __ ld(R11_scratch1, 0, R1_SP); + __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1); + // R4_ARG2 = &state->_oop_temp; + __ addi(R4_ARG2, R11_scratch1, _ijava_state_neg(oop_tmp)); + __ BIND(method_is_not_static); + } + + // At this point, arguments have been copied off the stack into + // their JNI positions. Oops are boxed in-place on the stack, with + // handles copied to arguments. The result handler address is in a + // register. + + // Pass JNIEnv address as first parameter. + __ addir(R3_ARG1, thread_(jni_environment)); + + // Load the native_method entry before we change the thread state. + __ ld(native_method_fd, method_(native_function)); + + //============================================================================= + // Transition from _thread_in_Java to _thread_in_native. As soon as + // we make this change the safepoint code needs to be certain that + // the last Java frame we established is good. The pc in that frame + // just needs to be near here not an actual return address. + + // We use release_store_fence to update values like the thread state, where + // we don't want the current thread to continue until all our prior memory + // accesses (including the new thread state) are visible to other threads. + __ li(R0, _thread_in_native); + __ release(); + + // TODO PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); + __ stw(R0, thread_(thread_state)); + + if (UseMembar) { + __ fence(); + } + + //============================================================================= + // Call the native method. Argument registers must not have been + // overwritten since "__ call_stub(signature_handler);" (except for + // ARG1 and ARG2 for static methods). + __ call_c(native_method_fd); + + __ li(R0, 0); + __ ld(R11_scratch1, 0, R1_SP); + __ std(R3_RET, _ijava_state_neg(lresult), R11_scratch1); + __ stfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1); + __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1); // reset + + // Note: C++ interpreter needs the following here: + // The frame_manager_lr field, which we use for setting the last + // java frame, gets overwritten by the signature handler. Restore + // it now. + //__ get_PC_trash_LR(R11_scratch1); + //__ std(R11_scratch1, _top_ijava_frame_abi(frame_manager_lr), R1_SP); + + // Because of GC R19_method may no longer be valid. + + // Block, if necessary, before resuming in _thread_in_Java state. + // In order for GC to work, don't clear the last_Java_sp until after + // blocking. + + //============================================================================= + // Switch thread to "native transition" state before reading the + // synchronization state. This additional state is necessary + // because reading and testing the synchronization state is not + // atomic w.r.t. GC, as this scenario demonstrates: Java thread A, + // in _thread_in_native state, loads _not_synchronized and is + // preempted. VM thread changes sync state to synchronizing and + // suspends threads for GC. Thread A is resumed to finish this + // native method, but doesn't block here since it didn't see any + // synchronization in progress, and escapes. + + // We use release_store_fence to update values like the thread state, where + // we don't want the current thread to continue until all our prior memory + // accesses (including the new thread state) are visible to other threads. + __ li(R0/*thread_state*/, _thread_in_native_trans); + __ release(); + __ stw(R0/*thread_state*/, thread_(thread_state)); + if (UseMembar) { + __ fence(); + } + // Write serialization page so that the VM thread can do a pseudo remote + // membar. We use the current thread pointer to calculate a thread + // specific offset to write to within the page. This minimizes bus + // traffic due to cache line collision. + else { + __ serialize_memory(R16_thread, R11_scratch1, R12_scratch2); + } + + // Now before we return to java we must look for a current safepoint + // (a new safepoint can not start since we entered native_trans). + // We must check here because a current safepoint could be modifying + // the callers registers right this moment. + + // Acquire isn't strictly necessary here because of the fence, but + // sync_state is declared to be volatile, so we do it anyway + // (cmp-br-isync on one path, release (same as acquire on PPC64) on the other path). + int sync_state_offs = __ load_const_optimized(sync_state_addr, SafepointSynchronize::address_of_state(), /*temp*/R0, true); + + // TODO PPC port assert(4 == SafepointSynchronize::sz_state(), "unexpected field size"); + __ lwz(sync_state, sync_state_offs, sync_state_addr); + + // TODO PPC port assert(4 == Thread::sz_suspend_flags(), "unexpected field size"); + __ lwz(suspend_flags, thread_(suspend_flags)); + + Label sync_check_done; + Label do_safepoint; + // No synchronization in progress nor yet synchronized. + __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized); + // Not suspended. + __ cmpwi(CCR1, suspend_flags, 0); + + __ bne(CCR0, do_safepoint); + __ beq(CCR1, sync_check_done); + __ bind(do_safepoint); + __ isync(); + // Block. We do the call directly and leave the current + // last_Java_frame setup undisturbed. We must save any possible + // native result across the call. No oop is present. + + __ mr(R3_ARG1, R16_thread); + __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans), + relocInfo::none); + + __ bind(sync_check_done); + + //============================================================================= + // <<<<<< Back in Interpreter Frame >>>>> + + // We are in thread_in_native_trans here and back in the normal + // interpreter frame. We don't have to do anything special about + // safepoints and we can switch to Java mode anytime we are ready. + + // Note: frame::interpreter_frame_result has a dependency on how the + // method result is saved across the call to post_method_exit. For + // native methods it assumes that the non-FPU/non-void result is + // saved in _native_lresult and a FPU result in _native_fresult. If + // this changes then the interpreter_frame_result implementation + // will need to be updated too. + + // On PPC64, we have stored the result directly after the native call. + + //============================================================================= + // Back in Java + + // We use release_store_fence to update values like the thread state, where + // we don't want the current thread to continue until all our prior memory + // accesses (including the new thread state) are visible to other threads. + __ li(R0/*thread_state*/, _thread_in_Java); + __ release(); + __ stw(R0/*thread_state*/, thread_(thread_state)); + if (UseMembar) { + __ fence(); + } + + __ reset_last_Java_frame(); + + // Jvmdi/jvmpi support. Whether we've got an exception pending or + // not, and whether unlocking throws an exception or not, we notify + // on native method exit. If we do have an exception, we'll end up + // in the caller's context to handle it, so if we don't do the + // notify here, we'll drop it on the floor. + __ notify_method_exit(true/*native method*/, + ilgl /*illegal state (not used for native methods)*/, + InterpreterMacroAssembler::NotifyJVMTI, + false /*check_exceptions*/); + + //============================================================================= + // Handle exceptions + + if (synchronized) { + // Don't check for exceptions since we're still in the i2n frame. Do that + // manually afterwards. + unlock_method(false); + } + + // Reset active handles after returning from native. + // thread->active_handles()->clear(); + __ ld(active_handles, thread_(active_handles)); + // TODO PPC port assert(4 == JNIHandleBlock::top_size_in_bytes(), "unexpected field size"); + __ li(R0, 0); + __ stw(R0, JNIHandleBlock::top_offset_in_bytes(), active_handles); + + Label exception_return_sync_check_already_unlocked; + __ ld(R0/*pending_exception*/, thread_(pending_exception)); + __ cmpdi(CCR0, R0/*pending_exception*/, 0); + __ bne(CCR0, exception_return_sync_check_already_unlocked); + + //----------------------------------------------------------------------------- + // No exception pending. + + // Move native method result back into proper registers and return. + // Invoke result handler (may unbox/promote). + __ ld(R11_scratch1, 0, R1_SP); + __ ld(R3_RET, _ijava_state_neg(lresult), R11_scratch1); + __ lfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1); + __ call_stub(result_handler_addr); + + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + + // Must use the return pc which was loaded from the caller's frame + // as the VM uses return-pc-patching for deoptimization. + __ mtlr(R0); + __ blr(); + + //----------------------------------------------------------------------------- + // An exception is pending. We call into the runtime only if the + // caller was not interpreted. If it was interpreted the + // interpreter will do the correct thing. If it isn't interpreted + // (call stub/compiled code) we will change our return and continue. + + __ BIND(exception_return_sync_check); + + if (synchronized) { + // Don't check for exceptions since we're still in the i2n frame. Do that + // manually afterwards. + unlock_method(false); + } + __ BIND(exception_return_sync_check_already_unlocked); + + const Register return_pc = R31; + + __ ld(return_pc, 0, R1_SP); + __ ld(return_pc, _abi(lr), return_pc); + + // Get the address of the exception handler. + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), + R16_thread, + return_pc /* return pc */); + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, noreg, R11_scratch1, R12_scratch2); + + // Load the PC of the the exception handler into LR. + __ mtlr(R3_RET); + + // Load exception into R3_ARG1 and clear pending exception in thread. + __ ld(R3_ARG1/*exception*/, thread_(pending_exception)); + __ li(R4_ARG2, 0); + __ std(R4_ARG2, thread_(pending_exception)); + + // Load the original return pc into R4_ARG2. + __ mr(R4_ARG2/*issuing_pc*/, return_pc); + + // Return to exception handler. + __ blr(); + + //============================================================================= + // Counter overflow. + + if (inc_counter) { + // Handle invocation counter overflow. + __ bind(invocation_counter_overflow); + + generate_counter_overflow(continue_after_compile); + } + + return entry; +} + +// Generic interpreted method entry to (asm) interpreter. +// +address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { + bool inc_counter = UseCompiler || CountCompiledCalls; + address entry = __ pc(); + // Generate the code to allocate the interpreter stack frame. + Register Rsize_of_parameters = R4_ARG2, // Written by generate_fixed_frame. + Rsize_of_locals = R5_ARG3; // Written by generate_fixed_frame. + + generate_fixed_frame(false, Rsize_of_parameters, Rsize_of_locals); + +#ifdef FAST_DISPATCH + __ unimplemented("Fast dispatch in generate_normal_entry"); +#if 0 + __ set((intptr_t)Interpreter::dispatch_table(), IdispatchTables); + // Set bytecode dispatch table base. +#endif +#endif + + // -------------------------------------------------------------------------- + // Zero out non-parameter locals. + // Note: *Always* zero out non-parameter locals as Sparc does. It's not + // worth to ask the flag, just do it. + Register Rslot_addr = R6_ARG4, + Rnum = R7_ARG5; + Label Lno_locals, Lzero_loop; + + // Set up the zeroing loop. + __ subf(Rnum, Rsize_of_parameters, Rsize_of_locals); + __ subf(Rslot_addr, Rsize_of_parameters, R18_locals); + __ srdi_(Rnum, Rnum, Interpreter::logStackElementSize); + __ beq(CCR0, Lno_locals); + __ li(R0, 0); + __ mtctr(Rnum); + + // The zero locals loop. + __ bind(Lzero_loop); + __ std(R0, 0, Rslot_addr); + __ addi(Rslot_addr, Rslot_addr, -Interpreter::stackElementSize); + __ bdnz(Lzero_loop); + + __ bind(Lno_locals); + + // -------------------------------------------------------------------------- + // Counter increment and overflow check. + Label invocation_counter_overflow, + profile_method, + profile_method_continue; + if (inc_counter || ProfileInterpreter) { + + Register Rdo_not_unlock_if_synchronized_addr = R11_scratch1; + if (synchronized) { + // Since at this point in the method invocation the exception handler + // would try to exit the monitor of synchronized methods which hasn't + // been entered yet, we set the thread local variable + // _do_not_unlock_if_synchronized to true. If any exception was thrown by + // runtime, exception handling i.e. unlock_if_synchronized_method will + // check this thread local flag. + // This flag has two effects, one is to force an unwind in the topmost + // interpreter frame and not perform an unlock while doing so. + __ li(R0, 1); + __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + } + // Increment invocation counter and check for overflow. + if (inc_counter) { + generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue); + } + + __ bind(profile_method_continue); + + // Reset the _do_not_unlock_if_synchronized flag. + if (synchronized) { + __ li(R0, 0); + __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + } + } + + // -------------------------------------------------------------------------- + // Locking of synchronized methods. Must happen AFTER invocation_counter + // check and stack overflow check, so method is not locked if overflows. + if (synchronized) { + lock_method(R3_ARG1, R4_ARG2, R5_ARG3); + } +#ifdef ASSERT + else { + Label Lok; + __ lwz(R0, in_bytes(Method::access_flags_offset()), R19_method); + __ andi_(R0, R0, JVM_ACC_SYNCHRONIZED); + __ asm_assert_eq("method needs synchronization", 0x8521); + __ bind(Lok); + } +#endif // ASSERT + + __ verify_thread(); + + // -------------------------------------------------------------------------- + // JVMTI support + __ notify_method_entry(); + + // -------------------------------------------------------------------------- + // Start executing instructions. + __ dispatch_next(vtos); + + // -------------------------------------------------------------------------- + // Out of line counter overflow and MDO creation code. + if (ProfileInterpreter) { + // We have decided to profile this method in the interpreter. + __ bind(profile_method); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); + __ set_method_data_pointer_for_bcp(); + __ b(profile_method_continue); + } + + if (inc_counter) { + // Handle invocation counter overflow. + __ bind(invocation_counter_overflow); + generate_counter_overflow(profile_method_continue); + } + return entry; +} + +// ============================================================================= +// Entry points + +address AbstractInterpreterGenerator::generate_method_entry( + AbstractInterpreter::MethodKind kind) { + // Determine code generation flags. + bool synchronized = false; + address entry_point = NULL; + + switch (kind) { + case Interpreter::zerolocals : break; + case Interpreter::zerolocals_synchronized: synchronized = true; break; + case Interpreter::native : entry_point = ((InterpreterGenerator*) this)->generate_native_entry(false); break; + case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*) this)->generate_native_entry(true); break; + case Interpreter::empty : entry_point = ((InterpreterGenerator*) this)->generate_empty_entry(); break; + case Interpreter::accessor : entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry(); break; + case Interpreter::abstract : entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry(); break; + + case Interpreter::java_lang_math_sin : // fall thru + case Interpreter::java_lang_math_cos : // fall thru + case Interpreter::java_lang_math_tan : // fall thru + case Interpreter::java_lang_math_abs : // fall thru + case Interpreter::java_lang_math_log : // fall thru + case Interpreter::java_lang_math_log10 : // fall thru + case Interpreter::java_lang_math_sqrt : // fall thru + case Interpreter::java_lang_math_pow : // fall thru + case Interpreter::java_lang_math_exp : entry_point = ((InterpreterGenerator*) this)->generate_math_entry(kind); break; + case Interpreter::java_lang_ref_reference_get + : entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break; + default : ShouldNotReachHere(); break; + } + + if (entry_point) { + return entry_point; + } + + return ((InterpreterGenerator*) this)->generate_normal_entry(synchronized); +} + +// These should never be compiled since the interpreter will prefer +// the compiled version to the intrinsic version. +bool AbstractInterpreter::can_be_compiled(methodHandle m) { + return !math_entry_available(method_kind(m)); +} + +// How much stack a method activation needs in stack slots. +// We must calc this exactly like in generate_fixed_frame. +// Note: This returns the conservative size assuming maximum alignment. +int AbstractInterpreter::size_top_interpreter_activation(Method* method) { + const int max_alignment_size = 2; + const int abi_scratch = frame::abi_reg_args_size; + return method->max_locals() + method->max_stack() + frame::interpreter_frame_monitor_size() + max_alignment_size + abi_scratch; +} + +// Fills a sceletal interpreter frame generated during deoptimizations +// and returns the frame size in slots. +// +// Parameters: +// +// interpreter_frame == NULL: +// Only calculate the size of an interpreter activation, no actual layout. +// Note: This calculation must exactly parallel the frame setup +// in TemplateInterpreter::generate_normal_entry. But it does not +// account for the SP alignment, that might further enhance the +// frame size, depending on FP. +// +// interpreter_frame != NULL: +// set up the method, locals, and monitors. +// The frame interpreter_frame, if not NULL, is guaranteed to be the +// right size, as determined by a previous call to this method. +// It is also guaranteed to be walkable even though it is in a skeletal state +// +// is_top_frame == true: +// We're processing the *oldest* interpreter frame! +// +// pop_frame_extra_args: +// If this is != 0 we are returning to a deoptimized frame by popping +// off the callee frame. We want to re-execute the call that called the +// callee interpreted, but since the return to the interpreter would pop +// the arguments off advance the esp by dummy popframe_extra_args slots. +// Popping off those will establish the stack layout as it was before the call. +// +int AbstractInterpreter::layout_activation(Method* method, + int tempcount, + int popframe_extra_args, + int moncount, + int caller_actual_parameters, + int callee_param_count, + int callee_locals, + frame* caller, + frame* interpreter_frame, + bool is_top_frame, + bool is_bottom_frame) { + + const int max_alignment_space = 2; + const int abi_scratch = is_top_frame ? (frame::abi_reg_args_size / Interpreter::stackElementSize) : + (frame::abi_minframe_size / Interpreter::stackElementSize) ; + const int conservative_framesize_in_slots = + method->max_stack() + callee_locals - callee_param_count + + (moncount * frame::interpreter_frame_monitor_size()) + max_alignment_space + + abi_scratch + frame::ijava_state_size / Interpreter::stackElementSize; + + assert(!is_top_frame || conservative_framesize_in_slots * 8 > frame::abi_reg_args_size + frame::ijava_state_size, "frame too small"); + + if (interpreter_frame == NULL) { + // Since we don't know the exact alignment, we return the conservative size. + return (conservative_framesize_in_slots & -2); + } else { + // Now we know our caller, calc the exact frame layout and size. + intptr_t* locals_base = (caller->is_interpreted_frame()) ? + caller->interpreter_frame_esp() + caller_actual_parameters : + caller->sp() + method->max_locals() - 1 + (frame::abi_minframe_size / Interpreter::stackElementSize) ; + + intptr_t* monitor_base = caller->sp() - frame::ijava_state_size / Interpreter::stackElementSize ; + intptr_t* monitor = monitor_base - (moncount * frame::interpreter_frame_monitor_size()); + intptr_t* esp_base = monitor - 1; + intptr_t* esp = esp_base - tempcount - popframe_extra_args; + intptr_t* sp = (intptr_t *) (((intptr_t) (esp_base- callee_locals + callee_param_count - method->max_stack()- abi_scratch)) & -StackAlignmentInBytes); + intptr_t* sender_sp = caller->sp() + (frame::abi_minframe_size - frame::abi_reg_args_size) / Interpreter::stackElementSize; + intptr_t* top_frame_sp = is_top_frame ? sp : sp + (frame::abi_minframe_size - frame::abi_reg_args_size) / Interpreter::stackElementSize; + + interpreter_frame->interpreter_frame_set_method(method); + interpreter_frame->interpreter_frame_set_locals(locals_base); + interpreter_frame->interpreter_frame_set_cpcache(method->constants()->cache()); + interpreter_frame->interpreter_frame_set_esp(esp); + interpreter_frame->interpreter_frame_set_monitor_end((BasicObjectLock *)monitor); + interpreter_frame->interpreter_frame_set_top_frame_sp(top_frame_sp); + if (!is_bottom_frame) { + interpreter_frame->interpreter_frame_set_sender_sp(sender_sp); + } + + int framesize_in_slots = caller->sp() - sp; + assert(!is_top_frame ||framesize_in_slots >= (frame::abi_reg_args_size / Interpreter::stackElementSize) + frame::ijava_state_size / Interpreter::stackElementSize, "frame too small"); + assert(framesize_in_slots <= conservative_framesize_in_slots, "exact frame size must be smaller than the convervative size!"); + return framesize_in_slots; + } +} + +// ============================================================================= +// Exceptions + +void TemplateInterpreterGenerator::generate_throw_exception() { + Register Rexception = R17_tos, + Rcontinuation = R3_RET; + + // -------------------------------------------------------------------------- + // Entry point if an method returns with a pending exception (rethrow). + Interpreter::_rethrow_exception_entry = __ pc(); + { + __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp. + __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1); + __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0); + + // Compiled code destroys templateTableBase, reload. + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); + } + + // Entry point if a interpreted method throws an exception (throw). + Interpreter::_throw_exception_entry = __ pc(); + { + __ mr(Rexception, R3_RET); + + __ verify_thread(); + __ verify_oop(Rexception); + + // Expression stack must be empty before entering the VM in case of an exception. + __ empty_expression_stack(); + // Find exception handler address and preserve exception oop. + // Call C routine to find handler and jump to it. + __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), Rexception); + __ mtctr(Rcontinuation); + // Push exception for exception handler bytecodes. + __ push_ptr(Rexception); + + // Jump to exception handler (may be remove activation entry!). + __ bctr(); + } + + // If the exception is not handled in the current frame the frame is + // removed and the exception is rethrown (i.e. exception + // continuation is _rethrow_exception). + // + // Note: At this point the bci is still the bxi for the instruction + // which caused the exception and the expression stack is + // empty. Thus, for any VM calls at this point, GC will find a legal + // oop map (with empty expression stack). + + // In current activation + // tos: exception + // bcp: exception bcp + + // -------------------------------------------------------------------------- + // JVMTI PopFrame support + + Interpreter::_remove_activation_preserving_args_entry = __ pc(); + { + // Set the popframe_processing bit in popframe_condition indicating that we are + // currently handling popframe, so that call_VMs that may happen later do not + // trigger new popframe handling cycles. + __ lwz(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + __ ori(R11_scratch1, R11_scratch1, JavaThread::popframe_processing_bit); + __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + + // Empty the expression stack, as in normal exception handling. + __ empty_expression_stack(); + __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, /* install_monitor_exception */ false); + + // Check to see whether we are returning to a deoptimized frame. + // (The PopFrame call ensures that the caller of the popped frame is + // either interpreted or compiled and deoptimizes it if compiled.) + // Note that we don't compare the return PC against the + // deoptimization blob's unpack entry because of the presence of + // adapter frames in C2. + Label Lcaller_not_deoptimized; + Register return_pc = R3_ARG1; + __ ld(return_pc, 0, R1_SP); + __ ld(return_pc, _abi(lr), return_pc); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), return_pc); + __ cmpdi(CCR0, R3_RET, 0); + __ bne(CCR0, Lcaller_not_deoptimized); + + // The deoptimized case. + // In this case, we can't call dispatch_next() after the frame is + // popped, but instead must save the incoming arguments and restore + // them after deoptimization has occurred. + __ ld(R4_ARG2, in_bytes(Method::const_offset()), R19_method); + __ lhz(R4_ARG2 /* number of params */, in_bytes(ConstMethod::size_of_parameters_offset()), R4_ARG2); + __ slwi(R4_ARG2, R4_ARG2, Interpreter::logStackElementSize); + __ addi(R5_ARG3, R18_locals, Interpreter::stackElementSize); + __ subf(R5_ARG3, R4_ARG2, R5_ARG3); + // Save these arguments. + __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), R16_thread, R4_ARG2, R5_ARG3); + + // Inform deoptimization that it is responsible for restoring these arguments. + __ load_const_optimized(R11_scratch1, JavaThread::popframe_force_deopt_reexecution_bit); + __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + + // Return from the current method into the deoptimization blob. Will eventually + // end up in the deopt interpeter entry, deoptimization prepared everything that + // we will reexecute the call that called us. + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*reload return_pc*/ return_pc, R11_scratch1, R12_scratch2); + __ mtlr(return_pc); + __ blr(); + + // The non-deoptimized case. + __ bind(Lcaller_not_deoptimized); + + // Clear the popframe condition flag. + __ li(R0, 0); + __ stw(R0, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + + // Get out of the current method and re-execute the call that called us. + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ return_pc, R11_scratch1, R12_scratch2); + __ restore_interpreter_state(R11_scratch1); + __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1); + __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0); + __ mtlr(return_pc); + if (ProfileInterpreter) { + __ set_method_data_pointer_for_bcp(); + } + __ dispatch_next(vtos); + } + // end of JVMTI PopFrame support + + // -------------------------------------------------------------------------- + // Remove activation exception entry. + // This is jumped to if an interpreted method can't handle an exception itself + // (we come from the throw/rethrow exception entry above). We're going to call + // into the VM to find the exception handler in the caller, pop the current + // frame and return the handler we calculated. + Interpreter::_remove_activation_entry = __ pc(); + { + __ pop_ptr(Rexception); + __ verify_thread(); + __ verify_oop(Rexception); + __ std(Rexception, in_bytes(JavaThread::vm_result_offset()), R16_thread); + + __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, true); + __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI, false); + + __ get_vm_result(Rexception); + + // We are done with this activation frame; find out where to go next. + // The continuation point will be an exception handler, which expects + // the following registers set up: + // + // RET: exception oop + // ARG2: Issuing PC (see generate_exception_blob()), only used if the caller is compiled. + + Register return_pc = R31; // Needs to survive the runtime call. + __ ld(return_pc, 0, R1_SP); + __ ld(return_pc, _abi(lr), return_pc); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, return_pc); + + // Remove the current activation. + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ noreg, R11_scratch1, R12_scratch2); + + __ mr(R4_ARG2, return_pc); + __ mtlr(R3_RET); + __ mr(R3_RET, Rexception); + __ blr(); + } +} + +// JVMTI ForceEarlyReturn support. +// Returns "in the middle" of a method with a "fake" return value. +address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) { + + Register Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2; + + address entry = __ pc(); + __ empty_expression_stack(); + + __ load_earlyret_value(state, Rscratch1); + + __ ld(Rscratch1, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread); + // Clear the earlyret state. + __ li(R0, 0); + __ stw(R0, in_bytes(JvmtiThreadState::earlyret_state_offset()), Rscratch1); + + __ remove_activation(state, false, false); + // Copied from TemplateTable::_return. + // Restoration of lr done by remove_activation. + switch (state) { + case ltos: + case btos: + case ctos: + case stos: + case atos: + case itos: __ mr(R3_RET, R17_tos); break; + case ftos: + case dtos: __ fmr(F1_RET, F15_ftos); break; + case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need + // to get visible before the reference to the object gets stored anywhere. + __ membar(Assembler::StoreStore); break; + default : ShouldNotReachHere(); + } + __ blr(); + + return entry; +} // end of ForceEarlyReturn support + +//----------------------------------------------------------------------------- +// Helper for vtos entry point generation + +void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, + address& bep, + address& cep, + address& sep, + address& aep, + address& iep, + address& lep, + address& fep, + address& dep, + address& vep) { + assert(t->is_valid() && t->tos_in() == vtos, "illegal template"); + Label L; + + aep = __ pc(); __ push_ptr(); __ b(L); + fep = __ pc(); __ push_f(); __ b(L); + dep = __ pc(); __ push_d(); __ b(L); + lep = __ pc(); __ push_l(); __ b(L); + __ align(32, 12, 24); // align L + bep = cep = sep = + iep = __ pc(); __ push_i(); + vep = __ pc(); + __ bind(L); + generate_and_dispatch(t); +} + +//----------------------------------------------------------------------------- +// Generation of individual instructions + +// helpers for generate_and_dispatch + +InterpreterGenerator::InterpreterGenerator(StubQueue* code) + : TemplateInterpreterGenerator(code) { + generate_all(); // Down here so it can be "virtual". +} + +//----------------------------------------------------------------------------- + +// Non-product code +#ifndef PRODUCT +address TemplateInterpreterGenerator::generate_trace_code(TosState state) { + //__ flush_bundle(); + address entry = __ pc(); + + char *bname = NULL; + uint tsize = 0; + switch(state) { + case ftos: + bname = "trace_code_ftos {"; + tsize = 2; + break; + case btos: + bname = "trace_code_btos {"; + tsize = 2; + break; + case ctos: + bname = "trace_code_ctos {"; + tsize = 2; + break; + case stos: + bname = "trace_code_stos {"; + tsize = 2; + break; + case itos: + bname = "trace_code_itos {"; + tsize = 2; + break; + case ltos: + bname = "trace_code_ltos {"; + tsize = 3; + break; + case atos: + bname = "trace_code_atos {"; + tsize = 2; + break; + case vtos: + // Note: In case of vtos, the topmost of stack value could be a int or doubl + // In case of a double (2 slots) we won't see the 2nd stack value. + // Maybe we simply should print the topmost 3 stack slots to cope with the problem. + bname = "trace_code_vtos {"; + tsize = 2; + + break; + case dtos: + bname = "trace_code_dtos {"; + tsize = 3; + break; + default: + ShouldNotReachHere(); + } + BLOCK_COMMENT(bname); + + // Support short-cut for TraceBytecodesAt. + // Don't call into the VM if we don't want to trace to speed up things. + Label Lskip_vm_call; + if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) { + int offs1 = __ load_const_optimized(R11_scratch1, (address) &TraceBytecodesAt, R0, true); + int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true); + __ ld(R11_scratch1, offs1, R11_scratch1); + __ lwa(R12_scratch2, offs2, R12_scratch2); + __ cmpd(CCR0, R12_scratch2, R11_scratch1); + __ blt(CCR0, Lskip_vm_call); + } + + __ push(state); + // Load 2 topmost expression stack values. + __ ld(R6_ARG4, tsize*Interpreter::stackElementSize, R15_esp); + __ ld(R5_ARG3, Interpreter::stackElementSize, R15_esp); + __ mflr(R31); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), /* unused */ R4_ARG2, R5_ARG3, R6_ARG4, false); + __ mtlr(R31); + __ pop(state); + + if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) { + __ bind(Lskip_vm_call); + } + __ blr(); + BLOCK_COMMENT("} trace_code"); + return entry; +} + +void TemplateInterpreterGenerator::count_bytecode() { + int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeCounter::_counter_value, R12_scratch2, true); + __ lwz(R12_scratch2, offs, R11_scratch1); + __ addi(R12_scratch2, R12_scratch2, 1); + __ stw(R12_scratch2, offs, R11_scratch1); +} + +void TemplateInterpreterGenerator::histogram_bytecode(Template* t) { + int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeHistogram::_counters[t->bytecode()], R12_scratch2, true); + __ lwz(R12_scratch2, offs, R11_scratch1); + __ addi(R12_scratch2, R12_scratch2, 1); + __ stw(R12_scratch2, offs, R11_scratch1); +} + +void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) { + const Register addr = R11_scratch1, + tmp = R12_scratch2; + // Get index, shift out old bytecode, bring in new bytecode, and store it. + // _index = (_index >> log2_number_of_codes) | + // (bytecode << log2_number_of_codes); + int offs1 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_index, tmp, true); + __ lwz(tmp, offs1, addr); + __ srwi(tmp, tmp, BytecodePairHistogram::log2_number_of_codes); + __ ori(tmp, tmp, ((int) t->bytecode()) << BytecodePairHistogram::log2_number_of_codes); + __ stw(tmp, offs1, addr); + + // Bump bucket contents. + // _counters[_index] ++; + int offs2 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_counters, R0, true); + __ sldi(tmp, tmp, LogBytesPerInt); + __ add(addr, tmp, addr); + __ lwz(tmp, offs2, addr); + __ addi(tmp, tmp, 1); + __ stw(tmp, offs2, addr); +} + +void TemplateInterpreterGenerator::trace_bytecode(Template* t) { + // Call a little run-time stub to avoid blow-up for each bytecode. + // The run-time runtime saves the right registers, depending on + // the tosca in-state for the given template. + + assert(Interpreter::trace_code(t->tos_in()) != NULL, + "entry must have been generated"); + + // Note: we destroy LR here. + __ bl(Interpreter::trace_code(t->tos_in())); +} + +void TemplateInterpreterGenerator::stop_interpreter_at() { + Label L; + int offs1 = __ load_const_optimized(R11_scratch1, (address) &StopInterpreterAt, R0, true); + int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true); + __ ld(R11_scratch1, offs1, R11_scratch1); + __ lwa(R12_scratch2, offs2, R12_scratch2); + __ cmpd(CCR0, R12_scratch2, R11_scratch1); + __ bne(CCR0, L); + __ illtrap(); + __ bind(L); +} + +#endif // !PRODUCT +#endif // !CC_INTERP diff --git a/langtools/test/tools/javac/ConditionalClass.java b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp similarity index 63% rename from langtools/test/tools/javac/ConditionalClass.java rename to hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp index 4628e4f3b3f..eb817b0a256 100644 --- a/langtools/test/tools/javac/ConditionalClass.java +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 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 @@ -19,31 +20,22 @@ * Please 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 4949627 - * @summary javac crashes on code for new rule for semantics of ? without -source 1.5 - * @author gafter * - * @compile -source 1.4 ConditionalClass.java */ -package conditional.clazz; +#ifndef CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP +#define CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP -class A{} -class B{} + protected: + + // Size of interpreter code. Increase if too small. Interpreter will + // fail with a guarantee ("not enough space for interpreter generation"); + // if too small. + // Run with +PrintInterpreter to get the VM to print out the size. + // Max size with JVMTI + + const static int InterpreterCodeSize = 210*K; + +#endif // CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP -public class ConditionalClass { - void foo(){ - boolean b = false; - Class a = b ? A.class : B.class; - System.out.println("a is " + a.getName()); - } - public static void main(String[] args) - { - new ConditionalClass().foo(); - } -} diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp new file mode 100644 index 00000000000..e7846bc2859 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp @@ -0,0 +1,4082 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2014 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "interpreter/templateInterpreter.hpp" +#include "interpreter/templateTable.hpp" +#include "memory/universe.inline.hpp" +#include "oops/objArrayKlass.hpp" +#include "oops/oop.inline.hpp" +#include "prims/methodHandles.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/synchronizer.hpp" +#include "utilities/macros.hpp" + +#ifndef CC_INTERP + +#undef __ +#define __ _masm-> + +// ============================================================================ +// Misc helpers + +// Do an oop store like *(base + index) = val OR *(base + offset) = val +// (only one of both variants is possible at the same time). +// Index can be noreg. +// Kills: +// Rbase, Rtmp +static void do_oop_store(InterpreterMacroAssembler* _masm, + Register Rbase, + RegisterOrConstant offset, + Register Rval, // Noreg means always null. + Register Rtmp1, + Register Rtmp2, + Register Rtmp3, + BarrierSet::Name barrier, + bool precise, + bool check_null) { + assert_different_registers(Rtmp1, Rtmp2, Rtmp3, Rval, Rbase); + + switch (barrier) { +#ifndef SERIALGC + case BarrierSet::G1SATBCT: + case BarrierSet::G1SATBCTLogging: + { + // Load and record the previous value. + __ g1_write_barrier_pre(Rbase, offset, + Rtmp3, /* holder of pre_val ? */ + Rtmp1, Rtmp2, false /* frame */); + + Label Lnull, Ldone; + if (Rval != noreg) { + if (check_null) { + __ cmpdi(CCR0, Rval, 0); + __ beq(CCR0, Lnull); + } + __ store_heap_oop_not_null(Rval, offset, Rbase, /*Rval must stay uncompressed.*/ Rtmp1); + // Mark the card. + if (!(offset.is_constant() && offset.as_constant() == 0) && precise) { + __ add(Rbase, offset, Rbase); + } + __ g1_write_barrier_post(Rbase, Rval, Rtmp1, Rtmp2, Rtmp3, /*filtered (fast path)*/ &Ldone); + if (check_null) { __ b(Ldone); } + } + + if (Rval == noreg || check_null) { // Store null oop. + Register Rnull = Rval; + __ bind(Lnull); + if (Rval == noreg) { + Rnull = Rtmp1; + __ li(Rnull, 0); + } + if (UseCompressedOops) { + __ stw(Rnull, offset, Rbase); + } else { + __ std(Rnull, offset, Rbase); + } + } + __ bind(Ldone); + } + break; +#endif // SERIALGC + case BarrierSet::CardTableModRef: + case BarrierSet::CardTableExtension: + { + Label Lnull, Ldone; + if (Rval != noreg) { + if (check_null) { + __ cmpdi(CCR0, Rval, 0); + __ beq(CCR0, Lnull); + } + __ store_heap_oop_not_null(Rval, offset, Rbase, /*Rval should better stay uncompressed.*/ Rtmp1); + // Mark the card. + if (!(offset.is_constant() && offset.as_constant() == 0) && precise) { + __ add(Rbase, offset, Rbase); + } + __ card_write_barrier_post(Rbase, Rval, Rtmp1); + if (check_null) { + __ b(Ldone); + } + } + + if (Rval == noreg || check_null) { // Store null oop. + Register Rnull = Rval; + __ bind(Lnull); + if (Rval == noreg) { + Rnull = Rtmp1; + __ li(Rnull, 0); + } + if (UseCompressedOops) { + __ stw(Rnull, offset, Rbase); + } else { + __ std(Rnull, offset, Rbase); + } + } + __ bind(Ldone); + } + break; + case BarrierSet::ModRef: + case BarrierSet::Other: + ShouldNotReachHere(); + break; + default: + ShouldNotReachHere(); + } +} + +// ============================================================================ +// Platform-dependent initialization + +void TemplateTable::pd_initialize() { + // No ppc64 specific initialization. +} + +Address TemplateTable::at_bcp(int offset) { + // Not used on ppc. + ShouldNotReachHere(); + return Address(); +} + +// Patches the current bytecode (ptr to it located in bcp) +// in the bytecode stream with a new one. +void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Register Rtemp, bool load_bc_into_bc_reg /*=true*/, int byte_no) { + // With sharing on, may need to test method flag. + if (!RewriteBytecodes) return; + Label L_patch_done; + + switch (new_bc) { + case Bytecodes::_fast_aputfield: + case Bytecodes::_fast_bputfield: + case Bytecodes::_fast_cputfield: + case Bytecodes::_fast_dputfield: + case Bytecodes::_fast_fputfield: + case Bytecodes::_fast_iputfield: + case Bytecodes::_fast_lputfield: + case Bytecodes::_fast_sputfield: + { + // We skip bytecode quickening for putfield instructions when + // the put_code written to the constant pool cache is zero. + // This is required so that every execution of this instruction + // calls out to InterpreterRuntime::resolve_get_put to do + // additional, required work. + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + assert(load_bc_into_bc_reg, "we use bc_reg as temp"); + __ get_cache_and_index_at_bcp(Rtemp /* dst = cache */, 1); + // Big Endian: ((*(cache+indices))>>((1+byte_no)*8))&0xFF + __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (1 + byte_no), Rtemp); + __ cmpwi(CCR0, Rnew_bc, 0); + __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc); + __ beq(CCR0, L_patch_done); + // __ isync(); // acquire not needed + break; + } + + default: + assert(byte_no == -1, "sanity"); + if (load_bc_into_bc_reg) { + __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc); + } + } + + if (JvmtiExport::can_post_breakpoint()) { + Label L_fast_patch; + __ lbz(Rtemp, 0, R14_bcp); + __ cmpwi(CCR0, Rtemp, (unsigned int)(unsigned char)Bytecodes::_breakpoint); + __ bne(CCR0, L_fast_patch); + // Perform the quickening, slowly, in the bowels of the breakpoint table. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), R19_method, R14_bcp, Rnew_bc); + __ b(L_patch_done); + __ bind(L_fast_patch); + } + + // Patch bytecode. + __ stb(Rnew_bc, 0, R14_bcp); + + __ bind(L_patch_done); +} + +// ============================================================================ +// Individual instructions + +void TemplateTable::nop() { + transition(vtos, vtos); + // Nothing to do. +} + +void TemplateTable::shouldnotreachhere() { + transition(vtos, vtos); + __ stop("shouldnotreachhere bytecode"); +} + +void TemplateTable::aconst_null() { + transition(vtos, atos); + __ li(R17_tos, 0); +} + +void TemplateTable::iconst(int value) { + transition(vtos, itos); + assert(value >= -1 && value <= 5, ""); + __ li(R17_tos, value); +} + +void TemplateTable::lconst(int value) { + transition(vtos, ltos); + assert(value >= -1 && value <= 5, ""); + __ li(R17_tos, value); +} + +void TemplateTable::fconst(int value) { + transition(vtos, ftos); + static float zero = 0.0; + static float one = 1.0; + static float two = 2.0; + switch (value) { + default: ShouldNotReachHere(); + case 0: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&zero, R0); + __ lfs(F15_ftos, simm16_offset, R11_scratch1); + break; + } + case 1: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&one, R0); + __ lfs(F15_ftos, simm16_offset, R11_scratch1); + break; + } + case 2: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&two, R0); + __ lfs(F15_ftos, simm16_offset, R11_scratch1); + break; + } + } +} + +void TemplateTable::dconst(int value) { + transition(vtos, dtos); + static double zero = 0.0; + static double one = 1.0; + switch (value) { + case 0: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&zero, R0); + __ lfd(F15_ftos, simm16_offset, R11_scratch1); + break; + } + case 1: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&one, R0); + __ lfd(F15_ftos, simm16_offset, R11_scratch1); + break; + } + default: ShouldNotReachHere(); + } +} + +void TemplateTable::bipush() { + transition(vtos, itos); + __ lbz(R17_tos, 1, R14_bcp); + __ extsb(R17_tos, R17_tos); +} + +void TemplateTable::sipush() { + transition(vtos, itos); + __ get_2_byte_integer_at_bcp(1, R17_tos, InterpreterMacroAssembler::Signed); +} + +void TemplateTable::ldc(bool wide) { + Register Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Rcpool = R3_ARG1; + + transition(vtos, vtos); + Label notInt, notClass, exit; + + __ get_cpool_and_tags(Rcpool, Rscratch2); // Set Rscratch2 = &tags. + if (wide) { // Read index. + __ get_2_byte_integer_at_bcp(1, Rscratch1, InterpreterMacroAssembler::Unsigned); + } else { + __ lbz(Rscratch1, 1, R14_bcp); + } + + const int base_offset = ConstantPool::header_size() * wordSize; + const int tags_offset = Array::base_offset_in_bytes(); + + // Get type from tags. + __ addi(Rscratch2, Rscratch2, tags_offset); + __ lbzx(Rscratch2, Rscratch2, Rscratch1); + + __ cmpwi(CCR0, Rscratch2, JVM_CONSTANT_UnresolvedClass); // Unresolved class? + __ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_UnresolvedClassInError); // Unresolved class in error state? + __ cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + + // Resolved class - need to call vm to get java mirror of the class. + __ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_Class); + __ crnor(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); // Neither resolved class nor unresolved case from above? + __ beq(CCR0, notClass); + + __ li(R4, wide ? 1 : 0); + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), R4); + __ push(atos); + __ b(exit); + + __ align(32, 12); + __ bind(notClass); + __ addi(Rcpool, Rcpool, base_offset); + __ sldi(Rscratch1, Rscratch1, LogBytesPerWord); + __ cmpdi(CCR0, Rscratch2, JVM_CONSTANT_Integer); + __ bne(CCR0, notInt); + __ isync(); // Order load of constant wrt. tags. + __ lwax(R17_tos, Rcpool, Rscratch1); + __ push(itos); + __ b(exit); + + __ align(32, 12); + __ bind(notInt); +#ifdef ASSERT + // String and Object are rewritten to fast_aldc + __ cmpdi(CCR0, Rscratch2, JVM_CONSTANT_Float); + __ asm_assert_eq("unexpected type", 0x8765); +#endif + __ isync(); // Order load of constant wrt. tags. + __ lfsx(F15_ftos, Rcpool, Rscratch1); + __ push(ftos); + + __ align(32, 12); + __ bind(exit); +} + +// Fast path for caching oop constants. +void TemplateTable::fast_aldc(bool wide) { + transition(vtos, atos); + + int index_size = wide ? sizeof(u2) : sizeof(u1); + const Register Rscratch = R11_scratch1; + Label resolved; + + // We are resolved if the resolved reference cache entry contains a + // non-null object (CallSite, etc.) + __ get_cache_index_at_bcp(Rscratch, 1, index_size); // Load index. + __ load_resolved_reference_at_index(R17_tos, Rscratch); + __ cmpdi(CCR0, R17_tos, 0); + __ bne(CCR0, resolved); + __ load_const_optimized(R3_ARG1, (int)bytecode()); + + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); + + // First time invocation - must resolve first. + __ call_VM(R17_tos, entry, R3_ARG1); + + __ align(32, 12); + __ bind(resolved); + __ verify_oop(R17_tos); +} + +void TemplateTable::ldc2_w() { + transition(vtos, vtos); + Label Llong, Lexit; + + Register Rindex = R11_scratch1, + Rcpool = R12_scratch2, + Rtag = R3_ARG1; + __ get_cpool_and_tags(Rcpool, Rtag); + __ get_2_byte_integer_at_bcp(1, Rindex, InterpreterMacroAssembler::Unsigned); + + const int base_offset = ConstantPool::header_size() * wordSize; + const int tags_offset = Array::base_offset_in_bytes(); + // Get type from tags. + __ addi(Rcpool, Rcpool, base_offset); + __ addi(Rtag, Rtag, tags_offset); + + __ lbzx(Rtag, Rtag, Rindex); + + __ sldi(Rindex, Rindex, LogBytesPerWord); + __ cmpdi(CCR0, Rtag, JVM_CONSTANT_Double); + __ bne(CCR0, Llong); + // A double can be placed at word-aligned locations in the constant pool. + // Check out Conversions.java for an example. + // Also ConstantPool::header_size() is 20, which makes it very difficult + // to double-align double on the constant pool. SG, 11/7/97 + __ isync(); // Order load of constant wrt. tags. + __ lfdx(F15_ftos, Rcpool, Rindex); + __ push(dtos); + __ b(Lexit); + + __ bind(Llong); + __ isync(); // Order load of constant wrt. tags. + __ ldx(R17_tos, Rcpool, Rindex); + __ push(ltos); + + __ bind(Lexit); +} + +// Get the locals index located in the bytecode stream at bcp + offset. +void TemplateTable::locals_index(Register Rdst, int offset) { + __ lbz(Rdst, offset, R14_bcp); +} + +void TemplateTable::iload() { + transition(vtos, itos); + + // Get the local value into tos + const Register Rindex = R22_tmp2; + locals_index(Rindex); + + // Rewrite iload,iload pair into fast_iload2 + // iload,caload pair into fast_icaload + if (RewriteFrequentPairs) { + Label Lrewrite, Ldone; + Register Rnext_byte = R3_ARG1, + Rrewrite_to = R6_ARG4, + Rscratch = R11_scratch1; + + // get next byte + __ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_iload), R14_bcp); + + // if _iload, wait to rewrite to iload2. We only want to rewrite the + // last two iloads in a pair. Comparing against fast_iload means that + // the next bytecode is neither an iload or a caload, and therefore + // an iload pair. + __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_iload); + __ beq(CCR0, Ldone); + + __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_iload); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iload2); + __ beq(CCR1, Lrewrite); + + __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_caload); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_icaload); + __ beq(CCR0, Lrewrite); + + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iload); + + __ bind(Lrewrite); + patch_bytecode(Bytecodes::_iload, Rrewrite_to, Rscratch, false); + __ bind(Ldone); + } + + __ load_local_int(R17_tos, Rindex, Rindex); +} + +// Load 2 integers in a row without dispatching +void TemplateTable::fast_iload2() { + transition(vtos, itos); + + __ lbz(R3_ARG1, 1, R14_bcp); + __ lbz(R17_tos, Bytecodes::length_for(Bytecodes::_iload) + 1, R14_bcp); + + __ load_local_int(R3_ARG1, R11_scratch1, R3_ARG1); + __ load_local_int(R17_tos, R12_scratch2, R17_tos); + __ push_i(R3_ARG1); +} + +void TemplateTable::fast_iload() { + transition(vtos, itos); + // Get the local value into tos + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_int(R17_tos, Rindex, Rindex); +} + +// Load a local variable type long from locals area to TOS cache register. +// Local index resides in bytecodestream. +void TemplateTable::lload() { + transition(vtos, ltos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_long(R17_tos, Rindex, Rindex); +} + +void TemplateTable::fload() { + transition(vtos, ftos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_float(F15_ftos, Rindex, Rindex); +} + +void TemplateTable::dload() { + transition(vtos, dtos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_double(F15_ftos, Rindex, Rindex); +} + +void TemplateTable::aload() { + transition(vtos, atos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_ptr(R17_tos, Rindex, Rindex); +} + +void TemplateTable::locals_index_wide(Register Rdst) { + // Offset is 2, not 1, because Lbcp points to wide prefix code. + __ get_2_byte_integer_at_bcp(2, Rdst, InterpreterMacroAssembler::Unsigned); +} + +void TemplateTable::wide_iload() { + // Get the local value into tos. + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_int(R17_tos, Rindex, Rindex); +} + +void TemplateTable::wide_lload() { + transition(vtos, ltos); + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_long(R17_tos, Rindex, Rindex); +} + +void TemplateTable::wide_fload() { + transition(vtos, ftos); + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_float(F15_ftos, Rindex, Rindex); +} + +void TemplateTable::wide_dload() { + transition(vtos, dtos); + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_double(F15_ftos, Rindex, Rindex); +} + +void TemplateTable::wide_aload() { + transition(vtos, atos); + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_ptr(R17_tos, Rindex, Rindex); +} + +void TemplateTable::iaload() { + transition(itos, itos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerInt, Rtemp, Rload_addr); + __ lwa(R17_tos, arrayOopDesc::base_offset_in_bytes(T_INT), Rload_addr); +} + +void TemplateTable::laload() { + transition(itos, ltos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerLong, Rtemp, Rload_addr); + __ ld(R17_tos, arrayOopDesc::base_offset_in_bytes(T_LONG), Rload_addr); +} + +void TemplateTable::faload() { + transition(itos, ftos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerInt, Rtemp, Rload_addr); + __ lfs(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Rload_addr); +} + +void TemplateTable::daload() { + transition(itos, dtos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerLong, Rtemp, Rload_addr); + __ lfd(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Rload_addr); +} + +void TemplateTable::aaload() { + transition(itos, atos); + + // tos: index + // result tos: array + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, UseCompressedOops ? 2 : LogBytesPerWord, Rtemp, Rload_addr); + __ load_heap_oop(R17_tos, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rload_addr); + __ verify_oop(R17_tos); + //__ dcbt(R17_tos); // prefetch +} + +void TemplateTable::baload() { + transition(itos, itos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, 0, Rtemp, Rload_addr); + __ lbz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rload_addr); + __ extsb(R17_tos, R17_tos); +} + +void TemplateTable::caload() { + transition(itos, itos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr); + __ lhz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rload_addr); +} + +// Iload followed by caload frequent pair. +void TemplateTable::fast_icaload() { + transition(vtos, itos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R11_scratch1; + + locals_index(R17_tos); + __ load_local_int(R17_tos, Rtemp, R17_tos); + __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr); + __ lhz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rload_addr); +} + +void TemplateTable::saload() { + transition(itos, itos); + + const Register Rload_addr = R11_scratch1, + Rarray = R12_scratch2, + Rtemp = R3_ARG1; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr); + __ lha(R17_tos, arrayOopDesc::base_offset_in_bytes(T_SHORT), Rload_addr); +} + +void TemplateTable::iload(int n) { + transition(vtos, itos); + + __ lwz(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::lload(int n) { + transition(vtos, ltos); + + __ ld(R17_tos, Interpreter::local_offset_in_bytes(n + 1), R18_locals); +} + +void TemplateTable::fload(int n) { + transition(vtos, ftos); + + __ lfs(F15_ftos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::dload(int n) { + transition(vtos, dtos); + + __ lfd(F15_ftos, Interpreter::local_offset_in_bytes(n + 1), R18_locals); +} + +void TemplateTable::aload(int n) { + transition(vtos, atos); + + __ ld(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::aload_0() { + transition(vtos, atos); + // According to bytecode histograms, the pairs: + // + // _aload_0, _fast_igetfield + // _aload_0, _fast_agetfield + // _aload_0, _fast_fgetfield + // + // occur frequently. If RewriteFrequentPairs is set, the (slow) + // _aload_0 bytecode checks if the next bytecode is either + // _fast_igetfield, _fast_agetfield or _fast_fgetfield and then + // rewrites the current bytecode into a pair bytecode; otherwise it + // rewrites the current bytecode into _0 that doesn't do + // the pair check anymore. + // + // Note: If the next bytecode is _getfield, the rewrite must be + // delayed, otherwise we may miss an opportunity for a pair. + // + // Also rewrite frequent pairs + // aload_0, aload_1 + // aload_0, iload_1 + // These bytecodes with a small amount of code are most profitable + // to rewrite. + + if (RewriteFrequentPairs) { + + Label Lrewrite, Ldont_rewrite; + Register Rnext_byte = R3_ARG1, + Rrewrite_to = R6_ARG4, + Rscratch = R11_scratch1; + + // Get next byte. + __ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_aload_0), R14_bcp); + + // If _getfield, wait to rewrite. We only want to rewrite the last two bytecodes in a pair. + __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_getfield); + __ beq(CCR0, Ldont_rewrite); + + __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_igetfield); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iaccess_0); + __ beq(CCR1, Lrewrite); + + __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_agetfield); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_aaccess_0); + __ beq(CCR0, Lrewrite); + + __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_fgetfield); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_faccess_0); + __ beq(CCR1, Lrewrite); + + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_aload_0); + + __ bind(Lrewrite); + patch_bytecode(Bytecodes::_aload_0, Rrewrite_to, Rscratch, false); + __ bind(Ldont_rewrite); + } + + // Do actual aload_0 (must do this after patch_bytecode which might call VM and GC might change oop). + aload(0); +} + +void TemplateTable::istore() { + transition(itos, vtos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ store_local_int(R17_tos, Rindex); +} + +void TemplateTable::lstore() { + transition(ltos, vtos); + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ store_local_long(R17_tos, Rindex); +} + +void TemplateTable::fstore() { + transition(ftos, vtos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ store_local_float(F15_ftos, Rindex); +} + +void TemplateTable::dstore() { + transition(dtos, vtos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ store_local_double(F15_ftos, Rindex); +} + +void TemplateTable::astore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_ptr(); + __ verify_oop_or_return_address(R17_tos, Rindex); + locals_index(Rindex); + __ store_local_ptr(R17_tos, Rindex); +} + +void TemplateTable::wide_istore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_i(); + locals_index_wide(Rindex); + __ store_local_int(R17_tos, Rindex); +} + +void TemplateTable::wide_lstore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_l(); + locals_index_wide(Rindex); + __ store_local_long(R17_tos, Rindex); +} + +void TemplateTable::wide_fstore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_f(); + locals_index_wide(Rindex); + __ store_local_float(F15_ftos, Rindex); +} + +void TemplateTable::wide_dstore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_d(); + locals_index_wide(Rindex); + __ store_local_double(F15_ftos, Rindex); +} + +void TemplateTable::wide_astore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_ptr(); + __ verify_oop_or_return_address(R17_tos, Rindex); + locals_index_wide(Rindex); + __ store_local_ptr(R17_tos, Rindex); +} + +void TemplateTable::iastore() { + transition(itos, vtos); + + const Register Rindex = R3_ARG1, + Rstore_addr = R4_ARG2, + Rarray = R5_ARG3, + Rtemp = R6_ARG4; + __ pop_i(Rindex); + __ index_check(Rarray, Rindex, LogBytesPerInt, Rtemp, Rstore_addr); + __ stw(R17_tos, arrayOopDesc::base_offset_in_bytes(T_INT), Rstore_addr); + } + +void TemplateTable::lastore() { + transition(ltos, vtos); + + const Register Rindex = R3_ARG1, + Rstore_addr = R4_ARG2, + Rarray = R5_ARG3, + Rtemp = R6_ARG4; + __ pop_i(Rindex); + __ index_check(Rarray, Rindex, LogBytesPerLong, Rtemp, Rstore_addr); + __ std(R17_tos, arrayOopDesc::base_offset_in_bytes(T_LONG), Rstore_addr); + } + +void TemplateTable::fastore() { + transition(ftos, vtos); + + const Register Rindex = R3_ARG1, + Rstore_addr = R4_ARG2, + Rarray = R5_ARG3, + Rtemp = R6_ARG4; + __ pop_i(Rindex); + __ index_check(Rarray, Rindex, LogBytesPerInt, Rtemp, Rstore_addr); + __ stfs(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Rstore_addr); + } + +void TemplateTable::dastore() { + transition(dtos, vtos); + + const Register Rindex = R3_ARG1, + Rstore_addr = R4_ARG2, + Rarray = R5_ARG3, + Rtemp = R6_ARG4; + __ pop_i(Rindex); + __ index_check(Rarray, Rindex, LogBytesPerLong, Rtemp, Rstore_addr); + __ stfd(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Rstore_addr); + } + +// Pop 3 values from the stack and... +void TemplateTable::aastore() { + transition(vtos, vtos); + + Label Lstore_ok, Lis_null, Ldone; + const Register Rindex = R3_ARG1, + Rarray = R4_ARG2, + Rscratch = R11_scratch1, + Rscratch2 = R12_scratch2, + Rarray_klass = R5_ARG3, + Rarray_element_klass = Rarray_klass, + Rvalue_klass = R6_ARG4, + Rstore_addr = R31; // Use register which survives VM call. + + __ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp); // Get value to store. + __ lwz(Rindex, Interpreter::expr_offset_in_bytes(1), R15_esp); // Get index. + __ ld(Rarray, Interpreter::expr_offset_in_bytes(2), R15_esp); // Get array. + + __ verify_oop(R17_tos); + __ index_check_without_pop(Rarray, Rindex, UseCompressedOops ? 2 : LogBytesPerWord, Rscratch, Rstore_addr); + // Rindex is dead! + Register Rscratch3 = Rindex; + + // Do array store check - check for NULL value first. + __ cmpdi(CCR0, R17_tos, 0); + __ beq(CCR0, Lis_null); + + __ load_klass(Rarray_klass, Rarray); + __ load_klass(Rvalue_klass, R17_tos); + + // Do fast instanceof cache test. + __ ld(Rarray_element_klass, in_bytes(ObjArrayKlass::element_klass_offset()), Rarray_klass); + + // Generate a fast subtype check. Branch to store_ok if no failure. Throw if failure. + __ gen_subtype_check(Rvalue_klass /*subklass*/, Rarray_element_klass /*superklass*/, Rscratch, Rscratch2, Rscratch3, Lstore_ok); + + // Fell through: subtype check failed => throw an exception. + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArrayStoreException_entry); + __ mtctr(R11_scratch1); + __ bctr(); + + __ bind(Lis_null); + do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), noreg /* 0 */, + Rscratch, Rscratch2, Rscratch3, _bs->kind(), true /* precise */, false /* check_null */); + __ profile_null_seen(Rscratch, Rscratch2); + __ b(Ldone); + + // Store is OK. + __ bind(Lstore_ok); + do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos /* value */, + Rscratch, Rscratch2, Rscratch3, _bs->kind(), true /* precise */, false /* check_null */); + + __ bind(Ldone); + // Adjust sp (pops array, index and value). + __ addi(R15_esp, R15_esp, 3 * Interpreter::stackElementSize); +} + +void TemplateTable::bastore() { + transition(itos, vtos); + + const Register Rindex = R11_scratch1, + Rarray = R12_scratch2, + Rscratch = R3_ARG1; + __ pop_i(Rindex); + // tos: val + // Rarray: array ptr (popped by index_check) + __ index_check(Rarray, Rindex, 0, Rscratch, Rarray); + __ stb(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rarray); +} + +void TemplateTable::castore() { + transition(itos, vtos); + + const Register Rindex = R11_scratch1, + Rarray = R12_scratch2, + Rscratch = R3_ARG1; + __ pop_i(Rindex); + // tos: val + // Rarray: array ptr (popped by index_check) + __ index_check(Rarray, Rindex, LogBytesPerShort, Rscratch, Rarray); + __ sth(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rarray); +} + +void TemplateTable::sastore() { + castore(); +} + +void TemplateTable::istore(int n) { + transition(itos, vtos); + __ stw(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::lstore(int n) { + transition(ltos, vtos); + __ std(R17_tos, Interpreter::local_offset_in_bytes(n + 1), R18_locals); +} + +void TemplateTable::fstore(int n) { + transition(ftos, vtos); + __ stfs(F15_ftos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::dstore(int n) { + transition(dtos, vtos); + __ stfd(F15_ftos, Interpreter::local_offset_in_bytes(n + 1), R18_locals); +} + +void TemplateTable::astore(int n) { + transition(vtos, vtos); + + __ pop_ptr(); + __ verify_oop_or_return_address(R17_tos, R11_scratch1); + __ std(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::pop() { + transition(vtos, vtos); + + __ addi(R15_esp, R15_esp, Interpreter::stackElementSize); +} + +void TemplateTable::pop2() { + transition(vtos, vtos); + + __ addi(R15_esp, R15_esp, Interpreter::stackElementSize * 2); +} + +void TemplateTable::dup() { + transition(vtos, vtos); + + __ ld(R11_scratch1, Interpreter::stackElementSize, R15_esp); + __ push_ptr(R11_scratch1); +} + +void TemplateTable::dup_x1() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2; + // stack: ..., a, b + __ ld(Rb, Interpreter::stackElementSize, R15_esp); + __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp); + __ std(Rb, Interpreter::stackElementSize * 2, R15_esp); + __ std(Ra, Interpreter::stackElementSize, R15_esp); + __ push_ptr(Rb); + // stack: ..., b, a, b +} + +void TemplateTable::dup_x2() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2, + Rc = R3_ARG1; + + // stack: ..., a, b, c + __ ld(Rc, Interpreter::stackElementSize, R15_esp); // load c + __ ld(Ra, Interpreter::stackElementSize * 3, R15_esp); // load a + __ std(Rc, Interpreter::stackElementSize * 3, R15_esp); // store c in a + __ ld(Rb, Interpreter::stackElementSize * 2, R15_esp); // load b + // stack: ..., c, b, c + __ std(Ra, Interpreter::stackElementSize * 2, R15_esp); // store a in b + // stack: ..., c, a, c + __ std(Rb, Interpreter::stackElementSize, R15_esp); // store b in c + __ push_ptr(Rc); // push c + // stack: ..., c, a, b, c +} + +void TemplateTable::dup2() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2; + // stack: ..., a, b + __ ld(Rb, Interpreter::stackElementSize, R15_esp); + __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp); + __ push_2ptrs(Ra, Rb); + // stack: ..., a, b, a, b +} + +void TemplateTable::dup2_x1() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2, + Rc = R3_ARG1; + // stack: ..., a, b, c + __ ld(Rc, Interpreter::stackElementSize, R15_esp); + __ ld(Rb, Interpreter::stackElementSize * 2, R15_esp); + __ std(Rc, Interpreter::stackElementSize * 2, R15_esp); + __ ld(Ra, Interpreter::stackElementSize * 3, R15_esp); + __ std(Ra, Interpreter::stackElementSize, R15_esp); + __ std(Rb, Interpreter::stackElementSize * 3, R15_esp); + // stack: ..., b, c, a + __ push_2ptrs(Rb, Rc); + // stack: ..., b, c, a, b, c +} + +void TemplateTable::dup2_x2() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2, + Rc = R3_ARG1, + Rd = R4_ARG2; + // stack: ..., a, b, c, d + __ ld(Rb, Interpreter::stackElementSize * 3, R15_esp); + __ ld(Rd, Interpreter::stackElementSize, R15_esp); + __ std(Rb, Interpreter::stackElementSize, R15_esp); // store b in d + __ std(Rd, Interpreter::stackElementSize * 3, R15_esp); // store d in b + __ ld(Ra, Interpreter::stackElementSize * 4, R15_esp); + __ ld(Rc, Interpreter::stackElementSize * 2, R15_esp); + __ std(Ra, Interpreter::stackElementSize * 2, R15_esp); // store a in c + __ std(Rc, Interpreter::stackElementSize * 4, R15_esp); // store c in a + // stack: ..., c, d, a, b + __ push_2ptrs(Rc, Rd); + // stack: ..., c, d, a, b, c, d +} + +void TemplateTable::swap() { + transition(vtos, vtos); + // stack: ..., a, b + + Register Ra = R11_scratch1, + Rb = R12_scratch2; + // stack: ..., a, b + __ ld(Rb, Interpreter::stackElementSize, R15_esp); + __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp); + __ std(Rb, Interpreter::stackElementSize * 2, R15_esp); + __ std(Ra, Interpreter::stackElementSize, R15_esp); + // stack: ..., b, a +} + +void TemplateTable::iop2(Operation op) { + transition(itos, itos); + + Register Rscratch = R11_scratch1; + + __ pop_i(Rscratch); + // tos = number of bits to shift + // Rscratch = value to shift + switch (op) { + case add: __ add(R17_tos, Rscratch, R17_tos); break; + case sub: __ sub(R17_tos, Rscratch, R17_tos); break; + case mul: __ mullw(R17_tos, Rscratch, R17_tos); break; + case _and: __ andr(R17_tos, Rscratch, R17_tos); break; + case _or: __ orr(R17_tos, Rscratch, R17_tos); break; + case _xor: __ xorr(R17_tos, Rscratch, R17_tos); break; + case shl: __ rldicl(R17_tos, R17_tos, 0, 64-5); __ slw(R17_tos, Rscratch, R17_tos); break; + case shr: __ rldicl(R17_tos, R17_tos, 0, 64-5); __ sraw(R17_tos, Rscratch, R17_tos); break; + case ushr: __ rldicl(R17_tos, R17_tos, 0, 64-5); __ srw(R17_tos, Rscratch, R17_tos); break; + default: ShouldNotReachHere(); + } +} + +void TemplateTable::lop2(Operation op) { + transition(ltos, ltos); + + Register Rscratch = R11_scratch1; + __ pop_l(Rscratch); + switch (op) { + case add: __ add(R17_tos, Rscratch, R17_tos); break; + case sub: __ sub(R17_tos, Rscratch, R17_tos); break; + case _and: __ andr(R17_tos, Rscratch, R17_tos); break; + case _or: __ orr(R17_tos, Rscratch, R17_tos); break; + case _xor: __ xorr(R17_tos, Rscratch, R17_tos); break; + default: ShouldNotReachHere(); + } +} + +void TemplateTable::idiv() { + transition(itos, itos); + + Label Lnormal, Lexception, Ldone; + Register Rdividend = R11_scratch1; // Used by irem. + + __ addi(R0, R17_tos, 1); + __ cmplwi(CCR0, R0, 2); + __ bgt(CCR0, Lnormal); // divisor <-1 or >1 + + __ cmpwi(CCR1, R17_tos, 0); + __ beq(CCR1, Lexception); // divisor == 0 + + __ pop_i(Rdividend); + __ mullw(R17_tos, Rdividend, R17_tos); // div by +/-1 + __ b(Ldone); + + __ bind(Lexception); + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArithmeticException_entry); + __ mtctr(R11_scratch1); + __ bctr(); + + __ align(32, 12); + __ bind(Lnormal); + __ pop_i(Rdividend); + __ divw(R17_tos, Rdividend, R17_tos); // Can't divide minint/-1. + __ bind(Ldone); +} + +void TemplateTable::irem() { + transition(itos, itos); + + __ mr(R12_scratch2, R17_tos); + idiv(); + __ mullw(R17_tos, R17_tos, R12_scratch2); + __ subf(R17_tos, R17_tos, R11_scratch1); // Dividend set by idiv. +} + +void TemplateTable::lmul() { + transition(ltos, ltos); + + __ pop_l(R11_scratch1); + __ mulld(R17_tos, R11_scratch1, R17_tos); +} + +void TemplateTable::ldiv() { + transition(ltos, ltos); + + Label Lnormal, Lexception, Ldone; + Register Rdividend = R11_scratch1; // Used by lrem. + + __ addi(R0, R17_tos, 1); + __ cmpldi(CCR0, R0, 2); + __ bgt(CCR0, Lnormal); // divisor <-1 or >1 + + __ cmpdi(CCR1, R17_tos, 0); + __ beq(CCR1, Lexception); // divisor == 0 + + __ pop_l(Rdividend); + __ mulld(R17_tos, Rdividend, R17_tos); // div by +/-1 + __ b(Ldone); + + __ bind(Lexception); + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArithmeticException_entry); + __ mtctr(R11_scratch1); + __ bctr(); + + __ align(32, 12); + __ bind(Lnormal); + __ pop_l(Rdividend); + __ divd(R17_tos, Rdividend, R17_tos); // Can't divide minint/-1. + __ bind(Ldone); +} + +void TemplateTable::lrem() { + transition(ltos, ltos); + + __ mr(R12_scratch2, R17_tos); + ldiv(); + __ mulld(R17_tos, R17_tos, R12_scratch2); + __ subf(R17_tos, R17_tos, R11_scratch1); // Dividend set by ldiv. +} + +void TemplateTable::lshl() { + transition(itos, ltos); + + __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits. + __ pop_l(R11_scratch1); + __ sld(R17_tos, R11_scratch1, R17_tos); +} + +void TemplateTable::lshr() { + transition(itos, ltos); + + __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits. + __ pop_l(R11_scratch1); + __ srad(R17_tos, R11_scratch1, R17_tos); +} + +void TemplateTable::lushr() { + transition(itos, ltos); + + __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits. + __ pop_l(R11_scratch1); + __ srd(R17_tos, R11_scratch1, R17_tos); +} + +void TemplateTable::fop2(Operation op) { + transition(ftos, ftos); + + switch (op) { + case add: __ pop_f(F0_SCRATCH); __ fadds(F15_ftos, F0_SCRATCH, F15_ftos); break; + case sub: __ pop_f(F0_SCRATCH); __ fsubs(F15_ftos, F0_SCRATCH, F15_ftos); break; + case mul: __ pop_f(F0_SCRATCH); __ fmuls(F15_ftos, F0_SCRATCH, F15_ftos); break; + case div: __ pop_f(F0_SCRATCH); __ fdivs(F15_ftos, F0_SCRATCH, F15_ftos); break; + case rem: + __ pop_f(F1_ARG1); + __ fmr(F2_ARG2, F15_ftos); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem)); + __ fmr(F15_ftos, F1_RET); + break; + + default: ShouldNotReachHere(); + } +} + +void TemplateTable::dop2(Operation op) { + transition(dtos, dtos); + + switch (op) { + case add: __ pop_d(F0_SCRATCH); __ fadd(F15_ftos, F0_SCRATCH, F15_ftos); break; + case sub: __ pop_d(F0_SCRATCH); __ fsub(F15_ftos, F0_SCRATCH, F15_ftos); break; + case mul: __ pop_d(F0_SCRATCH); __ fmul(F15_ftos, F0_SCRATCH, F15_ftos); break; + case div: __ pop_d(F0_SCRATCH); __ fdiv(F15_ftos, F0_SCRATCH, F15_ftos); break; + case rem: + __ pop_d(F1_ARG1); + __ fmr(F2_ARG2, F15_ftos); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem)); + __ fmr(F15_ftos, F1_RET); + break; + + default: ShouldNotReachHere(); + } +} + +// Negate the value in the TOS cache. +void TemplateTable::ineg() { + transition(itos, itos); + + __ neg(R17_tos, R17_tos); +} + +// Negate the value in the TOS cache. +void TemplateTable::lneg() { + transition(ltos, ltos); + + __ neg(R17_tos, R17_tos); +} + +void TemplateTable::fneg() { + transition(ftos, ftos); + + __ fneg(F15_ftos, F15_ftos); +} + +void TemplateTable::dneg() { + transition(dtos, dtos); + + __ fneg(F15_ftos, F15_ftos); +} + +// Increments a local variable in place. +void TemplateTable::iinc() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1, + Rincrement = R0, + Rvalue = R12_scratch2; + + locals_index(Rindex); // Load locals index from bytecode stream. + __ lbz(Rincrement, 2, R14_bcp); // Load increment from the bytecode stream. + __ extsb(Rincrement, Rincrement); + + __ load_local_int(Rvalue, Rindex, Rindex); // Puts address of local into Rindex. + + __ add(Rvalue, Rincrement, Rvalue); + __ stw(Rvalue, 0, Rindex); +} + +void TemplateTable::wide_iinc() { + transition(vtos, vtos); + + Register Rindex = R11_scratch1, + Rlocals_addr = Rindex, + Rincr = R12_scratch2; + locals_index_wide(Rindex); + __ get_2_byte_integer_at_bcp(4, Rincr, InterpreterMacroAssembler::Signed); + __ load_local_int(R17_tos, Rlocals_addr, Rindex); + __ add(R17_tos, Rincr, R17_tos); + __ stw(R17_tos, 0, Rlocals_addr); +} + +void TemplateTable::convert() { + // %%%%% Factor this first part accross platforms +#ifdef ASSERT + TosState tos_in = ilgl; + TosState tos_out = ilgl; + switch (bytecode()) { + case Bytecodes::_i2l: // fall through + case Bytecodes::_i2f: // fall through + case Bytecodes::_i2d: // fall through + case Bytecodes::_i2b: // fall through + case Bytecodes::_i2c: // fall through + case Bytecodes::_i2s: tos_in = itos; break; + case Bytecodes::_l2i: // fall through + case Bytecodes::_l2f: // fall through + case Bytecodes::_l2d: tos_in = ltos; break; + case Bytecodes::_f2i: // fall through + case Bytecodes::_f2l: // fall through + case Bytecodes::_f2d: tos_in = ftos; break; + case Bytecodes::_d2i: // fall through + case Bytecodes::_d2l: // fall through + case Bytecodes::_d2f: tos_in = dtos; break; + default : ShouldNotReachHere(); + } + switch (bytecode()) { + case Bytecodes::_l2i: // fall through + case Bytecodes::_f2i: // fall through + case Bytecodes::_d2i: // fall through + case Bytecodes::_i2b: // fall through + case Bytecodes::_i2c: // fall through + case Bytecodes::_i2s: tos_out = itos; break; + case Bytecodes::_i2l: // fall through + case Bytecodes::_f2l: // fall through + case Bytecodes::_d2l: tos_out = ltos; break; + case Bytecodes::_i2f: // fall through + case Bytecodes::_l2f: // fall through + case Bytecodes::_d2f: tos_out = ftos; break; + case Bytecodes::_i2d: // fall through + case Bytecodes::_l2d: // fall through + case Bytecodes::_f2d: tos_out = dtos; break; + default : ShouldNotReachHere(); + } + transition(tos_in, tos_out); +#endif + + // Conversion + Label done; + switch (bytecode()) { + case Bytecodes::_i2l: + __ extsw(R17_tos, R17_tos); + break; + + case Bytecodes::_l2i: + // Nothing to do, we'll continue to work with the lower bits. + break; + + case Bytecodes::_i2b: + __ extsb(R17_tos, R17_tos); + break; + + case Bytecodes::_i2c: + __ rldicl(R17_tos, R17_tos, 0, 64-2*8); + break; + + case Bytecodes::_i2s: + __ extsh(R17_tos, R17_tos); + break; + + case Bytecodes::_i2d: + __ extsw(R17_tos, R17_tos); + case Bytecodes::_l2d: + __ push_l_pop_d(); + __ fcfid(F15_ftos, F15_ftos); + break; + + case Bytecodes::_i2f: + __ extsw(R17_tos, R17_tos); + __ push_l_pop_d(); + if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only + // Comment: alternatively, load with sign extend could be done by lfiwax. + __ fcfids(F15_ftos, F15_ftos); + } else { + __ fcfid(F15_ftos, F15_ftos); + __ frsp(F15_ftos, F15_ftos); + } + break; + + case Bytecodes::_l2f: + if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only + __ push_l_pop_d(); + __ fcfids(F15_ftos, F15_ftos); + } else { + // Avoid rounding problem when result should be 0x3f800001: need fixup code before fcfid+frsp. + __ mr(R3_ARG1, R17_tos); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::l2f)); + __ fmr(F15_ftos, F1_RET); + } + break; + + case Bytecodes::_f2d: + // empty + break; + + case Bytecodes::_d2f: + __ frsp(F15_ftos, F15_ftos); + break; + + case Bytecodes::_d2i: + case Bytecodes::_f2i: + __ fcmpu(CCR0, F15_ftos, F15_ftos); + __ li(R17_tos, 0); // 0 in case of NAN + __ bso(CCR0, done); + __ fctiwz(F15_ftos, F15_ftos); + __ push_d_pop_l(); + break; + + case Bytecodes::_d2l: + case Bytecodes::_f2l: + __ fcmpu(CCR0, F15_ftos, F15_ftos); + __ li(R17_tos, 0); // 0 in case of NAN + __ bso(CCR0, done); + __ fctidz(F15_ftos, F15_ftos); + __ push_d_pop_l(); + break; + + default: ShouldNotReachHere(); + } + __ bind(done); +} + +// Long compare +void TemplateTable::lcmp() { + transition(ltos, itos); + + const Register Rscratch = R11_scratch1; + __ pop_l(Rscratch); // first operand, deeper in stack + + __ cmpd(CCR0, Rscratch, R17_tos); // compare + __ mfcr(R17_tos); // set bit 32..33 as follows: <: 0b10, =: 0b00, >: 0b01 + __ srwi(Rscratch, R17_tos, 30); + __ srawi(R17_tos, R17_tos, 31); + __ orr(R17_tos, Rscratch, R17_tos); // set result as follows: <: -1, =: 0, >: 1 +} + +// fcmpl/fcmpg and dcmpl/dcmpg bytecodes +// unordered_result == -1 => fcmpl or dcmpl +// unordered_result == 1 => fcmpg or dcmpg +void TemplateTable::float_cmp(bool is_float, int unordered_result) { + const FloatRegister Rfirst = F0_SCRATCH, + Rsecond = F15_ftos; + const Register Rscratch = R11_scratch1; + + if (is_float) { + __ pop_f(Rfirst); + } else { + __ pop_d(Rfirst); + } + + Label Lunordered, Ldone; + __ fcmpu(CCR0, Rfirst, Rsecond); // compare + if (unordered_result) { + __ bso(CCR0, Lunordered); + } + __ mfcr(R17_tos); // set bit 32..33 as follows: <: 0b10, =: 0b00, >: 0b01 + __ srwi(Rscratch, R17_tos, 30); + __ srawi(R17_tos, R17_tos, 31); + __ orr(R17_tos, Rscratch, R17_tos); // set result as follows: <: -1, =: 0, >: 1 + if (unordered_result) { + __ b(Ldone); + __ bind(Lunordered); + __ load_const_optimized(R17_tos, unordered_result); + } + __ bind(Ldone); +} + +// Branch_conditional which takes TemplateTable::Condition. +void TemplateTable::branch_conditional(ConditionRegister crx, TemplateTable::Condition cc, Label& L, bool invert) { + bool positive = false; + Assembler::Condition cond = Assembler::equal; + switch (cc) { + case TemplateTable::equal: positive = true ; cond = Assembler::equal ; break; + case TemplateTable::not_equal: positive = false; cond = Assembler::equal ; break; + case TemplateTable::less: positive = true ; cond = Assembler::less ; break; + case TemplateTable::less_equal: positive = false; cond = Assembler::greater; break; + case TemplateTable::greater: positive = true ; cond = Assembler::greater; break; + case TemplateTable::greater_equal: positive = false; cond = Assembler::less ; break; + default: ShouldNotReachHere(); + } + int bo = (positive != invert) ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0; + int bi = Assembler::bi0(crx, cond); + __ bc(bo, bi, L); +} + +void TemplateTable::branch(bool is_jsr, bool is_wide) { + + // Note: on SPARC, we use InterpreterMacroAssembler::if_cmp also. + __ verify_thread(); + + const Register Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Rscratch3 = R3_ARG1, + R4_counters = R4_ARG2, + bumped_count = R31, + Rdisp = R22_tmp2; + + __ profile_taken_branch(Rscratch1, bumped_count); + + // Get (wide) offset. + if (is_wide) { + __ get_4_byte_integer_at_bcp(1, Rdisp, InterpreterMacroAssembler::Signed); + } else { + __ get_2_byte_integer_at_bcp(1, Rdisp, InterpreterMacroAssembler::Signed); + } + + // -------------------------------------------------------------------------- + // Handle all the JSR stuff here, then exit. + // It's much shorter and cleaner than intermingling with the + // non-JSR normal-branch stuff occurring below. + if (is_jsr) { + // Compute return address as bci in Otos_i. + __ ld(Rscratch1, in_bytes(Method::const_offset()), R19_method); + __ addi(Rscratch2, R14_bcp, -in_bytes(ConstMethod::codes_offset()) + (is_wide ? 5 : 3)); + __ subf(R17_tos, Rscratch1, Rscratch2); + + // Bump bcp to target of JSR. + __ add(R14_bcp, Rdisp, R14_bcp); + // Push returnAddress for "ret" on stack. + __ push_ptr(R17_tos); + // And away we go! + __ dispatch_next(vtos); + return; + } + + // -------------------------------------------------------------------------- + // Normal (non-jsr) branch handling + + const bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter; + if (increment_invocation_counter_for_backward_branches) { + //__ unimplemented("branch invocation counter"); + + Label Lforward; + __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr. + + // Check branch direction. + __ cmpdi(CCR0, Rdisp, 0); + __ bgt(CCR0, Lforward); + + __ get_method_counters(R19_method, R4_counters, Lforward); + + if (TieredCompilation) { + Label Lno_mdo, Loverflow; + const int increment = InvocationCounter::count_increment; + const int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; + if (ProfileInterpreter) { + Register Rmdo = Rscratch1; + + // If no method data exists, go to profile_continue. + __ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method); + __ cmpdi(CCR0, Rmdo, 0); + __ beq(CCR0, Lno_mdo); + + // Increment backedge counter in the MDO. + const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ lwz(Rscratch2, mdo_bc_offs, Rmdo); + __ load_const_optimized(Rscratch3, mask, R0); + __ addi(Rscratch2, Rscratch2, increment); + __ stw(Rscratch2, mdo_bc_offs, Rmdo); + __ and_(Rscratch3, Rscratch2, Rscratch3); + __ bne(CCR0, Lforward); + __ b(Loverflow); + } + + // If there's no MDO, increment counter in method. + const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ bind(Lno_mdo); + __ lwz(Rscratch2, mo_bc_offs, R4_counters); + __ load_const_optimized(Rscratch3, mask, R0); + __ addi(Rscratch2, Rscratch2, increment); + __ stw(Rscratch2, mo_bc_offs, R19_method); + __ and_(Rscratch3, Rscratch2, Rscratch3); + __ bne(CCR0, Lforward); + + __ bind(Loverflow); + + // Notify point for loop, pass branch bytecode. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R14_bcp, true); + + // Was an OSR adapter generated? + // O0 = osr nmethod + __ cmpdi(CCR0, R3_RET, 0); + __ beq(CCR0, Lforward); + + // Has the nmethod been invalidated already? + __ lwz(R0, nmethod::entry_bci_offset(), R3_RET); + __ cmpwi(CCR0, R0, InvalidOSREntryBci); + __ beq(CCR0, Lforward); + + // Migrate the interpreter frame off of the stack. + // We can use all registers because we will not return to interpreter from this point. + + // Save nmethod. + const Register osr_nmethod = R31; + __ mr(osr_nmethod, R3_RET); + __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R11_scratch1); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), R16_thread); + __ reset_last_Java_frame(); + // OSR buffer is in ARG1. + + // Remove the interpreter frame. + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + + // Jump to the osr code. + __ ld(R11_scratch1, nmethod::osr_entry_point_offset(), osr_nmethod); + __ mtlr(R0); + __ mtctr(R11_scratch1); + __ bctr(); + + } else { + + const Register invoke_ctr = Rscratch1; + // Update Backedge branch separately from invocations. + __ increment_backedge_counter(R4_counters, invoke_ctr, Rscratch2, Rscratch3); + + if (ProfileInterpreter) { + __ test_invocation_counter_for_mdp(invoke_ctr, Rscratch2, Lforward); + if (UseOnStackReplacement) { + __ test_backedge_count_for_osr(bumped_count, R14_bcp, Rscratch2); + } + } else { + if (UseOnStackReplacement) { + __ test_backedge_count_for_osr(invoke_ctr, R14_bcp, Rscratch2); + } + } + } + + __ bind(Lforward); + + } else { + // Bump bytecode pointer by displacement (take the branch). + __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr. + } + // Continue with bytecode @ target. + // %%%%% Like Intel, could speed things up by moving bytecode fetch to code above, + // %%%%% and changing dispatch_next to dispatch_only. + __ dispatch_next(vtos); +} + +// Helper function for if_cmp* methods below. +// Factored out common compare and branch code. +void TemplateTable::if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool cmp0) { + Label Lnot_taken; + // Note: The condition code we get is the condition under which we + // *fall through*! So we have to inverse the CC here. + + if (is_jint) { + if (cmp0) { + __ cmpwi(CCR0, Rfirst, 0); + } else { + __ cmpw(CCR0, Rfirst, Rsecond); + } + } else { + if (cmp0) { + __ cmpdi(CCR0, Rfirst, 0); + } else { + __ cmpd(CCR0, Rfirst, Rsecond); + } + } + branch_conditional(CCR0, cc, Lnot_taken, /*invert*/ true); + + // Conition is false => Jump! + branch(false, false); + + // Condition is not true => Continue. + __ align(32, 12); + __ bind(Lnot_taken); + __ profile_not_taken_branch(Rscratch1, Rscratch2); +} + +// Compare integer values with zero and fall through if CC holds, branch away otherwise. +void TemplateTable::if_0cmp(Condition cc) { + transition(itos, vtos); + + if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, true, true); +} + +// Compare integer values and fall through if CC holds, branch away otherwise. +// +// Interface: +// - Rfirst: First operand (older stack value) +// - tos: Second operand (younger stack value) +void TemplateTable::if_icmp(Condition cc) { + transition(itos, vtos); + + const Register Rfirst = R0, + Rsecond = R17_tos; + + __ pop_i(Rfirst); + if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, true, false); +} + +void TemplateTable::if_nullcmp(Condition cc) { + transition(atos, vtos); + + if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, false, true); +} + +void TemplateTable::if_acmp(Condition cc) { + transition(atos, vtos); + + const Register Rfirst = R0, + Rsecond = R17_tos; + + __ pop_ptr(Rfirst); + if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, false, false); +} + +void TemplateTable::ret() { + locals_index(R11_scratch1); + __ load_local_ptr(R17_tos, R11_scratch1, R11_scratch1); + + __ profile_ret(vtos, R17_tos, R11_scratch1, R12_scratch2); + + __ ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method); + __ add(R11_scratch1, R17_tos, R11_scratch1); + __ addi(R14_bcp, R11_scratch1, in_bytes(ConstMethod::codes_offset())); + __ dispatch_next(vtos); +} + +void TemplateTable::wide_ret() { + transition(vtos, vtos); + + const Register Rindex = R3_ARG1, + Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2; + + locals_index_wide(Rindex); + __ load_local_ptr(R17_tos, R17_tos, Rindex); + __ profile_ret(vtos, R17_tos, Rscratch1, R12_scratch2); + // Tos now contains the bci, compute the bcp from that. + __ ld(Rscratch1, in_bytes(Method::const_offset()), R19_method); + __ addi(Rscratch2, R17_tos, in_bytes(ConstMethod::codes_offset())); + __ add(R14_bcp, Rscratch1, Rscratch2); + __ dispatch_next(vtos); +} + +void TemplateTable::tableswitch() { + transition(itos, vtos); + + Label Ldispatch, Ldefault_case; + Register Rlow_byte = R3_ARG1, + Rindex = Rlow_byte, + Rhigh_byte = R4_ARG2, + Rdef_offset_addr = R5_ARG3, // is going to contain address of default offset + Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Roffset = R6_ARG4; + + // Align bcp. + __ addi(Rdef_offset_addr, R14_bcp, BytesPerInt); + __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt)); + + // Load lo & hi. + __ lwz(Rlow_byte, BytesPerInt, Rdef_offset_addr); + __ lwz(Rhigh_byte, BytesPerInt * 2, Rdef_offset_addr); + + // Check for default case (=index outside [low,high]). + __ cmpw(CCR0, R17_tos, Rlow_byte); + __ cmpw(CCR1, R17_tos, Rhigh_byte); + __ blt(CCR0, Ldefault_case); + __ bgt(CCR1, Ldefault_case); + + // Lookup dispatch offset. + __ sub(Rindex, R17_tos, Rlow_byte); + __ extsw(Rindex, Rindex); + __ profile_switch_case(Rindex, Rhigh_byte /* scratch */, Rscratch1, Rscratch2); + __ sldi(Rindex, Rindex, LogBytesPerInt); + __ addi(Rindex, Rindex, 3 * BytesPerInt); + __ lwax(Roffset, Rdef_offset_addr, Rindex); + __ b(Ldispatch); + + __ bind(Ldefault_case); + __ profile_switch_default(Rhigh_byte, Rscratch1); + __ lwa(Roffset, 0, Rdef_offset_addr); + + __ bind(Ldispatch); + + __ add(R14_bcp, Roffset, R14_bcp); + __ dispatch_next(vtos); +} + +void TemplateTable::lookupswitch() { + transition(itos, itos); + __ stop("lookupswitch bytecode should have been rewritten"); +} + +// Table switch using linear search through cases. +// Bytecode stream format: +// Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ... +// Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value. +void TemplateTable::fast_linearswitch() { + transition(itos, vtos); + + Label Lloop_entry, Lsearch_loop, Lfound, Lcontinue_execution, Ldefault_case; + + Register Rcount = R3_ARG1, + Rcurrent_pair = R4_ARG2, + Rdef_offset_addr = R5_ARG3, // Is going to contain address of default offset. + Roffset = R31, // Might need to survive C call. + Rvalue = R12_scratch2, + Rscratch = R11_scratch1, + Rcmp_value = R17_tos; + + // Align bcp. + __ addi(Rdef_offset_addr, R14_bcp, BytesPerInt); + __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt)); + + // Setup loop counter and limit. + __ lwz(Rcount, BytesPerInt, Rdef_offset_addr); // Load count. + __ addi(Rcurrent_pair, Rdef_offset_addr, 2 * BytesPerInt); // Rcurrent_pair now points to first pair. + + // Set up search loop. + __ cmpwi(CCR0, Rcount, 0); + __ beq(CCR0, Ldefault_case); + + __ mtctr(Rcount); + + // linear table search + __ bind(Lsearch_loop); + + __ lwz(Rvalue, 0, Rcurrent_pair); + __ lwa(Roffset, 1 * BytesPerInt, Rcurrent_pair); + + __ cmpw(CCR0, Rvalue, Rcmp_value); + __ beq(CCR0, Lfound); + + __ addi(Rcurrent_pair, Rcurrent_pair, 2 * BytesPerInt); + __ bdnz(Lsearch_loop); + + // default case + __ bind(Ldefault_case); + + __ lwa(Roffset, 0, Rdef_offset_addr); + if (ProfileInterpreter) { + __ profile_switch_default(Rdef_offset_addr, Rcount/* scratch */); + __ b(Lcontinue_execution); + } + + // Entry found, skip Roffset bytecodes and continue. + __ bind(Lfound); + if (ProfileInterpreter) { + // Calc the num of the pair we hit. Careful, Rcurrent_pair points 2 ints + // beyond the actual current pair due to the auto update load above! + __ sub(Rcurrent_pair, Rcurrent_pair, Rdef_offset_addr); + __ addi(Rcurrent_pair, Rcurrent_pair, - 2 * BytesPerInt); + __ srdi(Rcurrent_pair, Rcurrent_pair, LogBytesPerInt + 1); + __ profile_switch_case(Rcurrent_pair, Rcount /*scratch*/, Rdef_offset_addr/*scratch*/, Rscratch); + __ bind(Lcontinue_execution); + } + __ add(R14_bcp, Roffset, R14_bcp); + __ dispatch_next(vtos); +} + +// Table switch using binary search (value/offset pairs are ordered). +// Bytecode stream format: +// Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ... +// Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value. +void TemplateTable::fast_binaryswitch() { + + transition(itos, vtos); + // Implementation using the following core algorithm: (copied from Intel) + // + // int binary_search(int key, LookupswitchPair* array, int n) { + // // Binary search according to "Methodik des Programmierens" by + // // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985. + // int i = 0; + // int j = n; + // while (i+1 < j) { + // // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q) + // // with Q: for all i: 0 <= i < n: key < a[i] + // // where a stands for the array and assuming that the (inexisting) + // // element a[n] is infinitely big. + // int h = (i + j) >> 1; + // // i < h < j + // if (key < array[h].fast_match()) { + // j = h; + // } else { + // i = h; + // } + // } + // // R: a[i] <= key < a[i+1] or Q + // // (i.e., if key is within array, i is the correct index) + // return i; + // } + + // register allocation + const Register Rkey = R17_tos; // already set (tosca) + const Register Rarray = R3_ARG1; + const Register Ri = R4_ARG2; + const Register Rj = R5_ARG3; + const Register Rh = R6_ARG4; + const Register Rscratch = R11_scratch1; + + const int log_entry_size = 3; + const int entry_size = 1 << log_entry_size; + + Label found; + + // Find Array start, + __ addi(Rarray, R14_bcp, 3 * BytesPerInt); + __ clrrdi(Rarray, Rarray, log2_long((jlong)BytesPerInt)); + + // initialize i & j + __ li(Ri,0); + __ lwz(Rj, -BytesPerInt, Rarray); + + // and start. + Label entry; + __ b(entry); + + // binary search loop + { Label loop; + __ bind(loop); + // int h = (i + j) >> 1; + __ srdi(Rh, Rh, 1); + // if (key < array[h].fast_match()) { + // j = h; + // } else { + // i = h; + // } + __ sldi(Rscratch, Rh, log_entry_size); + __ lwzx(Rscratch, Rscratch, Rarray); + + // if (key < current value) + // Rh = Rj + // else + // Rh = Ri + Label Lgreater; + __ cmpw(CCR0, Rkey, Rscratch); + __ bge(CCR0, Lgreater); + __ mr(Rj, Rh); + __ b(entry); + __ bind(Lgreater); + __ mr(Ri, Rh); + + // while (i+1 < j) + __ bind(entry); + __ addi(Rscratch, Ri, 1); + __ cmpw(CCR0, Rscratch, Rj); + __ add(Rh, Ri, Rj); // start h = i + j >> 1; + + __ blt(CCR0, loop); + } + + // End of binary search, result index is i (must check again!). + Label default_case; + Label continue_execution; + if (ProfileInterpreter) { + __ mr(Rh, Ri); // Save index in i for profiling. + } + // Ri = value offset + __ sldi(Ri, Ri, log_entry_size); + __ add(Ri, Ri, Rarray); + __ lwz(Rscratch, 0, Ri); + + Label not_found; + // Ri = offset offset + __ cmpw(CCR0, Rkey, Rscratch); + __ beq(CCR0, not_found); + // entry not found -> j = default offset + __ lwz(Rj, -2 * BytesPerInt, Rarray); + __ b(default_case); + + __ bind(not_found); + // entry found -> j = offset + __ profile_switch_case(Rh, Rj, Rscratch, Rkey); + __ lwz(Rj, BytesPerInt, Ri); + + if (ProfileInterpreter) { + __ b(continue_execution); + } + + __ bind(default_case); // fall through (if not profiling) + __ profile_switch_default(Ri, Rscratch); + + __ bind(continue_execution); + + __ extsw(Rj, Rj); + __ add(R14_bcp, Rj, R14_bcp); + __ dispatch_next(vtos); +} + +void TemplateTable::_return(TosState state) { + transition(state, state); + assert(_desc->calls_vm(), + "inconsistent calls_vm information"); // call in remove_activation + + if (_desc->bytecode() == Bytecodes::_return_register_finalizer) { + + Register Rscratch = R11_scratch1, + Rklass = R12_scratch2, + Rklass_flags = Rklass; + Label Lskip_register_finalizer; + + // Check if the method has the FINALIZER flag set and call into the VM to finalize in this case. + assert(state == vtos, "only valid state"); + __ ld(R17_tos, 0, R18_locals); + + // Load klass of this obj. + __ load_klass(Rklass, R17_tos); + __ lwz(Rklass_flags, in_bytes(Klass::access_flags_offset()), Rklass); + __ testbitdi(CCR0, R0, Rklass_flags, exact_log2(JVM_ACC_HAS_FINALIZER)); + __ bfalse(CCR0, Lskip_register_finalizer); + + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), R17_tos /* obj */); + + __ align(32, 12); + __ bind(Lskip_register_finalizer); + } + + // Move the result value into the correct register and remove memory stack frame. + __ remove_activation(state, /* throw_monitor_exception */ true); + // Restoration of lr done by remove_activation. + switch (state) { + case ltos: + case btos: + case ctos: + case stos: + case atos: + case itos: __ mr(R3_RET, R17_tos); break; + case ftos: + case dtos: __ fmr(F1_RET, F15_ftos); break; + case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need + // to get visible before the reference to the object gets stored anywhere. + __ membar(Assembler::StoreStore); break; + default : ShouldNotReachHere(); + } + __ blr(); +} + +// ============================================================================ +// Constant pool cache access +// +// Memory ordering: +// +// Like done in C++ interpreter, we load the fields +// - _indices +// - _f12_oop +// acquired, because these are asked if the cache is already resolved. We don't +// want to float loads above this check. +// See also comments in ConstantPoolCacheEntry::bytecode_1(), +// ConstantPoolCacheEntry::bytecode_2() and ConstantPoolCacheEntry::f1(); + +// Call into the VM if call site is not yet resolved +// +// Input regs: +// - None, all passed regs are outputs. +// +// Returns: +// - Rcache: The const pool cache entry that contains the resolved result. +// - Rresult: Either noreg or output for f1/f2. +// +// Kills: +// - Rscratch +void TemplateTable::resolve_cache_and_index(int byte_no, Register Rcache, Register Rscratch, size_t index_size) { + + __ get_cache_and_index_at_bcp(Rcache, 1, index_size); + Label Lresolved, Ldone; + + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + // We are resolved if the indices offset contains the current bytecode. + // Big Endian: + __ lbz(Rscratch, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (byte_no + 1), Rcache); + // Acquire by cmp-br-isync (see below). + __ cmpdi(CCR0, Rscratch, (int)bytecode()); + __ beq(CCR0, Lresolved); + + address entry = NULL; + switch (bytecode()) { + case Bytecodes::_getstatic : // fall through + case Bytecodes::_putstatic : // fall through + case Bytecodes::_getfield : // fall through + case Bytecodes::_putfield : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); break; + case Bytecodes::_invokevirtual : // fall through + case Bytecodes::_invokespecial : // fall through + case Bytecodes::_invokestatic : // fall through + case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; + case Bytecodes::_invokehandle : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle); break; + case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; + default : ShouldNotReachHere(); break; + } + __ li(R4_ARG2, (int)bytecode()); + __ call_VM(noreg, entry, R4_ARG2, true); + + // Update registers with resolved info. + __ get_cache_and_index_at_bcp(Rcache, 1, index_size); + __ b(Ldone); + + __ bind(Lresolved); + __ isync(); // Order load wrt. succeeding loads. + __ bind(Ldone); +} + +// Load the constant pool cache entry at field accesses into registers. +// The Rcache and Rindex registers must be set before call. +// Input: +// - Rcache, Rindex +// Output: +// - Robj, Roffset, Rflags +void TemplateTable::load_field_cp_cache_entry(Register Robj, + Register Rcache, + Register Rindex /* unused on PPC64 */, + Register Roffset, + Register Rflags, + bool is_static = false) { + assert_different_registers(Rcache, Rflags, Roffset); + // assert(Rindex == noreg, "parameter not used on PPC64"); + + ByteSize cp_base_offset = ConstantPoolCache::base_offset(); + __ ld(Rflags, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::flags_offset()), Rcache); + __ ld(Roffset, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f2_offset()), Rcache); + if (is_static) { + __ ld(Robj, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f1_offset()), Rcache); + __ ld(Robj, in_bytes(Klass::java_mirror_offset()), Robj); + // Acquire not needed here. Following access has an address dependency on this value. + } +} + +// Load the constant pool cache entry at invokes into registers. +// Resolve if necessary. + +// Input Registers: +// - None, bcp is used, though +// +// Return registers: +// - Rmethod (f1 field or f2 if invokevirtual) +// - Ritable_index (f2 field) +// - Rflags (flags field) +// +// Kills: +// - R21 +// +void TemplateTable::load_invoke_cp_cache_entry(int byte_no, + Register Rmethod, + Register Ritable_index, + Register Rflags, + bool is_invokevirtual, + bool is_invokevfinal, + bool is_invokedynamic) { + + ByteSize cp_base_offset = ConstantPoolCache::base_offset(); + // Determine constant pool cache field offsets. + assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant"); + const int method_offset = in_bytes(cp_base_offset + (is_invokevirtual ? ConstantPoolCacheEntry::f2_offset() : ConstantPoolCacheEntry::f1_offset())); + const int flags_offset = in_bytes(cp_base_offset + ConstantPoolCacheEntry::flags_offset()); + // Access constant pool cache fields. + const int index_offset = in_bytes(cp_base_offset + ConstantPoolCacheEntry::f2_offset()); + + Register Rcache = R21_tmp1; // Note: same register as R21_sender_SP. + + if (is_invokevfinal) { + assert(Ritable_index == noreg, "register not used"); + // Already resolved. + __ get_cache_and_index_at_bcp(Rcache, 1); + } else { + resolve_cache_and_index(byte_no, Rcache, R0, is_invokedynamic ? sizeof(u4) : sizeof(u2)); + } + + __ ld(Rmethod, method_offset, Rcache); + __ ld(Rflags, flags_offset, Rcache); + + if (Ritable_index != noreg) { + __ ld(Ritable_index, index_offset, Rcache); + } +} + +// ============================================================================ +// Field access + +// Volatile variables demand their effects be made known to all CPU's +// in order. Store buffers on most chips allow reads & writes to +// reorder; the JMM's ReadAfterWrite.java test fails in -Xint mode +// without some kind of memory barrier (i.e., it's not sufficient that +// the interpreter does not reorder volatile references, the hardware +// also must not reorder them). +// +// According to the new Java Memory Model (JMM): +// (1) All volatiles are serialized wrt to each other. ALSO reads & +// writes act as aquire & release, so: +// (2) A read cannot let unrelated NON-volatile memory refs that +// happen after the read float up to before the read. It's OK for +// non-volatile memory refs that happen before the volatile read to +// float down below it. +// (3) Similar a volatile write cannot let unrelated NON-volatile +// memory refs that happen BEFORE the write float down to after the +// write. It's OK for non-volatile memory refs that happen after the +// volatile write to float up before it. +// +// We only put in barriers around volatile refs (they are expensive), +// not _between_ memory refs (that would require us to track the +// flavor of the previous memory refs). Requirements (2) and (3) +// require some barriers before volatile stores and after volatile +// loads. These nearly cover requirement (1) but miss the +// volatile-store-volatile-load case. This final case is placed after +// volatile-stores although it could just as well go before +// volatile-loads. + +// The registers cache and index expected to be set before call. +// Correct values of the cache and index registers are preserved. +// Kills: +// Rcache (if has_tos) +// Rscratch +void TemplateTable::jvmti_post_field_access(Register Rcache, Register Rscratch, bool is_static, bool has_tos) { + + assert_different_registers(Rcache, Rscratch); + + if (JvmtiExport::can_post_field_access()) { + ByteSize cp_base_offset = ConstantPoolCache::base_offset(); + Label Lno_field_access_post; + + // Check if post field access in enabled. + int offs = __ load_const_optimized(Rscratch, JvmtiExport::get_field_access_count_addr(), R0, true); + __ lwz(Rscratch, offs, Rscratch); + + __ cmpwi(CCR0, Rscratch, 0); + __ beq(CCR0, Lno_field_access_post); + + // Post access enabled - do it! + __ addi(Rcache, Rcache, in_bytes(cp_base_offset)); + if (is_static) { + __ li(R17_tos, 0); + } else { + if (has_tos) { + // The fast bytecode versions have obj ptr in register. + // Thus, save object pointer before call_VM() clobbers it + // put object on tos where GC wants it. + __ push_ptr(R17_tos); + } else { + // Load top of stack (do not pop the value off the stack). + __ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp); + } + __ verify_oop(R17_tos); + } + // tos: object pointer or NULL if static + // cache: cache entry pointer + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), R17_tos, Rcache); + if (!is_static && has_tos) { + // Restore object pointer. + __ pop_ptr(R17_tos); + __ verify_oop(R17_tos); + } else { + // Cache is still needed to get class or obj. + __ get_cache_and_index_at_bcp(Rcache, 1); + } + + __ align(32, 12); + __ bind(Lno_field_access_post); + } +} + +// kills R11_scratch1 +void TemplateTable::pop_and_check_object(Register Roop) { + Register Rtmp = R11_scratch1; + + assert_different_registers(Rtmp, Roop); + __ pop_ptr(Roop); + // For field access must check obj. + __ null_check_throw(Roop, -1, Rtmp); + __ verify_oop(Roop); +} + +// PPC64: implement volatile loads as fence-store-acquire. +void TemplateTable::getfield_or_static(int byte_no, bool is_static) { + transition(vtos, vtos); + + Label Lacquire, Lisync; + + const Register Rcache = R3_ARG1, + Rclass_or_obj = R22_tmp2, + Roffset = R23_tmp3, + Rflags = R31, + Rbtable = R5_ARG3, + Rbc = R6_ARG4, + Rscratch = R12_scratch2; + + static address field_branch_table[number_of_states], + static_branch_table[number_of_states]; + + address* branch_table = is_static ? static_branch_table : field_branch_table; + + // Get field offset. + resolve_cache_and_index(byte_no, Rcache, Rscratch, sizeof(u2)); + + // JVMTI support + jvmti_post_field_access(Rcache, Rscratch, is_static, false); + + // Load after possible GC. + load_field_cp_cache_entry(Rclass_or_obj, Rcache, noreg, Roffset, Rflags, is_static); + + // Load pointer to branch table. + __ load_const_optimized(Rbtable, (address)branch_table, Rscratch); + + // Get volatile flag. + __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + // Note: sync is needed before volatile load on PPC64. + + // Check field type. + __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + +#ifdef ASSERT + Label LFlagInvalid; + __ cmpldi(CCR0, Rflags, number_of_states); + __ bge(CCR0, LFlagInvalid); +#endif + + // Load from branch table and dispatch (volatile case: one instruction ahead). + __ sldi(Rflags, Rflags, LogBytesPerWord); + __ cmpwi(CCR6, Rscratch, 1); // Volatile? + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // Volatile ? size of 1 instruction : 0. + } + __ ldx(Rbtable, Rbtable, Rflags); + + // Get the obj from stack. + if (!is_static) { + pop_and_check_object(Rclass_or_obj); // Kills R11_scratch1. + } else { + __ verify_oop(Rclass_or_obj); + } + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ subf(Rbtable, Rscratch, Rbtable); // Point to volatile/non-volatile entry point. + } + __ mtctr(Rbtable); + __ bctr(); + +#ifdef ASSERT + __ bind(LFlagInvalid); + __ stop("got invalid flag", 0x654); + + // __ bind(Lvtos); + address pc_before_fence = __ pc(); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(__ pc() - pc_before_fence == (ptrdiff_t)BytesPerInstWord, "must be single instruction"); + assert(branch_table[vtos] == 0, "can't compute twice"); + branch_table[vtos] = __ pc(); // non-volatile_entry point + __ stop("vtos unexpected", 0x655); +#endif + + __ align(32, 28, 28); // Align load. + // __ bind(Ldtos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[dtos] == 0, "can't compute twice"); + branch_table[dtos] = __ pc(); // non-volatile_entry point + __ lfdx(F15_ftos, Rclass_or_obj, Roffset); + __ push(dtos); + if (!is_static) patch_bytecode(Bytecodes::_fast_dgetfield, Rbc, Rscratch); + { + Label acquire_double; + __ beq(CCR6, acquire_double); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ bind(acquire_double); + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ beq_predict_taken(CCR0, Lisync); + __ b(Lisync); // In case of NAN. + } + + __ align(32, 28, 28); // Align load. + // __ bind(Lftos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ftos] == 0, "can't compute twice"); + branch_table[ftos] = __ pc(); // non-volatile_entry point + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ push(ftos); + if (!is_static) { patch_bytecode(Bytecodes::_fast_fgetfield, Rbc, Rscratch); } + { + Label acquire_float; + __ beq(CCR6, acquire_float); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ bind(acquire_float); + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ beq_predict_taken(CCR0, Lisync); + __ b(Lisync); // In case of NAN. + } + + __ align(32, 28, 28); // Align load. + // __ bind(Litos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[itos] == 0, "can't compute twice"); + branch_table[itos] = __ pc(); // non-volatile_entry point + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ push(itos); + if (!is_static) patch_bytecode(Bytecodes::_fast_igetfield, Rbc, Rscratch); + __ beq(CCR6, Lacquire); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align load. + // __ bind(Lltos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ltos] == 0, "can't compute twice"); + branch_table[ltos] = __ pc(); // non-volatile_entry point + __ ldx(R17_tos, Rclass_or_obj, Roffset); + __ push(ltos); + if (!is_static) patch_bytecode(Bytecodes::_fast_lgetfield, Rbc, Rscratch); + __ beq(CCR6, Lacquire); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align load. + // __ bind(Lbtos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[btos] == 0, "can't compute twice"); + branch_table[btos] = __ pc(); // non-volatile_entry point + __ lbzx(R17_tos, Rclass_or_obj, Roffset); + __ extsb(R17_tos, R17_tos); + __ push(btos); + if (!is_static) patch_bytecode(Bytecodes::_fast_bgetfield, Rbc, Rscratch); + __ beq(CCR6, Lacquire); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align load. + // __ bind(Lctos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ctos] == 0, "can't compute twice"); + branch_table[ctos] = __ pc(); // non-volatile_entry point + __ lhzx(R17_tos, Rclass_or_obj, Roffset); + __ push(ctos); + if (!is_static) patch_bytecode(Bytecodes::_fast_cgetfield, Rbc, Rscratch); + __ beq(CCR6, Lacquire); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align load. + // __ bind(Lstos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[stos] == 0, "can't compute twice"); + branch_table[stos] = __ pc(); // non-volatile_entry point + __ lhax(R17_tos, Rclass_or_obj, Roffset); + __ push(stos); + if (!is_static) patch_bytecode(Bytecodes::_fast_sgetfield, Rbc, Rscratch); + __ beq(CCR6, Lacquire); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align load. + // __ bind(Latos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[atos] == 0, "can't compute twice"); + branch_table[atos] = __ pc(); // non-volatile_entry point + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ push(atos); + //__ dcbt(R17_tos); // prefetch + if (!is_static) patch_bytecode(Bytecodes::_fast_agetfield, Rbc, Rscratch); + __ beq(CCR6, Lacquire); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 12); + __ bind(Lacquire); + __ twi_0(R17_tos); + __ bind(Lisync); + __ isync(); // acquire + +#ifdef ASSERT + for (int i = 0; iprint_cr("get: %s_branch_table[%d] = 0x%llx (opcode 0x%llx)", + // is_static ? "static" : "field", i, branch_table[i], *((unsigned int*)branch_table[i])); + } +#endif +} + +void TemplateTable::getfield(int byte_no) { + getfield_or_static(byte_no, false); +} + +void TemplateTable::getstatic(int byte_no) { + getfield_or_static(byte_no, true); +} + +// The registers cache and index expected to be set before call. +// The function may destroy various registers, just not the cache and index registers. +void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, bool is_static) { + + assert_different_registers(Rcache, Rscratch, R6_ARG4); + + if (JvmtiExport::can_post_field_modification()) { + Label Lno_field_mod_post; + + // Check if post field access in enabled. + int offs = __ load_const_optimized(Rscratch, JvmtiExport::get_field_modification_count_addr(), R0, true); + __ lwz(Rscratch, offs, Rscratch); + + __ cmpwi(CCR0, Rscratch, 0); + __ beq(CCR0, Lno_field_mod_post); + + // Do the post + ByteSize cp_base_offset = ConstantPoolCache::base_offset(); + const Register Robj = Rscratch; + + __ addi(Rcache, Rcache, in_bytes(cp_base_offset)); + if (is_static) { + // Life is simple. Null out the object pointer. + __ li(Robj, 0); + } else { + // In case of the fast versions, value lives in registers => put it back on tos. + int offs = Interpreter::expr_offset_in_bytes(0); + Register base = R15_esp; + switch(bytecode()) { + case Bytecodes::_fast_aputfield: __ push_ptr(); offs+= Interpreter::stackElementSize; break; + case Bytecodes::_fast_iputfield: // Fall through + case Bytecodes::_fast_bputfield: // Fall through + case Bytecodes::_fast_cputfield: // Fall through + case Bytecodes::_fast_sputfield: __ push_i(); offs+= Interpreter::stackElementSize; break; + case Bytecodes::_fast_lputfield: __ push_l(); offs+=2*Interpreter::stackElementSize; break; + case Bytecodes::_fast_fputfield: __ push_f(); offs+= Interpreter::stackElementSize; break; + case Bytecodes::_fast_dputfield: __ push_d(); offs+=2*Interpreter::stackElementSize; break; + default: { + offs = 0; + base = Robj; + const Register Rflags = Robj; + Label is_one_slot; + // Life is harder. The stack holds the value on top, followed by the + // object. We don't know the size of the value, though; it could be + // one or two words depending on its type. As a result, we must find + // the type to determine where the object is. + __ ld(Rflags, in_bytes(ConstantPoolCacheEntry::flags_offset()), Rcache); // Big Endian + __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + + __ cmpwi(CCR0, Rflags, ltos); + __ cmpwi(CCR1, Rflags, dtos); + __ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(1)); + __ crnor(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + __ beq(CCR0, is_one_slot); + __ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(2)); + __ bind(is_one_slot); + break; + } + } + __ ld(Robj, offs, base); + __ verify_oop(Robj); + } + + __ addi(R6_ARG4, R15_esp, Interpreter::expr_offset_in_bytes(0)); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), Robj, Rcache, R6_ARG4); + __ get_cache_and_index_at_bcp(Rcache, 1); + + // In case of the fast versions, value lives in registers => put it back on tos. + switch(bytecode()) { + case Bytecodes::_fast_aputfield: __ pop_ptr(); break; + case Bytecodes::_fast_iputfield: // Fall through + case Bytecodes::_fast_bputfield: // Fall through + case Bytecodes::_fast_cputfield: // Fall through + case Bytecodes::_fast_sputfield: __ pop_i(); break; + case Bytecodes::_fast_lputfield: __ pop_l(); break; + case Bytecodes::_fast_fputfield: __ pop_f(); break; + case Bytecodes::_fast_dputfield: __ pop_d(); break; + default: break; // Nothin' to do. + } + + __ align(32, 12); + __ bind(Lno_field_mod_post); + } +} + +// PPC64: implement volatile stores as release-store (return bytecode contains an additional release). +void TemplateTable::putfield_or_static(int byte_no, bool is_static) { + Label Lvolatile; + + const Register Rcache = R5_ARG3, // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod). + Rclass_or_obj = R31, // Needs to survive C call. + Roffset = R22_tmp2, // Needs to survive C call. + Rflags = R3_ARG1, + Rbtable = R4_ARG2, + Rscratch = R11_scratch1, + Rscratch2 = R12_scratch2, + Rscratch3 = R6_ARG4, + Rbc = Rscratch3; + const ConditionRegister CR_is_vol = CCR2; // Non-volatile condition register (survives runtime call in do_oop_store). + + static address field_branch_table[number_of_states], + static_branch_table[number_of_states]; + + address* branch_table = is_static ? static_branch_table : field_branch_table; + + // Stack (grows up): + // value + // obj + + // Load the field offset. + resolve_cache_and_index(byte_no, Rcache, Rscratch, sizeof(u2)); + jvmti_post_field_mod(Rcache, Rscratch, is_static); + load_field_cp_cache_entry(Rclass_or_obj, Rcache, noreg, Roffset, Rflags, is_static); + + // Load pointer to branch table. + __ load_const_optimized(Rbtable, (address)branch_table, Rscratch); + + // Get volatile flag. + __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + + // Check the field type. + __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + +#ifdef ASSERT + Label LFlagInvalid; + __ cmpldi(CCR0, Rflags, number_of_states); + __ bge(CCR0, LFlagInvalid); +#endif + + // Load from branch table and dispatch (volatile case: one instruction ahead). + __ sldi(Rflags, Rflags, LogBytesPerWord); + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ cmpwi(CR_is_vol, Rscratch, 1); } // Volatile? + __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // Volatile? size of instruction 1 : 0. + __ ldx(Rbtable, Rbtable, Rflags); + + __ subf(Rbtable, Rscratch, Rbtable); // Point to volatile/non-volatile entry point. + __ mtctr(Rbtable); + __ bctr(); + +#ifdef ASSERT + __ bind(LFlagInvalid); + __ stop("got invalid flag", 0x656); + + // __ bind(Lvtos); + address pc_before_release = __ pc(); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(__ pc() - pc_before_release == (ptrdiff_t)BytesPerInstWord, "must be single instruction"); + assert(branch_table[vtos] == 0, "can't compute twice"); + branch_table[vtos] = __ pc(); // non-volatile_entry point + __ stop("vtos unexpected", 0x657); +#endif + + __ align(32, 28, 28); // Align pop. + // __ bind(Ldtos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[dtos] == 0, "can't compute twice"); + branch_table[dtos] = __ pc(); // non-volatile_entry point + __ pop(dtos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stfdx(F15_ftos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_dputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + } + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lftos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ftos] == 0, "can't compute twice"); + branch_table[ftos] = __ pc(); // non-volatile_entry point + __ pop(ftos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stfsx(F15_ftos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_fputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + } + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align pop. + // __ bind(Litos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[itos] == 0, "can't compute twice"); + branch_table[itos] = __ pc(); // non-volatile_entry point + __ pop(itos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stwx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_iputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + } + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lltos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ltos] == 0, "can't compute twice"); + branch_table[ltos] = __ pc(); // non-volatile_entry point + __ pop(ltos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stdx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_lputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + } + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lbtos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[btos] == 0, "can't compute twice"); + branch_table[btos] = __ pc(); // non-volatile_entry point + __ pop(btos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stbx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_bputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + } + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lctos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ctos] == 0, "can't compute twice"); + branch_table[ctos] = __ pc(); // non-volatile_entry point + __ pop(ctos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.. + __ sthx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_cputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + } + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lstos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[stos] == 0, "can't compute twice"); + branch_table[stos] = __ pc(); // non-volatile_entry point + __ pop(stos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ sthx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_sputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + } + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align pop. + // __ bind(Latos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[atos] == 0, "can't compute twice"); + branch_table[atos] = __ pc(); // non-volatile_entry point + __ pop(atos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // kills R11_scratch1 + do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, _bs->kind(), false /* precise */, true /* check null */); + if (!is_static) { patch_bytecode(Bytecodes::_fast_aputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 12); + __ bind(Lvolatile); + __ fence(); + } + // fallthru: __ b(Lexit); + +#ifdef ASSERT + for (int i = 0; iprint_cr("put: %s_branch_table[%d] = 0x%llx (opcode 0x%llx)", + // is_static ? "static" : "field", i, branch_table[i], *((unsigned int*)branch_table[i])); + } +#endif +} + +void TemplateTable::putfield(int byte_no) { + putfield_or_static(byte_no, false); +} + +void TemplateTable::putstatic(int byte_no) { + putfield_or_static(byte_no, true); +} + +// See SPARC. On PPC64, we have a different jvmti_post_field_mod which does the job. +void TemplateTable::jvmti_post_fast_field_mod() { + __ should_not_reach_here(); +} + +void TemplateTable::fast_storefield(TosState state) { + transition(state, vtos); + + const Register Rcache = R5_ARG3, // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod). + Rclass_or_obj = R31, // Needs to survive C call. + Roffset = R22_tmp2, // Needs to survive C call. + Rflags = R3_ARG1, + Rscratch = R11_scratch1, + Rscratch2 = R12_scratch2, + Rscratch3 = R4_ARG2; + const ConditionRegister CR_is_vol = CCR2; // Non-volatile condition register (survives runtime call in do_oop_store). + + // Constant pool already resolved => Load flags and offset of field. + __ get_cache_and_index_at_bcp(Rcache, 1); + jvmti_post_field_mod(Rcache, Rscratch, false /* not static */); + load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false); + + // Get the obj and the final store addr. + pop_and_check_object(Rclass_or_obj); // Kills R11_scratch1. + + // Get volatile flag. + __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ cmpdi(CR_is_vol, Rscratch, 1); } + { + Label LnotVolatile; + __ beq(CCR0, LnotVolatile); + __ release(); + __ align(32, 12); + __ bind(LnotVolatile); + } + + // Do the store and fencing. + switch(bytecode()) { + case Bytecodes::_fast_aputfield: + // Store into the field. + do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, _bs->kind(), false /* precise */, true /* check null */); + break; + + case Bytecodes::_fast_iputfield: + __ stwx(R17_tos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_lputfield: + __ stdx(R17_tos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_bputfield: + __ stbx(R17_tos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_cputfield: + case Bytecodes::_fast_sputfield: + __ sthx(R17_tos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_fputfield: + __ stfsx(F15_ftos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_dputfield: + __ stfdx(F15_ftos, Rclass_or_obj, Roffset); + break; + + default: ShouldNotReachHere(); + } + + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + Label LVolatile; + __ beq(CR_is_vol, LVolatile); + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 12); + __ bind(LVolatile); + __ fence(); + } +} + +void TemplateTable::fast_accessfield(TosState state) { + transition(atos, state); + + Label LisVolatile; + ByteSize cp_base_offset = ConstantPoolCache::base_offset(); + + const Register Rcache = R3_ARG1, + Rclass_or_obj = R17_tos, + Roffset = R22_tmp2, + Rflags = R23_tmp3, + Rscratch = R12_scratch2; + + // Constant pool already resolved. Get the field offset. + __ get_cache_and_index_at_bcp(Rcache, 1); + load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false); + + // JVMTI support + jvmti_post_field_access(Rcache, Rscratch, false, true); + + // Get the load address. + __ null_check_throw(Rclass_or_obj, -1, Rscratch); + + // Get volatile flag. + __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + __ bne(CCR0, LisVolatile); + + switch(bytecode()) { + case Bytecodes::_fast_agetfield: + { + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode())); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_igetfield: + { + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode())); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_lgetfield: + { + __ ldx(R17_tos, Rclass_or_obj, Roffset); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode())); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ ldx(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_bgetfield: + { + __ lbzx(R17_tos, Rclass_or_obj, Roffset); + __ extsb(R17_tos, R17_tos); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode())); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lbzx(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ extsb(R17_tos, R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_cgetfield: + { + __ lhzx(R17_tos, Rclass_or_obj, Roffset); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode())); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lhzx(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_sgetfield: + { + __ lhax(R17_tos, Rclass_or_obj, Roffset); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode())); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lhax(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_fgetfield: + { + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode())); + + __ bind(LisVolatile); + Label Ldummy; + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ bne_predict_not_taken(CCR0, Ldummy); + __ bind(Ldummy); + __ isync(); + break; + } + case Bytecodes::_fast_dgetfield: + { + __ lfdx(F15_ftos, Rclass_or_obj, Roffset); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode())); + + __ bind(LisVolatile); + Label Ldummy; + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lfdx(F15_ftos, Rclass_or_obj, Roffset); + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ bne_predict_not_taken(CCR0, Ldummy); + __ bind(Ldummy); + __ isync(); + break; + } + default: ShouldNotReachHere(); + } +} + +void TemplateTable::fast_xaccess(TosState state) { + transition(vtos, state); + + Label LisVolatile; + ByteSize cp_base_offset = ConstantPoolCache::base_offset(); + const Register Rcache = R3_ARG1, + Rclass_or_obj = R17_tos, + Roffset = R22_tmp2, + Rflags = R23_tmp3, + Rscratch = R12_scratch2; + + __ ld(Rclass_or_obj, 0, R18_locals); + + // Constant pool already resolved. Get the field offset. + __ get_cache_and_index_at_bcp(Rcache, 2); + load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false); + + // JVMTI support not needed, since we switch back to single bytecode as soon as debugger attaches. + + // Needed to report exception at the correct bcp. + __ addi(R14_bcp, R14_bcp, 1); + + // Get the load address. + __ null_check_throw(Rclass_or_obj, -1, Rscratch); + + // Get volatile flag. + __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + __ bne(CCR0, LisVolatile); + + switch(state) { + case atos: + { + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode()) - 1); // Undo bcp increment. + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ twi_0(R17_tos); + __ isync(); + break; + } + case itos: + { + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode()) - 1); // Undo bcp increment. + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case ftos: + { + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ dispatch_epilog(state, Bytecodes::length_for(bytecode()) - 1); // Undo bcp increment. + + __ bind(LisVolatile); + Label Ldummy; + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ bne_predict_not_taken(CCR0, Ldummy); + __ bind(Ldummy); + __ isync(); + break; + } + default: ShouldNotReachHere(); + } + __ addi(R14_bcp, R14_bcp, -1); +} + +// ============================================================================ +// Calls + +// Common code for invoke +// +// Input: +// - byte_no +// +// Output: +// - Rmethod: The method to invoke next. +// - Rret_addr: The return address to return to. +// - Rindex: MethodType (invokehandle) or CallSite obj (invokedynamic) +// - Rrecv: Cache for "this" pointer, might be noreg if static call. +// - Rflags: Method flags from const pool cache. +// +// Kills: +// - Rscratch1 +// +void TemplateTable::prepare_invoke(int byte_no, + Register Rmethod, // linked method (or i-klass) + Register Rret_addr,// return address + Register Rindex, // itable index, MethodType, etc. + Register Rrecv, // If caller wants to see it. + Register Rflags, // If caller wants to test it. + Register Rscratch + ) { + // Determine flags. + const Bytecodes::Code code = bytecode(); + const bool is_invokeinterface = code == Bytecodes::_invokeinterface; + const bool is_invokedynamic = code == Bytecodes::_invokedynamic; + const bool is_invokehandle = code == Bytecodes::_invokehandle; + const bool is_invokevirtual = code == Bytecodes::_invokevirtual; + const bool is_invokespecial = code == Bytecodes::_invokespecial; + const bool load_receiver = (Rrecv != noreg); + assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), ""); + + assert_different_registers(Rmethod, Rindex, Rflags, Rscratch); + assert_different_registers(Rmethod, Rrecv, Rflags, Rscratch); + assert_different_registers(Rret_addr, Rscratch); + + load_invoke_cp_cache_entry(byte_no, Rmethod, Rindex, Rflags, is_invokevirtual, false, is_invokedynamic); + + // Saving of SP done in call_from_interpreter. + + // Maybe push "appendix" to arguments. + if (is_invokedynamic || is_invokehandle) { + Label Ldone; + __ rldicl_(R0, Rflags, 64-ConstantPoolCacheEntry::has_appendix_shift, 63); + __ beq(CCR0, Ldone); + // Push "appendix" (MethodType, CallSite, etc.). + // This must be done before we get the receiver, + // since the parameter_size includes it. + __ load_resolved_reference_at_index(Rscratch, Rindex); + __ verify_oop(Rscratch); + __ push_ptr(Rscratch); + __ bind(Ldone); + } + + // Load receiver if needed (after appendix is pushed so parameter size is correct). + if (load_receiver) { + const Register Rparam_count = Rscratch; + __ andi(Rparam_count, Rflags, ConstantPoolCacheEntry::parameter_size_mask); + __ load_receiver(Rparam_count, Rrecv); + __ verify_oop(Rrecv); + } + + // Get return address. + { + Register Rtable_addr = Rscratch; + Register Rret_type = Rret_addr; + address table_addr = (address) Interpreter::invoke_return_entry_table_for(code); + + // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, (address*)table_addr); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + // Get return address. + __ ldx(Rret_addr, Rtable_addr, Rret_type); + } +} + +// Helper for virtual calls. Load target out of vtable and jump off! +// Kills all passed registers. +void TemplateTable::generate_vtable_call(Register Rrecv_klass, Register Rindex, Register Rret, Register Rtemp) { + + assert_different_registers(Rrecv_klass, Rtemp, Rret); + const Register Rtarget_method = Rindex; + + // Get target method & entry point. + const int base = InstanceKlass::vtable_start_offset() * wordSize; + // Calc vtable addr scale the vtable index by 8. + __ sldi(Rindex, Rindex, exact_log2(vtableEntry::size() * wordSize)); + // Load target. + __ addi(Rrecv_klass, Rrecv_klass, base + vtableEntry::method_offset_in_bytes()); + __ ldx(Rtarget_method, Rindex, Rrecv_klass); + __ call_from_interpreter(Rtarget_method, Rret, Rrecv_klass /* scratch1 */, Rtemp /* scratch2 */); +} + +// Virtual or final call. Final calls are rewritten on the fly to run through "fast_finalcall" next time. +void TemplateTable::invokevirtual(int byte_no) { + transition(vtos, vtos); + + Register Rtable_addr = R11_scratch1, + Rret_type = R12_scratch2, + Rret_addr = R5_ARG3, + Rflags = R22_tmp2, // Should survive C call. + Rrecv = R3_ARG1, + Rrecv_klass = Rrecv, + Rvtableindex_or_method = R31, // Should survive C call. + Rnum_params = R4_ARG2, + Rnew_bc = R6_ARG4; + + Label LnotFinal; + + load_invoke_cp_cache_entry(byte_no, Rvtableindex_or_method, noreg, Rflags, /*virtual*/ true, false, false); + + __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_vfinal_shift); + __ bfalse(CCR0, LnotFinal); + + patch_bytecode(Bytecodes::_fast_invokevfinal, Rnew_bc, R12_scratch2); + invokevfinal_helper(Rvtableindex_or_method, Rflags, R11_scratch1, R12_scratch2); + + __ align(32, 12); + __ bind(LnotFinal); + // Load "this" pointer (receiver). + __ rldicl(Rnum_params, Rflags, 64, 48); + __ load_receiver(Rnum_params, Rrecv); + __ verify_oop(Rrecv); + + // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, Interpreter::invoke_return_entry_table()); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + __ ldx(Rret_addr, Rret_type, Rtable_addr); + __ null_check_throw(Rrecv, oopDesc::klass_offset_in_bytes(), R11_scratch1); + __ load_klass(Rrecv_klass, Rrecv); + __ verify_klass_ptr(Rrecv_klass); + __ profile_virtual_call(Rrecv_klass, R11_scratch1, R12_scratch2, false); + + generate_vtable_call(Rrecv_klass, Rvtableindex_or_method, Rret_addr, R11_scratch1); +} + +void TemplateTable::fast_invokevfinal(int byte_no) { + transition(vtos, vtos); + + assert(byte_no == f2_byte, "use this argument"); + Register Rflags = R22_tmp2, + Rmethod = R31; + load_invoke_cp_cache_entry(byte_no, Rmethod, noreg, Rflags, /*virtual*/ true, /*is_invokevfinal*/ true, false); + invokevfinal_helper(Rmethod, Rflags, R11_scratch1, R12_scratch2); +} + +void TemplateTable::invokevfinal_helper(Register Rmethod, Register Rflags, Register Rscratch1, Register Rscratch2) { + + assert_different_registers(Rmethod, Rflags, Rscratch1, Rscratch2); + + // Load receiver from stack slot. + Register Rrecv = Rscratch2; + Register Rnum_params = Rrecv; + + __ ld(Rnum_params, in_bytes(Method::const_offset()), Rmethod); + __ lhz(Rnum_params /* number of params */, in_bytes(ConstMethod::size_of_parameters_offset()), Rnum_params); + + // Get return address. + Register Rtable_addr = Rscratch1, + Rret_addr = Rflags, + Rret_type = Rret_addr; + // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, Interpreter::invoke_return_entry_table()); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + __ ldx(Rret_addr, Rret_type, Rtable_addr); + + // Load receiver and receiver NULL check. + __ load_receiver(Rnum_params, Rrecv); + __ null_check_throw(Rrecv, -1, Rscratch1); + + __ profile_final_call(Rrecv, Rscratch1); + + // Do the call. + __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1, Rscratch2); +} + +void TemplateTable::invokespecial(int byte_no) { + assert(byte_no == f1_byte, "use this argument"); + transition(vtos, vtos); + + Register Rtable_addr = R3_ARG1, + Rret_addr = R4_ARG2, + Rflags = R5_ARG3, + Rreceiver = R6_ARG4, + Rmethod = R31; + + prepare_invoke(byte_no, Rmethod, Rret_addr, noreg, Rreceiver, Rflags, R11_scratch1); + + // Receiver NULL check. + __ null_check_throw(Rreceiver, -1, R11_scratch1); + + __ profile_call(R11_scratch1, R12_scratch2); + __ call_from_interpreter(Rmethod, Rret_addr, R11_scratch1, R12_scratch2); +} + +void TemplateTable::invokestatic(int byte_no) { + assert(byte_no == f1_byte, "use this argument"); + transition(vtos, vtos); + + Register Rtable_addr = R3_ARG1, + Rret_addr = R4_ARG2, + Rflags = R5_ARG3; + + prepare_invoke(byte_no, R19_method, Rret_addr, noreg, noreg, Rflags, R11_scratch1); + + __ profile_call(R11_scratch1, R12_scratch2); + __ call_from_interpreter(R19_method, Rret_addr, R11_scratch1, R12_scratch2); +} + +void TemplateTable::invokeinterface_object_method(Register Rrecv_klass, + Register Rret, + Register Rflags, + Register Rindex, + Register Rtemp1, + Register Rtemp2) { + + assert_different_registers(Rindex, Rret, Rrecv_klass, Rflags, Rtemp1, Rtemp2); + Label LnotFinal; + + // Check for vfinal. + __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_vfinal_shift); + __ bfalse(CCR0, LnotFinal); + + Register Rscratch = Rflags; // Rflags is dead now. + + // Final call case. + __ profile_final_call(Rtemp1, Rscratch); + // Do the final call - the index (f2) contains the method. + __ call_from_interpreter(Rindex, Rret, Rscratch, Rrecv_klass /* scratch */); + + // Non-final callc case. + __ bind(LnotFinal); + __ profile_virtual_call(Rrecv_klass, Rtemp1, Rscratch, false); + generate_vtable_call(Rrecv_klass, Rindex, Rret, Rscratch); +} + +void TemplateTable::invokeinterface(int byte_no) { + assert(byte_no == f1_byte, "use this argument"); + transition(vtos, vtos); + + const Register Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Rscratch3 = R9_ARG7, + Rscratch4 = R10_ARG8, + Rtable_addr = Rscratch2, + Rinterface_klass = R5_ARG3, + Rret_type = R8_ARG6, + Rret_addr = Rret_type, + Rindex = R6_ARG4, + Rreceiver = R4_ARG2, + Rrecv_klass = Rreceiver, + Rflags = R7_ARG5; + + prepare_invoke(byte_no, Rinterface_klass, Rret_addr, Rindex, Rreceiver, Rflags, Rscratch1); + + // Get receiver klass. + __ null_check_throw(Rreceiver, oopDesc::klass_offset_in_bytes(), Rscratch3); + __ load_klass(Rrecv_klass, Rreceiver); + + // Check corner case object method. + Label LobjectMethod; + + __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift); + __ btrue(CCR0, LobjectMethod); + + // Fallthrough: The normal invokeinterface case. + __ profile_virtual_call(Rrecv_klass, Rscratch1, Rscratch2, false); + + // Find entry point to call. + Label Lthrow_icc, Lthrow_ame; + // Result will be returned in Rindex. + __ mr(Rscratch4, Rrecv_klass); + __ mr(Rscratch3, Rindex); + __ lookup_interface_method(Rrecv_klass, Rinterface_klass, Rindex, Rindex, Rscratch1, Rscratch2, Lthrow_icc); + + __ cmpdi(CCR0, Rindex, 0); + __ beq(CCR0, Lthrow_ame); + // Found entry. Jump off! + __ call_from_interpreter(Rindex, Rret_addr, Rscratch1, Rscratch2); + + // Vtable entry was NULL => Throw abstract method error. + __ bind(Lthrow_ame); + __ mr(Rrecv_klass, Rscratch4); + __ mr(Rindex, Rscratch3); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); + + // Interface was not found => Throw incompatible class change error. + __ bind(Lthrow_icc); + __ mr(Rrecv_klass, Rscratch4); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); + + __ should_not_reach_here(); + + // Special case of invokeinterface called for virtual method of + // java.lang.Object. See ConstantPoolCacheEntry::set_method() for details: + // The invokeinterface was rewritten to a invokevirtual, hence we have + // to handle this corner case. This code isn't produced by javac, but could + // be produced by another compliant java compiler. + __ bind(LobjectMethod); + invokeinterface_object_method(Rrecv_klass, Rret_addr, Rflags, Rindex, Rscratch1, Rscratch2); +} + +void TemplateTable::invokedynamic(int byte_no) { + transition(vtos, vtos); + + const Register Rret_addr = R3_ARG1, + Rflags = R4_ARG2, + Rmethod = R22_tmp2, + Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2; + + if (!EnableInvokeDynamic) { + // We should not encounter this bytecode if !EnableInvokeDynamic. + // The verifier will stop it. However, if we get past the verifier, + // this will stop the thread in a reasonable way, without crashing the JVM. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); + // The call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + return; + } + + prepare_invoke(byte_no, Rmethod, Rret_addr, Rscratch1, noreg, Rflags, Rscratch2); + + // Profile this call. + __ profile_call(Rscratch1, Rscratch2); + + // Off we go. With the new method handles, we don't jump to a method handle + // entry any more. Instead, we pushed an "appendix" in prepare invoke, which happens + // to be the callsite object the bootstrap method returned. This is passed to a + // "link" method which does the dispatch (Most likely just grabs the MH stored + // inside the callsite and does an invokehandle). + __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1 /* scratch1 */, Rscratch2 /* scratch2 */); +} + +void TemplateTable::invokehandle(int byte_no) { + transition(vtos, vtos); + + const Register Rret_addr = R3_ARG1, + Rflags = R4_ARG2, + Rrecv = R5_ARG3, + Rmethod = R22_tmp2, + Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2; + + if (!EnableInvokeDynamic) { + // Rewriter does not generate this bytecode. + __ should_not_reach_here(); + return; + } + + prepare_invoke(byte_no, Rmethod, Rret_addr, Rscratch1, Rrecv, Rflags, Rscratch2); + __ verify_method_ptr(Rmethod); + __ null_check_throw(Rrecv, -1, Rscratch2); + + __ profile_final_call(Rrecv, Rscratch1); + + // Still no call from handle => We call the method handle interpreter here. + __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1 /* scratch1 */, Rscratch2 /* scratch2 */); +} + +// ============================================================================= +// Allocation + +// Puts allocated obj ref onto the expression stack. +void TemplateTable::_new() { + transition(vtos, atos); + + Label Lslow_case, + Ldone, + Linitialize_header, + Lallocate_shared, + Linitialize_object; // Including clearing the fields. + + const Register RallocatedObject = R17_tos, + RinstanceKlass = R9_ARG7, + Rscratch = R11_scratch1, + Roffset = R8_ARG6, + Rinstance_size = Roffset, + Rcpool = R4_ARG2, + Rtags = R3_ARG1, + Rindex = R5_ARG3; + + const bool allow_shared_alloc = Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; + + // -------------------------------------------------------------------------- + // Check if fast case is possible. + + // Load pointers to const pool and const pool's tags array. + __ get_cpool_and_tags(Rcpool, Rtags); + // Load index of constant pool entry. + __ get_2_byte_integer_at_bcp(1, Rindex, InterpreterMacroAssembler::Unsigned); + + if (UseTLAB) { + // Make sure the class we're about to instantiate has been resolved + // This is done before loading instanceKlass to be consistent with the order + // how Constant Pool is updated (see ConstantPoolCache::klass_at_put). + __ addi(Rtags, Rtags, Array::base_offset_in_bytes()); + __ lbzx(Rtags, Rindex, Rtags); + + __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class); + __ bne(CCR0, Lslow_case); + + // Get instanceKlass (load from Rcpool + sizeof(ConstantPool) + Rindex*BytesPerWord). + __ sldi(Roffset, Rindex, LogBytesPerWord); + __ addi(Rscratch, Rcpool, sizeof(ConstantPool)); + __ isync(); // Order load of instance Klass wrt. tags. + __ ldx(RinstanceKlass, Roffset, Rscratch); + + // Make sure klass is fully initialized and get instance_size. + __ lbz(Rscratch, in_bytes(InstanceKlass::init_state_offset()), RinstanceKlass); + __ lwz(Rinstance_size, in_bytes(Klass::layout_helper_offset()), RinstanceKlass); + + __ cmpdi(CCR1, Rscratch, InstanceKlass::fully_initialized); + // Make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class. + __ andi_(R0, Rinstance_size, Klass::_lh_instance_slow_path_bit); // slow path bit equals 0? + + __ crnand(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); // slow path bit set or not fully initialized? + __ beq(CCR0, Lslow_case); + + // -------------------------------------------------------------------------- + // Fast case: + // Allocate the instance. + // 1) Try to allocate in the TLAB. + // 2) If fail, and the TLAB is not full enough to discard, allocate in the shared Eden. + // 3) If the above fails (or is not applicable), go to a slow case (creates a new TLAB, etc.). + + Register RoldTopValue = RallocatedObject; // Object will be allocated here if it fits. + Register RnewTopValue = R6_ARG4; + Register RendValue = R7_ARG5; + + // Check if we can allocate in the TLAB. + __ ld(RoldTopValue, in_bytes(JavaThread::tlab_top_offset()), R16_thread); + __ ld(RendValue, in_bytes(JavaThread::tlab_end_offset()), R16_thread); + + __ add(RnewTopValue, Rinstance_size, RoldTopValue); + + // If there is enough space, we do not CAS and do not clear. + __ cmpld(CCR0, RnewTopValue, RendValue); + __ bgt(CCR0, allow_shared_alloc ? Lallocate_shared : Lslow_case); + + __ std(RnewTopValue, in_bytes(JavaThread::tlab_top_offset()), R16_thread); + + if (ZeroTLAB) { + // The fields have already been cleared. + __ b(Linitialize_header); + } else { + // Initialize both the header and fields. + __ b(Linitialize_object); + } + + // Fall through: TLAB was too small. + if (allow_shared_alloc) { + Register RtlabWasteLimitValue = R10_ARG8; + Register RfreeValue = RnewTopValue; + + __ bind(Lallocate_shared); + // Check if tlab should be discarded (refill_waste_limit >= free). + __ ld(RtlabWasteLimitValue, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), R16_thread); + __ subf(RfreeValue, RoldTopValue, RendValue); + __ srdi(RfreeValue, RfreeValue, LogHeapWordSize); // in dwords + __ cmpld(CCR0, RtlabWasteLimitValue, RfreeValue); + __ bge(CCR0, Lslow_case); + + // Increment waste limit to prevent getting stuck on this slow path. + __ addi(RtlabWasteLimitValue, RtlabWasteLimitValue, (int)ThreadLocalAllocBuffer::refill_waste_limit_increment()); + __ std(RtlabWasteLimitValue, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), R16_thread); + } + // else: No allocation in the shared eden. // fallthru: __ b(Lslow_case); + } + // else: Always go the slow path. + + // -------------------------------------------------------------------------- + // slow case + __ bind(Lslow_case); + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), Rcpool, Rindex); + + if (UseTLAB) { + __ b(Ldone); + // -------------------------------------------------------------------------- + // Init1: Zero out newly allocated memory. + + if (!ZeroTLAB || allow_shared_alloc) { + // Clear object fields. + __ bind(Linitialize_object); + + // Initialize remaining object fields. + Register Rbase = Rtags; + __ addi(Rinstance_size, Rinstance_size, 7 - (int)sizeof(oopDesc)); + __ addi(Rbase, RallocatedObject, sizeof(oopDesc)); + __ srdi(Rinstance_size, Rinstance_size, 3); + + // Clear out object skipping header. Takes also care of the zero length case. + __ clear_memory_doubleword(Rbase, Rinstance_size); + // fallthru: __ b(Linitialize_header); + } + + // -------------------------------------------------------------------------- + // Init2: Initialize the header: mark, klass + __ bind(Linitialize_header); + + // Init mark. + if (UseBiasedLocking) { + __ ld(Rscratch, in_bytes(Klass::prototype_header_offset()), RinstanceKlass); + } else { + __ load_const_optimized(Rscratch, markOopDesc::prototype(), R0); + } + __ std(Rscratch, oopDesc::mark_offset_in_bytes(), RallocatedObject); + + // Init klass. + __ store_klass_gap(RallocatedObject); + __ store_klass(RallocatedObject, RinstanceKlass, Rscratch); // klass (last for cms) + + // Check and trigger dtrace event. + { + SkipIfEqualZero skip_if(_masm, Rscratch, &DTraceAllocProbes); + __ push(atos); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc)); + __ pop(atos); + } + } + + // continue + __ bind(Ldone); + + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(Assembler::StoreStore); +} + +void TemplateTable::newarray() { + transition(itos, atos); + + __ lbz(R4, 1, R14_bcp); + __ extsw(R5, R17_tos); + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), R4, R5 /* size */); + + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(Assembler::StoreStore); +} + +void TemplateTable::anewarray() { + transition(itos, atos); + + __ get_constant_pool(R4); + __ get_2_byte_integer_at_bcp(1, R5, InterpreterMacroAssembler::Unsigned); + __ extsw(R6, R17_tos); // size + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), R4 /* pool */, R5 /* index */, R6 /* size */); + + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(Assembler::StoreStore); +} + +// Allocate a multi dimensional array +void TemplateTable::multianewarray() { + transition(vtos, atos); + + Register Rptr = R31; // Needs to survive C call. + + // Put ndims * wordSize into frame temp slot + __ lbz(Rptr, 3, R14_bcp); + __ sldi(Rptr, Rptr, Interpreter::logStackElementSize); + // Esp points past last_dim, so set to R4 to first_dim address. + __ add(R4, Rptr, R15_esp); + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), R4 /* first_size_address */); + // Pop all dimensions off the stack. + __ add(R15_esp, Rptr, R15_esp); + + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(Assembler::StoreStore); +} + +void TemplateTable::arraylength() { + transition(atos, itos); + + Label LnoException; + __ verify_oop(R17_tos); + __ null_check_throw(R17_tos, arrayOopDesc::length_offset_in_bytes(), R11_scratch1); + __ lwa(R17_tos, arrayOopDesc::length_offset_in_bytes(), R17_tos); +} + +// ============================================================================ +// Typechecks + +void TemplateTable::checkcast() { + transition(atos, atos); + + Label Ldone, Lis_null, Lquicked, Lresolved; + Register Roffset = R5_ARG3, + RobjKlass = R4_ARG2, + RspecifiedKlass = R6_ARG4, // Generate_ClassCastException_verbose_handler will expect this register. + Rcpool = R11_scratch1, + Rtags = R12_scratch2; + + // Null does not pass. + __ cmpdi(CCR0, R17_tos, 0); + __ beq(CCR0, Lis_null); + + // Get constant pool tag to find out if the bytecode has already been "quickened". + __ get_cpool_and_tags(Rcpool, Rtags); + + __ get_2_byte_integer_at_bcp(1, Roffset, InterpreterMacroAssembler::Unsigned); + + __ addi(Rtags, Rtags, Array::base_offset_in_bytes()); + __ lbzx(Rtags, Rtags, Roffset); + + __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class); + __ beq(CCR0, Lquicked); + + // Call into the VM to "quicken" instanceof. + __ push_ptr(); // for GC + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); + __ get_vm_result_2(RspecifiedKlass); + __ pop_ptr(); // Restore receiver. + __ b(Lresolved); + + // Extract target class from constant pool. + __ bind(Lquicked); + __ sldi(Roffset, Roffset, LogBytesPerWord); + __ addi(Rcpool, Rcpool, sizeof(ConstantPool)); + __ isync(); // Order load of specified Klass wrt. tags. + __ ldx(RspecifiedKlass, Rcpool, Roffset); + + // Do the checkcast. + __ bind(Lresolved); + // Get value klass in RobjKlass. + __ load_klass(RobjKlass, R17_tos); + // Generate a fast subtype check. Branch to cast_ok if no failure. Return 0 if failure. + __ gen_subtype_check(RobjKlass, RspecifiedKlass, /*3 temp regs*/ Roffset, Rcpool, Rtags, /*target if subtype*/ Ldone); + + // Not a subtype; so must throw exception + // Target class oop is in register R6_ARG4 == RspecifiedKlass by convention. + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ClassCastException_entry); + __ mtctr(R11_scratch1); + __ bctr(); + + // Profile the null case. + __ align(32, 12); + __ bind(Lis_null); + __ profile_null_seen(R11_scratch1, Rtags); // Rtags used as scratch. + + __ align(32, 12); + __ bind(Ldone); +} + +// Output: +// - tos == 0: Obj was null or not an instance of class. +// - tos == 1: Obj was an instance of class. +void TemplateTable::instanceof() { + transition(atos, itos); + + Label Ldone, Lis_null, Lquicked, Lresolved; + Register Roffset = R5_ARG3, + RobjKlass = R4_ARG2, + RspecifiedKlass = R6_ARG4, // Generate_ClassCastException_verbose_handler will expect the value in this register. + Rcpool = R11_scratch1, + Rtags = R12_scratch2; + + // Null does not pass. + __ cmpdi(CCR0, R17_tos, 0); + __ beq(CCR0, Lis_null); + + // Get constant pool tag to find out if the bytecode has already been "quickened". + __ get_cpool_and_tags(Rcpool, Rtags); + + __ get_2_byte_integer_at_bcp(1, Roffset, InterpreterMacroAssembler::Unsigned); + + __ addi(Rtags, Rtags, Array::base_offset_in_bytes()); + __ lbzx(Rtags, Rtags, Roffset); + + __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class); + __ beq(CCR0, Lquicked); + + // Call into the VM to "quicken" instanceof. + __ push_ptr(); // for GC + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); + __ get_vm_result_2(RspecifiedKlass); + __ pop_ptr(); // Restore receiver. + __ b(Lresolved); + + // Extract target class from constant pool. + __ bind(Lquicked); + __ sldi(Roffset, Roffset, LogBytesPerWord); + __ addi(Rcpool, Rcpool, sizeof(ConstantPool)); + __ isync(); // Order load of specified Klass wrt. tags. + __ ldx(RspecifiedKlass, Rcpool, Roffset); + + // Do the checkcast. + __ bind(Lresolved); + // Get value klass in RobjKlass. + __ load_klass(RobjKlass, R17_tos); + // Generate a fast subtype check. Branch to cast_ok if no failure. Return 0 if failure. + __ li(R17_tos, 1); + __ gen_subtype_check(RobjKlass, RspecifiedKlass, /*3 temp regs*/ Roffset, Rcpool, Rtags, /*target if subtype*/ Ldone); + __ li(R17_tos, 0); + + if (ProfileInterpreter) { + __ b(Ldone); + } + + // Profile the null case. + __ align(32, 12); + __ bind(Lis_null); + __ profile_null_seen(Rcpool, Rtags); // Rcpool and Rtags used as scratch. + + __ align(32, 12); + __ bind(Ldone); +} + +// ============================================================================= +// Breakpoints + +void TemplateTable::_breakpoint() { + transition(vtos, vtos); + + // Get the unpatched byte code. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::get_original_bytecode_at), R19_method, R14_bcp); + __ mr(R31, R3_RET); + + // Post the breakpoint event. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), R19_method, R14_bcp); + + // Complete the execution of original bytecode. + __ dispatch_Lbyte_code(vtos, R31, Interpreter::normal_table(vtos)); +} + +// ============================================================================= +// Exceptions + +void TemplateTable::athrow() { + transition(atos, vtos); + + // Exception oop is in tos + __ verify_oop(R17_tos); + + __ null_check_throw(R17_tos, -1, R11_scratch1); + + // Throw exception interpreter entry expects exception oop to be in R3. + __ mr(R3_RET, R17_tos); + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::throw_exception_entry()); + __ mtctr(R11_scratch1); + __ bctr(); +} + +// ============================================================================= +// Synchronization +// Searches the basic object lock list on the stack for a free slot +// and uses it to lock the obect in tos. +// +// Recursive locking is enabled by exiting the search if the same +// object is already found in the list. Thus, a new basic lock obj lock +// is allocated "higher up" in the stack and thus is found first +// at next monitor exit. +void TemplateTable::monitorenter() { + transition(atos, vtos); + + __ verify_oop(R17_tos); + + Register Rcurrent_monitor = R11_scratch1, + Rcurrent_obj = R12_scratch2, + Robj_to_lock = R17_tos, + Rscratch1 = R3_ARG1, + Rscratch2 = R4_ARG2, + Rscratch3 = R5_ARG3, + Rcurrent_obj_addr = R6_ARG4; + + // ------------------------------------------------------------------------------ + // Null pointer exception. + __ null_check_throw(Robj_to_lock, -1, R11_scratch1); + + // Try to acquire a lock on the object. + // Repeat until succeeded (i.e., until monitorenter returns true). + + // ------------------------------------------------------------------------------ + // Find a free slot in the monitor block. + Label Lfound, Lexit, Lallocate_new; + ConditionRegister found_free_slot = CCR0, + found_same_obj = CCR1, + reached_limit = CCR6; + { + Label Lloop, Lentry; + Register Rlimit = Rcurrent_monitor; + + // Set up search loop - start with topmost monitor. + __ add(Rcurrent_obj_addr, BasicObjectLock::obj_offset_in_bytes(), R26_monitor); + + __ ld(Rlimit, 0, R1_SP); + __ addi(Rlimit, Rlimit, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes() - BasicObjectLock::obj_offset_in_bytes())); // Monitor base + + // Check if any slot is present => short cut to allocation if not. + __ cmpld(reached_limit, Rcurrent_obj_addr, Rlimit); + __ bgt(reached_limit, Lallocate_new); + + // Pre-load topmost slot. + __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); + // The search loop. + __ bind(Lloop); + // Found free slot? + __ cmpdi(found_free_slot, Rcurrent_obj, 0); + // Is this entry for same obj? If so, stop the search and take the found + // free slot or allocate a new one to enable recursive locking. + __ cmpd(found_same_obj, Rcurrent_obj, Robj_to_lock); + __ cmpld(reached_limit, Rcurrent_obj_addr, Rlimit); + __ beq(found_free_slot, Lexit); + __ beq(found_same_obj, Lallocate_new); + __ bgt(reached_limit, Lallocate_new); + // Check if last allocated BasicLockObj reached. + __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); + // Next iteration if unchecked BasicObjectLocks exist on the stack. + __ b(Lloop); + } + + // ------------------------------------------------------------------------------ + // Check if we found a free slot. + __ bind(Lexit); + + __ addi(Rcurrent_monitor, Rcurrent_obj_addr, -(frame::interpreter_frame_monitor_size() * wordSize) - BasicObjectLock::obj_offset_in_bytes()); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, - frame::interpreter_frame_monitor_size() * wordSize); + __ b(Lfound); + + // We didn't find a free BasicObjLock => allocate one. + __ align(32, 12); + __ bind(Lallocate_new); + __ add_monitor_to_stack(false, Rscratch1, Rscratch2); + __ mr(Rcurrent_monitor, R26_monitor); + __ addi(Rcurrent_obj_addr, R26_monitor, BasicObjectLock::obj_offset_in_bytes()); + + // ------------------------------------------------------------------------------ + // We now have a slot to lock. + __ bind(Lfound); + + // Increment bcp to point to the next bytecode, so exception handling for async. exceptions work correctly. + // The object has already been poped from the stack, so the expression stack looks correct. + __ addi(R14_bcp, R14_bcp, 1); + + __ std(Robj_to_lock, 0, Rcurrent_obj_addr); + __ lock_object(Rcurrent_monitor, Robj_to_lock); + + // Check if there's enough space on the stack for the monitors after locking. + Label Lskip_stack_check; + // Optimization: If the monitors stack section is less then a std page size (4K) don't run + // the stack check. There should be enough shadow pages to fit that in. + __ ld(Rscratch3, 0, R1_SP); + __ sub(Rscratch3, Rscratch3, R26_monitor); + __ cmpdi(CCR0, Rscratch3, 4*K); + __ blt(CCR0, Lskip_stack_check); + + DEBUG_ONLY(__ untested("stack overflow check during monitor enter");) + __ li(Rscratch1, 0); + __ generate_stack_overflow_check_with_compare_and_throw(Rscratch1, Rscratch2); + + __ align(32, 12); + __ bind(Lskip_stack_check); + + // The bcp has already been incremented. Just need to dispatch to next instruction. + __ dispatch_next(vtos); +} + +void TemplateTable::monitorexit() { + transition(atos, vtos); + __ verify_oop(R17_tos); + + Register Rcurrent_monitor = R11_scratch1, + Rcurrent_obj = R12_scratch2, + Robj_to_lock = R17_tos, + Rcurrent_obj_addr = R3_ARG1, + Rlimit = R4_ARG2; + Label Lfound, Lillegal_monitor_state; + + // Check corner case: unbalanced monitorEnter / Exit. + __ ld(Rlimit, 0, R1_SP); + __ addi(Rlimit, Rlimit, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes())); // Monitor base + + // Null pointer check. + __ null_check_throw(Robj_to_lock, -1, R11_scratch1); + + __ cmpld(CCR0, R26_monitor, Rlimit); + __ bgt(CCR0, Lillegal_monitor_state); + + // Find the corresponding slot in the monitors stack section. + { + Label Lloop; + + // Start with topmost monitor. + __ addi(Rcurrent_obj_addr, R26_monitor, BasicObjectLock::obj_offset_in_bytes()); + __ addi(Rlimit, Rlimit, BasicObjectLock::obj_offset_in_bytes()); + __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); + + __ bind(Lloop); + // Is this entry for same obj? + __ cmpd(CCR0, Rcurrent_obj, Robj_to_lock); + __ beq(CCR0, Lfound); + + // Check if last allocated BasicLockObj reached. + + __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + __ cmpld(CCR0, Rcurrent_obj_addr, Rlimit); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); + + // Next iteration if unchecked BasicObjectLocks exist on the stack. + __ ble(CCR0, Lloop); + } + + // Fell through without finding the basic obj lock => throw up! + __ bind(Lillegal_monitor_state); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); + __ should_not_reach_here(); + + __ align(32, 12); + __ bind(Lfound); + __ addi(Rcurrent_monitor, Rcurrent_obj_addr, + -(frame::interpreter_frame_monitor_size() * wordSize) - BasicObjectLock::obj_offset_in_bytes()); + __ unlock_object(Rcurrent_monitor); +} + +// ============================================================================ +// Wide bytecodes + +// Wide instructions. Simply redirects to the wide entry point for that instruction. +void TemplateTable::wide() { + transition(vtos, vtos); + + const Register Rtable = R11_scratch1, + Rindex = R12_scratch2, + Rtmp = R0; + + __ lbz(Rindex, 1, R14_bcp); + + __ load_dispatch_table(Rtable, Interpreter::_wentry_point); + + __ slwi(Rindex, Rindex, LogBytesPerWord); + __ ldx(Rtmp, Rtable, Rindex); + __ mtctr(Rtmp); + __ bctr(); + // Note: the bcp increment step is part of the individual wide bytecode implementations. +} +#endif // !CC_INTERP diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.hpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.hpp new file mode 100644 index 00000000000..1dfa8841c64 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 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. + * + */ + +#ifndef CPU_PPC_VM_TEMPLATETABLE_PPC_64_HPP +#define CPU_PPC_VM_TEMPLATETABLE_PPC_64_HPP + + static void prepare_invoke(int byte_no, Register Rmethod, Register Rret_addr, Register Rindex, Register Rrecv, Register Rflags, Register Rscratch); + static void invokevfinal_helper(Register Rmethod, Register Rflags, Register Rscratch1, Register Rscratch2); + static void generate_vtable_call(Register Rrecv_klass, Register Rindex, Register Rret, Register Rtemp); + static void invokeinterface_object_method(Register Rrecv_klass, Register Rret, Register Rflags, Register Rindex, Register Rtemp, Register Rtemp2); + + // Branch_conditional which takes TemplateTable::Condition. + static void branch_conditional(ConditionRegister crx, TemplateTable::Condition cc, Label& L, bool invert = false); + static void if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool cmp0); + +#endif // CPU_PPC_VM_TEMPLATETABLE_PPC_64_HPP diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index a732c7bfc80..567a5d0d3f6 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -24,7 +24,8 @@ */ #include "precompiled.hpp" -#include "assembler_ppc.inline.hpp" +#include "asm/assembler.inline.hpp" +#include "asm/macroAssembler.inline.hpp" #include "compiler/disassembler.hpp" #include "memory/resourceArea.hpp" #include "runtime/java.hpp" @@ -168,7 +169,7 @@ void VM_Version::determine_section_size() { uint32_t *code = (uint32_t *)a->pc(); // Emit code. - void (*test1)() = (void(*)())(void *)a->emit_fd(); + void (*test1)() = (void(*)())(void *)a->function_entry(); Label l1; @@ -242,7 +243,7 @@ void VM_Version::determine_section_size() { a->blr(); // Emit code. - void (*test2)() = (void(*)())(void *)a->emit_fd(); + void (*test2)() = (void(*)())(void *)a->function_entry(); // uint32_t *code = (uint32_t *)a->pc(); Label l2; @@ -383,8 +384,12 @@ void VM_Version::determine_section_size() { #endif // COMPILER2 void VM_Version::determine_features() { +#if defined(ABI_ELFv2) + const int code_size = (num_features+1+2*7)*BytesPerInstWord; // TODO(asmundak): calculation is incorrect. +#else // 7 InstWords for each call (function descriptor + blr instruction). const int code_size = (num_features+1+2*7)*BytesPerInstWord; +#endif int features = 0; // create test area @@ -398,7 +403,7 @@ void VM_Version::determine_features() { MacroAssembler* a = new MacroAssembler(&cb); // Emit code. - void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->emit_fd(); + void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->function_entry(); uint32_t *code = (uint32_t *)a->pc(); // Don't use R0 in ldarx. // Keep R3_ARG1 unmodified, it contains &field (see below). @@ -415,7 +420,7 @@ void VM_Version::determine_features() { a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. - void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->emit_fd(); + void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->function_entry(); a->dcbz(R3_ARG1); // R3_ARG1 = addr a->blr(); diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp index 371b6aa7f71..1a53471e596 100644 --- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp @@ -413,16 +413,15 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile // Update standard invocation counters __ increment_invocation_counter(Rcounters, O0, G4_scratch); if (ProfileInterpreter) { - Address interpreter_invocation_counter(Rcounters, 0, + Address interpreter_invocation_counter(Rcounters, in_bytes(MethodCounters::interpreter_invocation_counter_offset())); __ ld(interpreter_invocation_counter, G4_scratch); __ inc(G4_scratch); __ st(G4_scratch, interpreter_invocation_counter); } - Address invocation_limit(G3_scratch, (address)&InvocationCounter::InterpreterInvocationLimit); - __ sethi(invocation_limit); - __ ld(invocation_limit, G3_scratch); + AddressLiteral invocation_limit((address)&InvocationCounter::InterpreterInvocationLimit); + __ load_contents(invocation_limit, G3_scratch); __ cmp(O0, G3_scratch); __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); __ delayed()->nop(); @@ -439,7 +438,7 @@ address InterpreterGenerator::generate_empty_entry(void) { // do nothing for empty methods (do not even increment invocation counter) if ( UseFastEmptyMethods) { // If we need a safepoint check, generate full interpreter entry. - Address sync_state(G3_scratch, SafepointSynchronize::address_of_state()); + AddressLiteral sync_state(SafepointSynchronize::address_of_state()); __ load_contents(sync_state, G3_scratch); __ cmp(G3_scratch, SafepointSynchronize::_not_synchronized); __ br(Assembler::notEqual, false, Assembler::pn, frame_manager_entry); @@ -471,7 +470,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { if ( UseFastAccessorMethods) { // Check if we need to reach a safepoint and generate full interpreter // frame if so. - Address sync_state(G3_scratch, SafepointSynchronize::address_of_state()); + AddressLiteral sync_state(SafepointSynchronize::address_of_state()); __ load_contents(sync_state, G3_scratch); __ cmp(G3_scratch, SafepointSynchronize::_not_synchronized); __ br(Assembler::notEqual, false, Assembler::pn, slow_path); @@ -486,8 +485,8 @@ address InterpreterGenerator::generate_accessor_entry(void) { // read first instruction word and extract bytecode @ 1 and index @ 2 // get first 4 bytes of the bytecodes (big endian!) - __ ld_ptr(Address(G5_method, 0, in_bytes(Method::const_offset())), G1_scratch); - __ ld(Address(G1_scratch, 0, in_bytes(ConstMethod::codes_offset())), G1_scratch); + __ ld_ptr(Address(G5_method, in_bytes(Method::const_offset())), G1_scratch); + __ ld(Address(G1_scratch, in_bytes(ConstMethod::codes_offset())), G1_scratch); // move index @ 2 far left then to the right most two bytes. __ sll(G1_scratch, 2*BitsPerByte, G1_scratch); @@ -590,15 +589,15 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { const Register Gtmp1 = G3_scratch ; const Register Gtmp2 = G1_scratch; const Register RconstMethod = Gtmp1; - const Address constMethod(G5_method, 0, in_bytes(Method::const_offset())); - const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset())); + const Address constMethod(G5_method, in_bytes(Method::const_offset())); + const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset())); bool inc_counter = UseCompiler || CountCompiledCalls; // make sure registers are different! assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2); - const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset())); + const Address access_flags (G5_method, in_bytes(Method::access_flags_offset())); Label Lentry; __ bind(Lentry); @@ -643,7 +642,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // At this point Lstate points to new interpreter state // - const Address do_not_unlock_if_synchronized(G2_thread, 0, + const Address do_not_unlock_if_synchronized(G2_thread, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); // Since at this point in the method invocation the exception handler // would try to exit the monitor of synchronized methods which hasn't @@ -717,17 +716,17 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { { Label L; __ ld_ptr(STATE(_method), G5_method); - __ ld_ptr(Address(G5_method, 0, in_bytes(Method::signature_handler_offset())), G3_scratch); + __ ld_ptr(Address(G5_method, in_bytes(Method::signature_handler_offset())), G3_scratch); __ tst(G3_scratch); __ brx(Assembler::notZero, false, Assembler::pt, L); __ delayed()->nop(); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), G5_method, false); __ ld_ptr(STATE(_method), G5_method); - Address exception_addr(G2_thread, 0, in_bytes(Thread::pending_exception_offset())); + Address exception_addr(G2_thread, in_bytes(Thread::pending_exception_offset())); __ ld_ptr(exception_addr, G3_scratch); __ br_notnull_short(G3_scratch, Assembler::pn, pending_exception_present); - __ ld_ptr(Address(G5_method, 0, in_bytes(Method::signature_handler_offset())), G3_scratch); + __ ld_ptr(Address(G5_method, in_bytes(Method::signature_handler_offset())), G3_scratch); __ bind(L); } @@ -771,13 +770,13 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { __ br( Assembler::zero, false, Assembler::pt, not_static); __ delayed()-> // get native function entry point(O0 is a good temp until the very end) - ld_ptr(Address(G5_method, 0, in_bytes(Method::native_function_offset())), O0); + ld_ptr(Address(G5_method, in_bytes(Method::native_function_offset())), O0); // for static methods insert the mirror argument const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - __ ld_ptr(Address(G5_method, 0, in_bytes(Method:: const_offset())), O1); - __ ld_ptr(Address(O1, 0, in_bytes(ConstMethod::constants_offset())), O1); - __ ld_ptr(Address(O1, 0, ConstantPool::pool_holder_offset_in_bytes()), O1); + __ ld_ptr(Address(G5_method, in_bytes(Method:: const_offset())), O1); + __ ld_ptr(Address(O1, in_bytes(ConstMethod::constants_offset())), O1); + __ ld_ptr(Address(O1, ConstantPool::pool_holder_offset_in_bytes()), O1); __ ld_ptr(O1, mirror_offset, O1); // where the mirror handle body is allocated: #ifdef ASSERT @@ -831,18 +830,17 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // flush the windows now. We don't care about the current (protection) frame // only the outer frames - __ flush_windows(); + __ flushw(); // mark windows as flushed Address flags(G2_thread, - 0, in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::flags_offset())); __ set(JavaFrameAnchor::flushed, G3_scratch); __ st(G3_scratch, flags); // Transition from _thread_in_Java to _thread_in_native. We are already safepoint ready. - Address thread_state(G2_thread, 0, in_bytes(JavaThread::thread_state_offset())); + Address thread_state(G2_thread, in_bytes(JavaThread::thread_state_offset())); #ifdef ASSERT { Label L; __ ld(thread_state, G3_scratch); @@ -867,7 +865,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // Block, if necessary, before resuming in _thread_in_Java state. // In order for GC to work, don't clear the last_Java_sp until after blocking. { Label no_block; - Address sync_state(G3_scratch, SafepointSynchronize::address_of_state()); + AddressLiteral sync_state(SafepointSynchronize::address_of_state()); // Switch thread to "native transition" state before reading the synchronization state. // This additional state is necessary because reading and testing the synchronization @@ -890,7 +888,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { Label L; - Address suspend_state(G2_thread, 0, in_bytes(JavaThread::suspend_flags_offset())); + Address suspend_state(G2_thread, in_bytes(JavaThread::suspend_flags_offset())); __ br(Assembler::notEqual, false, Assembler::pn, L); __ delayed()-> ld(suspend_state, G3_scratch); @@ -965,7 +963,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // handle exceptions (exception handling will handle unlocking!) { Label L; - Address exception_addr (G2_thread, 0, in_bytes(Thread::pending_exception_offset())); + Address exception_addr (G2_thread, in_bytes(Thread::pending_exception_offset())); __ ld_ptr(exception_addr, Gtemp); __ tst(Gtemp); @@ -1055,8 +1053,8 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register assert_different_registers(state, prev_state); assert_different_registers(prev_state, G3_scratch); const Register Gtmp = G3_scratch; - const Address constMethod (G5_method, 0, in_bytes(Method::const_offset())); - const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset())); + const Address constMethod (G5_method, in_bytes(Method::const_offset())); + const Address access_flags (G5_method, in_bytes(Method::access_flags_offset())); // slop factor is two extra slots on the expression stack so that // we always have room to store a result when returning from a call without parameters @@ -1075,7 +1073,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register if (native) { const Register RconstMethod = Gtmp; - const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset())); + const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset())); __ ld_ptr(constMethod, RconstMethod); __ lduh( size_of_parameters, Gtmp ); __ calc_mem_param_words(Gtmp, Gtmp); // space for native call parameters passed on the stack in words @@ -1246,8 +1244,8 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register if (init_value != noreg) { Label clear_loop; const Register RconstMethod = O1; - const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset())); - const Address size_of_locals (RconstMethod, 0, in_bytes(ConstMethod::size_of_locals_offset())); + const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset())); + const Address size_of_locals (RconstMethod, in_bytes(ConstMethod::size_of_locals_offset())); // NOTE: If you change the frame layout, this code will need to // be updated! @@ -1496,11 +1494,11 @@ void CppInterpreterGenerator::adjust_callers_stack(Register args) { // // assert_different_registers(state, prev_state); const Register Gtmp = G3_scratch; - const RconstMethod = G3_scratch; + const Register RconstMethod = G3_scratch; const Register tmp = O2; - const Address constMethod(G5_method, 0, in_bytes(Method::const_offset())); - const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset())); - const Address size_of_locals (RconstMethod, 0, in_bytes(ConstMethod::size_of_locals_offset())); + const Address constMethod(G5_method, in_bytes(Method::const_offset())); + const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset())); + const Address size_of_locals (RconstMethod, in_bytes(ConstMethod::size_of_locals_offset())); __ ld_ptr(constMethod, RconstMethod); __ lduh(size_of_parameters, tmp); @@ -1555,8 +1553,8 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { const Register Gtmp1 = G3_scratch; // const Register Lmirror = L1; // native mirror (native calls only) - const Address constMethod (G5_method, 0, in_bytes(Method::const_offset())); - const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset())); + const Address constMethod (G5_method, in_bytes(Method::const_offset())); + const Address access_flags (G5_method, in_bytes(Method::access_flags_offset())); address entry_point = __ pc(); __ mov(G0, prevState); // no current activation @@ -1709,7 +1707,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { // We want exception in the thread no matter what we ultimately decide about frame type. - Address exception_addr (G2_thread, 0, in_bytes(Thread::pending_exception_offset())); + Address exception_addr (G2_thread, in_bytes(Thread::pending_exception_offset())); __ verify_thread(); __ st_ptr(O0, exception_addr); diff --git a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp index 6ce05bdfce1..29b37f006a5 100644 --- a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp @@ -827,6 +827,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) { } if (is_interpreted_frame()) { +#ifndef CC_INTERP DESCRIBE_FP_OFFSET(interpreter_frame_d_scratch_fp); DESCRIBE_FP_OFFSET(interpreter_frame_l_scratch_fp); DESCRIBE_FP_OFFSET(interpreter_frame_padding); @@ -837,6 +838,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) { if ((esp >= sp()) && (esp < fp())) { values.describe(-1, esp, "*Lesp"); } +#endif } if (!is_compiled_frame()) { diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index c22f20a23d4..9d4d13bf663 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -2497,6 +2497,24 @@ void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Regis void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { if (state == ftos || state == dtos) MacroAssembler::verify_FPU(stack_depth); } + + +// Jump if ((*counter_addr += increment) & mask) satisfies the condition. +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, + int increment, int mask, + Register scratch1, Register scratch2, + Condition cond, Label *where) { + ld(counter_addr, scratch1); + add(scratch1, increment, scratch1); + if (is_simm13(mask)) { + andcc(scratch1, mask, G0); + } else { + set(mask, scratch2); + andcc(scratch1, scratch2, G0); + } + br(cond, false, Assembler::pn, *where); + delayed()->st(scratch1, counter_addr); +} #endif /* CC_INTERP */ // Inline assembly for: @@ -2646,20 +2664,3 @@ void InterpreterMacroAssembler::restore_return_value( TosState state, bool is_na } #endif // CC_INTERP } - -// Jump if ((*counter_addr += increment) & mask) satisfies the condition. -void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, - Register scratch1, Register scratch2, - Condition cond, Label *where) { - ld(counter_addr, scratch1); - add(scratch1, increment, scratch1); - if (is_simm13(mask)) { - andcc(scratch1, mask, G0); - } else { - set(mask, scratch2); - andcc(scratch1, scratch2, G0); - } - br(cond, false, Assembler::pn, *where); - delayed()->st(scratch1, counter_addr); -} diff --git a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp index f5ac37cf6fa..c15c3c0994f 100644 --- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp @@ -23,7 +23,8 @@ */ #include "precompiled.hpp" -#include "asm/macroAssembler.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/codeCache.hpp" #include "memory/resourceArea.hpp" #include "nativeInst_sparc.hpp" #include "oops/oop.inline.hpp" diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 49cc9ed65cf..d305ac18537 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -1089,6 +1089,21 @@ void Assembler::andl(Register dst, Register src) { emit_arith(0x23, 0xC0, dst, src); } +void Assembler::andnl(Register dst, Register src1, Register src2) { + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + int encode = vex_prefix_0F38_and_encode(dst, src1, src2); + emit_int8((unsigned char)0xF2); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::andnl(Register dst, Register src1, Address src2) { + InstructionMark im(this); + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + vex_prefix_0F38(dst, src1, src2); + emit_int8((unsigned char)0xF2); + emit_operand(dst, src2); +} + void Assembler::bsfl(Register dst, Register src) { int encode = prefix_and_encode(dst->encoding(), src->encoding()); emit_int8(0x0F); @@ -1110,6 +1125,51 @@ void Assembler::bswapl(Register reg) { // bswap emit_int8((unsigned char)(0xC8 | encode)); } +void Assembler::blsil(Register dst, Register src) { + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + int encode = vex_prefix_0F38_and_encode(rbx, dst, src); + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::blsil(Register dst, Address src) { + InstructionMark im(this); + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + vex_prefix_0F38(rbx, dst, src); + emit_int8((unsigned char)0xF3); + emit_operand(rbx, src); +} + +void Assembler::blsmskl(Register dst, Register src) { + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + int encode = vex_prefix_0F38_and_encode(rdx, dst, src); + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::blsmskl(Register dst, Address src) { + InstructionMark im(this); + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + vex_prefix_0F38(rdx, dst, src); + emit_int8((unsigned char)0xF3); + emit_operand(rdx, src); +} + +void Assembler::blsrl(Register dst, Register src) { + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + int encode = vex_prefix_0F38_and_encode(rcx, dst, src); + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::blsrl(Register dst, Address src) { + InstructionMark im(this); + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + vex_prefix_0F38(rcx, dst, src); + emit_int8((unsigned char)0xF3); + emit_operand(rcx, src); +} + void Assembler::call(Label& L, relocInfo::relocType rtype) { // suspect disp32 is always good int operand = LP64_ONLY(disp32_operand) NOT_LP64(imm_operand); @@ -2878,6 +2938,24 @@ void Assembler::testl(Register dst, Address src) { emit_operand(dst, src); } +void Assembler::tzcntl(Register dst, Register src) { + assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + emit_int8((unsigned char)0xF3); + int encode = prefix_and_encode(dst->encoding(), src->encoding()); + emit_int8(0x0F); + emit_int8((unsigned char)0xBC); + emit_int8((unsigned char)0xC0 | encode); +} + +void Assembler::tzcntq(Register dst, Register src) { + assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + emit_int8((unsigned char)0xF3); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_int8(0x0F); + emit_int8((unsigned char)0xBC); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::ucomisd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); emit_simd_arith_nonds(0x2E, dst, src, VEX_SIMD_66); @@ -4837,6 +4915,21 @@ void Assembler::andq(Register dst, Register src) { emit_arith(0x23, 0xC0, dst, src); } +void Assembler::andnq(Register dst, Register src1, Register src2) { + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + int encode = vex_prefix_0F38_and_encode_q(dst, src1, src2); + emit_int8((unsigned char)0xF2); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::andnq(Register dst, Register src1, Address src2) { + InstructionMark im(this); + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + vex_prefix_0F38_q(dst, src1, src2); + emit_int8((unsigned char)0xF2); + emit_operand(dst, src2); +} + void Assembler::bsfq(Register dst, Register src) { int encode = prefixq_and_encode(dst->encoding(), src->encoding()); emit_int8(0x0F); @@ -4858,6 +4951,51 @@ void Assembler::bswapq(Register reg) { emit_int8((unsigned char)(0xC8 | encode)); } +void Assembler::blsiq(Register dst, Register src) { + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + int encode = vex_prefix_0F38_and_encode_q(rbx, dst, src); + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::blsiq(Register dst, Address src) { + InstructionMark im(this); + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + vex_prefix_0F38_q(rbx, dst, src); + emit_int8((unsigned char)0xF3); + emit_operand(rbx, src); +} + +void Assembler::blsmskq(Register dst, Register src) { + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + int encode = vex_prefix_0F38_and_encode_q(rdx, dst, src); + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::blsmskq(Register dst, Address src) { + InstructionMark im(this); + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + vex_prefix_0F38_q(rdx, dst, src); + emit_int8((unsigned char)0xF3); + emit_operand(rdx, src); +} + +void Assembler::blsrq(Register dst, Register src) { + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + int encode = vex_prefix_0F38_and_encode_q(rcx, dst, src); + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::blsrq(Register dst, Address src) { + InstructionMark im(this); + assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + vex_prefix_0F38_q(rcx, dst, src); + emit_int8((unsigned char)0xF3); + emit_operand(rcx, src); +} + void Assembler::cdqq() { prefix(REX_W); emit_int8((unsigned char)0x99); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 1ad66bd6a95..95ca231cef4 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -590,10 +590,35 @@ private: vex_prefix(src, nds_enc, dst_enc, pre, VEX_OPCODE_0F, false, vector256); } + void vex_prefix_0F38(Register dst, Register nds, Address src) { + bool vex_w = false; + bool vector256 = false; + vex_prefix(src, nds->encoding(), dst->encoding(), + VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector256); + } + + void vex_prefix_0F38_q(Register dst, Register nds, Address src) { + bool vex_w = true; + bool vector256 = false; + vex_prefix(src, nds->encoding(), dst->encoding(), + VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector256); + } int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, bool vex_w, bool vector256); + int vex_prefix_0F38_and_encode(Register dst, Register nds, Register src) { + bool vex_w = false; + bool vector256 = false; + return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), + VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector256); + } + int vex_prefix_0F38_and_encode_q(Register dst, Register nds, Register src) { + bool vex_w = true; + bool vector256 = false; + return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), + VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector256); + } int vex_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, VexSimdPrefix pre, bool vector256 = false, VexOpcode opc = VEX_OPCODE_0F) { @@ -897,6 +922,27 @@ private: void andq(Register dst, Address src); void andq(Register dst, Register src); + // BMI instructions + void andnl(Register dst, Register src1, Register src2); + void andnl(Register dst, Register src1, Address src2); + void andnq(Register dst, Register src1, Register src2); + void andnq(Register dst, Register src1, Address src2); + + void blsil(Register dst, Register src); + void blsil(Register dst, Address src); + void blsiq(Register dst, Register src); + void blsiq(Register dst, Address src); + + void blsmskl(Register dst, Register src); + void blsmskl(Register dst, Address src); + void blsmskq(Register dst, Register src); + void blsmskq(Register dst, Address src); + + void blsrl(Register dst, Register src); + void blsrl(Register dst, Address src); + void blsrq(Register dst, Register src); + void blsrq(Register dst, Address src); + void bsfl(Register dst, Register src); void bsrl(Register dst, Register src); @@ -1574,6 +1620,9 @@ private: void testq(Register dst, int32_t imm32); void testq(Register dst, Register src); + // BMI - count trailing zeros + void tzcntl(Register dst, Register src); + void tzcntq(Register dst, Register src); // Unordered Compare Scalar Double-Precision Floating-Point Values and set EFLAGS void ucomisd(XMMRegister dst, Address src); diff --git a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp index 4f60b455801..d205f1db79a 100644 --- a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp @@ -250,7 +250,7 @@ inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { return op1 - op2; } -inline jint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { +inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { return ((juint) op1) >> (op2 & 0x1f); } diff --git a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp index e669f5b6638..0ddf854f364 100644 --- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp +++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp @@ -574,7 +574,7 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile MethodCounters::invocation_counter_offset() + InvocationCounter::counter_offset()); const Address backedge_counter (rax, - MethodCounter::backedge_counter_offset() + + MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); @@ -982,16 +982,18 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // to save/restore. address entry_point = __ pc(); - const Address constMethod (rbx, Method::const_offset()); const Address access_flags (rbx, Method::access_flags_offset()); - const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset()); // rsi/r13 == state/locals rdi == prevstate const Register locals = rdi; // get parameter size (always needed) - __ movptr(rcx, constMethod); - __ load_unsigned_short(rcx, size_of_parameters); + { + const Address constMethod (rbx, Method::const_offset()); + const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset()); + __ movptr(rcx, constMethod); + __ load_unsigned_short(rcx, size_of_parameters); + } // rbx: Method* // rcx: size of parameters @@ -1111,14 +1113,16 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { const Register method = rbx; const Register thread = LP64_ONLY(r15_thread) NOT_LP64(rdi); const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp(); // rcx|rscratch1 - const Address constMethod (method, Method::const_offset()); - const Address size_of_parameters(t, ConstMethod::size_of_parameters_offset()); - // allocate space for parameters + // allocate space for parameters __ movptr(method, STATE(_method)); __ verify_method_ptr(method); - __ movptr(t, constMethod); - __ load_unsigned_short(t, size_of_parameters); + { + const Address constMethod (method, Method::const_offset()); + const Address size_of_parameters(t, ConstMethod::size_of_parameters_offset()); + __ movptr(t, constMethod); + __ load_unsigned_short(t, size_of_parameters); + } __ shll(t, 2); #ifdef _LP64 __ subptr(rsp, t); @@ -2221,7 +2225,6 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter: case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break; case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break; case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break; - case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break; case Interpreter::java_lang_math_sin : // fall thru case Interpreter::java_lang_math_cos : // fall thru @@ -2229,7 +2232,10 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter: case Interpreter::java_lang_math_abs : // fall thru case Interpreter::java_lang_math_log : // fall thru case Interpreter::java_lang_math_log10 : // fall thru - case Interpreter::java_lang_math_sqrt : entry_point = ((InterpreterGenerator*)this)->generate_math_entry(kind); break; + case Interpreter::java_lang_math_sqrt : // fall thru + case Interpreter::java_lang_math_pow : // fall thru + case Interpreter::java_lang_math_exp : // fall thru + entry_point = ((InterpreterGenerator*)this)->generate_math_entry(kind); break; case Interpreter::java_lang_ref_reference_get : entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break; default : ShouldNotReachHere(); break; @@ -2451,4 +2457,22 @@ int AbstractInterpreter::layout_activation(Method* method, return frame_size/BytesPerWord; } +bool AbstractInterpreter::can_be_compiled(methodHandle m) { + switch (method_kind(m)) { + case Interpreter::java_lang_math_sin : // fall thru + case Interpreter::java_lang_math_cos : // fall thru + case Interpreter::java_lang_math_tan : // fall thru + case Interpreter::java_lang_math_abs : // fall thru + case Interpreter::java_lang_math_log : // fall thru + case Interpreter::java_lang_math_log10 : // fall thru + case Interpreter::java_lang_math_sqrt : // fall thru + case Interpreter::java_lang_math_pow : // fall thru + case Interpreter::java_lang_math_exp : + return false; + default: + return true; + } +} + + #endif // CC_INTERP (all) diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index 4e83863a9f9..deeb48a44bb 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -687,6 +687,7 @@ intptr_t* frame::interpreter_frame_tos_at(jint offset) const { void frame::describe_pd(FrameValues& values, int frame_no) { if (is_interpreted_frame()) { +#ifndef CC_INTERP DESCRIBE_FP_OFFSET(interpreter_frame_sender_sp); DESCRIBE_FP_OFFSET(interpreter_frame_last_sp); DESCRIBE_FP_OFFSET(interpreter_frame_method); @@ -695,6 +696,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) { DESCRIBE_FP_OFFSET(interpreter_frame_locals); DESCRIBE_FP_OFFSET(interpreter_frame_bcx); DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp); +#endif } } #endif diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index e82c192901b..f29e5d6e322 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -135,5 +135,11 @@ define_pd_global(uintx, TypeProfileLevel, 111); \ product(bool, UseCountLeadingZerosInstruction, false, \ "Use count leading zeros instruction") \ + \ + product(bool, UseCountTrailingZerosInstruction, false, \ + "Use count trailing zeros instruction") \ + \ + product(bool, UseBMI1Instructions, false, \ + "Use BMI instructions") #endif // CPU_X86_VM_GLOBALS_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp index b6f2438db83..92f58b4d61a 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -266,20 +266,6 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, R addptr(cache, tmp); // construct pointer to cache entry } -void InterpreterMacroAssembler::get_method_counters(Register method, - Register mcs, Label& skip) { - Label has_counters; - movptr(mcs, Address(method, Method::method_counters_offset())); - testptr(mcs, mcs); - jcc(Assembler::notZero, has_counters); - call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::build_method_counters), method); - movptr(mcs, Address(method,Method::method_counters_offset())); - testptr(mcs, mcs); - jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory - bind(has_counters); -} - // Load object from cpool->resolved_references(index) void InterpreterMacroAssembler::load_resolved_reference_at_index( Register result, Register index) { @@ -678,6 +664,20 @@ void InterpreterMacroAssembler::remove_activation(TosState state, Register ret_a #endif /* !CC_INTERP */ +void InterpreterMacroAssembler::get_method_counters(Register method, + Register mcs, Label& skip) { + Label has_counters; + movptr(mcs, Address(method, Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::notZero, has_counters); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::build_method_counters), method); + movptr(mcs, Address(method,Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory + bind(has_counters); +} + // Lock object // @@ -1359,6 +1359,19 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { if (state == ftos || state == dtos) MacroAssembler::verify_FPU(stack_depth); } +// Jump if ((*counter_addr += increment) & mask) satisfies the condition. +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, + int increment, int mask, + Register scratch, bool preloaded, + Condition cond, Label* where) { + if (!preloaded) { + movl(scratch, counter_addr); + } + incrementl(scratch, increment); + movl(counter_addr, scratch); + andl(scratch, mask); + jcc(cond, *where); +} #endif /* CC_INTERP */ @@ -1430,17 +1443,3 @@ void InterpreterMacroAssembler::notify_method_exit( NOT_CC_INTERP(pop(state)); } } - -// Jump if ((*counter_addr += increment) & mask) satisfies the condition. -void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, - Register scratch, bool preloaded, - Condition cond, Label* where) { - if (!preloaded) { - movl(scratch, counter_addr); - } - incrementl(scratch, increment); - movl(counter_addr, scratch); - andl(scratch, mask); - jcc(cond, *where); -} diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp index 19ff288bfee..88f01fc5852 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp @@ -77,7 +77,6 @@ void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); - void get_method_counters(Register method, Register mcs, Label& skip); // load cpool->resolved_references(index); void load_resolved_reference_at_index(Register result, Register index); @@ -156,6 +155,7 @@ bool install_monitor_exception = true, bool notify_jvmdi = true); #endif /* !CC_INTERP */ + void get_method_counters(Register method, Register mcs, Label& skip); // Debugging void verify_oop(Register reg, TosState state = atos); // only if +VerifyOops && state == atos diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp index 520c872a604..356106e946f 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -271,20 +271,6 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, addptr(cache, tmp); // construct pointer to cache entry } -void InterpreterMacroAssembler::get_method_counters(Register method, - Register mcs, Label& skip) { - Label has_counters; - movptr(mcs, Address(method, Method::method_counters_offset())); - testptr(mcs, mcs); - jcc(Assembler::notZero, has_counters); - call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::build_method_counters), method); - movptr(mcs, Address(method,Method::method_counters_offset())); - testptr(mcs, mcs); - jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory - bind(has_counters); -} - // Load object from cpool->resolved_references(index) void InterpreterMacroAssembler::load_resolved_reference_at_index( Register result, Register index) { @@ -676,6 +662,21 @@ void InterpreterMacroAssembler::remove_activation( #endif // C_INTERP +void InterpreterMacroAssembler::get_method_counters(Register method, + Register mcs, Label& skip) { + Label has_counters; + movptr(mcs, Address(method, Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::notZero, has_counters); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::build_method_counters), method); + movptr(mcs, Address(method,Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory + bind(has_counters); +} + + // Lock object // // Args: @@ -1423,6 +1424,20 @@ void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { } + +// Jump if ((*counter_addr += increment) & mask) satisfies the condition. +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, + int increment, int mask, + Register scratch, bool preloaded, + Condition cond, Label* where) { + if (!preloaded) { + movl(scratch, counter_addr); + } + incrementl(scratch, increment); + movl(counter_addr, scratch); + andl(scratch, mask); + jcc(cond, *where); +} #endif // !CC_INTERP @@ -1491,16 +1506,3 @@ void InterpreterMacroAssembler::notify_method_exit( } } -// Jump if ((*counter_addr += increment) & mask) satisfies the condition. -void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, - Register scratch, bool preloaded, - Condition cond, Label* where) { - if (!preloaded) { - movl(scratch, counter_addr); - } - incrementl(scratch, increment); - movl(counter_addr, scratch); - andl(scratch, mask); - jcc(cond, *where); -} diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp index 36bd779ef9b..9186009fa9a 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp @@ -99,7 +99,6 @@ void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); - void get_method_counters(Register method, Register mcs, Label& skip); // load cpool->resolved_references(index); void load_resolved_reference_at_index(Register result, Register index); @@ -172,6 +171,7 @@ bool install_monitor_exception = true, bool notify_jvmdi = true); #endif // CC_INTERP + void get_method_counters(Register method, Register mcs, Label& skip); // Object locking void lock_object (Register lock_reg); diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp index 865801e3de7..3c66bf4fb45 100644 --- a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp @@ -229,10 +229,12 @@ address InterpreterGenerator::generate_abstract_entry(void) { // abstract method entry +#ifndef CC_INTERP // pop return address, reset last_sp to NULL __ empty_expression_stack(); __ restore_bcp(); // rsi must be correct for exception handler (was destroyed) __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) +#endif // throw exception __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp index bc5229b997d..02ee74506bb 100644 --- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp @@ -310,10 +310,12 @@ address InterpreterGenerator::generate_abstract_entry(void) { // abstract method entry +#ifndef CC_INTERP // pop return address, reset last_sp to NULL __ empty_expression_stack(); __ restore_bcp(); // rsi must be correct for exception handler (was destroyed) __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) +#endif // throw exception __ call_VM(noreg, CAST_FROM_FN_PTR(address, diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index de38b4a3a53..b949e4e2998 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -429,7 +429,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", + 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", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, (supports_cmov() ? ", cmov" : ""), @@ -455,7 +455,9 @@ void VM_Version::get_processor_features() { (supports_ht() ? ", ht": ""), (supports_tsc() ? ", tsc": ""), (supports_tscinv_bit() ? ", tscinvbit": ""), - (supports_tscinv() ? ", tscinv": "")); + (supports_tscinv() ? ", tscinv": ""), + (supports_bmi1() ? ", bmi1" : ""), + (supports_bmi2() ? ", bmi2" : "")); _features_str = strdup(buf); // UseSSE is set to the smaller of what hardware supports and what @@ -600,13 +602,6 @@ void VM_Version::get_processor_features() { } } - // Use count leading zeros count instruction if available. - if (supports_lzcnt()) { - if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) { - UseCountLeadingZerosInstruction = true; - } - } - // some defaults for AMD family 15h if ( cpu_family() == 0x15 ) { // On family 15h processors default is no sw prefetch @@ -692,6 +687,35 @@ void VM_Version::get_processor_features() { } #endif // COMPILER2 + // Use count leading zeros count instruction if available. + if (supports_lzcnt()) { + if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) { + UseCountLeadingZerosInstruction = true; + } + } else if (UseCountLeadingZerosInstruction) { + warning("lzcnt instruction is not available on this CPU"); + FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false); + } + + if (supports_bmi1()) { + if (FLAG_IS_DEFAULT(UseBMI1Instructions)) { + UseBMI1Instructions = true; + } + } else if (UseBMI1Instructions) { + warning("BMI1 instructions are not available on this CPU"); + FLAG_SET_DEFAULT(UseBMI1Instructions, false); + } + + // Use count trailing zeros instruction if available + if (supports_bmi1()) { + if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) { + UseCountTrailingZerosInstruction = UseBMI1Instructions; + } + } else if (UseCountTrailingZerosInstruction) { + warning("tzcnt instruction is not available on this CPU"); + FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false); + } + // Use population count instruction if available. if (supports_popcnt()) { if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index 86e9b662d52..07d64451870 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -141,7 +141,8 @@ public: struct { uint32_t LahfSahf : 1, CmpLegacy : 1, - : 4, + : 3, + lzcnt_intel : 1, lzcnt : 1, sse4a : 1, misalignsse : 1, @@ -251,7 +252,9 @@ protected: CPU_AVX2 = (1 << 18), CPU_AES = (1 << 19), CPU_ERMS = (1 << 20), // enhanced 'rep movsb/stosb' instructions - CPU_CLMUL = (1 << 21) // carryless multiply for CRC + CPU_CLMUL = (1 << 21), // carryless multiply for CRC + CPU_BMI1 = (1 << 22), + CPU_BMI2 = (1 << 23) } cpuFeatureFlags; enum { @@ -423,6 +426,8 @@ protected: if (_cpuid_info.sef_cpuid7_ebx.bits.avx2 != 0) result |= CPU_AVX2; } + if(_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0) + result |= CPU_BMI1; if (_cpuid_info.std_cpuid1_edx.bits.tsc != 0) result |= CPU_TSC; if (_cpuid_info.ext_cpuid7_edx.bits.tsc_invariance != 0) @@ -444,6 +449,13 @@ protected: if (_cpuid_info.ext_cpuid1_ecx.bits.sse4a != 0) result |= CPU_SSE4A; } + // Intel features. + if(is_intel()) { + if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0) + result |= CPU_BMI2; + if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) + result |= CPU_LZCNT; + } return result; } @@ -560,7 +572,8 @@ 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_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; } + static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; } // Intel features static bool is_intel_family_core() { return is_intel() && extended_cpu_family() == CPU_FAMILY_INTEL_CORE; } diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 8948682a99f..c4820db3b07 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -5163,6 +5163,19 @@ instruct countLeadingZerosL_bsr(rRegI dst, eRegL src, eFlagsReg cr) %{ %} instruct countTrailingZerosI(rRegI dst, rRegI src, eFlagsReg cr) %{ + predicate(UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosI src)); + effect(KILL cr); + + format %{ "TZCNT $dst, $src\t# count trailing zeros (int)" %} + ins_encode %{ + __ tzcntl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosI_bsf(rRegI dst, rRegI src, eFlagsReg cr) %{ + predicate(!UseCountTrailingZerosInstruction); match(Set dst (CountTrailingZerosI src)); effect(KILL cr); @@ -5182,6 +5195,30 @@ instruct countTrailingZerosI(rRegI dst, rRegI src, eFlagsReg cr) %{ %} instruct countTrailingZerosL(rRegI dst, eRegL src, eFlagsReg cr) %{ + predicate(UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosL src)); + effect(TEMP dst, KILL cr); + + format %{ "TZCNT $dst, $src.lo\t# count trailing zeros (long) \n\t" + "JNC done\n\t" + "TZCNT $dst, $src.hi\n\t" + "ADD $dst, 32\n" + "done:" %} + ins_encode %{ + Register Rdst = $dst$$Register; + Register Rsrc = $src$$Register; + Label done; + __ tzcntl(Rdst, Rsrc); + __ jccb(Assembler::carryClear, done); + __ tzcntl(Rdst, HIGH_FROM_LOW(Rsrc)); + __ addl(Rdst, BitsPerInt); + __ bind(done); + %} + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosL_bsf(rRegI dst, eRegL src, eFlagsReg cr) %{ + predicate(!UseCountTrailingZerosInstruction); match(Set dst (CountTrailingZerosL src)); effect(TEMP dst, KILL cr); @@ -8027,6 +8064,123 @@ instruct andI_mem_imm(memory dst, immI src, eFlagsReg cr) %{ ins_pipe( ialu_mem_imm ); %} +// BMI1 instructions +instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1, eFlagsReg cr) %{ + match(Set dst (AndI (XorI src1 minus_1) src2)); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "ANDNL $dst, $src1, $src2" %} + + ins_encode %{ + __ andnl($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1, eFlagsReg cr) %{ + match(Set dst (AndI (XorI src1 minus_1) (LoadI src2) )); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "ANDNL $dst, $src1, $src2" %} + + ins_encode %{ + __ andnl($dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI0 imm_zero, eFlagsReg cr) %{ + match(Set dst (AndI (SubI imm_zero src) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "BLSIL $dst, $src" %} + + ins_encode %{ + __ blsil($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct blsiI_rReg_mem(rRegI dst, memory src, immI0 imm_zero, eFlagsReg cr) %{ + match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) )); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "BLSIL $dst, $src" %} + + ins_encode %{ + __ blsil($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, eFlagsReg cr) +%{ + match(Set dst (XorI (AddI src minus_1) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "BLSMSKL $dst, $src" %} + + ins_encode %{ + __ blsmskl($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, eFlagsReg cr) +%{ + match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) )); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "BLSMSKL $dst, $src" %} + + ins_encode %{ + __ blsmskl($dst$$Register, $src$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, eFlagsReg cr) +%{ + match(Set dst (AndI (AddI src minus_1) src) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "BLSRL $dst, $src" %} + + ins_encode %{ + __ blsrl($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, eFlagsReg cr) +%{ + match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) )); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "BLSRL $dst, $src" %} + + ins_encode %{ + __ blsrl($dst$$Register, $src$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + // Or Instructions // Or Register with Register instruct orI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{ @@ -8649,6 +8803,210 @@ instruct andL_eReg_mem(eRegL dst, load_long_memory mem, eFlagsReg cr) %{ ins_pipe( ialu_reg_long_mem ); %} +// BMI1 instructions +instruct andnL_eReg_eReg_eReg(eRegL dst, eRegL src1, eRegL src2, immL_M1 minus_1, eFlagsReg cr) %{ + match(Set dst (AndL (XorL src1 minus_1) src2)); + predicate(UseBMI1Instructions); + effect(KILL cr, TEMP dst); + + format %{ "ANDNL $dst.lo, $src1.lo, $src2.lo\n\t" + "ANDNL $dst.hi, $src1.hi, $src2.hi" + %} + + ins_encode %{ + Register Rdst = $dst$$Register; + Register Rsrc1 = $src1$$Register; + Register Rsrc2 = $src2$$Register; + __ andnl(Rdst, Rsrc1, Rsrc2); + __ andnl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc1), HIGH_FROM_LOW(Rsrc2)); + %} + ins_pipe(ialu_reg_reg_long); +%} + +instruct andnL_eReg_eReg_mem(eRegL dst, eRegL src1, memory src2, immL_M1 minus_1, eFlagsReg cr) %{ + match(Set dst (AndL (XorL src1 minus_1) (LoadL src2) )); + predicate(UseBMI1Instructions); + effect(KILL cr, TEMP dst); + + ins_cost(125); + format %{ "ANDNL $dst.lo, $src1.lo, $src2\n\t" + "ANDNL $dst.hi, $src1.hi, $src2+4" + %} + + ins_encode %{ + Register Rdst = $dst$$Register; + Register Rsrc1 = $src1$$Register; + Address src2_hi = Address::make_raw($src2$$base, $src2$$index, $src2$$scale, $src2$$disp + 4, relocInfo::none); + + __ andnl(Rdst, Rsrc1, $src2$$Address); + __ andnl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc1), src2_hi); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsiL_eReg_eReg(eRegL dst, eRegL src, immL0 imm_zero, eFlagsReg cr) %{ + match(Set dst (AndL (SubL imm_zero src) src)); + predicate(UseBMI1Instructions); + effect(KILL cr, TEMP dst); + + format %{ "MOVL $dst.hi, 0\n\t" + "BLSIL $dst.lo, $src.lo\n\t" + "JNZ done\n\t" + "BLSIL $dst.hi, $src.hi\n" + "done:" + %} + + ins_encode %{ + Label done; + Register Rdst = $dst$$Register; + Register Rsrc = $src$$Register; + __ movl(HIGH_FROM_LOW(Rdst), 0); + __ blsil(Rdst, Rsrc); + __ jccb(Assembler::notZero, done); + __ blsil(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc)); + __ bind(done); + %} + ins_pipe(ialu_reg); +%} + +instruct blsiL_eReg_mem(eRegL dst, memory src, immL0 imm_zero, eFlagsReg cr) %{ + match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) )); + predicate(UseBMI1Instructions); + effect(KILL cr, TEMP dst); + + ins_cost(125); + format %{ "MOVL $dst.hi, 0\n\t" + "BLSIL $dst.lo, $src\n\t" + "JNZ done\n\t" + "BLSIL $dst.hi, $src+4\n" + "done:" + %} + + ins_encode %{ + Label done; + Register Rdst = $dst$$Register; + Address src_hi = Address::make_raw($src$$base, $src$$index, $src$$scale, $src$$disp + 4, relocInfo::none); + + __ movl(HIGH_FROM_LOW(Rdst), 0); + __ blsil(Rdst, $src$$Address); + __ jccb(Assembler::notZero, done); + __ blsil(HIGH_FROM_LOW(Rdst), src_hi); + __ bind(done); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskL_eReg_eReg(eRegL dst, eRegL src, immL_M1 minus_1, eFlagsReg cr) +%{ + match(Set dst (XorL (AddL src minus_1) src)); + predicate(UseBMI1Instructions); + effect(KILL cr, TEMP dst); + + format %{ "MOVL $dst.hi, 0\n\t" + "BLSMSKL $dst.lo, $src.lo\n\t" + "JNC done\n\t" + "BLSMSKL $dst.hi, $src.hi\n" + "done:" + %} + + ins_encode %{ + Label done; + Register Rdst = $dst$$Register; + Register Rsrc = $src$$Register; + __ movl(HIGH_FROM_LOW(Rdst), 0); + __ blsmskl(Rdst, Rsrc); + __ jccb(Assembler::carryClear, done); + __ blsmskl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc)); + __ bind(done); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsmskL_eReg_mem(eRegL dst, memory src, immL_M1 minus_1, eFlagsReg cr) +%{ + match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) )); + predicate(UseBMI1Instructions); + effect(KILL cr, TEMP dst); + + ins_cost(125); + format %{ "MOVL $dst.hi, 0\n\t" + "BLSMSKL $dst.lo, $src\n\t" + "JNC done\n\t" + "BLSMSKL $dst.hi, $src+4\n" + "done:" + %} + + ins_encode %{ + Label done; + Register Rdst = $dst$$Register; + Address src_hi = Address::make_raw($src$$base, $src$$index, $src$$scale, $src$$disp + 4, relocInfo::none); + + __ movl(HIGH_FROM_LOW(Rdst), 0); + __ blsmskl(Rdst, $src$$Address); + __ jccb(Assembler::carryClear, done); + __ blsmskl(HIGH_FROM_LOW(Rdst), src_hi); + __ bind(done); + %} + + ins_pipe(ialu_reg_mem); +%} + +instruct blsrL_eReg_eReg(eRegL dst, eRegL src, immL_M1 minus_1, eFlagsReg cr) +%{ + match(Set dst (AndL (AddL src minus_1) src) ); + predicate(UseBMI1Instructions); + effect(KILL cr, TEMP dst); + + format %{ "MOVL $dst.hi, $src.hi\n\t" + "BLSRL $dst.lo, $src.lo\n\t" + "JNC done\n\t" + "BLSRL $dst.hi, $src.hi\n" + "done:" + %} + + ins_encode %{ + Label done; + Register Rdst = $dst$$Register; + Register Rsrc = $src$$Register; + __ movl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc)); + __ blsrl(Rdst, Rsrc); + __ jccb(Assembler::carryClear, done); + __ blsrl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc)); + __ bind(done); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsrL_eReg_mem(eRegL dst, memory src, immL_M1 minus_1, eFlagsReg cr) +%{ + match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src) )); + predicate(UseBMI1Instructions); + effect(KILL cr, TEMP dst); + + ins_cost(125); + format %{ "MOVL $dst.hi, $src+4\n\t" + "BLSRL $dst.lo, $src\n\t" + "JNC done\n\t" + "BLSRL $dst.hi, $src+4\n" + "done:" + %} + + ins_encode %{ + Label done; + Register Rdst = $dst$$Register; + Address src_hi = Address::make_raw($src$$base, $src$$index, $src$$scale, $src$$disp + 4, relocInfo::none); + __ movl(HIGH_FROM_LOW(Rdst), src_hi); + __ blsrl(Rdst, $src$$Address); + __ jccb(Assembler::carryClear, done); + __ blsrl(HIGH_FROM_LOW(Rdst), src_hi); + __ bind(done); + %} + + ins_pipe(ialu_reg_mem); +%} + // Or Long Register with Register instruct orl_eReg(eRegL dst, eRegL src, eFlagsReg cr) %{ match(Set dst (OrL dst src)); diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index b10f920793e..cebc37cc25c 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -6022,6 +6022,19 @@ instruct countLeadingZerosL_bsr(rRegI dst, rRegL src, rFlagsReg cr) %{ %} instruct countTrailingZerosI(rRegI dst, rRegI src, rFlagsReg cr) %{ + predicate(UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosI src)); + effect(KILL cr); + + format %{ "tzcntl $dst, $src\t# count trailing zeros (int)" %} + ins_encode %{ + __ tzcntl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosI_bsf(rRegI dst, rRegI src, rFlagsReg cr) %{ + predicate(!UseCountTrailingZerosInstruction); match(Set dst (CountTrailingZerosI src)); effect(KILL cr); @@ -6041,6 +6054,19 @@ instruct countTrailingZerosI(rRegI dst, rRegI src, rFlagsReg cr) %{ %} instruct countTrailingZerosL(rRegI dst, rRegL src, rFlagsReg cr) %{ + predicate(UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosL src)); + effect(KILL cr); + + format %{ "tzcntq $dst, $src\t# count trailing zeros (long)" %} + ins_encode %{ + __ tzcntq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosL_bsf(rRegI dst, rRegL src, rFlagsReg cr) %{ + predicate(!UseCountTrailingZerosInstruction); match(Set dst (CountTrailingZerosL src)); effect(KILL cr); @@ -8622,6 +8648,122 @@ instruct andI_mem_imm(memory dst, immI src, rFlagsReg cr) ins_pipe(ialu_mem_imm); %} +// BMI1 instructions +instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1, rFlagsReg cr) %{ + match(Set dst (AndI (XorI src1 minus_1) (LoadI src2))); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "andnl $dst, $src1, $src2" %} + + ins_encode %{ + __ andnl($dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1, rFlagsReg cr) %{ + match(Set dst (AndI (XorI src1 minus_1) src2)); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "andnl $dst, $src1, $src2" %} + + ins_encode %{ + __ andnl($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI0 imm_zero, rFlagsReg cr) %{ + match(Set dst (AndI (SubI imm_zero src) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "blsil $dst, $src" %} + + ins_encode %{ + __ blsil($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct blsiI_rReg_mem(rRegI dst, memory src, immI0 imm_zero, rFlagsReg cr) %{ + match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) )); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "blsil $dst, $src" %} + + ins_encode %{ + __ blsil($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "blsmskl $dst, $src" %} + + ins_encode %{ + __ blsmskl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (XorI (AddI src minus_1) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "blsmskl $dst, $src" %} + + ins_encode %{ + __ blsmskl($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (AndI (AddI src minus_1) src) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "blsrl $dst, $src" %} + + ins_encode %{ + __ blsrl($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg_mem); +%} + +instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "blsrl $dst, $src" %} + + ins_encode %{ + __ blsrl($dst$$Register, $src$$Address); + %} + + ins_pipe(ialu_reg); +%} + // Or Instructions // Or Register with Register instruct orI_rReg(rRegI dst, rRegI src, rFlagsReg cr) @@ -8853,6 +8995,122 @@ instruct andL_mem_imm(memory dst, immL32 src, rFlagsReg cr) ins_pipe(ialu_mem_imm); %} +// BMI1 instructions +instruct andnL_rReg_rReg_mem(rRegL dst, rRegL src1, memory src2, immL_M1 minus_1, rFlagsReg cr) %{ + match(Set dst (AndL (XorL src1 minus_1) (LoadL src2))); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "andnq $dst, $src1, $src2" %} + + ins_encode %{ + __ andnq($dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct andnL_rReg_rReg_rReg(rRegL dst, rRegL src1, rRegL src2, immL_M1 minus_1, rFlagsReg cr) %{ + match(Set dst (AndL (XorL src1 minus_1) src2)); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "andnq $dst, $src1, $src2" %} + + ins_encode %{ + __ andnq($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsiL_rReg_rReg(rRegL dst, rRegL src, immL0 imm_zero, rFlagsReg cr) %{ + match(Set dst (AndL (SubL imm_zero src) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "blsiq $dst, $src" %} + + ins_encode %{ + __ blsiq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct blsiL_rReg_mem(rRegL dst, memory src, immL0 imm_zero, rFlagsReg cr) %{ + match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) )); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "blsiq $dst, $src" %} + + ins_encode %{ + __ blsiq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "blsmskq $dst, $src" %} + + ins_encode %{ + __ blsmskq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (XorL (AddL src minus_1) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "blsmskq $dst, $src" %} + + ins_encode %{ + __ blsmskq($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsrL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (AndL (AddL src minus_1) src) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + + format %{ "blsrq $dst, $src" %} + + ins_encode %{ + __ blsrq($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsrL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + + ins_cost(125); + format %{ "blsrq $dst, $src" %} + + ins_encode %{ + __ blsrq($dst$$Register, $src$$Address); + %} + + ins_pipe(ialu_reg); +%} + // Or Instructions // Or Register with Register instruct orL_rReg(rRegL dst, rRegL src, rFlagsReg cr) diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index ba6b8d494c6..33385e7a09a 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -1135,15 +1135,10 @@ jlong os::javaTimeNanos() { } void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { - { - // gettimeofday - based on time in seconds since the Epoch thus does not wrap - info_ptr->max_value = ALL_64_BITS; - - // gettimeofday is a real time clock so it skips - info_ptr->may_skip_backward = true; - info_ptr->may_skip_forward = true; - } - + info_ptr->max_value = ALL_64_BITS; + // mread_real_time() is monotonic (see 'os::javaTimeNanos()') + info_ptr->may_skip_backward = false; + info_ptr->may_skip_forward = false; info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time } @@ -2799,105 +2794,6 @@ size_t os::read(int fd, void *buf, unsigned int nBytes) { return ::read(fd, buf, nBytes); } -#define NANOSECS_PER_MILLISEC 1000000 - -int os::sleep(Thread* thread, jlong millis, bool interruptible) { - assert(thread == Thread::current(), "thread consistency check"); - - // Prevent nasty overflow in deadline calculation - // by handling long sleeps similar to solaris or windows. - const jlong limit = INT_MAX; - int result; - while (millis > limit) { - if ((result = os::sleep(thread, limit, interruptible)) != OS_OK) { - return result; - } - millis -= limit; - } - - ParkEvent * const slp = thread->_SleepEvent; - slp->reset(); - OrderAccess::fence(); - - if (interruptible) { - jlong prevtime = javaTimeNanos(); - - // Prevent precision loss and too long sleeps - jlong deadline = prevtime + millis * NANOSECS_PER_MILLISEC; - - for (;;) { - if (os::is_interrupted(thread, true)) { - return OS_INTRPT; - } - - jlong newtime = javaTimeNanos(); - - assert(newtime >= prevtime, "time moving backwards"); - // Doing prevtime and newtime in microseconds doesn't help precision, - // and trying to round up to avoid lost milliseconds can result in a - // too-short delay. - millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC; - - if (millis <= 0) { - return OS_OK; - } - - // Stop sleeping if we passed the deadline - if (newtime >= deadline) { - return OS_OK; - } - - prevtime = newtime; - - { - assert(thread->is_Java_thread(), "sanity check"); - JavaThread *jt = (JavaThread *) thread; - ThreadBlockInVM tbivm(jt); - OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */); - - jt->set_suspend_equivalent(); - - slp->park(millis); - - // were we externally suspended while we were waiting? - jt->check_and_wait_while_suspended(); - } - } - } else { - OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */); - jlong prevtime = javaTimeNanos(); - - // Prevent precision loss and too long sleeps - jlong deadline = prevtime + millis * NANOSECS_PER_MILLISEC; - - for (;;) { - // It'd be nice to avoid the back-to-back javaTimeNanos() calls on - // the 1st iteration ... - jlong newtime = javaTimeNanos(); - - if (newtime - prevtime < 0) { - // time moving backwards, should only happen if no monotonic clock - // not a guarantee() because JVM should not abort on kernel/glibc bugs - // - HS14 Commented out as not implemented. - // - TODO Maybe we should implement it? - //assert(!Aix::supports_monotonic_clock(), "time moving backwards"); - } else { - millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC; - } - - if (millis <= 0) break; - - if (newtime >= deadline) { - break; - } - - prevtime = newtime; - slp->park(millis); - } - return OS_OK; - } -} - void os::naked_short_sleep(jlong ms) { struct timespec req; @@ -3246,50 +3142,6 @@ static void do_resume(OSThread* osthread) { guarantee(osthread->sr.is_running(), "Must be running!"); } -//////////////////////////////////////////////////////////////////////////////// -// interrupt support - -void os::interrupt(Thread* thread) { - assert(Thread::current() == thread || Threads_lock->owned_by_self(), - "possibility of dangling Thread pointer"); - - OSThread* osthread = thread->osthread(); - - if (!osthread->interrupted()) { - osthread->set_interrupted(true); - // More than one thread can get here with the same value of osthread, - // resulting in multiple notifications. We do, however, want the store - // to interrupted() to be visible to other threads before we execute unpark(). - OrderAccess::fence(); - ParkEvent * const slp = thread->_SleepEvent; - if (slp != NULL) slp->unpark(); - } - - // For JSR166. Unpark even if interrupt status already was set - if (thread->is_Java_thread()) - ((JavaThread*)thread)->parker()->unpark(); - - ParkEvent * ev = thread->_ParkEvent; - if (ev != NULL) ev->unpark(); - -} - -bool os::is_interrupted(Thread* thread, bool clear_interrupted) { - assert(Thread::current() == thread || Threads_lock->owned_by_self(), - "possibility of dangling Thread pointer"); - - OSThread* osthread = thread->osthread(); - - bool interrupted = osthread->interrupted(); - - if (interrupted && clear_interrupted) { - osthread->set_interrupted(false); - // consider thread->_SleepEvent->reset() ... optional optimization - } - - return interrupted; -} - /////////////////////////////////////////////////////////////////////////////////// // signal handling (except suspend/resume) diff --git a/hotspot/src/os/aix/vm/os_aix.inline.hpp b/hotspot/src/os/aix/vm/os_aix.inline.hpp index ff9c7a7aa3e..4a648559f52 100644 --- a/hotspot/src/os/aix/vm/os_aix.inline.hpp +++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp @@ -283,4 +283,10 @@ inline int os::set_sock_opt(int fd, int level, int optname, const char* optval, socklen_t optlen) { return ::setsockopt(fd, level, optname, optval, optlen); } + +inline bool os::supports_monotonic_clock() { + // mread_real_time() is monotonic on AIX (see os::javaTimeNanos() comments) + return true; +} + #endif // OS_AIX_VM_OS_AIX_INLINE_HPP diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 4490c5f2f71..20ef1e10fb4 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -5284,7 +5284,6 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { static bool proc_task_unchecked = true; - static const char *proc_stat_path = "/proc/%d/stat"; pid_t tid = thread->osthread()->thread_id(); char *s; char stat[2048]; @@ -5297,6 +5296,8 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { long ldummy; FILE *fp; + snprintf(proc_name, 64, "/proc/%d/stat", tid); + // The /proc//stat aggregates per-process usage on // new Linux kernels 2.6+ where NPTL is supported. // The /proc/self/task//stat still has the per-thread usage. @@ -5308,12 +5309,11 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { proc_task_unchecked = false; fp = fopen("/proc/self/task", "r"); if (fp != NULL) { - proc_stat_path = "/proc/self/task/%d/stat"; + snprintf(proc_name, 64, "/proc/self/task/%d/stat", tid); fclose(fp); } } - sprintf(proc_name, proc_stat_path, tid); fp = fopen(proc_name, "r"); if ( fp == NULL ) return -1; statlen = fread(stat, 1, 2047, fp); diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 4cc42970ad0..69fb8bc0600 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -3619,13 +3619,14 @@ bool os::is_interrupted(Thread* thread, bool clear_interrupted) { "possibility of dangling Thread pointer"); OSThread* osthread = thread->osthread(); - bool interrupted = osthread->interrupted(); // There is no synchronization between the setting of the interrupt // and it being cleared here. It is critical - see 6535709 - that // we only clear the interrupt state, and reset the interrupt event, // if we are going to report that we were indeed interrupted - else // an interrupt can be "lost", leading to spurious wakeups or lost wakeups - // depending on the timing + // depending on the timing. By checking thread interrupt event to see + // if the thread gets real interrupt thus prevent spurious wakeup. + bool interrupted = osthread->interrupted() && (WaitForSingleObject(osthread->interrupt_event(), 0) == WAIT_OBJECT_0); if (interrupted && clear_interrupted) { osthread->set_interrupted(false); ResetEvent(osthread->interrupt_event()); diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index 614aaf1553a..df58c5746de 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -660,6 +660,7 @@ int InstructForm::memory_operand(FormDict &globals) const { int USE_of_memory = 0; int DEF_of_memory = 0; const char* last_memory_DEF = NULL; // to test DEF/USE pairing in asserts + const char* last_memory_USE = NULL; Component *unique = NULL; Component *comp = NULL; ComponentList &components = (ComponentList &)_components; @@ -681,7 +682,16 @@ int InstructForm::memory_operand(FormDict &globals) const { assert(0 == strcmp(last_memory_DEF, comp->_name), "every memory DEF is followed by a USE of the same name"); last_memory_DEF = NULL; } - USE_of_memory++; + // Handles same memory being used multiple times in the case of BMI1 instructions. + if (last_memory_USE != NULL) { + if (strcmp(comp->_name, last_memory_USE) != 0) { + USE_of_memory++; + } + } else { + USE_of_memory++; + } + last_memory_USE = comp->_name; + if (DEF_of_memory == 0) // defs take precedence unique = comp; } else { diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 7cb6d3dfa47..974bc04cc4d 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -1436,7 +1436,7 @@ void GraphBuilder::method_return(Value x) { bool need_mem_bar = false; if (method()->name() == ciSymbol::object_initializer_name() && - scope()->wrote_final()) { + (scope()->wrote_final() || (AlwaysSafeConstructors && scope()->wrote_fields()))) { need_mem_bar = true; } @@ -1550,6 +1550,10 @@ void GraphBuilder::access_field(Bytecodes::Code code) { scope()->set_wrote_final(); } + if (code == Bytecodes::_putfield) { + scope()->set_wrote_fields(); + } + const int offset = !needs_patching ? field->offset() : -1; switch (code) { case Bytecodes::_getstatic: { @@ -3767,11 +3771,14 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode } // now perform tests that are based on flag settings - if (callee->force_inline()) { - if (inline_level() > MaxForceInlineLevel) INLINE_BAILOUT("MaxForceInlineLevel"); - print_inlining(callee, "force inline by annotation"); - } else if (callee->should_inline()) { - print_inlining(callee, "force inline by CompileOracle"); + if (callee->force_inline() || callee->should_inline()) { + if (inline_level() > MaxForceInlineLevel ) INLINE_BAILOUT("MaxForceInlineLevel"); + if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("recursive inlining too deep"); + + const char* msg = ""; + if (callee->force_inline()) msg = "force inline by annotation"; + if (callee->should_inline()) msg = "force inline by CompileOracle"; + print_inlining(callee, msg); } else { // use heuristic controls on inlining if (inline_level() > MaxInlineLevel ) INLINE_BAILOUT("inlining too deep"); diff --git a/hotspot/src/share/vm/c1/c1_IR.cpp b/hotspot/src/share/vm/c1/c1_IR.cpp index c377e56ecef..b2a4fbbc494 100644 --- a/hotspot/src/share/vm/c1/c1_IR.cpp +++ b/hotspot/src/share/vm/c1/c1_IR.cpp @@ -142,6 +142,7 @@ IRScope::IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMe _number_of_locks = 0; _monitor_pairing_ok = method->has_balanced_monitors(); _wrote_final = false; + _wrote_fields = false; _start = NULL; if (osr_bci == -1) { diff --git a/hotspot/src/share/vm/c1/c1_IR.hpp b/hotspot/src/share/vm/c1/c1_IR.hpp index ba1abee0d01..6dc0e3a98bd 100644 --- a/hotspot/src/share/vm/c1/c1_IR.hpp +++ b/hotspot/src/share/vm/c1/c1_IR.hpp @@ -150,6 +150,7 @@ class IRScope: public CompilationResourceObj { int _number_of_locks; // the number of monitor lock slots needed bool _monitor_pairing_ok; // the monitor pairing info bool _wrote_final; // has written final field + bool _wrote_fields; // has written fields BlockBegin* _start; // the start block, successsors are method entries BitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable @@ -184,6 +185,9 @@ class IRScope: public CompilationResourceObj { BlockBegin* start() const { return _start; } void set_wrote_final() { _wrote_final = true; } bool wrote_final () const { return _wrote_final; } + void set_wrote_fields() { _wrote_fields = true; } + bool wrote_fields () const { return _wrote_fields; } + }; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 5ed04765618..ca8383b2542 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -1734,7 +1734,8 @@ void LIRGenerator::do_StoreField(StoreField* x) { (info ? new CodeEmitInfo(info) : NULL)); } - if (is_volatile && !needs_patching) { + bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses; + if (needs_atomic_access && !needs_patching) { volatile_field_store(value.result(), address, info); } else { LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; @@ -1807,7 +1808,8 @@ void LIRGenerator::do_LoadField(LoadField* x) { address = generate_address(object.result(), x->offset(), field_type); } - if (is_volatile && !needs_patching) { + bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses; + if (needs_atomic_access && !needs_patching) { volatile_field_load(address, reg, info); } else { LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index e3bac09c5b4..11542c4a50b 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -809,11 +809,10 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i int bci = vfst.bci(); Bytecodes::Code code = caller_method()->java_code_at(bci); -#ifndef PRODUCT // this is used by assertions in the access_field_patching_id BasicType patch_field_type = T_ILLEGAL; -#endif // PRODUCT bool deoptimize_for_volatile = false; + bool deoptimize_for_atomic = false; int patch_field_offset = -1; KlassHandle init_klass(THREAD, NULL); // klass needed by load_klass_patching code KlassHandle load_klass(THREAD, NULL); // klass needed by load_klass_patching code @@ -839,11 +838,24 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i // is the path for patching field offsets. load_klass is only // used for patching references to oops which don't need special // handling in the volatile case. + deoptimize_for_volatile = result.access_flags().is_volatile(); -#ifndef PRODUCT + // If we are patching a field which should be atomic, then + // the generated code is not correct either, force deoptimizing. + // We need to only cover T_LONG and T_DOUBLE fields, as we can + // break access atomicity only for them. + + // Strictly speaking, the deoptimizaation on 64-bit platforms + // is unnecessary, and T_LONG stores on 32-bit platforms need + // to be handled by special patching code when AlwaysAtomicAccesses + // becomes product feature. At this point, we are still going + // for the deoptimization for consistency against volatile + // accesses. + patch_field_type = result.field_type(); -#endif + deoptimize_for_atomic = (AlwaysAtomicAccesses && (patch_field_type == T_DOUBLE || patch_field_type == T_LONG)); + } else if (load_klass_or_mirror_patch_id) { Klass* k = NULL; switch (code) { @@ -918,13 +930,19 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i ShouldNotReachHere(); } - if (deoptimize_for_volatile) { - // At compile time we assumed the field wasn't volatile but after - // loading it turns out it was volatile so we have to throw the + if (deoptimize_for_volatile || deoptimize_for_atomic) { + // At compile time we assumed the field wasn't volatile/atomic but after + // loading it turns out it was volatile/atomic so we have to throw the // compiled code out and let it be regenerated. if (TracePatching) { - tty->print_cr("Deoptimizing for patching volatile field reference"); + if (deoptimize_for_volatile) { + tty->print_cr("Deoptimizing for patching volatile field reference"); + } + if (deoptimize_for_atomic) { + tty->print_cr("Deoptimizing for patching atomic field reference"); + } } + // It's possible the nmethod was invalidated in the last // safepoint, but if it's still alive then make it not_entrant. nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 86f1ed31bef..c927b10a030 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -724,6 +724,11 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, VM_ENTRY_MARK; + // Disable CHA for default methods for now + if (root_m->get_Method()->is_default_method()) { + return NULL; + } + methodHandle target; { MutexLocker locker(Compile_lock); diff --git a/hotspot/src/share/vm/ci/ciMethodData.cpp b/hotspot/src/share/vm/ci/ciMethodData.cpp index 950e3d6dd21..bc8794063ad 100644 --- a/hotspot/src/share/vm/ci/ciMethodData.cpp +++ b/hotspot/src/share/vm/ci/ciMethodData.cpp @@ -87,8 +87,9 @@ void ciMethodData::load_extra_data() { DataLayout* dp_dst = extra_data_base(); for (;; dp_src = MethodData::next_extra(dp_src), dp_dst = MethodData::next_extra(dp_dst)) { assert(dp_src < end_src, "moved past end of extra data"); - assert(dp_src->tag() == dp_dst->tag(), err_msg("should be same tags %d != %d", dp_src->tag(), dp_dst->tag())); - switch(dp_src->tag()) { + // New traps in the MDO can be added as we translate the copy so + // look at the entries in the copy. + switch(dp_dst->tag()) { case DataLayout::speculative_trap_data_tag: { ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst); SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src); @@ -102,7 +103,7 @@ void ciMethodData::load_extra_data() { // An empty slot or ArgInfoData entry marks the end of the trap data return; default: - fatal(err_msg("bad tag = %d", dp_src->tag())); + fatal(err_msg("bad tag = %d", dp_dst->tag())); } } } diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 3d7758304a8..b3a857c2062 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -198,14 +198,12 @@ CodeBlob* CodeCache::allocate(int size, bool is_critical) { } maxCodeCacheUsed = MAX2(maxCodeCacheUsed, ((address)_heap->high_boundary() - (address)_heap->low_boundary()) - unallocated_capacity()); - verify_if_often(); print_trace("allocation", cb, size); return cb; } void CodeCache::free(CodeBlob* cb) { assert_locked_or_safepoint(CodeCache_lock); - verify_if_often(); print_trace("free", cb); if (cb->is_nmethod()) { @@ -221,7 +219,6 @@ void CodeCache::free(CodeBlob* cb) { _heap->deallocate(cb); - verify_if_often(); assert(_number_of_blobs >= 0, "sanity check"); } @@ -244,12 +241,6 @@ void CodeCache::commit(CodeBlob* cb) { } -void CodeCache::flush() { - assert_locked_or_safepoint(CodeCache_lock); - Unimplemented(); -} - - // Iteration over CodeBlobs #define FOR_ALL_BLOBS(var) for (CodeBlob *var = first() ; var != NULL; var = next(var) ) @@ -269,7 +260,7 @@ bool CodeCache::contains(void *p) { CodeBlob* CodeCache::find_blob(void* start) { CodeBlob* result = find_blob_unsafe(start); if (result == NULL) return NULL; - // We could potientially look up non_entrant methods + // We could potentially look up non_entrant methods guarantee(!result->is_zombie() || result->is_locked_by_vm() || is_error_reported(), "unsafe access to zombie method"); return result; } @@ -741,17 +732,26 @@ void CodeCache::report_codemem_full() { } } +void CodeCache::print_memory_overhead() { + size_t wasted_bytes = 0; + CodeBlob *cb; + for (cb = first(); cb != NULL; cb = next(cb)) { + HeapBlock* heap_block = ((HeapBlock*)cb) - 1; + wasted_bytes += heap_block->length() * CodeCacheSegmentSize - cb->size(); + } + // Print bytes that are allocated in the freelist + ttyLocker ttl; + tty->print_cr("Number of elements in freelist: %d", freelist_length()); + tty->print_cr("Allocated in freelist: %dkB", bytes_allocated_in_freelist()/K); + tty->print_cr("Unused bytes in CodeBlobs: %dkB", (int)(wasted_bytes/K)); + tty->print_cr("Segment map size: %dkB", allocated_segments()/K); // 1 byte per segment +} + //------------------------------------------------------------------------------------------------ // Non-product version #ifndef PRODUCT -void CodeCache::verify_if_often() { - if (VerifyCodeCacheOften) { - _heap->verify(); - } -} - void CodeCache::print_trace(const char* event, CodeBlob* cb, int size) { if (PrintCodeCache2) { // Need to add a new flag ResourceMark rm; @@ -774,7 +774,7 @@ void CodeCache::print_internals() { int nmethodUnloaded = 0; int nmethodJava = 0; int nmethodNative = 0; - int maxCodeSize = 0; + int max_nm_size = 0; ResourceMark rm; CodeBlob *cb; @@ -798,13 +798,11 @@ void CodeCache::print_internals() { if(nm->is_not_entrant()) { nmethodNotEntrant++; } if(nm->is_zombie()) { nmethodZombie++; } if(nm->is_unloaded()) { nmethodUnloaded++; } - if(nm->is_native_method()) { nmethodNative++; } + if(nm->method() != NULL && nm->is_native_method()) { nmethodNative++; } if(nm->method() != NULL && nm->is_java_method()) { nmethodJava++; - if (nm->insts_size() > maxCodeSize) { - maxCodeSize = nm->insts_size(); - } + max_nm_size = MAX2(max_nm_size, nm->size()); } } else if (cb->is_runtime_stub()) { runtimeStubCount++; @@ -820,18 +818,19 @@ void CodeCache::print_internals() { } int bucketSize = 512; - int bucketLimit = maxCodeSize / bucketSize + 1; + int bucketLimit = max_nm_size / bucketSize + 1; int *buckets = NEW_C_HEAP_ARRAY(int, bucketLimit, mtCode); - memset(buckets,0,sizeof(int) * bucketLimit); + memset(buckets, 0, sizeof(int) * bucketLimit); for (cb = first(); cb != NULL; cb = next(cb)) { if (cb->is_nmethod()) { nmethod* nm = (nmethod*)cb; if(nm->is_java_method()) { - buckets[nm->insts_size() / bucketSize]++; - } + buckets[nm->size() / bucketSize]++; + } } } + tty->print_cr("Code Cache Entries (total of %d)",total); tty->print_cr("-------------------------------------------------"); tty->print_cr("nmethods: %d",nmethodCount); @@ -858,6 +857,7 @@ void CodeCache::print_internals() { } FREE_C_HEAP_ARRAY(int, buckets, mtCode); + print_memory_overhead(); } #endif // !PRODUCT diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index e190b11ae7e..f9f656cc35a 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -58,12 +58,13 @@ class CodeCache : AllStatic { static bool _needs_cache_clean; static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link() - static void verify_if_often() PRODUCT_RETURN; - static void mark_scavenge_root_nmethods() PRODUCT_RETURN; static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN; static int _codemem_full_count; + static size_t bytes_allocated_in_freelist() { return _heap->allocated_in_freelist(); } + static int allocated_segments() { return _heap->allocated_segments(); } + static size_t freelist_length() { return _heap->freelist_length(); } public: @@ -78,7 +79,6 @@ class CodeCache : AllStatic { static int alignment_unit(); // guaranteed alignment of all CodeBlobs static int alignment_offset(); // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header) static void free(CodeBlob* cb); // frees a CodeBlob - static void flush(); // flushes all CodeBlobs static bool contains(void *p); // returns whether p is included static void blobs_do(void f(CodeBlob* cb)); // iterates over all CodeBlobs static void blobs_do(CodeBlobClosure* f); // iterates over all CodeBlobs @@ -150,6 +150,7 @@ class CodeCache : AllStatic { // Printing/debugging static void print(); // prints summary static void print_internals(); + static void print_memory_overhead(); static void verify(); // verifies the code cache static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN; static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage diff --git a/hotspot/src/share/vm/code/debugInfo.hpp b/hotspot/src/share/vm/code/debugInfo.hpp index cf0a9a6d39f..287ff876cb0 100644 --- a/hotspot/src/share/vm/code/debugInfo.hpp +++ b/hotspot/src/share/vm/code/debugInfo.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 @@ -273,8 +273,8 @@ class DebugInfoReadStream : public CompressedReadStream { } Method* read_method() { Method* o = (Method*)(code()->metadata_at(read_int())); - assert(o == NULL || - o->is_metaspace_object(), "meta data only"); + // is_metadata() is a faster check than is_metaspace_object() + assert(o == NULL || o->is_metadata(), "meta data only"); return o; } ScopeValue* read_object_value(); diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp index d3dcf5da9a6..bee31fcacfc 100644 --- a/hotspot/src/share/vm/code/dependencies.cpp +++ b/hotspot/src/share/vm/code/dependencies.cpp @@ -725,13 +725,13 @@ Klass* Dependencies::DepStream::context_type() { } // ----------------- DependencySignature -------------------------------------- -bool DependencySignature::equals(DependencySignature* sig) const { - if ((type() != sig->type()) || (args_count() != sig->args_count())) { +bool DependencySignature::equals(DependencySignature const& s1, DependencySignature const& s2) { + if ((s1.type() != s2.type()) || (s1.args_count() != s2.args_count())) { return false; } - for (int i = 0; i < sig->args_count(); i++) { - if (arg(i) != sig->arg(i)) { + for (int i = 0; i < s1.args_count(); i++) { + if (s1.arg(i) != s2.arg(i)) { return false; } } diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp index 050478cbc85..3501b57fd51 100644 --- a/hotspot/src/share/vm/code/dependencies.hpp +++ b/hotspot/src/share/vm/code/dependencies.hpp @@ -527,7 +527,7 @@ class Dependencies: public ResourceObj { }; -class DependencySignature : public GenericHashtableEntry { +class DependencySignature : public ResourceObj { private: int _args_count; uintptr_t _argument_hash[Dependencies::max_arg_count]; @@ -542,12 +542,13 @@ class DependencySignature : public GenericHashtableEntry> 2; } + static bool equals(DependencySignature const& s1, DependencySignature const& s2); + static unsigned hash (DependencySignature const& s1) { return s1.arg(0) >> 2; } int args_count() const { return _args_count; } uintptr_t arg(int idx) const { return _argument_hash[idx]; } Dependencies::DepType type() const { return _type; } + }; diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 020916b8d34..a002ee76ea4 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -39,6 +39,7 @@ #include "prims/jvmtiImpl.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/sweeper.hpp" +#include "utilities/resourceHash.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" @@ -2135,7 +2136,11 @@ void nmethod::check_all_dependencies(DepChange& changes) { // Turn off dependency tracing while actually testing dependencies. NOT_PRODUCT( FlagSetting fs(TraceDependencies, false) ); - GenericHashtable* table = new GenericHashtable(11027); + typedef ResourceHashtable DepTable; + + DepTable* table = new DepTable(); + // Iterate over live nmethods and check dependencies of all nmethods that are not // marked for deoptimization. A particular dependency is only checked once. for(nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); nm != NULL; nm = CodeCache::alive_nmethod(CodeCache::next(nm))) { @@ -2143,9 +2148,10 @@ void nmethod::check_all_dependencies(DepChange& changes) { for (Dependencies::DepStream deps(nm); deps.next(); ) { // Construct abstraction of a dependency. DependencySignature* current_sig = new DependencySignature(deps); - // Determine if 'deps' is already checked. table->add() returns - // 'true' if the dependency was added (i.e., was not in the hashtable). - if (table->add(current_sig)) { + + // Determine if dependency is already checked. table->put(...) returns + // 'true' if the dependency is added (i.e., was not in the hashtable). + if (table->put(*current_sig, 1)) { if (deps.check_dependency() != NULL) { // Dependency checking failed. Print out information about the failed // dependency and finally fail with an assert. We can fail here, since diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp index cb5068dc4c6..582ec675d4d 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp @@ -374,25 +374,8 @@ static void usage() { "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" #define RANGE0 "[*" RANGEBASE "]" -#define RANGEDOT "[*" RANGEBASE ".]" #define RANGESLASH "[*" RANGEBASE "/]" - -// Accept several syntaxes for these patterns -// original syntax -// cmd java.lang.String foo -// PrintCompilation syntax -// cmd java.lang.String::foo -// VM syntax -// cmd java/lang/String[. ]foo -// - -static const char* patterns[] = { - "%*[ \t]%255" RANGEDOT " " "%255" RANGE0 "%n", - "%*[ \t]%255" RANGEDOT "::" "%255" RANGE0 "%n", - "%*[ \t]%255" RANGESLASH "%*[ .]" "%255" RANGE0 "%n", -}; - static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) { int match = MethodMatcher::Exact; while (name[0] == '*') { @@ -421,12 +404,10 @@ static bool scan_line(const char * line, int* bytes_read, const char*& error_msg) { *bytes_read = 0; error_msg = NULL; - for (uint i = 0; i < ARRAY_SIZE(patterns); i++) { - if (2 == sscanf(line, patterns[i], class_name, method_name, bytes_read)) { - *c_mode = check_mode(class_name, error_msg); - *m_mode = check_mode(method_name, error_msg); - return *c_mode != MethodMatcher::Unknown && *m_mode != MethodMatcher::Unknown; - } + if (2 == sscanf(line, "%*[ \t]%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, bytes_read)) { + *c_mode = check_mode(class_name, error_msg); + *m_mode = check_mode(method_name, error_msg); + return *c_mode != MethodMatcher::Unknown && *m_mode != MethodMatcher::Unknown; } return false; } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp index 39d88816718..ca2037cb6f9 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp @@ -280,6 +280,16 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { if (UseAdaptiveGenerationSizePolicyAtMajorCollection && ((gc_cause != GCCause::_java_lang_system_gc) || UseAdaptiveSizePolicyWithSystemGC)) { + // Swap the survivor spaces if from_space is empty. The + // resize_young_gen() called below is normally used after + // a successful young GC and swapping of survivor spaces; + // otherwise, it will fail to resize the young gen with + // the current implementation. + if (young_gen->from_space()->is_empty()) { + young_gen->from_space()->clear(SpaceDecorator::Mangle); + young_gen->swap_spaces(); + } + // Calculate optimal free space amounts assert(young_gen->max_size() > young_gen->from_space()->capacity_in_bytes() + @@ -318,12 +328,8 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { heap->resize_old_gen(size_policy->calculated_old_free_size_in_bytes()); - // Don't resize the young generation at an major collection. A - // desired young generation size may have been calculated but - // resizing the young generation complicates the code because the - // resizing of the old generation may have moved the boundary - // between the young generation and the old generation. Let the - // young generation resizing happen at the minor collections. + heap->resize_young_gen(size_policy->calculated_eden_size_in_bytes(), + size_policy->calculated_survivor_size_in_bytes()); } if (PrintAdaptiveSizePolicy) { gclog_or_tty->print_cr("AdaptiveSizeStop: collection: %d ", diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp index f2e83ca21df..31ee8bc5938 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -43,6 +43,7 @@ #include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/gcTraceTime.hpp" #include "gc_implementation/shared/isGCActiveMark.hpp" +#include "gc_implementation/shared/spaceDecorator.hpp" #include "gc_interface/gcCause.hpp" #include "memory/gcLocker.inline.hpp" #include "memory/referencePolicy.hpp" @@ -2115,6 +2116,16 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { if (UseAdaptiveGenerationSizePolicyAtMajorCollection && ((gc_cause != GCCause::_java_lang_system_gc) || UseAdaptiveSizePolicyWithSystemGC)) { + // Swap the survivor spaces if from_space is empty. The + // resize_young_gen() called below is normally used after + // a successful young GC and swapping of survivor spaces; + // otherwise, it will fail to resize the young gen with + // the current implementation. + if (young_gen->from_space()->is_empty()) { + young_gen->from_space()->clear(SpaceDecorator::Mangle); + young_gen->swap_spaces(); + } + // Calculate optimal free space amounts assert(young_gen->max_size() > young_gen->from_space()->capacity_in_bytes() + @@ -2154,12 +2165,8 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { heap->resize_old_gen( size_policy->calculated_old_free_size_in_bytes()); - // Don't resize the young generation at an major collection. A - // desired young generation size may have been calculated but - // resizing the young generation complicates the code because the - // resizing of the old generation may have moved the boundary - // between the young generation and the old generation. Let the - // young generation resizing happen at the minor collections. + heap->resize_young_gen(size_policy->calculated_eden_size_in_bytes(), + size_policy->calculated_survivor_size_in_bytes()); } if (PrintAdaptiveSizePolicy) { gclog_or_tty->print_cr("AdaptiveSizeStop: collection: %d ", diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 06261c804de..9453b50febb 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -3475,7 +3475,7 @@ BytecodeInterpreter::print() { tty->print_cr("&native_fresult: " INTPTR_FORMAT, (uintptr_t) &this->_native_fresult); tty->print_cr("native_lresult: " INTPTR_FORMAT, (uintptr_t) this->_native_lresult); #endif -#if !defined(ZERO) +#if !defined(ZERO) && defined(PPC) tty->print_cr("last_Java_fp: " INTPTR_FORMAT, (uintptr_t) this->_last_Java_fp); #endif // !ZERO tty->print_cr("self_link: " INTPTR_FORMAT, (uintptr_t) this->_self_link); diff --git a/hotspot/src/share/vm/interpreter/templateTable.hpp b/hotspot/src/share/vm/interpreter/templateTable.hpp index bb5169a6ccb..c6ea51537a2 100644 --- a/hotspot/src/share/vm/interpreter/templateTable.hpp +++ b/hotspot/src/share/vm/interpreter/templateTable.hpp @@ -376,6 +376,9 @@ class TemplateTable: AllStatic { #ifdef TARGET_ARCH_MODEL_ppc_32 # include "templateTable_ppc_32.hpp" #endif +#ifdef TARGET_ARCH_MODEL_ppc_64 +# include "templateTable_ppc_64.hpp" +#endif }; #endif /* !CC_INTERP */ diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index a2f7166eda7..83ec563f153 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -304,10 +304,13 @@ void GenCollectorPolicy::initialize_flags() { } // Now take the actual NewSize into account. We will silently increase NewSize - // if the user specified a smaller value. + // if the user specified a smaller or unaligned value. smallest_new_size = MAX2(smallest_new_size, (uintx)align_size_down(NewSize, _gen_alignment)); if (smallest_new_size != NewSize) { - FLAG_SET_ERGO(uintx, NewSize, smallest_new_size); + // Do not use FLAG_SET_ERGO to update NewSize here, since this will override + // if NewSize was set on the command line or not. This information is needed + // later when setting the initial and minimum young generation size. + NewSize = smallest_new_size; } _initial_gen0_size = NewSize; diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 8eb5f452495..1420c279036 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -78,6 +78,10 @@ void FileMapInfo::fail_continue(const char *msg, ...) { va_start(ap, msg); if (RequireSharedSpaces) { fail(msg, ap); + } else { + if (PrintSharedSpaces) { + tty->print_cr("UseSharedSpaces: %s", msg); + } } va_end(ap); UseSharedSpaces = false; diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp index a241af2eee9..db0105fb3a1 100644 --- a/hotspot/src/share/vm/memory/heap.cpp +++ b/hotspot/src/share/vm/memory/heap.cpp @@ -43,6 +43,7 @@ CodeHeap::CodeHeap() { _next_segment = 0; _freelist = NULL; _freelist_segments = 0; + _freelist_length = 0; } @@ -53,7 +54,7 @@ void CodeHeap::mark_segmap_as_free(size_t beg, size_t end) { address p = (address)_segmap.low() + beg; address q = (address)_segmap.low() + end; // initialize interval - while (p < q) *p++ = 0xFF; + while (p < q) *p++ = free_sentinel; } @@ -67,7 +68,7 @@ void CodeHeap::mark_segmap_as_used(size_t beg, size_t end) { int i = 0; while (p < q) { *p++ = i++; - if (i == 0xFF) i = 1; + if (i == free_sentinel) i = 1; } } @@ -139,11 +140,6 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size, } -void CodeHeap::release() { - Unimplemented(); -} - - bool CodeHeap::expand_by(size_t size) { // expand _memory space size_t dm = align_to_page_size(_memory.committed_size() + size) - _memory.committed_size(); @@ -157,8 +153,8 @@ bool CodeHeap::expand_by(size_t size) { assert(_number_of_reserved_segments >= _number_of_committed_segments, "just checking"); // expand _segmap space size_t ds = align_to_page_size(_number_of_committed_segments) - _segmap.committed_size(); - if (ds > 0) { - if (!_segmap.expand_by(ds)) return false; + if ((ds > 0) && !_segmap.expand_by(ds)) { + return false; } assert(_segmap.committed_size() >= (size_t) _number_of_committed_segments, "just checking"); // initialize additional segmap entries @@ -167,12 +163,6 @@ bool CodeHeap::expand_by(size_t size) { return true; } - -void CodeHeap::shrink_by(size_t size) { - Unimplemented(); -} - - void CodeHeap::clear() { _next_segment = 0; mark_segmap_as_free(0, _number_of_committed_segments); @@ -180,26 +170,23 @@ void CodeHeap::clear() { void* CodeHeap::allocate(size_t instance_size, bool is_critical) { - size_t number_of_segments = size_to_segments(instance_size + sizeof(HeapBlock)); + size_t number_of_segments = size_to_segments(instance_size + header_size()); assert(segments_to_size(number_of_segments) >= sizeof(FreeBlock), "not enough room for FreeList"); // First check if we can satisfy request from freelist - debug_only(verify()); + NOT_PRODUCT(verify()); HeapBlock* block = search_freelist(number_of_segments, is_critical); - debug_only(if (VerifyCodeCacheOften) verify()); + NOT_PRODUCT(verify()); + if (block != NULL) { assert(block->length() >= number_of_segments && block->length() < number_of_segments + CodeCacheMinBlockLength, "sanity check"); assert(!block->free(), "must be marked free"); -#ifdef ASSERT - memset((void *)block->allocated_space(), badCodeHeapNewVal, instance_size); -#endif + DEBUG_ONLY(memset((void*)block->allocated_space(), badCodeHeapNewVal, instance_size)); return block->allocated_space(); } // Ensure minimum size for allocation to the heap. - if (number_of_segments < CodeCacheMinBlockLength) { - number_of_segments = CodeCacheMinBlockLength; - } + number_of_segments = MAX2((int)CodeCacheMinBlockLength, (int)number_of_segments); if (!is_critical) { // Make sure the allocation fits in the unallocated heap without using @@ -215,9 +202,7 @@ void* CodeHeap::allocate(size_t instance_size, bool is_critical) { HeapBlock* b = block_at(_next_segment); b->initialize(number_of_segments); _next_segment += number_of_segments; -#ifdef ASSERT - memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size); -#endif + DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size)); return b->allocated_space(); } else { return NULL; @@ -230,28 +215,56 @@ void CodeHeap::deallocate(void* p) { // Find start of HeapBlock HeapBlock* b = (((HeapBlock *)p) - 1); assert(b->allocated_space() == p, "sanity check"); -#ifdef ASSERT - memset((void *)b->allocated_space(), - badCodeHeapFreeVal, - segments_to_size(b->length()) - sizeof(HeapBlock)); -#endif + DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapFreeVal, + segments_to_size(b->length()) - sizeof(HeapBlock))); add_to_freelist(b); - - debug_only(if (VerifyCodeCacheOften) verify()); + NOT_PRODUCT(verify()); } - +/** + * Uses segment map to find the the start (header) of a nmethod. This works as follows: + * The memory of the code cache is divided into 'segments'. The size of a segment is + * determined by -XX:CodeCacheSegmentSize=XX. Allocation in the code cache can only + * happen at segment boundaries. A pointer in the code cache can be mapped to a segment + * by calling segment_for(addr). Each time memory is requested from the code cache, + * the segmap is updated accordingly. See the following example, which illustrates the + * state of code cache and the segment map: (seg -> segment, nm ->nmethod) + * + * code cache segmap + * ----------- --------- + * seg 1 | nm 1 | -> | 0 | + * seg 2 | nm 1 | -> | 1 | + * ... | nm 1 | -> | .. | + * seg m | nm 2 | -> | 0 | + * seg m+1 | nm 2 | -> | 1 | + * ... | nm 2 | -> | 2 | + * ... | nm 2 | -> | .. | + * ... | nm 2 | -> | 0xFE | + * seg m+n | nm 2 | -> | 1 | + * ... | nm 2 | -> | | + * + * A value of '0' in the segmap indicates that this segment contains the beginning of + * an nmethod. Let's walk through a simple example: If we want to find the start of + * an nmethod that falls into seg 2, we read the value of the segmap[2]. The value + * is an offset that points to the segment that contains the start of the nmethod. + * Another example: If we want to get the start of nm 2, and we happen to get a pointer + * that points to seg m+n, we first read seg[n+m], which returns '1'. So we have to + * do one more read of the segmap[m+n-1] to finally get the segment header. + */ void* CodeHeap::find_start(void* p) const { if (!contains(p)) { return NULL; } - size_t i = segment_for(p); - address b = (address)_segmap.low(); - if (b[i] == 0xFF) { + size_t seg_idx = segment_for(p); + address seg_map = (address)_segmap.low(); + if (is_segment_unused(seg_map[seg_idx])) { return NULL; } - while (b[i] > 0) i -= (int)b[i]; - HeapBlock* h = block_at(i); + while (seg_map[seg_idx] > 0) { + seg_idx -= (int)seg_map[seg_idx]; + } + + HeapBlock* h = block_at(seg_idx); if (h->free()) { return NULL; } @@ -272,7 +285,7 @@ size_t CodeHeap::alignment_offset() const { } // Finds the next free heapblock. If the current one is free, that it returned -void* CodeHeap::next_free(HeapBlock *b) const { +void* CodeHeap::next_free(HeapBlock* b) const { // Since free blocks are merged, there is max. on free block // between two used ones if (b != NULL && b->free()) b = next_block(b); @@ -287,7 +300,7 @@ HeapBlock* CodeHeap::first_block() const { return NULL; } -HeapBlock *CodeHeap::block_start(void *q) const { +HeapBlock* CodeHeap::block_start(void* q) const { HeapBlock* b = (HeapBlock*)find_start(q); if (b == NULL) return NULL; return b - 1; @@ -312,6 +325,10 @@ size_t CodeHeap::max_capacity() const { return _memory.reserved_size(); } +int CodeHeap::allocated_segments() const { + return (int)_next_segment; +} + size_t CodeHeap::allocated_capacity() const { // size of used heap - size on freelist return segments_to_size(_next_segment - _freelist_segments); @@ -325,7 +342,7 @@ size_t CodeHeap::heap_unallocated_capacity() const { // Free list management -FreeBlock *CodeHeap::following_block(FreeBlock *b) { +FreeBlock* CodeHeap::following_block(FreeBlock *b) { return (FreeBlock*)(((address)b) + _segment_size * b->length()); } @@ -343,7 +360,7 @@ void CodeHeap::insert_after(FreeBlock* a, FreeBlock* b) { } // Try to merge this block with the following block -void CodeHeap::merge_right(FreeBlock *a) { +bool CodeHeap::merge_right(FreeBlock* a) { assert(a->free(), "must be a free block"); if (following_block(a) == a->link()) { assert(a->link() != NULL && a->link()->free(), "must be free too"); @@ -353,13 +370,20 @@ void CodeHeap::merge_right(FreeBlock *a) { // Update find_start map size_t beg = segment_for(a); mark_segmap_as_used(beg, beg + a->length()); + _freelist_length--; + return true; } + return false; } -void CodeHeap::add_to_freelist(HeapBlock *a) { + +void CodeHeap::add_to_freelist(HeapBlock* a) { FreeBlock* b = (FreeBlock*)a; + _freelist_length++; + assert(b != _freelist, "cannot be removed twice"); + // Mark as free and update free space count _freelist_segments += b->length(); b->set_free(); @@ -371,95 +395,96 @@ void CodeHeap::add_to_freelist(HeapBlock *a) { return; } - // Scan for right place to put into list. List - // is sorted by increasing addresses - FreeBlock* prev = NULL; - FreeBlock* cur = _freelist; - while(cur != NULL && cur < b) { - assert(prev == NULL || prev < cur, "must be ordered"); - prev = cur; - cur = cur->link(); - } - - assert( (prev == NULL && b < _freelist) || - (prev < b && (cur == NULL || b < cur)), "list must be ordered"); - - if (prev == NULL) { + // Since the freelist is ordered (smaller addresses -> larger addresses) and the + // element we want to insert into the freelist has a smaller address than the first + // element, we can simply add 'b' as the first element and we are done. + if (b < _freelist) { // Insert first in list b->set_link(_freelist); _freelist = b; merge_right(_freelist); - } else { - insert_after(prev, b); + return; } + + // Scan for right place to put into list. List + // is sorted by increasing addresses + FreeBlock* prev = _freelist; + FreeBlock* cur = _freelist->link(); + while(cur != NULL && cur < b) { + assert(prev < cur, "Freelist must be ordered"); + prev = cur; + cur = cur->link(); + } + assert((prev < b) && (cur == NULL || b < cur), "free-list must be ordered"); + insert_after(prev, b); } -// Search freelist for an entry on the list with the best fit -// Return NULL if no one was found +/** + * Search freelist for an entry on the list with the best fit. + * @return NULL, if no one was found + */ FreeBlock* CodeHeap::search_freelist(size_t length, bool is_critical) { - FreeBlock *best_block = NULL; - FreeBlock *best_prev = NULL; - size_t best_length = 0; + FreeBlock* found_block = NULL; + FreeBlock* found_prev = NULL; + size_t found_length = 0; - // Search for smallest block which is bigger than length - FreeBlock *prev = NULL; - FreeBlock *cur = _freelist; + FreeBlock* prev = NULL; + FreeBlock* cur = _freelist; + const size_t critical_boundary = (size_t)high_boundary() - CodeCacheMinimumFreeSpace; + + // Search for first block that fits while(cur != NULL) { - size_t l = cur->length(); - if (l >= length && (best_block == NULL || best_length > l)) { - + if (cur->length() >= length) { // Non critical allocations are not allowed to use the last part of the code heap. - if (!is_critical) { - // Make sure the end of the allocation doesn't cross into the last part of the code heap - if (((size_t)cur + length) > ((size_t)high_boundary() - CodeCacheMinimumFreeSpace)) { - // the freelist is sorted by address - if one fails, all consecutive will also fail. - break; - } + // Make sure the end of the allocation doesn't cross into the last part of the code heap. + if (!is_critical && (((size_t)cur + length) > critical_boundary)) { + // The freelist is sorted by address - if one fails, all consecutive will also fail. + break; } + // Remember block, its previous element, and its length + found_block = cur; + found_prev = prev; + found_length = found_block->length(); - // Remember best block, its previous element, and its length - best_block = cur; - best_prev = prev; - best_length = best_block->length(); + break; } - // Next element in list prev = cur; cur = cur->link(); } - if (best_block == NULL) { + if (found_block == NULL) { // None found return NULL; } - assert((best_prev == NULL && _freelist == best_block ) || - (best_prev != NULL && best_prev->link() == best_block), "sanity check"); - // Exact (or at least good enough) fit. Remove from list. // Don't leave anything on the freelist smaller than CodeCacheMinBlockLength. - if (best_length < length + CodeCacheMinBlockLength) { - length = best_length; - if (best_prev == NULL) { - assert(_freelist == best_block, "sanity check"); + if (found_length - length < CodeCacheMinBlockLength) { + _freelist_length--; + length = found_length; + if (found_prev == NULL) { + assert(_freelist == found_block, "sanity check"); _freelist = _freelist->link(); } else { + assert((found_prev->link() == found_block), "sanity check"); // Unmap element - best_prev->set_link(best_block->link()); + found_prev->set_link(found_block->link()); } } else { // Truncate block and return a pointer to the following block - best_block->set_length(best_length - length); - best_block = following_block(best_block); // Set used bit and length on new block - size_t beg = segment_for(best_block); + found_block->set_length(found_length - length); + found_block = following_block(found_block); + + size_t beg = segment_for(found_block); mark_segmap_as_used(beg, beg + length); - best_block->set_length(length); + found_block->set_length(length); } - best_block->set_used(); + found_block->set_used(); _freelist_segments -= length; - return best_block; + return found_block; } //---------------------------------------------------------------------------- @@ -471,33 +496,34 @@ void CodeHeap::print() { tty->print_cr("The Heap"); } -#endif - void CodeHeap::verify() { - // Count the number of blocks on the freelist, and the amount of space - // represented. - int count = 0; - size_t len = 0; - for(FreeBlock* b = _freelist; b != NULL; b = b->link()) { - len += b->length(); - count++; - } + if (VerifyCodeCache) { + size_t len = 0; + int count = 0; + for(FreeBlock* b = _freelist; b != NULL; b = b->link()) { + len += b->length(); + count++; + // Check if we have merged all free blocks + assert(merge_right(b) == false, "Missed merging opportunity"); + } + // Verify that freelist contains the right amount of free space + assert(len == _freelist_segments, "wrong freelist"); - // Verify that freelist contains the right amount of free space - // guarantee(len == _freelist_segments, "wrong freelist"); + for(HeapBlock* h = first_block(); h != NULL; h = next_block(h)) { + if (h->free()) count--; + } + // Verify that the freelist contains the same number of blocks + // than free blocks found on the full list. + assert(count == 0, "missing free blocks"); - // Verify that the number of free blocks is not out of hand. - static int free_block_threshold = 10000; - if (count > free_block_threshold) { - warning("CodeHeap: # of free blocks > %d", free_block_threshold); - // Double the warning limit - free_block_threshold *= 2; + // Verify that the number of free blocks is not out of hand. + static int free_block_threshold = 10000; + if (count > free_block_threshold) { + warning("CodeHeap: # of free blocks > %d", free_block_threshold); + // Double the warning limit + free_block_threshold *= 2; + } } - - // Verify that the freelist contains the same number of free blocks that is - // found on the full list. - for(HeapBlock *h = first_block(); h != NULL; h = next_block(h)) { - if (h->free()) count--; - } - // guarantee(count == 0, "missing free blocks"); } + +#endif diff --git a/hotspot/src/share/vm/memory/heap.hpp b/hotspot/src/share/vm/memory/heap.hpp index e271d1be2fc..849931ee70b 100644 --- a/hotspot/src/share/vm/memory/heap.hpp +++ b/hotspot/src/share/vm/memory/heap.hpp @@ -92,24 +92,28 @@ class CodeHeap : public CHeapObj { FreeBlock* _freelist; size_t _freelist_segments; // No. of segments in freelist + int _freelist_length; + + enum { free_sentinel = 0xFF }; // Helper functions size_t size_to_segments(size_t size) const { return (size + _segment_size - 1) >> _log2_segment_size; } size_t segments_to_size(size_t number_of_segments) const { return number_of_segments << _log2_segment_size; } size_t segment_for(void* p) const { return ((char*)p - _memory.low()) >> _log2_segment_size; } + bool is_segment_unused(int val) const { return val == free_sentinel; } HeapBlock* block_at(size_t i) const { return (HeapBlock*)(_memory.low() + (i << _log2_segment_size)); } void mark_segmap_as_free(size_t beg, size_t end); void mark_segmap_as_used(size_t beg, size_t end); // Freelist management helpers - FreeBlock* following_block(FreeBlock *b); + FreeBlock* following_block(FreeBlock* b); void insert_after(FreeBlock* a, FreeBlock* b); - void merge_right (FreeBlock* a); + bool merge_right (FreeBlock* a); // Toplevel freelist management - void add_to_freelist(HeapBlock *b); + void add_to_freelist(HeapBlock* b); FreeBlock* search_freelist(size_t length, bool is_critical); // Iteration helpers @@ -120,20 +124,18 @@ class CodeHeap : public CHeapObj { // to perform additional actions on creation of executable code void on_code_mapping(char* base, size_t size); + void clear(); // clears all heap contents public: CodeHeap(); // Heap extents bool reserve(size_t reserved_size, size_t committed_size, size_t segment_size); - void release(); // releases all allocated memory bool expand_by(size_t size); // expands committed memory by size - void shrink_by(size_t size); // shrinks committed memory by size - void clear(); // clears all heap contents // Memory allocation void* allocate (size_t size, bool is_critical); // allocates a block of size or returns NULL - void deallocate(void* p); // deallocates a block + void deallocate(void* p); // deallocates a block // Attributes char* low_boundary() const { return _memory.low_boundary (); } @@ -141,12 +143,13 @@ class CodeHeap : public CHeapObj { char* high_boundary() const { return _memory.high_boundary(); } bool contains(const void* p) const { return low_boundary() <= p && p < high(); } - void* find_start(void* p) const; // returns the block containing p or NULL - size_t alignment_unit() const; // alignment of any block - size_t alignment_offset() const; // offset of first byte of any block, within the enclosing alignment unit - static size_t header_size(); // returns the header size for each heap block + void* find_start(void* p) const; // returns the block containing p or NULL + size_t alignment_unit() const; // alignment of any block + size_t alignment_offset() const; // offset of first byte of any block, within the enclosing alignment unit + static size_t header_size(); // returns the header size for each heap block - // Iteration + size_t allocated_in_freelist() const { return _freelist_segments * CodeCacheSegmentSize; } + int freelist_length() const { return _freelist_length; } // number of elements in the freelist // returns the first block or NULL void* first() const { return next_free(first_block()); } @@ -156,6 +159,7 @@ class CodeHeap : public CHeapObj { // Statistics size_t capacity() const; size_t max_capacity() const; + int allocated_segments() const; size_t allocated_capacity() const; size_t unallocated_capacity() const { return max_capacity() - allocated_capacity(); } @@ -164,7 +168,7 @@ private: public: // Debugging - void verify(); + void verify() PRODUCT_RETURN; void print() PRODUCT_RETURN; }; diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index e008ccb8d4a..9ed7628985d 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -1295,6 +1295,7 @@ void ConstantPool::copy_entry_to(constantPoolHandle from_cp, int from_i, } break; case JVM_CONSTANT_UnresolvedClass: + case JVM_CONSTANT_UnresolvedClassInError: { // Can be resolved after checking tag, so check the slot first. CPSlot entry = from_cp->slot_at(from_i); diff --git a/hotspot/src/share/vm/oops/metadata.hpp b/hotspot/src/share/vm/oops/metadata.hpp index 84a60893e81..dc52c452ee3 100644 --- a/hotspot/src/share/vm/oops/metadata.hpp +++ b/hotspot/src/share/vm/oops/metadata.hpp @@ -42,6 +42,7 @@ class Metadata : public MetaspaceObj { // Rehashing support for tables containing pointers to this unsigned int new_hash(juint seed) { ShouldNotReachHere(); return 0; } + virtual bool is_metadata() const volatile { return true; } virtual bool is_klass() const volatile { return false; } virtual bool is_method() const volatile { return false; } virtual bool is_methodData() const volatile { return false; } diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 931b08b5264..98598dbeeff 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -108,12 +108,16 @@ class Method : public Metadata { #endif u2 _method_size; // size of this object u1 _intrinsic_id; // vmSymbols::intrinsic_id (0 == _none) - u1 _jfr_towrite : 1, // Flags - _caller_sensitive : 1, - _force_inline : 1, - _hidden : 1, - _dont_inline : 1, - : 3; + + // Flags + enum Flags { + _jfr_towrite = 1 << 0, + _caller_sensitive = 1 << 1, + _force_inline = 1 << 2, + _dont_inline = 1 << 3, + _hidden = 1 << 4 + }; + u1 _flags; #ifndef PRODUCT int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging) @@ -759,16 +763,41 @@ class Method : public Metadata { void init_intrinsic_id(); // updates from _none if a match static vmSymbols::SID klass_id_for_intrinsics(Klass* holder); - bool jfr_towrite() { return _jfr_towrite; } - void set_jfr_towrite(bool x) { _jfr_towrite = x; } - bool caller_sensitive() { return _caller_sensitive; } - void set_caller_sensitive(bool x) { _caller_sensitive = x; } - bool force_inline() { return _force_inline; } - void set_force_inline(bool x) { _force_inline = x; } - bool dont_inline() { return _dont_inline; } - void set_dont_inline(bool x) { _dont_inline = x; } - bool is_hidden() { return _hidden; } - void set_hidden(bool x) { _hidden = x; } + bool jfr_towrite() { + return (_flags & _jfr_towrite) != 0; + } + void set_jfr_towrite(bool x) { + _flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite); + } + + bool caller_sensitive() { + return (_flags & _caller_sensitive) != 0; + } + void set_caller_sensitive(bool x) { + _flags = x ? (_flags | _caller_sensitive) : (_flags & ~_caller_sensitive); + } + + bool force_inline() { + return (_flags & _force_inline) != 0; + } + void set_force_inline(bool x) { + _flags = x ? (_flags | _force_inline) : (_flags & ~_force_inline); + } + + bool dont_inline() { + return (_flags & _dont_inline) != 0; + } + void set_dont_inline(bool x) { + _flags = x ? (_flags | _dont_inline) : (_flags & ~_dont_inline); + } + + bool is_hidden() { + return (_flags & _hidden) != 0; + } + void set_hidden(bool x) { + _flags = x ? (_flags | _hidden) : (_flags & ~_hidden); + } + ConstMethod::MethodType method_type() const { return _constMethod->method_type(); } diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index b226173d832..0e6e0ec0130 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -1071,7 +1071,8 @@ void MethodData::post_initialize(BytecodeStream* stream) { } // Initialize the MethodData* corresponding to a given method. -MethodData::MethodData(methodHandle method, int size, TRAPS) { +MethodData::MethodData(methodHandle method, int size, TRAPS) + : _extra_data_lock(Monitor::leaf, "MDO extra data lock") { No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC ResourceMark rm; // Set the method back-pointer. @@ -1235,7 +1236,7 @@ DataLayout* MethodData::next_extra(DataLayout* dp) { return (DataLayout*)((address)dp + DataLayout::compute_size_in_bytes(nb_cells)); } -ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp) { +ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp, bool concurrent) { DataLayout* end = extra_data_limit(); for (;; dp = next_extra(dp)) { @@ -1257,10 +1258,11 @@ ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout if (m != NULL) { SpeculativeTrapData* data = new SpeculativeTrapData(dp); // data->method() may be null in case of a concurrent - // allocation. Assume it's for the same method and use that + // allocation. Maybe it's for the same method. Try to use that // entry in that case. if (dp->bci() == bci) { if (data->method() == NULL) { + assert(concurrent, "impossible because no concurrent allocation"); return NULL; } else if (data->method() == m) { return data; @@ -1289,40 +1291,40 @@ ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_mi // Allocation in the extra data space has to be atomic because not // all entries have the same size and non atomic concurrent // allocation would result in a corrupted extra data space. - while (true) { - ProfileData* result = bci_to_extra_data_helper(bci, m, dp); - if (result != NULL) { + ProfileData* result = bci_to_extra_data_helper(bci, m, dp, true); + if (result != NULL) { + return result; + } + + if (create_if_missing && dp < end) { + MutexLocker ml(&_extra_data_lock); + // Check again now that we have the lock. Another thread may + // have added extra data entries. + ProfileData* result = bci_to_extra_data_helper(bci, m, dp, false); + if (result != NULL || dp >= end) { return result; } - if (create_if_missing && dp < end) { - assert(dp->tag() == DataLayout::no_tag || (dp->tag() == DataLayout::speculative_trap_data_tag && m != NULL), "should be free"); - assert(next_extra(dp)->tag() == DataLayout::no_tag || next_extra(dp)->tag() == DataLayout::arg_info_data_tag, "should be free or arg info"); - u1 tag = m == NULL ? DataLayout::bit_data_tag : DataLayout::speculative_trap_data_tag; - // SpeculativeTrapData is 2 slots. Make sure we have room. - if (m != NULL && next_extra(dp)->tag() != DataLayout::no_tag) { - return NULL; - } - DataLayout temp; - temp.initialize(tag, bci, 0); - // May have been set concurrently - if (dp->header() != temp.header() && !dp->atomic_set_header(temp.header())) { - // Allocation failure because of concurrent allocation. Try - // again. - continue; - } - assert(dp->tag() == tag, "sane"); - assert(dp->bci() == bci, "no concurrent allocation"); - if (tag == DataLayout::bit_data_tag) { - return new BitData(dp); - } else { - // If being allocated concurrently, one trap may be lost - SpeculativeTrapData* data = new SpeculativeTrapData(dp); - data->set_method(m); - return data; - } + assert(dp->tag() == DataLayout::no_tag || (dp->tag() == DataLayout::speculative_trap_data_tag && m != NULL), "should be free"); + assert(next_extra(dp)->tag() == DataLayout::no_tag || next_extra(dp)->tag() == DataLayout::arg_info_data_tag, "should be free or arg info"); + u1 tag = m == NULL ? DataLayout::bit_data_tag : DataLayout::speculative_trap_data_tag; + // SpeculativeTrapData is 2 slots. Make sure we have room. + if (m != NULL && next_extra(dp)->tag() != DataLayout::no_tag) { + return NULL; + } + DataLayout temp; + temp.initialize(tag, bci, 0); + + dp->set_header(temp.header()); + assert(dp->tag() == tag, "sane"); + assert(dp->bci() == bci, "no concurrent allocation"); + if (tag == DataLayout::bit_data_tag) { + return new BitData(dp); + } else { + SpeculativeTrapData* data = new SpeculativeTrapData(dp); + data->set_method(m); + return data; } - return NULL; } return NULL; } diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index 76b0708f233..e0218f9fd47 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -190,12 +190,6 @@ public: void set_header(intptr_t value) { _header._bits = value; } - bool atomic_set_header(intptr_t value) { - if (Atomic::cmpxchg_ptr(value, (volatile intptr_t*)&_header._bits, 0) == 0) { - return true; - } - return false; - } intptr_t header() { return _header._bits; } @@ -2047,10 +2041,12 @@ private: // Cached hint for bci_to_dp and bci_to_data int _hint_di; + Mutex _extra_data_lock; + MethodData(methodHandle method, int size, TRAPS); public: static MethodData* allocate(ClassLoaderData* loader_data, methodHandle method, TRAPS); - MethodData() {}; // For ciMethodData + MethodData() : _extra_data_lock(Monitor::leaf, "MDO extra data lock") {}; // For ciMethodData bool is_methodData() const volatile { return true; } @@ -2155,7 +2151,7 @@ private: // What is the index of the first data entry? int first_di() const { return 0; } - ProfileData* bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp); + ProfileData* bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp, bool concurrent); // Find or create an extra ProfileData: ProfileData* bci_to_extra_data(int bci, Method* m, bool create_if_missing); diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index cc5e2ced6b3..0db9dab8104 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -452,7 +452,7 @@ product(bool, EliminateAutoBox, true, \ "Control optimizations for autobox elimination") \ \ - experimental(bool, UseImplicitStableValues, false, \ + diagnostic(bool, UseImplicitStableValues, true, \ "Mark well-known stable fields as such (e.g. String.value)") \ \ product(intx, AutoBoxCacheMax, 128, \ @@ -650,7 +650,7 @@ experimental(bool, ReplaceInParentMaps, false, \ "Propagate type improvements in callers of inlinee if possible") \ \ - experimental(bool, UseTypeSpeculation, false, \ + product(bool, UseTypeSpeculation, true, \ "Speculatively propagate types from profiles") \ \ diagnostic(bool, UseInlineDepthForSpeculativeTypes, true, \ diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index d11e4ff5ccf..d9fcfb2cb91 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -3007,22 +3007,28 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, } Node* cast_obj = NULL; - const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr(); - // We may not have profiling here or it may not help us. If we have - // a speculative type use it to perform an exact cast. - ciKlass* spec_obj_type = obj_type->speculative_type(); - if (spec_obj_type != NULL || - (data != NULL && - // Counter has never been decremented (due to cast failure). - // ...This is a reasonable thing to expect. It is true of - // all casts inserted by javac to implement generic types. - data->as_CounterData()->count() >= 0)) { - cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace); - if (cast_obj != NULL) { - if (failure_control != NULL) // failure is now impossible - (*failure_control) = top(); - // adjust the type of the phi to the exact klass: - phi->raise_bottom_type(_gvn.type(cast_obj)->meet_speculative(TypePtr::NULL_PTR)); + if (tk->klass_is_exact()) { + // The following optimization tries to statically cast the speculative type of the object + // (for example obtained during profiling) to the type of the superklass and then do a + // dynamic check that the type of the object is what we expect. To work correctly + // for checkcast and aastore the type of superklass should be exact. + const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr(); + // We may not have profiling here or it may not help us. If we have + // a speculative type use it to perform an exact cast. + ciKlass* spec_obj_type = obj_type->speculative_type(); + if (spec_obj_type != NULL || + (data != NULL && + // Counter has never been decremented (due to cast failure). + // ...This is a reasonable thing to expect. It is true of + // all casts inserted by javac to implement generic types. + data->as_CounterData()->count() >= 0)) { + cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace); + if (cast_obj != NULL) { + if (failure_control != NULL) // failure is now impossible + (*failure_control) = top(); + // adjust the type of the phi to the exact klass: + phi->raise_bottom_type(_gvn.type(cast_obj)->meet_speculative(TypePtr::NULL_PTR)); + } } } diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 73c6e9090f9..bd2ef020bb2 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -3180,7 +3180,8 @@ bool LibraryCallKit::inline_native_currentThread() { // private native boolean java.lang.Thread.isInterrupted(boolean ClearInterrupted); bool LibraryCallKit::inline_native_isInterrupted() { // Add a fast path to t.isInterrupted(clear_int): - // (t == Thread.current() && (!TLS._osthread._interrupted || !clear_int)) + // (t == Thread.current() && + // (!TLS._osthread._interrupted || WINDOWS_ONLY(false) NOT_WINDOWS(!clear_int))) // ? TLS._osthread._interrupted : /*slow path:*/ t.isInterrupted(clear_int) // So, in the common case that the interrupt bit is false, // we avoid making a call into the VM. Even if the interrupt bit @@ -3237,6 +3238,7 @@ bool LibraryCallKit::inline_native_isInterrupted() { // drop through to next case set_control( _gvn.transform(new (C) IfTrueNode(iff_bit))); +#ifndef TARGET_OS_FAMILY_windows // (c) Or, if interrupt bit is set and clear_int is false, use 2nd fast path. Node* clr_arg = argument(1); Node* cmp_arg = _gvn.transform(new (C) CmpINode(clr_arg, intcon(0))); @@ -3250,6 +3252,10 @@ bool LibraryCallKit::inline_native_isInterrupted() { // drop through to next case set_control( _gvn.transform(new (C) IfTrueNode(iff_arg))); +#else + // To return true on Windows you must read the _interrupted field + // and check the the event state i.e. take the slow path. +#endif // TARGET_OS_FAMILY_windows // (d) Otherwise, go to the slow path. slow_region->add_req(control()); diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 03ee1dc8086..f263a3c5044 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -1922,6 +1922,105 @@ OptoReg::Name Matcher::find_receiver( bool is_outgoing ) { return OptoReg::as_OptoReg(regs.first()); } +// This function identifies sub-graphs in which a 'load' node is +// input to two different nodes, and such that it can be matched +// with BMI instructions like blsi, blsr, etc. +// Example : for b = -a[i] & a[i] can be matched to blsi r32, m32. +// The graph is (AndL (SubL Con0 LoadL*) LoadL*), where LoadL* +// refers to the same node. +#ifdef X86 +// Match the generic fused operations pattern (op1 (op2 Con{ConType} mop) mop) +// This is a temporary solution until we make DAGs expressible in ADL. +template +class FusedPatternMatcher { + Node* _op1_node; + Node* _mop_node; + int _con_op; + + static int match_next(Node* n, int next_op, int next_op_idx) { + if (n->in(1) == NULL || n->in(2) == NULL) { + return -1; + } + + if (next_op_idx == -1) { // n is commutative, try rotations + if (n->in(1)->Opcode() == next_op) { + return 1; + } else if (n->in(2)->Opcode() == next_op) { + return 2; + } + } else { + assert(next_op_idx > 0 && next_op_idx <= 2, "Bad argument index"); + if (n->in(next_op_idx)->Opcode() == next_op) { + return next_op_idx; + } + } + return -1; + } +public: + FusedPatternMatcher(Node* op1_node, Node *mop_node, int con_op) : + _op1_node(op1_node), _mop_node(mop_node), _con_op(con_op) { } + + bool match(int op1, int op1_op2_idx, // op1 and the index of the op1->op2 edge, -1 if op1 is commutative + int op2, int op2_con_idx, // op2 and the index of the op2->con edge, -1 if op2 is commutative + typename ConType::NativeType con_value) { + if (_op1_node->Opcode() != op1) { + return false; + } + if (_mop_node->outcnt() > 2) { + return false; + } + op1_op2_idx = match_next(_op1_node, op2, op1_op2_idx); + if (op1_op2_idx == -1) { + return false; + } + // Memory operation must be the other edge + int op1_mop_idx = (op1_op2_idx & 1) + 1; + + // Check that the mop node is really what we want + if (_op1_node->in(op1_mop_idx) == _mop_node) { + Node *op2_node = _op1_node->in(op1_op2_idx); + if (op2_node->outcnt() > 1) { + return false; + } + assert(op2_node->Opcode() == op2, "Should be"); + op2_con_idx = match_next(op2_node, _con_op, op2_con_idx); + if (op2_con_idx == -1) { + return false; + } + // Memory operation must be the other edge + int op2_mop_idx = (op2_con_idx & 1) + 1; + // Check that the memory operation is the same node + if (op2_node->in(op2_mop_idx) == _mop_node) { + // Now check the constant + const Type* con_type = op2_node->in(op2_con_idx)->bottom_type(); + if (con_type != Type::TOP && ConType::as_self(con_type)->get_con() == con_value) { + return true; + } + } + } + return false; + } +}; + + +bool Matcher::is_bmi_pattern(Node *n, Node *m) { + if (n != NULL && m != NULL) { + if (m->Opcode() == Op_LoadI) { + FusedPatternMatcher bmii(n, m, Op_ConI); + return bmii.match(Op_AndI, -1, Op_SubI, 1, 0) || + bmii.match(Op_AndI, -1, Op_AddI, -1, -1) || + bmii.match(Op_XorI, -1, Op_AddI, -1, -1); + } else if (m->Opcode() == Op_LoadL) { + FusedPatternMatcher bmil(n, m, Op_ConL); + return bmil.match(Op_AndL, -1, Op_SubL, 1, 0) || + bmil.match(Op_AndL, -1, Op_AddL, -1, -1) || + bmil.match(Op_XorL, -1, Op_AddL, -1, -1); + } + } + return false; +} +#endif // X86 + // A method-klass-holder may be passed in the inline_cache_reg // and then expanded into the inline_cache_reg and a method_oop register // defined in ad_.cpp @@ -2077,6 +2176,14 @@ void Matcher::find_shared( Node *n ) { set_shared(m->in(AddPNode::Base)->in(1)); } + // if 'n' and 'm' are part of a graph for BMI instruction, clone this node. +#ifdef X86 + if (UseBMI1Instructions && is_bmi_pattern(n, m)) { + mstack.push(m, Visit); + continue; + } +#endif + // Clone addressing expressions as they are "free" in memory access instructions if( mem_op && i == MemNode::Address && mop == Op_AddP ) { // Some inputs for address expression are not put on stack diff --git a/hotspot/src/share/vm/opto/matcher.hpp b/hotspot/src/share/vm/opto/matcher.hpp index 38eeca40290..66d4a0adab9 100644 --- a/hotspot/src/share/vm/opto/matcher.hpp +++ b/hotspot/src/share/vm/opto/matcher.hpp @@ -79,6 +79,9 @@ class Matcher : public PhaseTransform { // Find shared Nodes, or Nodes that otherwise are Matcher roots void find_shared( Node *n ); +#ifdef X86 + bool is_bmi_pattern(Node *n, Node *m); +#endif // Debug and profile information for nodes in old space: GrowableArray* _old_node_note_array; diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 8097eade89f..3a6d4998b06 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1593,35 +1593,33 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, // Try to constant-fold a stable array element. static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) { + assert(ary->const_oop(), "array should be constant"); assert(ary->is_stable(), "array should be stable"); - if (ary->const_oop() != NULL) { - // Decode the results of GraphKit::array_element_address. - ciArray* aobj = ary->const_oop()->as_array(); - ciConstant con = aobj->element_value_by_offset(off); + // Decode the results of GraphKit::array_element_address. + ciArray* aobj = ary->const_oop()->as_array(); + ciConstant con = aobj->element_value_by_offset(off); - if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { - const Type* con_type = Type::make_from_constant(con); - if (con_type != NULL) { - if (con_type->isa_aryptr()) { - // Join with the array element type, in case it is also stable. - int dim = ary->stable_dimension(); - con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1); - } - if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) { - con_type = con_type->make_narrowoop(); - } -#ifndef PRODUCT - if (TraceIterativeGVN) { - tty->print("FoldStableValues: array element [off=%d]: con_type=", off); - con_type->dump(); tty->cr(); - } -#endif //PRODUCT - return con_type; + if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { + const Type* con_type = Type::make_from_constant(con); + if (con_type != NULL) { + if (con_type->isa_aryptr()) { + // Join with the array element type, in case it is also stable. + int dim = ary->stable_dimension(); + con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1); } + if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) { + con_type = con_type->make_narrowoop(); + } +#ifndef PRODUCT + if (TraceIterativeGVN) { + tty->print("FoldStableValues: array element [off=%d]: con_type=", off); + con_type->dump(); tty->cr(); + } +#endif //PRODUCT + return con_type; } } - return NULL; } @@ -1641,7 +1639,7 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const { // Try to guess loaded type from pointer type if (tp->isa_aryptr()) { const TypeAryPtr* ary = tp->is_aryptr(); - const Type *t = ary->elem(); + const Type* t = ary->elem(); // Determine whether the reference is beyond the header or not, by comparing // the offset against the offset of the start of the array's data. @@ -1653,10 +1651,9 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const { const bool off_beyond_header = ((uint)off >= (uint)min_base_off); // Try to constant-fold a stable array element. - if (FoldStableValues && ary->is_stable()) { - // Make sure the reference is not into the header - if (off_beyond_header && off != Type::OffsetBot) { - assert(adr->is_AddP() && adr->in(AddPNode::Offset)->is_Con(), "offset is a constant"); + if (FoldStableValues && ary->is_stable() && ary->const_oop() != NULL) { + // Make sure the reference is not into the header and the offset is constant + if (off_beyond_header && adr->is_AddP() && off != Type::OffsetBot) { const Type* con_type = fold_stable_ary_elem(ary, off, memory_type()); if (con_type != NULL) { return con_type; diff --git a/hotspot/src/share/vm/opto/multnode.cpp b/hotspot/src/share/vm/opto/multnode.cpp index 300f6246369..1da4b7789f4 100644 --- a/hotspot/src/share/vm/opto/multnode.cpp +++ b/hotspot/src/share/vm/opto/multnode.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 @@ -194,7 +194,9 @@ bool ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) { } } - ProjNode* other_proj = iff->proj_out(1-_con)->as_Proj(); + ProjNode* other_proj = iff->proj_out(1-_con); + if (other_proj == NULL) // Should never happen, but make Parfait happy. + return false; if (other_proj->is_uncommon_trap_proj(reason)) { assert(reason == Deoptimization::Reason_none || Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list"); diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index cca8a8b6c3c..092e40a7f64 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -338,6 +338,8 @@ class Parse : public GraphKit { GraphKit _exits; // Record all normal returns and throws here. bool _wrote_final; // Did we write a final field? bool _wrote_volatile; // Did we write a volatile field? + bool _wrote_stable; // Did we write a @Stable field? + bool _wrote_fields; // Did we write any field? bool _count_invocations; // update and test invocation counter bool _method_data_update; // update method data oop Node* _alloc_with_final; // An allocation node with final field @@ -383,6 +385,10 @@ class Parse : public GraphKit { void set_wrote_final(bool z) { _wrote_final = z; } bool wrote_volatile() const { return _wrote_volatile; } void set_wrote_volatile(bool z) { _wrote_volatile = z; } + bool wrote_stable() const { return _wrote_stable; } + void set_wrote_stable(bool z) { _wrote_stable = z; } + bool wrote_fields() const { return _wrote_fields; } + void set_wrote_fields(bool z) { _wrote_fields = z; } bool count_invocations() const { return _count_invocations; } bool method_data_update() const { return _method_data_update; } Node* alloc_with_final() const { return _alloc_with_final; } diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index 74b1f1a4ac8..db50f98492b 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -391,6 +391,8 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Pars _depth = 1 + (caller->has_method() ? caller->depth() : 0); _wrote_final = false; _wrote_volatile = false; + _wrote_stable = false; + _wrote_fields = false; _alloc_with_final = NULL; _entry_bci = InvocationEntryBci; _tf = NULL; @@ -908,26 +910,35 @@ void Parse::do_exits() { Node* iophi = _exits.i_o(); _exits.set_i_o(gvn().transform(iophi)); - // On PPC64, also add MemBarRelease for constructors which write - // volatile fields. As support_IRIW_for_not_multiple_copy_atomic_cpu - // is set on PPC64, no sync instruction is issued after volatile - // stores. We want to quarantee the same behaviour as on platforms - // with total store order, although this is not required by the Java - // memory model. So as with finals, we add a barrier here. - if (wrote_final() PPC64_ONLY(|| (wrote_volatile() && method()->is_initializer()))) { - // This method (which must be a constructor by the rules of Java) - // wrote a final. The effects of all initializations must be - // committed to memory before any code after the constructor - // publishes the reference to the newly constructor object. - // Rather than wait for the publication, we simply block the - // writes here. Rather than put a barrier on only those writes - // which are required to complete, we force all writes to complete. - // - // "All bets are off" unless the first publication occurs after a - // normal return from the constructor. We do not attempt to detect - // such unusual early publications. But no barrier is needed on - // exceptional returns, since they cannot publish normally. - // + // Figure out if we need to emit the trailing barrier. The barrier is only + // needed in the constructors, and only in three cases: + // + // 1. The constructor wrote a final. The effects of all initializations + // must be committed to memory before any code after the constructor + // publishes the reference to the newly constructed object. Rather + // than wait for the publication, we simply block the writes here. + // Rather than put a barrier on only those writes which are required + // to complete, we force all writes to complete. + // + // 2. On PPC64, also add MemBarRelease for constructors which write + // volatile fields. As support_IRIW_for_not_multiple_copy_atomic_cpu + // is set on PPC64, no sync instruction is issued after volatile + // stores. We want to guarantee the same behavior as on platforms + // with total store order, although this is not required by the Java + // memory model. So as with finals, we add a barrier here. + // + // 3. Experimental VM option is used to force the barrier if any field + // was written out in the constructor. + // + // "All bets are off" unless the first publication occurs after a + // normal return from the constructor. We do not attempt to detect + // such unusual early publications. But no barrier is needed on + // exceptional returns, since they cannot publish normally. + // + if (method()->is_initializer() && + (wrote_final() || + PPC64_ONLY(wrote_volatile() ||) + (AlwaysSafeConstructors && wrote_fields()))) { _exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final()); #ifndef PRODUCT if (PrintOpto && (Verbose || WizardMode)) { @@ -937,6 +948,19 @@ void Parse::do_exits() { #endif } + // Any method can write a @Stable field; insert memory barriers after + // those also. If there is a predecessor allocation node, bind the + // barrier there. + if (wrote_stable()) { + _exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final()); +#ifndef PRODUCT + if (PrintOpto && (Verbose || WizardMode)) { + method()->print_name(); + tty->print_cr(" writes @Stable and needs a memory barrier"); + } +#endif + } + for (MergeMemStream mms(_exits.merged_memory()); mms.next_non_empty(); ) { // transform each slice of the original memphi: mms.set_memory(_gvn.transform(mms.memory())); diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp index 466e1ca3b90..1f7ea1d3f8b 100644 --- a/hotspot/src/share/vm/opto/parse3.cpp +++ b/hotspot/src/share/vm/opto/parse3.cpp @@ -233,7 +233,8 @@ void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) { // Build the load. // MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered; - Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, is_vol); + bool needs_atomic_access = is_vol || AlwaysAtomicAccesses; + Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, needs_atomic_access); // Adjust Java stack if (type2size[bt] == 1) @@ -314,7 +315,8 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { } store = store_oop_to_object(control(), obj, adr, adr_type, val, field_type, bt, mo); } else { - store = store_to_memory(control(), adr, val, bt, adr_type, mo, is_vol); + bool needs_atomic_access = is_vol || AlwaysAtomicAccesses; + store = store_to_memory(control(), adr, val, bt, adr_type, mo, needs_atomic_access); } // If reference is volatile, prevent following volatiles ops from @@ -332,13 +334,23 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { } } + if (is_field) { + set_wrote_fields(true); + } + // If the field is final, the rules of Java say we are in or . // Note the presence of writes to final non-static fields, so that we // can insert a memory barrier later on to keep the writes from floating // out of the constructor. // Any method can write a @Stable field; insert memory barriers after those also. if (is_field && (field->is_final() || field->is_stable())) { - set_wrote_final(true); + if (field->is_final()) { + set_wrote_final(true); + } + if (field->is_stable()) { + set_wrote_stable(true); + } + // Preserve allocation ptr to create precedent edge to it in membar // generated on exit from constructor. if (C->eliminate_boxing() && diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 5003db9119a..1c95046c77b 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -4360,7 +4360,7 @@ JVM_END JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t info_size)) { - memset(info, 0, sizeof(info_size)); + memset(info, 0, info_size); info->jvm_version = Abstract_VM_Version::jvm_version(); info->update_version = 0; /* 0 in HotSpot Express VM */ diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp index 5aba54b6ca9..6dcf2e1bf95 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp @@ -1464,7 +1464,19 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) { // It's fine to update the thread state here because no JVMTI events // shall be posted for this PopFrame. - state->update_for_pop_top_frame(); + // It is only safe to perform the direct operation on the current + // thread. All other usage needs to use a vm-safepoint-op for safety. + if (java_thread == JavaThread::current()) { + state->update_for_pop_top_frame(); + } else { + VM_UpdateForPopTopFrame op(state); + VMThread::execute(&op); + jvmtiError err = op.result(); + if (err != JVMTI_ERROR_NONE) { + return err; + } + } + java_thread->set_popframe_condition(JavaThread::popframe_pending_bit); // Set pending step flag for this popframe and it is cleared when next // step event is posted. @@ -1505,6 +1517,7 @@ JvmtiEnv::GetFrameLocation(JavaThread* java_thread, jint depth, jmethodID* metho // depth - pre-checked as non-negative jvmtiError JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) { + jvmtiError err = JVMTI_ERROR_NONE; ResourceMark rm; uint32_t debug_bits = 0; @@ -1532,10 +1545,17 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) { assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL"); - int frame_number = state->count_frames() - depth; - state->env_thread_state(this)->set_frame_pop(frame_number); - - return JVMTI_ERROR_NONE; + // It is only safe to perform the direct operation on the current + // thread. All other usage needs to use a vm-safepoint-op for safety. + if (java_thread == JavaThread::current()) { + int frame_number = state->count_frames() - depth; + state->env_thread_state(this)->set_frame_pop(frame_number); + } else { + VM_SetFramePop op(this, state, depth); + VMThread::execute(&op); + err = op.result(); + } + return err; } /* end NotifyFramePop */ diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp index 0f9495945ec..f3c06c30c34 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp @@ -29,6 +29,7 @@ #include "prims/jvmtiEnvThreadState.hpp" #include "prims/jvmtiEventController.hpp" #include "prims/jvmtiThreadState.hpp" +#include "prims/jvmtiThreadState.inline.hpp" #include "runtime/fieldDescriptor.hpp" #include "runtime/frame.hpp" #include "runtime/handles.inline.hpp" @@ -334,6 +335,60 @@ class JvmtiEnvIterator : public StackObj { JvmtiEnv* next(JvmtiEnvBase* env) { return env->next_environment(); } }; +// VM operation to update for pop top frame. +class VM_UpdateForPopTopFrame : public VM_Operation { +private: + JvmtiThreadState* _state; + jvmtiError _result; + +public: + VM_UpdateForPopTopFrame(JvmtiThreadState* state) { + _state = state; + _result = JVMTI_ERROR_NONE; + } + VMOp_Type type() const { return VMOp_UpdateForPopTopFrame; } + jvmtiError result() { return _result; } + void doit() { + JavaThread* jt = _state->get_thread(); + if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) { + _state->update_for_pop_top_frame(); + } else { + _result = JVMTI_ERROR_THREAD_NOT_ALIVE; + } + } +}; + +// VM operation to set frame pop. +class VM_SetFramePop : public VM_Operation { +private: + JvmtiEnv *_env; + JvmtiThreadState* _state; + jint _depth; + jvmtiError _result; + +public: + VM_SetFramePop(JvmtiEnv *env, JvmtiThreadState* state, jint depth) { + _env = env; + _state = state; + _depth = depth; + _result = JVMTI_ERROR_NONE; + } + // Nested operation must be allowed for the VM_EnterInterpOnlyMode that is + // called from the JvmtiEventControllerPrivate::recompute_thread_enabled. + bool allow_nested_vm_operations() const { return true; } + VMOp_Type type() const { return VMOp_SetFramePop; } + jvmtiError result() { return _result; } + void doit() { + JavaThread* jt = _state->get_thread(); + if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) { + int frame_number = _state->count_frames() - _depth; + _state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number); + } else { + _result = JVMTI_ERROR_THREAD_NOT_ALIVE; + } + } +}; + // VM operation to get monitor information with stack depth. class VM_GetOwnedMonitorInfo : public VM_Operation { diff --git a/hotspot/src/share/vm/prims/jvmtiEnvThreadState.cpp b/hotspot/src/share/vm/prims/jvmtiEnvThreadState.cpp index ab3c5f445b3..3b290af1a0d 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvThreadState.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvThreadState.cpp @@ -190,12 +190,8 @@ void JvmtiEnvThreadState::compare_and_set_current_location(Method* new_method, JvmtiFramePops* JvmtiEnvThreadState::get_frame_pops() { -#ifdef ASSERT - uint32_t debug_bits = 0; -#endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); - + assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(), + "frame pop data only accessible from same thread or at safepoint"); if (_frame_pops == NULL) { _frame_pops = new JvmtiFramePops(); assert(_frame_pops != NULL, "_frame_pops != NULL"); @@ -209,44 +205,32 @@ bool JvmtiEnvThreadState::has_frame_pops() { } void JvmtiEnvThreadState::set_frame_pop(int frame_number) { -#ifdef ASSERT - uint32_t debug_bits = 0; -#endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); + assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(), + "frame pop data only accessible from same thread or at safepoint"); JvmtiFramePop fpop(frame_number); JvmtiEventController::set_frame_pop(this, fpop); } void JvmtiEnvThreadState::clear_frame_pop(int frame_number) { -#ifdef ASSERT - uint32_t debug_bits = 0; -#endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); + assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(), + "frame pop data only accessible from same thread or at safepoint"); JvmtiFramePop fpop(frame_number); JvmtiEventController::clear_frame_pop(this, fpop); } void JvmtiEnvThreadState::clear_to_frame_pop(int frame_number) { -#ifdef ASSERT - uint32_t debug_bits = 0; -#endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); + assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(), + "frame pop data only accessible from same thread or at safepoint"); JvmtiFramePop fpop(frame_number); JvmtiEventController::clear_to_frame_pop(this, fpop); } bool JvmtiEnvThreadState::is_frame_pop(int cur_frame_number) { -#ifdef ASSERT - uint32_t debug_bits = 0; -#endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); + assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(), + "frame pop data only accessible from same thread or at safepoint"); if (!get_thread()->is_interp_only_mode() || _frame_pops == NULL) { return false; } diff --git a/hotspot/src/share/vm/prims/jvmtiEventController.cpp b/hotspot/src/share/vm/prims/jvmtiEventController.cpp index 52bfb1f7632..dff9989736e 100644 --- a/hotspot/src/share/vm/prims/jvmtiEventController.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEventController.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 @@ -989,21 +989,21 @@ JvmtiEventController::set_extension_event_callback(JvmtiEnvBase *env, void JvmtiEventController::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) { - MutexLocker mu(JvmtiThreadState_lock); + MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock); JvmtiEventControllerPrivate::set_frame_pop(ets, fpop); } void JvmtiEventController::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) { - MutexLocker mu(JvmtiThreadState_lock); + MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock); JvmtiEventControllerPrivate::clear_frame_pop(ets, fpop); } void JvmtiEventController::clear_to_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) { - MutexLocker mu(JvmtiThreadState_lock); + MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock); JvmtiEventControllerPrivate::clear_to_frame_pop(ets, fpop); } diff --git a/hotspot/src/share/vm/prims/jvmtiThreadState.cpp b/hotspot/src/share/vm/prims/jvmtiThreadState.cpp index 34b5bdc8f44..42f4854bd89 100644 --- a/hotspot/src/share/vm/prims/jvmtiThreadState.cpp +++ b/hotspot/src/share/vm/prims/jvmtiThreadState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,7 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread) _vm_object_alloc_event_collector = NULL; _the_class_for_redefinition_verification = NULL; _scratch_class_for_redefinition_verification = NULL; + _cur_stack_depth = UNKNOWN_STACK_DEPTH; // JVMTI ForceEarlyReturn support _pending_step_for_earlyret = false; @@ -213,12 +214,9 @@ void JvmtiThreadState::leave_interp_only_mode() { // Helper routine used in several places int JvmtiThreadState::count_frames() { -#ifdef ASSERT - uint32_t debug_bits = 0; -#endif - assert(SafepointSynchronize::is_at_safepoint() || - JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "at safepoint or must be suspended"); + guarantee(SafepointSynchronize::is_at_safepoint() || + (JavaThread *)Thread::current() == get_thread(), + "must be current thread or at safepoint"); if (!get_thread()->has_last_Java_frame()) return 0; // no Java frames @@ -243,15 +241,9 @@ int JvmtiThreadState::count_frames() { void JvmtiThreadState::invalidate_cur_stack_depth() { - Thread *cur = Thread::current(); - uint32_t debug_bits = 0; - - // The caller can be the VMThread at a safepoint, the current thread - // or the target thread must be suspended. - guarantee((cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()) || - (JavaThread *)cur == get_thread() || - JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "sanity check"); + guarantee(SafepointSynchronize::is_at_safepoint() || + (JavaThread *)Thread::current() == get_thread(), + "must be current thread or at safepoint"); _cur_stack_depth = UNKNOWN_STACK_DEPTH; } @@ -280,10 +272,9 @@ void JvmtiThreadState::decr_cur_stack_depth() { } int JvmtiThreadState::cur_stack_depth() { - uint32_t debug_bits = 0; - guarantee(JavaThread::current() == get_thread() || - JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "must be current thread or suspended"); + guarantee(SafepointSynchronize::is_at_safepoint() || + (JavaThread *)Thread::current() == get_thread(), + "must be current thread or at safepoint"); if (!is_interp_only_mode() || _cur_stack_depth == UNKNOWN_STACK_DEPTH) { _cur_stack_depth = count_frames(); diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 1e02bf0cad8..3099df2e8ef 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1699,7 +1699,8 @@ void Arguments::set_heap_size() { // HeapBaseMinAddress can be greater than default but not less than. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { if (HeapBaseMinAddress < DefaultHeapBaseMinAddress) { - if (PrintMiscellaneous && Verbose) { // matches compressed oops printing flags + // matches compressed oops printing flags + if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) { jio_fprintf(defaultStream::error_stream(), "HeapBaseMinAddress must be at least " UINTX_FORMAT " (" UINTX_FORMAT "G) which is greater than value given " @@ -2407,9 +2408,11 @@ bool Arguments::check_vm_args_consistency() { status &= verify_interval(NmethodSweepFraction, 1, ReservedCodeCacheSize/K, "NmethodSweepFraction"); status &= verify_interval(NmethodSweepActivity, 0, 2000, "NmethodSweepActivity"); + status &= verify_interval(CodeCacheMinBlockLength, 1, 100, "CodeCacheMinBlockLength"); + status &= verify_interval(CodeCacheSegmentSize, 1, 1024, "CodeCacheSegmentSize"); // TieredCompilation needs at least 2 compiler threads. - const int num_min_compiler_threads = (TieredCompilation) ? 2 : 1; + const int num_min_compiler_threads = (TieredCompilation && (TieredStopAtLevel >= CompLevel_full_optimization)) ? 2 : 1; status &=verify_min_value(CICompilerCount, num_min_compiler_threads, "CICompilerCount"); return status; diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index b971907b980..945e8ea667e 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -535,6 +535,9 @@ class CommandLineFlags { develop(bool, CleanChunkPoolAsync, falseInEmbedded, \ "Clean the chunk pool asynchronously") \ \ + experimental(bool, AlwaysSafeConstructors, false, \ + "Force safe construction, as if all fields are final.") \ + \ /* Temporary: See 6948537 */ \ experimental(bool, UseMemSetInBOT, true, \ "(Unstable) uses memset in BOT updates in GC code") \ @@ -811,8 +814,8 @@ class CommandLineFlags { product(bool, PrintOopAddress, false, \ "Always print the location of the oop") \ \ - notproduct(bool, VerifyCodeCacheOften, false, \ - "Verify compiled-code cache often") \ + notproduct(bool, VerifyCodeCache, false, \ + "Verify code cache on memory allocation/deallocation") \ \ develop(bool, ZapDeadCompiledLocals, false, \ "Zap dead locals in compiler frames") \ @@ -2984,7 +2987,8 @@ class CommandLineFlags { "maximum number of nested recursive calls that are inlined") \ \ develop(intx, MaxForceInlineLevel, 100, \ - "maximum number of nested @ForceInline calls that are inlined") \ + "maximum number of nested calls that are forced for inlining " \ + "(using CompilerOracle or marked w/ @ForceInline)") \ \ product_pd(intx, InlineSmallCode, \ "Only inline already compiled methods if their code size is " \ @@ -3292,8 +3296,8 @@ class CommandLineFlags { "disable this feature") \ \ /* code cache parameters */ \ - /* ppc64 has large code-entry alignment. */ \ - develop(uintx, CodeCacheSegmentSize, 64 PPC64_ONLY(+64), \ + /* ppc64/tiered compilation has large code-entry alignment. */ \ + develop(uintx, CodeCacheSegmentSize, 64 PPC64_ONLY(+64) NOT_PPC64(TIERED_ONLY(+64)),\ "Code cache segment size (in bytes) - smallest unit of " \ "allocation") \ \ @@ -3795,8 +3799,8 @@ class CommandLineFlags { experimental(bool, TrustFinalNonStaticFields, false, \ "trust final non-static declarations for constant folding") \ \ - experimental(bool, FoldStableValues, false, \ - "Private flag to control optimizations for stable variables") \ + diagnostic(bool, FoldStableValues, true, \ + "Optimize loads from stable fields (marked w/ @Stable)") \ \ develop(bool, TraceInvokeDynamic, false, \ "trace internal invoke dynamic operations") \ @@ -3864,6 +3868,9 @@ class CommandLineFlags { "Allocation less than this value will be allocated " \ "using malloc. Larger allocations will use mmap.") \ \ + experimental(bool, AlwaysAtomicAccesses, false, \ + "Accesses to all variables should always be atomic") \ + \ product(bool, EnableTracing, false, \ "Enable event-based tracing") \ \ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index d0fb67715ae..bd794da4524 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -910,7 +910,7 @@ void Thread::check_for_valid_safepoint_state(bool potential_vm_operation) { cur != VMOperationRequest_lock && cur != VMOperationQueue_lock) || cur->rank() == Mutex::special) { - warning("Thread holding lock at safepoint that vm can block on: %s", cur->name()); + fatal(err_msg("Thread holding lock at safepoint that vm can block on: %s", cur->name())); } } } diff --git a/hotspot/src/share/vm/runtime/timer.cpp b/hotspot/src/share/vm/runtime/timer.cpp index ccb3322cedd..e33a51cfb97 100644 --- a/hotspot/src/share/vm/runtime/timer.cpp +++ b/hotspot/src/share/vm/runtime/timer.cpp @@ -194,7 +194,7 @@ TraceCPUTime::~TraceCPUTime() { system_secs = system_time - _starting_system_time; real_secs = real_time - _starting_real_time; - _logfile->print(" [Times: user=%3.2f sys=%3.2f, real=%3.2f secs] ", + _logfile->print(" [Times: user=%3.2f sys=%3.2f real=%3.2f secs] ", user_secs, system_secs, real_secs); } else { diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 7044dc9b2b7..2475de0480a 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -2336,6 +2336,12 @@ typedef TwoOopHashtable SymbolTwoOopHashtable; /* ConstMethod anon-enum */ \ /********************************/ \ \ + declare_constant(Method::_jfr_towrite) \ + declare_constant(Method::_caller_sensitive) \ + declare_constant(Method::_force_inline) \ + declare_constant(Method::_dont_inline) \ + declare_constant(Method::_hidden) \ + \ declare_constant(ConstMethod::_has_linenumber_table) \ declare_constant(ConstMethod::_has_checked_exceptions) \ declare_constant(ConstMethod::_has_localvariable_table) \ diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 005fc11780b..a3a58e4d4c3 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.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 @@ -74,6 +74,8 @@ template(PopulateDumpSharedSpace) \ template(JNIFunctionTableCopier) \ template(RedefineClasses) \ + template(UpdateForPopTopFrame) \ + template(SetFramePop) \ template(GetOwnedMonitorInfo) \ template(GetObjectMonitorUsage) \ template(GetCurrentContendedMonitor) \ diff --git a/hotspot/src/share/vm/shark/llvmHeaders.hpp b/hotspot/src/share/vm/shark/llvmHeaders.hpp index 1f2c2c79778..05ef7fea1d3 100644 --- a/hotspot/src/share/vm/shark/llvmHeaders.hpp +++ b/hotspot/src/share/vm/shark/llvmHeaders.hpp @@ -36,21 +36,43 @@ #endif #include +#include + +// includes specific to each version +#if SHARK_LLVM_VERSION <= 31 +#include +#include #include #include #include -#include #include #include #include -#if SHARK_LLVM_VERSION <= 31 -#include -#else +#elif SHARK_LLVM_VERSION <= 32 #include +#include +#include +#include +#include +#include +#include +#include +#else // SHARK_LLVM_VERSION <= 34 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif + +// common includes #include #include -#include #include #include #include diff --git a/hotspot/src/share/vm/shark/sharkCompiler.cpp b/hotspot/src/share/vm/shark/sharkCompiler.cpp index 17fdcfcbbe3..fe62efdecbd 100644 --- a/hotspot/src/share/vm/shark/sharkCompiler.cpp +++ b/hotspot/src/share/vm/shark/sharkCompiler.cpp @@ -364,3 +364,7 @@ const char* SharkCompiler::methodname(const char* klass, const char* method) { *(dst++) = '\0'; return buf; } + +void SharkCompiler::print_timers() { + // do nothing +} diff --git a/hotspot/src/share/vm/shark/sharkCompiler.hpp b/hotspot/src/share/vm/shark/sharkCompiler.hpp index 97400298865..1b8681771a0 100644 --- a/hotspot/src/share/vm/shark/sharkCompiler.hpp +++ b/hotspot/src/share/vm/shark/sharkCompiler.hpp @@ -56,6 +56,9 @@ class SharkCompiler : public AbstractCompiler { // Compile a normal (bytecode) method and install it in the VM void compile_method(ciEnv* env, ciMethod* target, int entry_bci); + // Print compilation timers and statistics + void print_timers(); + // Generate a wrapper for a native (JNI) method nmethod* generate_native_wrapper(MacroAssembler* masm, methodHandle target, diff --git a/hotspot/src/share/vm/shark/sharkInliner.cpp b/hotspot/src/share/vm/shark/sharkInliner.cpp index 76b63a16342..47465848d7d 100644 --- a/hotspot/src/share/vm/shark/sharkInliner.cpp +++ b/hotspot/src/share/vm/shark/sharkInliner.cpp @@ -744,6 +744,10 @@ bool SharkInlinerHelper::do_field_access(bool is_get, bool is_field) { } bool SharkInliner::attempt_inline(ciMethod *target, SharkState *state) { + if (!Inline) { + return false; + } + if (SharkIntrinsics::is_intrinsic(target)) { SharkIntrinsics::inline_intrinsic(target, state); return true; diff --git a/hotspot/src/share/vm/shark/sharkMemoryManager.cpp b/hotspot/src/share/vm/shark/sharkMemoryManager.cpp index 20cb0e5ebfe..d986ae8868b 100644 --- a/hotspot/src/share/vm/shark/sharkMemoryManager.cpp +++ b/hotspot/src/share/vm/shark/sharkMemoryManager.cpp @@ -59,18 +59,6 @@ void SharkMemoryManager::endFunctionBody(const Function* F, entry->set_code_limit(FunctionEnd); } -unsigned char* SharkMemoryManager::startExceptionTable(const Function* F, - uintptr_t& ActualSize) { - return mm()->startExceptionTable(F, ActualSize); -} - -void SharkMemoryManager::endExceptionTable(const Function* F, - unsigned char* TableStart, - unsigned char* TableEnd, - unsigned char* FrameRegister) { - mm()->endExceptionTable(F, TableStart, TableEnd, FrameRegister); -} - void SharkMemoryManager::setMemoryWritable() { mm()->setMemoryWritable(); } @@ -79,10 +67,6 @@ void SharkMemoryManager::setMemoryExecutable() { mm()->setMemoryExecutable(); } -void SharkMemoryManager::deallocateExceptionTable(void *ptr) { - mm()->deallocateExceptionTable(ptr); -} - void SharkMemoryManager::deallocateFunctionBody(void *ptr) { mm()->deallocateFunctionBody(ptr); } @@ -96,14 +80,6 @@ void* SharkMemoryManager::getPointerToNamedFunction(const std::string &Name, boo return mm()->getPointerToNamedFunction(Name, AbortOnFailure); } -uint8_t* SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { - return mm()->allocateCodeSection(Size, Alignment, SectionID); -} - -uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { - return mm()->allocateDataSection(Size, Alignment, SectionID); -} - void SharkMemoryManager::setPoisonMemory(bool poison) { mm()->setPoisonMemory(poison); } @@ -112,3 +88,45 @@ unsigned char *SharkMemoryManager::allocateSpace(intptr_t Size, unsigned int Alignment) { return mm()->allocateSpace(Size, Alignment); } + +#if SHARK_LLVM_VERSION <= 32 + +uint8_t* SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { + return mm()->allocateCodeSection(Size, Alignment, SectionID); +} + +uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { + return mm()->allocateDataSection(Size, Alignment, SectionID); +} + +void SharkMemoryManager::deallocateExceptionTable(void *ptr) { + mm()->deallocateExceptionTable(ptr); +} + +unsigned char* SharkMemoryManager::startExceptionTable(const Function* F, + uintptr_t& ActualSize) { + return mm()->startExceptionTable(F, ActualSize); +} + +void SharkMemoryManager::endExceptionTable(const Function* F, + unsigned char* TableStart, + unsigned char* TableEnd, + unsigned char* FrameRegister) { + mm()->endExceptionTable(F, TableStart, TableEnd, FrameRegister); +} + +#else + +uint8_t *SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) { + return mm()->allocateCodeSection(Size, Alignment, SectionID, SectionName); +} + +uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, bool IsReadOnly) { + return mm()->allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly); +} + +bool SharkMemoryManager::finalizeMemory(std::string *ErrMsg) { + return mm()->finalizeMemory(ErrMsg); +} + +#endif diff --git a/hotspot/src/share/vm/shark/sharkMemoryManager.hpp b/hotspot/src/share/vm/shark/sharkMemoryManager.hpp index fa725a14502..7a5ad7b3e1c 100644 --- a/hotspot/src/share/vm/shark/sharkMemoryManager.hpp +++ b/hotspot/src/share/vm/shark/sharkMemoryManager.hpp @@ -69,23 +69,32 @@ class SharkMemoryManager : public llvm::JITMemoryManager { void endFunctionBody(const llvm::Function* F, unsigned char* FunctionStart, unsigned char* FunctionEnd); - unsigned char* startExceptionTable(const llvm::Function* F, - uintptr_t& ActualSize); - void endExceptionTable(const llvm::Function* F, - unsigned char* TableStart, - unsigned char* TableEnd, - unsigned char* FrameRegister); + void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true); - uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID); - uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID); void setPoisonMemory(bool); uint8_t* allocateGlobal(uintptr_t, unsigned int); void setMemoryWritable(); void setMemoryExecutable(); - void deallocateExceptionTable(void *ptr); void deallocateFunctionBody(void *ptr); unsigned char *allocateSpace(intptr_t Size, unsigned int Alignment); + +#if SHARK_LLVM_VERSION <= 32 +uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID); +uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID); +unsigned char* startExceptionTable(const llvm::Function* F, + uintptr_t& ActualSize); +void deallocateExceptionTable(void *ptr); +void endExceptionTable(const llvm::Function* F, + unsigned char* TableStart, + unsigned char* TableEnd, + unsigned char* FrameRegister); +#else +uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName); +uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName, bool IsReadOnly); +bool finalizeMemory(std::string *ErrMsg = 0); +#endif + }; #endif // SHARE_VM_SHARK_SHARKMEMORYMANAGER_HPP diff --git a/hotspot/src/share/vm/utilities/elfFile.cpp b/hotspot/src/share/vm/utilities/elfFile.cpp index 371a036406c..3d895956315 100644 --- a/hotspot/src/share/vm/utilities/elfFile.cpp +++ b/hotspot/src/share/vm/utilities/elfFile.cpp @@ -140,7 +140,7 @@ bool ElfFile::load_tables() { } } -#if defined(PPC64) +#if defined(PPC64) && !defined(ABI_ELFv2) // Now read the .opd section wich contains the PPC64 function descriptor table. // The .opd section is only available on PPC64 (see for example: // http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html) diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp index a850ebe87f4..8698cca914a 100644 --- a/hotspot/src/share/vm/utilities/hashtable.cpp +++ b/hotspot/src/share/vm/utilities/hashtable.cpp @@ -25,7 +25,6 @@ #include "precompiled.hpp" #include "classfile/altHashing.hpp" #include "classfile/javaClasses.hpp" -#include "code/dependencies.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "memory/resourceArea.hpp" @@ -353,116 +352,6 @@ template void BasicHashtable::verify_lookup_length(double load) #endif -template GenericHashtable::GenericHashtable(int size, bool C_heap, MEMFLAGS memflag) { - assert(size > 0, " Invalid hashtable size"); - _size = size; - _C_heap = C_heap; - _memflag = memflag; - // Perform subtype-specific resource allocation - _items = (C_heap) ? NEW_C_HEAP_ARRAY(T*, size, memflag) : NEW_RESOURCE_ARRAY(T*, size); - memset(_items, 0, sizeof(T*) * size); - - DEBUG_ONLY(_num_items = 0;) -} - -template GenericHashtable::~GenericHashtable() { - if (on_C_heap()) { - // Check backing array - for (int i = 0; i < size(); i++) { - T* item = head(i); - // Delete all items in linked list - while (item != NULL) { - T* next_item = item->next(); - delete item; - DEBUG_ONLY(_num_items--); - item = next_item; - } - } - FREE_C_HEAP_ARRAY(T*, _items, _memflag); - _items = NULL; - assert (_num_items == 0, "Not all memory released"); - } -} - -/** - * Return a pointer to the item 'I' that is stored in the hashtable for - * which match_item->equals(I) == true. If no such item is found, NULL - * is returned. - */ -template T* GenericHashtable::contains(T* match_item) { - if (match_item != NULL) { - int idx = index(match_item); - return contains_impl(match_item, idx); - } - return NULL; -} - -/** - * Add item to the hashtable. Return 'true' if the item was added - * and false otherwise. - */ -template bool GenericHashtable::add(T* item) { - if (item != NULL) { - int idx = index(item); - T* found_item = contains_impl(item, idx); - if (found_item == NULL) { - T* list_head = head(idx); - item->set_next(list_head); - item->set_prev(NULL); - - if (list_head != NULL) { - list_head->set_prev(item); - } - set_head(item, idx); - DEBUG_ONLY(_num_items++); - return true; - } - } - return false; -} - -/** - * Removes an item 'I' from the hashtable, if present. 'I' is removed, if - * match_item->equals(I) == true. Removing an item from the hashtable does - * not free memory. - */ -template T* GenericHashtable::remove(T* match_item) { - if (match_item != NULL) { - int idx = index(match_item); - T* found_item = contains_impl(match_item, idx); - if (found_item != NULL) { - // Remove item from linked list - T* prev = found_item->prev(); - T* next = found_item->next(); - if (prev != NULL) { - prev->set_next(next); - } else { - set_head(next, idx); - } - if (next != NULL) { - next->set_prev(prev); - } - - DEBUG_ONLY(_num_items--); - return found_item; - } - } - return NULL; -} - - -template T* GenericHashtable::contains_impl(T* item, int idx) { - T* current_item = head(idx); - while (current_item != NULL) { - if (current_item->equals(item)) { - return current_item; - } - current_item = current_item->next(); - } - return NULL; -} - - // Explicitly instantiate these types template class Hashtable; template class Hashtable; @@ -482,5 +371,3 @@ template class BasicHashtable; template class BasicHashtable; template class BasicHashtable; template class BasicHashtable; - -template class GenericHashtable; diff --git a/hotspot/src/share/vm/utilities/hashtable.hpp b/hotspot/src/share/vm/utilities/hashtable.hpp index 8294eaab3d2..fcebf72ea95 100644 --- a/hotspot/src/share/vm/utilities/hashtable.hpp +++ b/hotspot/src/share/vm/utilities/hashtable.hpp @@ -327,86 +327,4 @@ public: } }; - -/* - * Usage of GenericHashtable: - * - * class X : public GenericHashtableEntry { - * - * // Implement virtual functions in class X - * bool equals(X* sig) const; - * uintptr_t hash() const; - * }; - * - * void foo() { - * GenericHashtable* table = new GenericHashtable(11027, false); - * - * X* elem = new X(); - * table->add(elem); - * table->contains(elem); - * } - * - * You can choose other allocation types as well. For example, to store the hashtable to a - * particular region (CHeapObj) simply replace ResourceObj with the desired type: - * - * class X : public GenericHashtableEntry > { ... }; - * - * To make the destructor (and remove) of the hashtable work: - * 1) override the delete operator of X - * 2) provide a destructor of the X - * - * You may also find it convenient to override the new operator. - * - * If you use this templates do not forget to add an explicit initialization - * (at the end of hashtable.cpp). - * - * template class GenericHashtable; - */ -template class GenericHashtableEntry : public M { - private: - T* _next; - T* _prev; - public: - // Must be implemented by subclass. - virtual uintptr_t key() const = 0; - virtual bool equals(T* other) const = 0; - - T* next() const { return _next; } - T* prev() const { return _prev; } - void set_next(T* item) { _next = item; } - void set_prev(T* item) { _prev = item; } - - // Constructor and destructor - GenericHashtableEntry() : _next(NULL), _prev(NULL) { }; - virtual ~GenericHashtableEntry() {}; -}; - -template class GenericHashtable : public M { - private: - T** _items; - int _size; - bool _C_heap; - MEMFLAGS _memflag; - - // Accessor methods - T* head (int idx) const { return _items[idx]; } - void set_head(T* item, int idx) { _items[idx] = item; } - int index (T* item) { assert(item != NULL, "missing null check"); return item->key() % size(); } - - // Helper function - T* contains_impl(T* item, int idx); - - DEBUG_ONLY(int _num_items;) - public: - GenericHashtable(int size, bool C_heap = false, MEMFLAGS memflag = mtNone); - ~GenericHashtable(); - T* contains(T* match_item); - T* remove (T* match_item); - bool add (T* item); - - - bool on_C_heap() const { return _C_heap; } - int size() const { return _size; } -}; - #endif // SHARE_VM_UTILITIES_HASHTABLE_HPP diff --git a/hotspot/src/share/vm/utilities/resourceHash.hpp b/hotspot/src/share/vm/utilities/resourceHash.hpp index 2fe5dec941a..211d6bca117 100644 --- a/hotspot/src/share/vm/utilities/resourceHash.hpp +++ b/hotspot/src/share/vm/utilities/resourceHash.hpp @@ -105,14 +105,20 @@ class ResourceHashtable : public ResourceObj { } } - // Inserts or replaces a value in the table - void put(K const& key, V const& value) { + /** + * Inserts or replaces a value in the table. + * @return: true: if a new item is added + * false: if the item already existed and the value is updated + */ + bool put(K const& key, V const& value) { unsigned hv = HASH(key); Node** ptr = lookup_node(hv, key); if (*ptr != NULL) { (*ptr)->_value = value; + return false; } else { *ptr = new Node(hv, key, value); + return true; } } diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index 4b0953ae499..e950d338681 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -592,13 +592,24 @@ void VMError::report(outputStream* st) { st->cr(); // Compiled code may use EBP register on x86 so it looks like // non-walkable C frame. Use frame.sender() for java frames. - if (_thread && _thread->is_Java_thread() && fr.is_java_frame()) { - RegisterMap map((JavaThread*)_thread, false); // No update - fr = fr.sender(&map); - continue; + if (_thread && _thread->is_Java_thread()) { + // Catch very first native frame by using stack address. + // For JavaThread stack_base and stack_size should be set. + if (!_thread->on_local_stack((address)(fr.sender_sp() + 1))) { + break; + } + if (fr.is_java_frame()) { + RegisterMap map((JavaThread*)_thread, false); // No update + fr = fr.sender(&map); + } else { + fr = os::get_sender_for_C_frame(&fr); + } + } else { + // is_first_C_frame() does only simple checks for frame pointer, + // it will pass if java compiled code has a pointer in EBP. + if (os::is_first_C_frame(&fr)) break; + fr = os::get_sender_for_C_frame(&fr); } - if (os::is_first_C_frame(&fr)) break; - fr = os::get_sender_for_C_frame(&fr); } if (count > StackPrintLimit) { diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index 946cb2be8cf..676d859686d 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -130,7 +130,9 @@ needs_compact3 = \ gc/arguments/TestG1HeapRegionSize.java \ gc/metaspace/TestMetaspaceMemoryPool.java \ runtime/InternalApi/ThreadCpuTimesDeadlock.java \ - serviceability/threads/TestFalseDeadLock.java + serviceability/threads/TestFalseDeadLock.java \ + compiler/tiered/NonTieredLevelsTest.java \ + compiler/tiered/TieredLevelsTest.java # Compact 2 adds full VM tests compact2 = \ diff --git a/hotspot/test/compiler/ciReplay/TestVM.sh b/hotspot/test/compiler/ciReplay/TestVM.sh index e6c3cc56946..6154466671d 100644 --- a/hotspot/test/compiler/ciReplay/TestVM.sh +++ b/hotspot/test/compiler/ciReplay/TestVM.sh @@ -78,8 +78,8 @@ then positive_test `expr $stop_level + 50` "TIERED LEVEL $stop_level :: REPLAY" \ "-XX:TieredStopAtLevel=$stop_level" stop_level=`expr $stop_level + 1` + cleanup done - cleanup fi echo TEST PASSED diff --git a/hotspot/test/compiler/ciReplay/common.sh b/hotspot/test/compiler/ciReplay/common.sh index e03acaa8b30..608f68e551a 100644 --- a/hotspot/test/compiler/ciReplay/common.sh +++ b/hotspot/test/compiler/ciReplay/common.sh @@ -99,13 +99,12 @@ common_tests() { # $2 - non-tiered comp_level nontiered_tests() { level=`grep "^compile " $replay_data | awk '{print $6}'` - # is level available in non-tiere + # is level available in non-tiered if [ "$level" -eq $2 ] then positive_test $1 "NON-TIERED :: AVAILABLE COMP_LEVEL" \ -XX:-TieredCompilation else - negative_test `expr $1 + 1` "NON-TIERED :: UNAVAILABLE COMP_LEVEL" \ negative_test `expr $1 + 1` "NON-TIERED :: UNAVAILABLE COMP_LEVEL" \ -XX:-TieredCompilation fi diff --git a/hotspot/test/compiler/codegen/BMI1.java b/hotspot/test/compiler/codegen/BMI1.java new file mode 100644 index 00000000000..ada9cf06c34 --- /dev/null +++ b/hotspot/test/compiler/codegen/BMI1.java @@ -0,0 +1,301 @@ +/* + * 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 Support BMI1 instructions on x86/x64 + * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:CompileCommand=compileonly,BMITests.* BMI1 + * + */ + +class MemI { + public int x; + public MemI(int x) { this.x = x; } +} + +class MemL { + public long x; + public MemL(long x) { this.x = x; } +} + +class BMITests { + static int andnl(int src1, int src2) { + return ~src1 & src2; + } + static long andnq(long src1, long src2) { + return ~src1 & src2; + } + static int andnl(int src1, MemI src2) { + return ~src1 & src2.x; + } + static long andnq(long src1, MemL src2) { + return ~src1 & src2.x; + } + static int blsil(int src1) { + return src1 & -src1; + } + static long blsiq(long src1) { + return src1 & -src1; + } + static int blsil(MemI src1) { + return src1.x & -src1.x; + } + static long blsiq(MemL src1) { + return src1.x & -src1.x; + } + static int blsmskl(int src1) { + return (src1 - 1) ^ src1; + } + static long blsmskq(long src1) { + return (src1 - 1) ^ src1; + } + static int blsmskl(MemI src1) { + return (src1.x - 1) ^ src1.x; + } + static long blsmskq(MemL src1) { + return (src1.x - 1) ^ src1.x; + } + static int blsrl(int src1) { + return (src1 - 1) & src1; + } + static long blsrq(long src1) { + return (src1 - 1) & src1; + } + static int blsrl(MemI src1) { + return (src1.x - 1) & src1.x; + } + static long blsrq(MemL src1) { + return (src1.x - 1) & src1.x; + } + static int lzcntl(int src1) { + return Integer.numberOfLeadingZeros(src1); + } + static int lzcntq(long src1) { + return Long.numberOfLeadingZeros(src1); + } + static int tzcntl(int src1) { + return Integer.numberOfTrailingZeros(src1); + } + static int tzcntq(long src1) { + return Long.numberOfTrailingZeros(src1); + } +} + +public class BMI1 { + private final static int ITERATIONS = 1000000; + + public static void main(String[] args) { + int ix = 0x01234567; + int iy = 0x89abcdef; + MemI imy = new MemI(iy); + long lx = 0x0123456701234567L; + long ly = 0x89abcdef89abcdefL; + MemL lmy = new MemL(ly); + + { // match(Set dst (AndI (XorI src1 minus_1) src2)) + int z = BMITests.andnl(ix, iy); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.andnl(ix, iy); + if (ii != z) { + throw new Error("andnl with register failed"); + } + } + } + { // match(Set dst (AndL (XorL src1 minus_1) src2)) + long z = BMITests.andnq(lx, ly); + for (int i = 0; i < ITERATIONS; i++) { + long ll = BMITests.andnq(lx, ly); + if (ll != z) { + throw new Error("andnq with register failed"); + } + } + } + { // match(Set dst (AndI (XorI src1 minus_1) (LoadI src2))) + int z = BMITests.andnl(ix, imy); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.andnl(ix, imy); + if (ii != z) { + throw new Error("andnl with memory failed"); + } + } + } + { // match(Set dst (AndL (XorL src1 minus_1) (LoadL src2))) + long z = BMITests.andnq(lx, lmy); + for (int i = 0; i < ITERATIONS; i++) { + long ll = BMITests.andnq(lx, lmy); + if (ll != z) { + throw new Error("andnq with memory failed"); + } + } + } + { // match(Set dst (AndI (SubI imm_zero src) src)) + int z = BMITests.blsil(ix); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.blsil(ix); + if (ii != z) { + throw new Error("blsil with register failed"); + } + } + } + { // match(Set dst (AndL (SubL imm_zero src) src)) + long z = BMITests.blsiq(lx); + for (int i = 0; i < ITERATIONS; i++) { + long ll = BMITests.blsiq(lx); + if (ll != z) { + throw new Error("blsiq with register failed"); + } + } + } + { // match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) )) + int z = BMITests.blsil(imy); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.blsil(imy); + if (ii != z) { + throw new Error("blsil with memory failed"); + } + } + } + { // match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) )) + long z = BMITests.blsiq(lmy); + for (int i = 0; i < ITERATIONS; i++) { + long ll = BMITests.blsiq(lmy); + if (ll != z) { + throw new Error("blsiq with memory failed"); + } + } + } + + { // match(Set dst (XorI (AddI src minus_1) src)) + int z = BMITests.blsmskl(ix); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.blsmskl(ix); + if (ii != z) { + throw new Error("blsmskl with register failed"); + } + } + } + { // match(Set dst (XorL (AddL src minus_1) src)) + long z = BMITests.blsmskq(lx); + for (int i = 0; i < ITERATIONS; i++) { + long ll = BMITests.blsmskq(lx); + if (ll != z) { + throw new Error("blsmskq with register failed"); + } + } + } + { // match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) ) + int z = BMITests.blsmskl(imy); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.blsmskl(imy); + if (ii != z) { + throw new Error("blsmskl with memory failed"); + } + } + } + { // match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) ) + long z = BMITests.blsmskq(lmy); + for (int i = 0; i < ITERATIONS; i++) { + long ll = BMITests.blsmskq(lmy); + if (ll != z) { + throw new Error("blsmskq with memory failed"); + } + } + } + + { // match(Set dst (AndI (AddI src minus_1) src) ) + int z = BMITests.blsrl(ix); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.blsrl(ix); + if (ii != z) { + throw new Error("blsrl with register failed"); + } + } + } + { // match(Set dst (AndL (AddL src minus_1) src) ) + long z = BMITests.blsrq(lx); + for (int i = 0; i < ITERATIONS; i++) { + long ll = BMITests.blsrq(lx); + if (ll != z) { + throw new Error("blsrq with register failed"); + } + } + } + { // match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) ) + int z = BMITests.blsrl(imy); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.blsrl(imy); + if (ii != z) { + throw new Error("blsrl with memory failed"); + } + } + } + { // match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) ) + long z = BMITests.blsrq(lmy); + for (int i = 0; i < ITERATIONS; i++) { + long ll = BMITests.blsrq(lmy); + if (ll != z) { + throw new Error("blsrq with memory failed"); + } + } + } + + { + int z = BMITests.lzcntl(ix); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.lzcntl(ix); + if (ii != z) { + throw new Error("lzcntl failed"); + } + } + } + { + int z = BMITests.lzcntq(lx); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.lzcntq(lx); + if (ii != z) { + throw new Error("lzcntq failed"); + } + } + } + + { + int z = BMITests.tzcntl(ix); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.tzcntl(ix); + if (ii != z) { + throw new Error("tzcntl failed"); + } + } + } + { + int z = BMITests.tzcntq(lx); + for (int i = 0; i < ITERATIONS; i++) { + int ii = BMITests.tzcntq(lx); + if (ii != z) { + throw new Error("tzcntq failed"); + } + } + } + } +} diff --git a/langtools/test/tools/javac/foreach/T6682380.java b/hotspot/test/compiler/inlining/InlineDefaultMethod1.java similarity index 54% rename from langtools/test/tools/javac/foreach/T6682380.java rename to hotspot/test/compiler/inlining/InlineDefaultMethod1.java index 7c3eb84074a..d0cadb8fe4e 100644 --- a/langtools/test/tools/javac/foreach/T6682380.java +++ b/hotspot/test/compiler/inlining/InlineDefaultMethod1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 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,23 +23,36 @@ /* * @test - * @bug 6682380 6679509 - * @summary Foreach loop with generics inside finally block crashes javac with -target 1.5 - * @author Jan Lahoda, Maurizio Cimadamore - * @compile -source 1.5 -target 1.5 T6682380.java + * @bug 8036100 + * @summary Default method returns true for a while, and then returns false + * @run main/othervm -Xcomp -XX:CompileOnly=InlineDefaultMethod1::test + * -XX:CompileOnly=I1::m -XX:CompileOnly=I2::m + * InlineDefaultMethod1 */ +interface I1 { + default public int m() { return 0; } +} -import java.util.List; +interface I2 extends I1 { + default public int m() { return 1; } +} -public class T6682380 { +abstract class A implements I1 { +} - public static void main(String[] args) { - try { - } finally { - List> l = null; - T6682380[] a = null; - for (T6682380 e1 : l); - for (T6682380 e2 : a); +class B extends A implements I2 { +} + +public class InlineDefaultMethod1 { + public static void test(A obj) { + int id = obj.m(); + if (id != 1) { + throw new AssertionError("Called wrong method: 1 != "+id); } } + + public static void main(String[] args) throws InterruptedException { + test(new B()); + System.out.println("TEST PASSED"); + } } diff --git a/hotspot/test/compiler/membars/DekkerTest.java b/hotspot/test/compiler/membars/DekkerTest.java index ed313576010..f4f2826b6e4 100644 --- a/hotspot/test/compiler/membars/DekkerTest.java +++ b/hotspot/test/compiler/membars/DekkerTest.java @@ -25,9 +25,9 @@ * @test * @bug 8007898 * @summary Incorrect optimization of Memory Barriers in Matcher::post_store_load_barrier(). - * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest - * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest - * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest * @author Martin Doerr martin DOT doerr AT sap DOT com * * Run 3 times since the failure is intermittent. diff --git a/hotspot/test/compiler/stable/TestStableBoolean.java b/hotspot/test/compiler/stable/TestStableBoolean.java new file mode 100644 index 00000000000..37f42875022 --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableBoolean.java @@ -0,0 +1,627 @@ +/* + * 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. + */ + +/* + * @test TestStableBoolean + * @summary tests on stable fields and arrays + * @library /testlibrary + * @compile -XDignore.symbol.file TestStableBoolean.java + * @run main ClassFileInstaller + * java/lang/invoke/TestStableBoolean + * java/lang/invoke/TestStableBoolean$BooleanStable + * java/lang/invoke/TestStableBoolean$StaticBooleanStable + * java/lang/invoke/TestStableBoolean$VolatileBooleanStable + * java/lang/invoke/TestStableBoolean$BooleanArrayDim1 + * java/lang/invoke/TestStableBoolean$BooleanArrayDim2 + * java/lang/invoke/TestStableBoolean$BooleanArrayDim3 + * java/lang/invoke/TestStableBoolean$BooleanArrayDim4 + * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim0 + * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim1 + * java/lang/invoke/TestStableBoolean$NestedStableField + * java/lang/invoke/TestStableBoolean$NestedStableField$A + * java/lang/invoke/TestStableBoolean$NestedStableField1 + * java/lang/invoke/TestStableBoolean$NestedStableField1$A + * java/lang/invoke/TestStableBoolean$NestedStableField2 + * java/lang/invoke/TestStableBoolean$NestedStableField2$A + * java/lang/invoke/TestStableBoolean$NestedStableField3 + * java/lang/invoke/TestStableBoolean$NestedStableField3$A + * java/lang/invoke/TestStableBoolean$DefaultValue + * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim2 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableBoolean + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableBoolean + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableBoolean + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableBoolean + */ +package java.lang.invoke; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import sun.management.ManagementFactoryHelper; +import java.lang.reflect.InvocationTargetException; + +public class TestStableBoolean { + public static void main(String[] args) throws Exception { + System.out.println("@Stable enabled: "+isStableEnabled); + System.out.println(); + + run(DefaultValue.class); + run(BooleanStable.class); + run(StaticBooleanStable.class); + run(VolatileBooleanStable.class); + + // @Stable arrays: Dim 1-4 + run(BooleanArrayDim1.class); + run(BooleanArrayDim2.class); + run(BooleanArrayDim3.class); + run(BooleanArrayDim4.class); + + // @Stable Object field: dynamic arrays + run(ObjectArrayLowerDim0.class); + run(ObjectArrayLowerDim1.class); + run(ObjectArrayLowerDim2.class); + + // Nested @Stable fields + run(NestedStableField.class); + run(NestedStableField1.class); + run(NestedStableField2.class); + run(NestedStableField3.class); + + if (failed) { + throw new Error("TEST FAILED"); + } + } + + /* ==================================================== */ + + static class DefaultValue { + public @Stable boolean v; + + public static final DefaultValue c = new DefaultValue(); + public static boolean get() { return c.v; } + public static void test() throws Exception { + boolean val1 = get(); + c.v = true; boolean val2 = get(); + assertEquals(val1, false); + assertEquals(val2, true); + } + } + + /* ==================================================== */ + + static class BooleanStable { + public @Stable boolean v; + + public static final BooleanStable c = new BooleanStable(); + public static boolean get() { return c.v; } + public static void test() throws Exception { + c.v = true; boolean val1 = get(); + c.v = false; boolean val2 = get(); + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + } + } + + /* ==================================================== */ + + static class StaticBooleanStable { + public static @Stable boolean v; + + public static final StaticBooleanStable c = new StaticBooleanStable(); + public static boolean get() { return c.v; } + public static void test() throws Exception { + c.v = true; boolean val1 = get(); + c.v = false; boolean val2 = get(); + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + } + } + + /* ==================================================== */ + + static class VolatileBooleanStable { + public @Stable volatile boolean v; + + public static final VolatileBooleanStable c = new VolatileBooleanStable(); + public static boolean get() { return c.v; } + public static void test() throws Exception { + c.v = true; boolean val1 = get(); + c.v = false; boolean val2 = get(); + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + } + } + + /* ==================================================== */ + // @Stable array == field && all components are stable + + static class BooleanArrayDim1 { + public @Stable boolean[] v; + + public static final BooleanArrayDim1 c = new BooleanArrayDim1(); + public static boolean get() { return c.v[0]; } + public static boolean get1() { return c.v[10]; } + public static boolean[] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new boolean[1]; c.v[0] = true; boolean val1 = get(); + c.v[0] = false; boolean val2 = get(); + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + } + + { + c.v = new boolean[20]; c.v[10] = true; boolean val1 = get1(); + c.v[10] = false; boolean val2 = get1(); + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + } + + { + c.v = new boolean[1]; boolean[] val1 = get2(); + c.v = new boolean[1]; boolean[] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class BooleanArrayDim2 { + public @Stable boolean[][] v; + + public static final BooleanArrayDim2 c = new BooleanArrayDim2(); + public static boolean get() { return c.v[0][0]; } + public static boolean[] get1() { return c.v[0]; } + public static boolean[][] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new boolean[1][1]; c.v[0][0] = true; boolean val1 = get(); + c.v[0][0] = false; boolean val2 = get(); + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + + c.v = new boolean[1][1]; c.v[0][0] = false; boolean val3 = get(); + assertEquals(val3, (isStableEnabled ? true : false)); + + c.v[0] = new boolean[1]; c.v[0][0] = false; boolean val4 = get(); + assertEquals(val4, (isStableEnabled ? true : false)); + } + + { + c.v = new boolean[1][1]; boolean[] val1 = get1(); + c.v[0] = new boolean[1]; boolean[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new boolean[1][1]; boolean[][] val1 = get2(); + c.v = new boolean[1][1]; boolean[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class BooleanArrayDim3 { + public @Stable boolean[][][] v; + + public static final BooleanArrayDim3 c = new BooleanArrayDim3(); + public static boolean get() { return c.v[0][0][0]; } + public static boolean[] get1() { return c.v[0][0]; } + public static boolean[][] get2() { return c.v[0]; } + public static boolean[][][] get3() { return c.v; } + public static void test() throws Exception { + { + c.v = new boolean[1][1][1]; c.v[0][0][0] = true; boolean val1 = get(); + c.v[0][0][0] = false; boolean val2 = get(); + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + + c.v = new boolean[1][1][1]; c.v[0][0][0] = false; boolean val3 = get(); + assertEquals(val3, (isStableEnabled ? true : false)); + + c.v[0] = new boolean[1][1]; c.v[0][0][0] = false; boolean val4 = get(); + assertEquals(val4, (isStableEnabled ? true : false)); + + c.v[0][0] = new boolean[1]; c.v[0][0][0] = false; boolean val5 = get(); + assertEquals(val5, (isStableEnabled ? true : false)); + } + + { + c.v = new boolean[1][1][1]; boolean[] val1 = get1(); + c.v[0][0] = new boolean[1]; boolean[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new boolean[1][1][1]; boolean[][] val1 = get2(); + c.v[0] = new boolean[1][1]; boolean[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new boolean[1][1][1]; boolean[][][] val1 = get3(); + c.v = new boolean[1][1][1]; boolean[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class BooleanArrayDim4 { + public @Stable boolean[][][][] v; + + public static final BooleanArrayDim4 c = new BooleanArrayDim4(); + public static boolean get() { return c.v[0][0][0][0]; } + public static boolean[] get1() { return c.v[0][0][0]; } + public static boolean[][] get2() { return c.v[0][0]; } + public static boolean[][][] get3() { return c.v[0]; } + public static boolean[][][][] get4() { return c.v; } + public static void test() throws Exception { + { + c.v = new boolean[1][1][1][1]; c.v[0][0][0][0] = true; boolean val1 = get(); + c.v[0][0][0][0] = false; boolean val2 = get(); + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + + c.v = new boolean[1][1][1][1]; c.v[0][0][0][0] = false; boolean val3 = get(); + assertEquals(val3, (isStableEnabled ? true : false)); + + c.v[0] = new boolean[1][1][1]; c.v[0][0][0][0] = false; boolean val4 = get(); + assertEquals(val4, (isStableEnabled ? true : false)); + + c.v[0][0] = new boolean[1][1]; c.v[0][0][0][0] = false; boolean val5 = get(); + assertEquals(val5, (isStableEnabled ? true : false)); + + c.v[0][0][0] = new boolean[1]; c.v[0][0][0][0] = false; boolean val6 = get(); + assertEquals(val6, (isStableEnabled ? true : false)); + } + + { + c.v = new boolean[1][1][1][1]; boolean[] val1 = get1(); + c.v[0][0][0] = new boolean[1]; boolean[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new boolean[1][1][1][1]; boolean[][] val1 = get2(); + c.v[0][0] = new boolean[1][1]; boolean[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new boolean[1][1][1][1]; boolean[][][] val1 = get3(); + c.v[0] = new boolean[1][1][1]; boolean[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new boolean[1][1][1][1]; boolean[][][][] val1 = get4(); + c.v = new boolean[1][1][1][1]; boolean[][][][] val2 = get4(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + } + } + + /* ==================================================== */ + // Dynamic Dim is higher than static + + static class ObjectArrayLowerDim0 { + public @Stable Object v; + + public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); + public static boolean get() { return ((boolean[])c.v)[0]; } + public static boolean[] get1() { return (boolean[])c.v; } + public static boolean[] get2() { return (boolean[])c.v; } + + public static void test() throws Exception { + { + c.v = new boolean[1]; ((boolean[])c.v)[0] = true; boolean val1 = get(); + ((boolean[])c.v)[0] = false; boolean val2 = get(); + + assertEquals(val1, true); + assertEquals(val2, false); + } + + { + c.v = new boolean[1]; boolean[] val1 = get1(); + c.v = new boolean[1]; boolean[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim1 { + public @Stable Object[] v; + + public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); + public static boolean get() { return ((boolean[][])c.v)[0][0]; } + public static boolean[] get1() { return (boolean[])(c.v[0]); } + public static Object[] get2() { return c.v; } + + public static void test() throws Exception { + { + c.v = new boolean[1][1]; ((boolean[][])c.v)[0][0] = true; boolean val1 = get(); + ((boolean[][])c.v)[0][0] = false; boolean val2 = get(); + + assertEquals(val1, true); + assertEquals(val2, false); + } + + { + c.v = new boolean[1][1]; c.v[0] = new boolean[0]; boolean[] val1 = get1(); + c.v[0] = new boolean[0]; boolean[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new boolean[0][0]; Object[] val1 = get2(); + c.v = new boolean[0][0]; Object[] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); + public static boolean get() { return ((boolean[][][])c.v)[0][0][0]; } + public static boolean[] get1() { return (boolean[])(c.v[0][0]); } + public static boolean[][] get2() { return (boolean[][])(c.v[0]); } + public static Object[][] get3() { return c.v; } + + public static void test() throws Exception { + { + c.v = new boolean[1][1][1]; ((boolean[][][])c.v)[0][0][0] = true; boolean val1 = get(); + ((boolean[][][])c.v)[0][0][0] = false; boolean val2 = get(); + + assertEquals(val1, true); + assertEquals(val2, false); + } + + { + c.v = new boolean[1][1][1]; c.v[0][0] = new boolean[0]; boolean[] val1 = get1(); + c.v[0][0] = new boolean[0]; boolean[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new boolean[1][1][1]; c.v[0] = new boolean[0][0]; boolean[][] val1 = get2(); + c.v[0] = new boolean[0][0]; boolean[][] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new boolean[0][0][0]; Object[][] val1 = get3(); + c.v = new boolean[0][0][0]; Object[][] val2 = get3(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class NestedStableField { + static class A { + public @Stable boolean a; + + } + public @Stable A v; + + public static final NestedStableField c = new NestedStableField(); + public static A get() { return c.v; } + public static boolean get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.a = true; A val1 = get(); + c.v.a = false; A val2 = get(); + + assertEquals(val1.a, false); + assertEquals(val2.a, false); + } + + { + c.v = new A(); c.v.a = true; boolean val1 = get1(); + c.v.a = false; boolean val2 = get1(); + c.v = new A(); c.v.a = false; boolean val3 = get1(); + + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + assertEquals(val3, (isStableEnabled ? true : false)); + } + } + } + + /* ==================================================== */ + + static class NestedStableField1 { + static class A { + public @Stable boolean a; + public @Stable A next; + } + public @Stable A v; + + public static final NestedStableField1 c = new NestedStableField1(); + public static A get() { return c.v.next.next.next.next.next.next.next; } + public static boolean get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; + c.v.a = true; c.v.next.a = true; A val1 = get(); + c.v.a = false; c.v.next.a = false; A val2 = get(); + + assertEquals(val1.a, false); + assertEquals(val2.a, false); + } + + { + c.v = new A(); c.v.next = c.v; + c.v.a = true; boolean val1 = get1(); + c.v.a = false; boolean val2 = get1(); + c.v = new A(); c.v.next = c.v; + c.v.a = false; boolean val3 = get1(); + + assertEquals(val1, true); + assertEquals(val2, (isStableEnabled ? true : false)); + assertEquals(val3, (isStableEnabled ? true : false)); + } + } + } + /* ==================================================== */ + + static class NestedStableField2 { + static class A { + public @Stable boolean a; + public @Stable A left; + public A right; + } + + public @Stable A v; + + public static final NestedStableField2 c = new NestedStableField2(); + public static boolean get() { return c.v.left.left.left.a; } + public static boolean get1() { return c.v.left.left.right.left.a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.left = c.v.right = c.v; + c.v.a = true; boolean val1 = get(); boolean val2 = get1(); + c.v.a = false; boolean val3 = get(); boolean val4 = get1(); + + assertEquals(val1, true); + assertEquals(val3, (isStableEnabled ? true : false)); + + assertEquals(val2, true); + assertEquals(val4, false); + } + } + } + + /* ==================================================== */ + + static class NestedStableField3 { + static class A { + public @Stable boolean a; + public @Stable A[] left; + public A[] right; + } + + public @Stable A[] v; + + public static final NestedStableField3 c = new NestedStableField3(); + public static boolean get() { return c.v[0].left[1].left[0].left[1].a; } + public static boolean get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } + + public static void test() throws Exception { + { + A elem = new A(); + c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; + elem.a = true; boolean val1 = get(); boolean val2 = get1(); + elem.a = false; boolean val3 = get(); boolean val4 = get1(); + + assertEquals(val1, true); + assertEquals(val3, (isStableEnabled ? true : false)); + + assertEquals(val2, true); + assertEquals(val4, false); + } + } + } + + /* ==================================================== */ + // Auxiliary methods + static void assertEquals(boolean i, boolean j) { if (i != j) throw new AssertionError(i + " != " + j); } + static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } + + static boolean failed = false; + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + failed = true; + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } + + static final boolean isStableEnabled; + static { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption tmp; + try { + tmp = diagnostic.getVMOption("FoldStableValues"); + } catch (IllegalArgumentException e) { + tmp = null; + } + isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); + } +} diff --git a/hotspot/test/compiler/stable/TestStableByte.java b/hotspot/test/compiler/stable/TestStableByte.java new file mode 100644 index 00000000000..4a14fcc3b2f --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableByte.java @@ -0,0 +1,632 @@ +/* + * 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. + */ + +/* + * @test TestStableByte + * @summary tests on stable fields and arrays + * @library /testlibrary + * @compile -XDignore.symbol.file TestStableByte.java + * @run main ClassFileInstaller + * java/lang/invoke/TestStableByte + * java/lang/invoke/TestStableByte$ByteStable + * java/lang/invoke/TestStableByte$StaticByteStable + * java/lang/invoke/TestStableByte$VolatileByteStable + * java/lang/invoke/TestStableByte$ByteArrayDim1 + * java/lang/invoke/TestStableByte$ByteArrayDim2 + * java/lang/invoke/TestStableByte$ByteArrayDim3 + * java/lang/invoke/TestStableByte$ByteArrayDim4 + * java/lang/invoke/TestStableByte$ObjectArrayLowerDim0 + * java/lang/invoke/TestStableByte$ObjectArrayLowerDim1 + * java/lang/invoke/TestStableByte$NestedStableField + * java/lang/invoke/TestStableByte$NestedStableField$A + * java/lang/invoke/TestStableByte$NestedStableField1 + * java/lang/invoke/TestStableByte$NestedStableField1$A + * java/lang/invoke/TestStableByte$NestedStableField2 + * java/lang/invoke/TestStableByte$NestedStableField2$A + * java/lang/invoke/TestStableByte$NestedStableField3 + * java/lang/invoke/TestStableByte$NestedStableField3$A + * java/lang/invoke/TestStableByte$DefaultValue + * java/lang/invoke/TestStableByte$ObjectArrayLowerDim2 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableByte + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableByte + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableByte + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableByte + */ +package java.lang.invoke; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import sun.management.ManagementFactoryHelper; +import java.lang.reflect.InvocationTargetException; + +public class TestStableByte { + public static void main(String[] args) throws Exception { + System.out.println("@Stable enabled: "+isStableEnabled); + System.out.println(); + + run(DefaultValue.class); + run(ByteStable.class); + run(StaticByteStable.class); + run(VolatileByteStable.class); + + // @Stable arrays: Dim 1-4 + run(ByteArrayDim1.class); + run(ByteArrayDim2.class); + run(ByteArrayDim3.class); + run(ByteArrayDim4.class); + + // @Stable Object field: dynamic arrays + run(ObjectArrayLowerDim0.class); + run(ObjectArrayLowerDim1.class); + run(ObjectArrayLowerDim2.class); + + // Nested @Stable fields + run(NestedStableField.class); + run(NestedStableField1.class); + run(NestedStableField2.class); + run(NestedStableField3.class); + + if (failed) { + throw new Error("TEST FAILED"); + } + } + + /* ==================================================== */ + + static class DefaultValue { + public @Stable byte v; + + public static final DefaultValue c = new DefaultValue(); + public static byte get() { return c.v; } + public static void test() throws Exception { + byte val1 = get(); + c.v = 1; byte val2 = get(); + assertEquals(val1, 0); + assertEquals(val2, 1); + } + } + + /* ==================================================== */ + + static class ByteStable { + public @Stable byte v; + + public static final ByteStable c = new ByteStable(); + public static byte get() { return c.v; } + public static void test() throws Exception { + c.v = 5; byte val1 = get(); + c.v = 127; byte val2 = get(); + assertEquals(val1, 5); + assertEquals(val2, (isStableEnabled ? 5 : 127)); + } + } + + /* ==================================================== */ + + static class StaticByteStable { + public static @Stable byte v; + + public static final StaticByteStable c = new StaticByteStable(); + public static byte get() { return c.v; } + public static void test() throws Exception { + c.v = 5; byte val1 = get(); + c.v = 127; byte val2 = get(); + assertEquals(val1, 5); + assertEquals(val2, (isStableEnabled ? 5 : 127)); + } + } + + /* ==================================================== */ + + static class VolatileByteStable { + public @Stable volatile byte v; + + public static final VolatileByteStable c = new VolatileByteStable(); + public static byte get() { return c.v; } + public static void test() throws Exception { + c.v = 5; byte val1 = get(); + c.v = 127; byte val2 = get(); + assertEquals(val1, 5); + assertEquals(val2, (isStableEnabled ? 5 : 127)); + } + } + + /* ==================================================== */ + // @Stable array == field && all components are stable + + static class ByteArrayDim1 { + public @Stable byte[] v; + + public static final ByteArrayDim1 c = new ByteArrayDim1(); + public static byte get() { return c.v[0]; } + public static byte get1() { return c.v[10]; } + public static byte[] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new byte[1]; c.v[0] = 1; byte val1 = get(); + c.v[0] = 2; byte val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new byte[1]; c.v[0] = 3; byte val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + + { + c.v = new byte[20]; c.v[10] = 1; byte val1 = get1(); + c.v[10] = 2; byte val2 = get1(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new byte[20]; c.v[10] = 3; byte val3 = get1(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + + { + c.v = new byte[1]; byte[] val1 = get2(); + c.v = new byte[1]; byte[] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ByteArrayDim2 { + public @Stable byte[][] v; + + public static final ByteArrayDim2 c = new ByteArrayDim2(); + public static byte get() { return c.v[0][0]; } + public static byte[] get1() { return c.v[0]; } + public static byte[][] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new byte[1][1]; c.v[0][0] = 1; byte val1 = get(); + c.v[0][0] = 2; byte val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new byte[1][1]; c.v[0][0] = 3; byte val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new byte[1]; c.v[0][0] = 4; byte val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + } + + { + c.v = new byte[1][1]; byte[] val1 = get1(); + c.v[0] = new byte[1]; byte[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new byte[1][1]; byte[][] val1 = get2(); + c.v = new byte[1][1]; byte[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ByteArrayDim3 { + public @Stable byte[][][] v; + + public static final ByteArrayDim3 c = new ByteArrayDim3(); + public static byte get() { return c.v[0][0][0]; } + public static byte[] get1() { return c.v[0][0]; } + public static byte[][] get2() { return c.v[0]; } + public static byte[][][] get3() { return c.v; } + public static void test() throws Exception { + { + c.v = new byte[1][1][1]; c.v[0][0][0] = 1; byte val1 = get(); + c.v[0][0][0] = 2; byte val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new byte[1][1][1]; c.v[0][0][0] = 3; byte val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new byte[1][1]; c.v[0][0][0] = 4; byte val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + + c.v[0][0] = new byte[1]; c.v[0][0][0] = 5; byte val5 = get(); + assertEquals(val5, (isStableEnabled ? 1 : 5)); + } + + { + c.v = new byte[1][1][1]; byte[] val1 = get1(); + c.v[0][0] = new byte[1]; byte[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new byte[1][1][1]; byte[][] val1 = get2(); + c.v[0] = new byte[1][1]; byte[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new byte[1][1][1]; byte[][][] val1 = get3(); + c.v = new byte[1][1][1]; byte[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ByteArrayDim4 { + public @Stable byte[][][][] v; + + public static final ByteArrayDim4 c = new ByteArrayDim4(); + public static byte get() { return c.v[0][0][0][0]; } + public static byte[] get1() { return c.v[0][0][0]; } + public static byte[][] get2() { return c.v[0][0]; } + public static byte[][][] get3() { return c.v[0]; } + public static byte[][][][] get4() { return c.v; } + public static void test() throws Exception { + { + c.v = new byte[1][1][1][1]; c.v[0][0][0][0] = 1; byte val1 = get(); + c.v[0][0][0][0] = 2; byte val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new byte[1][1][1][1]; c.v[0][0][0][0] = 3; byte val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new byte[1][1][1]; c.v[0][0][0][0] = 4; byte val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + + c.v[0][0] = new byte[1][1]; c.v[0][0][0][0] = 5; byte val5 = get(); + assertEquals(val5, (isStableEnabled ? 1 : 5)); + + c.v[0][0][0] = new byte[1]; c.v[0][0][0][0] = 6; byte val6 = get(); + assertEquals(val6, (isStableEnabled ? 1 : 6)); + } + + { + c.v = new byte[1][1][1][1]; byte[] val1 = get1(); + c.v[0][0][0] = new byte[1]; byte[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new byte[1][1][1][1]; byte[][] val1 = get2(); + c.v[0][0] = new byte[1][1]; byte[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new byte[1][1][1][1]; byte[][][] val1 = get3(); + c.v[0] = new byte[1][1][1]; byte[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new byte[1][1][1][1]; byte[][][][] val1 = get4(); + c.v = new byte[1][1][1][1]; byte[][][][] val2 = get4(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + } + } + + /* ==================================================== */ + // Dynamic Dim is higher than static + + static class ObjectArrayLowerDim0 { + public @Stable Object v; + + public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); + public static byte get() { return ((byte[])c.v)[0]; } + public static byte[] get1() { return (byte[])c.v; } + + public static void test() throws Exception { + { + c.v = new byte[1]; ((byte[])c.v)[0] = 1; byte val1 = get(); + ((byte[])c.v)[0] = 2; byte val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new byte[1]; byte[] val1 = get1(); + c.v = new byte[1]; byte[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim1 { + public @Stable Object[] v; + + public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); + public static byte get() { return ((byte[][])c.v)[0][0]; } + public static byte[] get1() { return (byte[])(c.v[0]); } + public static Object[] get2() { return c.v; } + + public static void test() throws Exception { + { + c.v = new byte[1][1]; ((byte[][])c.v)[0][0] = 1; byte val1 = get(); + ((byte[][])c.v)[0][0] = 2; byte val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new byte[1][1]; c.v[0] = new byte[0]; byte[] val1 = get1(); + c.v[0] = new byte[0]; byte[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new byte[0][0]; Object[] val1 = get2(); + c.v = new byte[0][0]; Object[] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); + public static byte get() { return ((byte[][][])c.v)[0][0][0]; } + public static byte[] get1() { return (byte[])(c.v[0][0]); } + public static byte[][] get2() { return (byte[][])(c.v[0]); } + public static Object[][] get3() { return c.v; } + + public static void test() throws Exception { + { + c.v = new byte[1][1][1]; ((byte[][][])c.v)[0][0][0] = 1; byte val1 = get(); + ((byte[][][])c.v)[0][0][0] = 2; byte val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new byte[1][1][1]; c.v[0][0] = new byte[0]; byte[] val1 = get1(); + c.v[0][0] = new byte[0]; byte[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new byte[1][1][1]; c.v[0] = new byte[0][0]; byte[][] val1 = get2(); + c.v[0] = new byte[0][0]; byte[][] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new byte[0][0][0]; Object[][] val1 = get3(); + c.v = new byte[0][0][0]; Object[][] val2 = get3(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class NestedStableField { + static class A { + public @Stable byte a; + + } + public @Stable A v; + + public static final NestedStableField c = new NestedStableField(); + public static A get() { return c.v; } + public static byte get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.a = 1; A val1 = get(); + c.v.a = 2; A val2 = get(); + + assertEquals(val1.a, 2); + assertEquals(val2.a, 2); + } + + { + c.v = new A(); c.v.a = 1; byte val1 = get1(); + c.v.a = 2; byte val2 = get1(); + c.v = new A(); c.v.a = 3; byte val3 = get1(); + + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + } + } + + /* ==================================================== */ + + static class NestedStableField1 { + static class A { + public @Stable byte a; + public @Stable A next; + } + public @Stable A v; + + public static final NestedStableField1 c = new NestedStableField1(); + public static A get() { return c.v.next.next.next.next.next.next.next; } + public static byte get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; + c.v.a = 1; c.v.next.a = 1; A val1 = get(); + c.v.a = 2; c.v.next.a = 2; A val2 = get(); + + assertEquals(val1.a, 2); + assertEquals(val2.a, 2); + } + + { + c.v = new A(); c.v.next = c.v; + c.v.a = 1; byte val1 = get1(); + c.v.a = 2; byte val2 = get1(); + c.v = new A(); c.v.next = c.v; + c.v.a = 3; byte val3 = get1(); + + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + } + } + /* ==================================================== */ + + static class NestedStableField2 { + static class A { + public @Stable byte a; + public @Stable A left; + public A right; + } + + public @Stable A v; + + public static final NestedStableField2 c = new NestedStableField2(); + public static byte get() { return c.v.left.left.left.a; } + public static byte get1() { return c.v.left.left.right.left.a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.left = c.v.right = c.v; + c.v.a = 1; byte val1 = get(); byte val2 = get1(); + c.v.a = 2; byte val3 = get(); byte val4 = get1(); + + assertEquals(val1, 1); + assertEquals(val3, (isStableEnabled ? 1 : 2)); + + assertEquals(val2, 1); + assertEquals(val4, 2); + } + } + } + + /* ==================================================== */ + + static class NestedStableField3 { + static class A { + public @Stable byte a; + public @Stable A[] left; + public A[] right; + } + + public @Stable A[] v; + + public static final NestedStableField3 c = new NestedStableField3(); + public static byte get() { return c.v[0].left[1].left[0].left[1].a; } + public static byte get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } + + public static void test() throws Exception { + { + A elem = new A(); + c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; + elem.a = 1; byte val1 = get(); byte val2 = get1(); + elem.a = 2; byte val3 = get(); byte val4 = get1(); + + assertEquals(val1, 1); + assertEquals(val3, (isStableEnabled ? 1 : 2)); + + assertEquals(val2, 1); + assertEquals(val4, 2); + } + } + } + + /* ==================================================== */ + // Auxiliary methods + static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); } + static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } + + static boolean failed = false; + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + failed = true; + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } + + static final boolean isStableEnabled; + static { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption tmp; + try { + tmp = diagnostic.getVMOption("FoldStableValues"); + } catch (IllegalArgumentException e) { + tmp = null; + } + isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); + } +} diff --git a/hotspot/test/compiler/stable/TestStableChar.java b/hotspot/test/compiler/stable/TestStableChar.java new file mode 100644 index 00000000000..ede8e9a4df7 --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableChar.java @@ -0,0 +1,631 @@ +/* + * 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. + */ + +/* + * @test TestStableChar + * @summary tests on stable fields and arrays + * @library /testlibrary + * @compile -XDignore.symbol.file TestStableChar.java + * @run main ClassFileInstaller + * java/lang/invoke/TestStableChar + * java/lang/invoke/TestStableChar$CharStable + * java/lang/invoke/TestStableChar$StaticCharStable + * java/lang/invoke/TestStableChar$VolatileCharStable + * java/lang/invoke/TestStableChar$CharArrayDim1 + * java/lang/invoke/TestStableChar$CharArrayDim2 + * java/lang/invoke/TestStableChar$CharArrayDim3 + * java/lang/invoke/TestStableChar$CharArrayDim4 + * java/lang/invoke/TestStableChar$ObjectArrayLowerDim0 + * java/lang/invoke/TestStableChar$ObjectArrayLowerDim1 + * java/lang/invoke/TestStableChar$NestedStableField + * java/lang/invoke/TestStableChar$NestedStableField$A + * java/lang/invoke/TestStableChar$NestedStableField1 + * java/lang/invoke/TestStableChar$NestedStableField1$A + * java/lang/invoke/TestStableChar$NestedStableField2 + * java/lang/invoke/TestStableChar$NestedStableField2$A + * java/lang/invoke/TestStableChar$NestedStableField3 + * java/lang/invoke/TestStableChar$NestedStableField3$A + * java/lang/invoke/TestStableChar$DefaultValue + * java/lang/invoke/TestStableChar$ObjectArrayLowerDim2 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableChar + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableChar + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableChar + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableChar + */ +package java.lang.invoke; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import sun.management.ManagementFactoryHelper; +import java.lang.reflect.InvocationTargetException; + +public class TestStableChar { + public static void main(String[] args) throws Exception { + System.out.println("@Stable enabled: "+isStableEnabled); + System.out.println(); + + run(DefaultValue.class); + run(CharStable.class); + run(StaticCharStable.class); + run(VolatileCharStable.class); + + // @Stable arrays: Dim 1-4 + run(CharArrayDim1.class); + run(CharArrayDim2.class); + run(CharArrayDim3.class); + run(CharArrayDim4.class); + + // @Stable Object field: dynamic arrays + run(ObjectArrayLowerDim0.class); + run(ObjectArrayLowerDim1.class); + run(ObjectArrayLowerDim2.class); + + // Nested @Stable fields + run(NestedStableField.class); + run(NestedStableField1.class); + run(NestedStableField2.class); + run(NestedStableField3.class); + + if (failed) { + throw new Error("TEST FAILED"); + } + } + + /* ==================================================== */ + + static class DefaultValue { + public @Stable char v; + + public static final DefaultValue c = new DefaultValue(); + public static char get() { return c.v; } + public static void test() throws Exception { + char val1 = get(); + c.v = 'a'; char val2 = get(); + assertEquals(val1, 0); + assertEquals(val2, 'a'); + } + } + + /* ==================================================== */ + + static class CharStable { + public @Stable char v; + + public static final CharStable c = new CharStable(); + public static char get() { return c.v; } + public static void test() throws Exception { + c.v = 'a'; char val1 = get(); + c.v = 'b'; char val2 = get(); + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + } + } + + /* ==================================================== */ + + static class StaticCharStable { + public @Stable char v; + + public static final StaticCharStable c = new StaticCharStable(); + public static char get() { return c.v; } + public static void test() throws Exception { + c.v = 'a'; char val1 = get(); + c.v = 'b'; char val2 = get(); + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + } + } + + /* ==================================================== */ + + static class VolatileCharStable { + public @Stable volatile char v; + + public static final VolatileCharStable c = new VolatileCharStable(); + public static char get() { return c.v; } + public static void test() throws Exception { + c.v = 'a'; char val1 = get(); + c.v = 'b'; char val2 = get(); + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + } + } + + /* ==================================================== */ + // @Stable array == field && all components are stable + + static class CharArrayDim1 { + public @Stable char[] v; + + public static final CharArrayDim1 c = new CharArrayDim1(); + public static char get() { return c.v[0]; } + public static char get1() { return c.v[10]; } + public static char[] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new char[1]; c.v[0] = 'a'; char val1 = get(); + c.v[0] = 'b'; char val2 = get(); + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + + c.v = new char[1]; c.v[0] = 'c'; char val3 = get(); + assertEquals(val3, (isStableEnabled ? 'a' : 'c')); + } + + { + c.v = new char[20]; c.v[10] = 'a'; char val1 = get1(); + c.v[10] = 'b'; char val2 = get1(); + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + + c.v = new char[20]; c.v[10] = 'c'; char val3 = get1(); + assertEquals(val3, (isStableEnabled ? 'a' : 'c')); + } + + { + c.v = new char[1]; char[] val1 = get2(); + c.v = new char[1]; char[] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class CharArrayDim2 { + public @Stable char[][] v; + + public static final CharArrayDim2 c = new CharArrayDim2(); + public static char get() { return c.v[0][0]; } + public static char[] get1() { return c.v[0]; } + public static char[][] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new char[1][1]; c.v[0][0] = 'a'; char val1 = get(); + c.v[0][0] = 'b'; char val2 = get(); + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + + c.v = new char[1][1]; c.v[0][0] = 'c'; char val3 = get(); + assertEquals(val3, (isStableEnabled ? 'a' : 'c')); + + c.v[0] = new char[1]; c.v[0][0] = 'd'; char val4 = get(); + assertEquals(val4, (isStableEnabled ? 'a' : 'd')); + } + + { + c.v = new char[1][1]; char[] val1 = get1(); + c.v[0] = new char[1]; char[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new char[1][1]; char[][] val1 = get2(); + c.v = new char[1][1]; char[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class CharArrayDim3 { + public @Stable char[][][] v; + + public static final CharArrayDim3 c = new CharArrayDim3(); + public static char get() { return c.v[0][0][0]; } + public static char[] get1() { return c.v[0][0]; } + public static char[][] get2() { return c.v[0]; } + public static char[][][] get3() { return c.v; } + public static void test() throws Exception { + { + c.v = new char[1][1][1]; c.v[0][0][0] = 'a'; char val1 = get(); + c.v[0][0][0] = 'b'; char val2 = get(); + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + + c.v = new char[1][1][1]; c.v[0][0][0] = 'c'; char val3 = get(); + assertEquals(val3, (isStableEnabled ? 'a' : 'c')); + + c.v[0] = new char[1][1]; c.v[0][0][0] = 'd'; char val4 = get(); + assertEquals(val4, (isStableEnabled ? 'a' : 'd')); + + c.v[0][0] = new char[1]; c.v[0][0][0] = 'e'; char val5 = get(); + assertEquals(val5, (isStableEnabled ? 'a' : 'e')); + } + + { + c.v = new char[1][1][1]; char[] val1 = get1(); + c.v[0][0] = new char[1]; char[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new char[1][1][1]; char[][] val1 = get2(); + c.v[0] = new char[1][1]; char[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new char[1][1][1]; char[][][] val1 = get3(); + c.v = new char[1][1][1]; char[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class CharArrayDim4 { + public @Stable char[][][][] v; + + public static final CharArrayDim4 c = new CharArrayDim4(); + public static char get() { return c.v[0][0][0][0]; } + public static char[] get1() { return c.v[0][0][0]; } + public static char[][] get2() { return c.v[0][0]; } + public static char[][][] get3() { return c.v[0]; } + public static char[][][][] get4() { return c.v; } + public static void test() throws Exception { + { + c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'a'; char val1 = get(); + c.v[0][0][0][0] = 'b'; char val2 = get(); + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + + c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'c'; char val3 = get(); + assertEquals(val3, (isStableEnabled ? 'a' : 'c')); + + c.v[0] = new char[1][1][1]; c.v[0][0][0][0] = 'd'; char val4 = get(); + assertEquals(val4, (isStableEnabled ? 'a' : 'd')); + + c.v[0][0] = new char[1][1]; c.v[0][0][0][0] = 'e'; char val5 = get(); + assertEquals(val5, (isStableEnabled ? 'a' : 'e')); + + c.v[0][0][0] = new char[1]; c.v[0][0][0][0] = 'f'; char val6 = get(); + assertEquals(val6, (isStableEnabled ? 'a' : 'f')); + } + + { + c.v = new char[1][1][1][1]; char[] val1 = get1(); + c.v[0][0][0] = new char[1]; char[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new char[1][1][1][1]; char[][] val1 = get2(); + c.v[0][0] = new char[1][1]; char[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new char[1][1][1][1]; char[][][] val1 = get3(); + c.v[0] = new char[1][1][1]; char[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new char[1][1][1][1]; char[][][][] val1 = get4(); + c.v = new char[1][1][1][1]; char[][][][] val2 = get4(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + } + } + + /* ==================================================== */ + // Dynamic Dim is higher than static + static class ObjectArrayLowerDim0 { + public @Stable Object v; + + public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); + public static char get() { return ((char[])c.v)[0]; } + public static char[] get1() { return (char[])c.v; } + + public static void test() throws Exception { + { + c.v = new char[1]; ((char[])c.v)[0] = 'a'; char val1 = get(); + ((char[])c.v)[0] = 'b'; char val2 = get(); + + assertEquals(val1, 'a'); + assertEquals(val2, 'b'); + } + + { + c.v = new char[1]; char[] val1 = get1(); + c.v = new char[1]; char[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim1 { + public @Stable Object[] v; + + public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); + public static char get() { return ((char[][])c.v)[0][0]; } + public static char[] get1() { return (char[])(c.v[0]); } + public static Object[] get2() { return c.v; } + + public static void test() throws Exception { + { + c.v = new char[1][1]; ((char[][])c.v)[0][0] = 'a'; char val1 = get(); + ((char[][])c.v)[0][0] = 'b'; char val2 = get(); + + assertEquals(val1, 'a'); + assertEquals(val2, 'b'); + } + + { + c.v = new char[1][1]; c.v[0] = new char[0]; char[] val1 = get1(); + c.v[0] = new char[0]; char[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new char[0][0]; Object[] val1 = get2(); + c.v = new char[0][0]; Object[] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); + public static char get() { return ((char[][][])c.v)[0][0][0]; } + public static char[] get1() { return (char[])(c.v[0][0]); } + public static char[][] get2() { return (char[][])(c.v[0]); } + public static Object[][] get3() { return c.v; } + + public static void test() throws Exception { + { + c.v = new char[1][1][1]; ((char[][][])c.v)[0][0][0] = 'a'; char val1 = get(); + ((char[][][])c.v)[0][0][0] = 'b'; char val2 = get(); + + assertEquals(val1, 'a'); + assertEquals(val2, 'b'); + } + + { + c.v = new char[1][1][1]; c.v[0][0] = new char[0]; char[] val1 = get1(); + c.v[0][0] = new char[0]; char[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new char[1][1][1]; c.v[0] = new char[0][0]; char[][] val1 = get2(); + c.v[0] = new char[0][0]; char[][] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new char[0][0][0]; Object[][] val1 = get3(); + c.v = new char[0][0][0]; Object[][] val2 = get3(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class NestedStableField { + static class A { + public @Stable char a; + + } + public @Stable A v; + + public static final NestedStableField c = new NestedStableField(); + public static A get() { return c.v; } + public static char get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.a = 'a'; A val1 = get(); + c.v.a = 'b'; A val2 = get(); + + assertEquals(val1.a, 'b'); + assertEquals(val2.a, 'b'); + } + + { + c.v = new A(); c.v.a = 'a'; char val1 = get1(); + c.v.a = 'b'; char val2 = get1(); + c.v = new A(); c.v.a = 'c'; char val3 = get1(); + + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + assertEquals(val3, (isStableEnabled ? 'a' : 'c')); + } + } + } + + /* ==================================================== */ + + static class NestedStableField1 { + static class A { + public @Stable char a; + public @Stable A next; + } + public @Stable A v; + + public static final NestedStableField1 c = new NestedStableField1(); + public static A get() { return c.v.next.next.next.next.next.next.next; } + public static char get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; + c.v.a = 'a'; c.v.next.a = 'a'; A val1 = get(); + c.v.a = 'b'; c.v.next.a = 'b'; A val2 = get(); + + assertEquals(val1.a, 'b'); + assertEquals(val2.a, 'b'); + } + + { + c.v = new A(); c.v.next = c.v; + c.v.a = 'a'; char val1 = get1(); + c.v.a = 'b'; char val2 = get1(); + c.v = new A(); c.v.next = c.v; + c.v.a = 'c'; char val3 = get1(); + + assertEquals(val1, 'a'); + assertEquals(val2, (isStableEnabled ? 'a' : 'b')); + assertEquals(val3, (isStableEnabled ? 'a' : 'c')); + } + } + } + /* ==================================================== */ + + static class NestedStableField2 { + static class A { + public @Stable char a; + public @Stable A left; + public A right; + } + + public @Stable A v; + + public static final NestedStableField2 c = new NestedStableField2(); + public static char get() { return c.v.left.left.left.a; } + public static char get1() { return c.v.left.left.right.left.a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.left = c.v.right = c.v; + c.v.a = 'a'; char val1 = get(); char val2 = get1(); + c.v.a = 'b'; char val3 = get(); char val4 = get1(); + + assertEquals(val1, 'a'); + assertEquals(val3, (isStableEnabled ? 'a' : 'b')); + + assertEquals(val2, 'a'); + assertEquals(val4, 'b'); + } + } + } + + /* ==================================================== */ + + static class NestedStableField3 { + static class A { + public @Stable char a; + public @Stable A[] left; + public A[] right; + } + + public @Stable A[] v; + + public static final NestedStableField3 c = new NestedStableField3(); + public static char get() { return c.v[0].left[1].left[0].left[1].a; } + public static char get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } + + public static void test() throws Exception { + { + A elem = new A(); + c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; + elem.a = 'a'; char val1 = get(); char val2 = get1(); + elem.a = 'b'; char val3 = get(); char val4 = get1(); + + assertEquals(val1, 'a'); + assertEquals(val3, (isStableEnabled ? 'a' : 'b')); + + assertEquals(val2, 'a'); + assertEquals(val4, 'b'); + } + } + } + + /* ==================================================== */ + // Auxiliary methods + static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); } + static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } + + static boolean failed = false; + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + failed = true; + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } + + static final boolean isStableEnabled; + static { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption tmp; + try { + tmp = diagnostic.getVMOption("FoldStableValues"); + } catch (IllegalArgumentException e) { + tmp = null; + } + isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); + } +} diff --git a/hotspot/test/compiler/stable/TestStableDouble.java b/hotspot/test/compiler/stable/TestStableDouble.java new file mode 100644 index 00000000000..b656acbd1ae --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableDouble.java @@ -0,0 +1,632 @@ +/* + * 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. + */ + +/* + * @test TestStableDouble + * @summary tests on stable fields and arrays + * @library /testlibrary + * @compile -XDignore.symbol.file TestStableDouble.java + * @run main ClassFileInstaller + * java/lang/invoke/TestStableDouble + * java/lang/invoke/TestStableDouble$DoubleStable + * java/lang/invoke/TestStableDouble$StaticDoubleStable + * java/lang/invoke/TestStableDouble$VolatileDoubleStable + * java/lang/invoke/TestStableDouble$DoubleArrayDim1 + * java/lang/invoke/TestStableDouble$DoubleArrayDim2 + * java/lang/invoke/TestStableDouble$DoubleArrayDim3 + * java/lang/invoke/TestStableDouble$DoubleArrayDim4 + * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim0 + * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim1 + * java/lang/invoke/TestStableDouble$NestedStableField + * java/lang/invoke/TestStableDouble$NestedStableField$A + * java/lang/invoke/TestStableDouble$NestedStableField1 + * java/lang/invoke/TestStableDouble$NestedStableField1$A + * java/lang/invoke/TestStableDouble$NestedStableField2 + * java/lang/invoke/TestStableDouble$NestedStableField2$A + * java/lang/invoke/TestStableDouble$NestedStableField3 + * java/lang/invoke/TestStableDouble$NestedStableField3$A + * java/lang/invoke/TestStableDouble$DefaultValue + * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim2 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableDouble + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableDouble + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableDouble + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableDouble + */ +package java.lang.invoke; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import sun.management.ManagementFactoryHelper; +import java.lang.reflect.InvocationTargetException; + +public class TestStableDouble { + public static void main(String[] args) throws Exception { + System.out.println("@Stable enabled: "+isStableEnabled); + System.out.println(); + + run(DefaultValue.class); + run(DoubleStable.class); + run(StaticDoubleStable.class); + run(VolatileDoubleStable.class); + + // @Stable arrays: Dim 1-4 + run(DoubleArrayDim1.class); + run(DoubleArrayDim2.class); + run(DoubleArrayDim3.class); + run(DoubleArrayDim4.class); + + // @Stable Object field: dynamic arrays + run(ObjectArrayLowerDim0.class); + run(ObjectArrayLowerDim1.class); + run(ObjectArrayLowerDim2.class); + + // Nested @Stable fields + run(NestedStableField.class); + run(NestedStableField1.class); + run(NestedStableField2.class); + run(NestedStableField3.class); + + if (failed) { + throw new Error("TEST FAILED"); + } + } + + /* ==================================================== */ + + static class DefaultValue { + public @Stable double v; + + public static final DefaultValue c = new DefaultValue(); + public static double get() { return c.v; } + public static void test() throws Exception { + double val1 = get(); + c.v = 1.0; double val2 = get(); + assertEquals(val1, 0); + assertEquals(val2, 1.0); + } + } + + /* ==================================================== */ + + static class DoubleStable { + public @Stable double v; + + public static final DoubleStable c = new DoubleStable(); + public static double get() { return c.v; } + public static void test() throws Exception { + c.v = 1.0; double val1 = get(); + c.v = Double.MAX_VALUE; double val2 = get(); + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : Double.MAX_VALUE)); + } + } + + /* ==================================================== */ + + static class StaticDoubleStable { + public static @Stable double v; + + public static final StaticDoubleStable c = new StaticDoubleStable(); + public static double get() { return c.v; } + public static void test() throws Exception { + c.v = 1.0; double val1 = get(); + c.v = Double.MAX_VALUE; double val2 = get(); + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : Double.MAX_VALUE)); + } + } + + /* ==================================================== */ + + static class VolatileDoubleStable { + public @Stable double v; + + public static final VolatileDoubleStable c = new VolatileDoubleStable(); + public static double get() { return c.v; } + public static void test() throws Exception { + c.v = 1.0; double val1 = get(); + c.v = Double.MAX_VALUE; double val2 = get(); + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : Double.MAX_VALUE)); + } + } + + /* ==================================================== */ + // @Stable array == field && all components are stable + + static class DoubleArrayDim1 { + public @Stable double[] v; + + public static final DoubleArrayDim1 c = new DoubleArrayDim1(); + public static double get() { return c.v[0]; } + public static double get1() { return c.v[10]; } + public static double[] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new double[1]; c.v[0] = 1.0; double val1 = get(); + c.v[0] = 2.0; double val2 = get(); + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : 2.0)); + + c.v = new double[1]; c.v[0] = 3.0; double val3 = get(); + assertEquals(val3, (isStableEnabled ? 1.0 : 3.0)); + } + + { + c.v = new double[20]; c.v[10] = 1.0; double val1 = get1(); + c.v[10] = 2.0; double val2 = get1(); + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : 2.0)); + + c.v = new double[20]; c.v[10] = 3.0; double val3 = get1(); + assertEquals(val3, (isStableEnabled ? 1.0 : 3.0)); + } + + { + c.v = new double[1]; double[] val1 = get2(); + c.v = new double[1]; double[] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class DoubleArrayDim2 { + public @Stable double[][] v; + + public static final DoubleArrayDim2 c = new DoubleArrayDim2(); + public static double get() { return c.v[0][0]; } + public static double[] get1() { return c.v[0]; } + public static double[][] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new double[1][1]; c.v[0][0] = 1.0; double val1 = get(); + c.v[0][0] = 2.0; double val2 = get(); + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : 2.0)); + + c.v = new double[1][1]; c.v[0][0] = 3.0; double val3 = get(); + assertEquals(val3, (isStableEnabled ? 1.0 : 3.0)); + + c.v[0] = new double[1]; c.v[0][0] = 4.0; double val4 = get(); + assertEquals(val4, (isStableEnabled ? 1.0 : 4.0)); + } + + { + c.v = new double[1][1]; double[] val1 = get1(); + c.v[0] = new double[1]; double[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new double[1][1]; double[][] val1 = get2(); + c.v = new double[1][1]; double[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class DoubleArrayDim3 { + public @Stable double[][][] v; + + public static final DoubleArrayDim3 c = new DoubleArrayDim3(); + public static double get() { return c.v[0][0][0]; } + public static double[] get1() { return c.v[0][0]; } + public static double[][] get2() { return c.v[0]; } + public static double[][][] get3() { return c.v; } + public static void test() throws Exception { + { + c.v = new double[1][1][1]; c.v[0][0][0] = 1.0; double val1 = get(); + c.v[0][0][0] = 2.0; double val2 = get(); + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : 2.0)); + + c.v = new double[1][1][1]; c.v[0][0][0] = 3.0; double val3 = get(); + assertEquals(val3, (isStableEnabled ? 1.0 : 3.0)); + + c.v[0] = new double[1][1]; c.v[0][0][0] = 4.0; double val4 = get(); + assertEquals(val4, (isStableEnabled ? 1.0 : 4.0)); + + c.v[0][0] = new double[1]; c.v[0][0][0] = 5.0; double val5 = get(); + assertEquals(val5, (isStableEnabled ? 1.0 : 5.0)); + } + + { + c.v = new double[1][1][1]; double[] val1 = get1(); + c.v[0][0] = new double[1]; double[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new double[1][1][1]; double[][] val1 = get2(); + c.v[0] = new double[1][1]; double[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new double[1][1][1]; double[][][] val1 = get3(); + c.v = new double[1][1][1]; double[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class DoubleArrayDim4 { + public @Stable double[][][][] v; + + public static final DoubleArrayDim4 c = new DoubleArrayDim4(); + public static double get() { return c.v[0][0][0][0]; } + public static double[] get1() { return c.v[0][0][0]; } + public static double[][] get2() { return c.v[0][0]; } + public static double[][][] get3() { return c.v[0]; } + public static double[][][][] get4() { return c.v; } + public static void test() throws Exception { + { + c.v = new double[1][1][1][1]; c.v[0][0][0][0] = 1.0; double val1 = get(); + c.v[0][0][0][0] = 2.0; double val2 = get(); + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : 2.0)); + + c.v = new double[1][1][1][1]; c.v[0][0][0][0] = 3.0; double val3 = get(); + assertEquals(val3, (isStableEnabled ? 1.0 : 3.0)); + + c.v[0] = new double[1][1][1]; c.v[0][0][0][0] = 4.0; double val4 = get(); + assertEquals(val4, (isStableEnabled ? 1.0 : 4.0)); + + c.v[0][0] = new double[1][1]; c.v[0][0][0][0] = 5.0; double val5 = get(); + assertEquals(val5, (isStableEnabled ? 1.0 : 5.0)); + + c.v[0][0][0] = new double[1]; c.v[0][0][0][0] = 6.0; double val6 = get(); + assertEquals(val6, (isStableEnabled ? 1.0 : 6.0)); + } + + { + c.v = new double[1][1][1][1]; double[] val1 = get1(); + c.v[0][0][0] = new double[1]; double[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new double[1][1][1][1]; double[][] val1 = get2(); + c.v[0][0] = new double[1][1]; double[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new double[1][1][1][1]; double[][][] val1 = get3(); + c.v[0] = new double[1][1][1]; double[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new double[1][1][1][1]; double[][][][] val1 = get4(); + c.v = new double[1][1][1][1]; double[][][][] val2 = get4(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + } + } + + /* ==================================================== */ + // Dynamic Dim is higher than static + + static class ObjectArrayLowerDim0 { + public @Stable Object v; + + public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); + public static double get() { return ((double[])c.v)[0]; } + public static double[] get1() { return (double[])c.v; } + + public static void test() throws Exception { + { + c.v = new double[1]; ((double[])c.v)[0] = 1.0; double val1 = get(); + ((double[])c.v)[0] = 2.0; double val2 = get(); + + assertEquals(val1, 1.0); + assertEquals(val2, 2.0); + } + + { + c.v = new double[1]; double[] val1 = get1(); + c.v = new double[1]; double[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim1 { + public @Stable Object[] v; + + public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); + public static double get() { return ((double[][])c.v)[0][0]; } + public static double[] get1() { return (double[])(c.v[0]); } + public static Object[] get2() { return c.v; } + + public static void test() throws Exception { + { + c.v = new double[1][1]; ((double[][])c.v)[0][0] = 1.0; double val1 = get(); + ((double[][])c.v)[0][0] = 2.0; double val2 = get(); + + assertEquals(val1, 1.0); + assertEquals(val2, 2.0); + } + + { + c.v = new double[1][1]; c.v[0] = new double[0]; double[] val1 = get1(); + c.v[0] = new double[0]; double[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new double[0][0]; Object[] val1 = get2(); + c.v = new double[0][0]; Object[] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); + public static double get() { return ((double[][][])c.v)[0][0][0]; } + public static double[] get1() { return (double[])(c.v[0][0]); } + public static double[][] get2() { return (double[][])(c.v[0]); } + public static Object[][] get3() { return c.v; } + + public static void test() throws Exception { + { + c.v = new double[1][1][1]; ((double[][][])c.v)[0][0][0] = 1.0; double val1 = get(); + ((double[][][])c.v)[0][0][0] = 2.0; double val2 = get(); + + assertEquals(val1, 1.0); + assertEquals(val2, 2.0); + } + + { + c.v = new double[1][1][1]; c.v[0][0] = new double[0]; double[] val1 = get1(); + c.v[0][0] = new double[0]; double[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new double[1][1][1]; c.v[0] = new double[0][0]; double[][] val1 = get2(); + c.v[0] = new double[0][0]; double[][] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new double[0][0][0]; Object[][] val1 = get3(); + c.v = new double[0][0][0]; Object[][] val2 = get3(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class NestedStableField { + static class A { + public @Stable double a; + + } + public @Stable A v; + + public static final NestedStableField c = new NestedStableField(); + public static A get() { return c.v; } + public static double get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.a = 1.0; A val1 = get(); + c.v.a = 2.0; A val2 = get(); + + assertEquals(val1.a, 2.0); + assertEquals(val2.a, 2.0); + } + + { + c.v = new A(); c.v.a = 1.0; double val1 = get1(); + c.v.a = 2.0; double val2 = get1(); + c.v = new A(); c.v.a = 3.0; double val3 = get1(); + + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : 2.0)); + assertEquals(val3, (isStableEnabled ? 1.0 : 3.0)); + } + } + } + + /* ==================================================== */ + + static class NestedStableField1 { + static class A { + public @Stable double a; + public @Stable A next; + } + public @Stable A v; + + public static final NestedStableField1 c = new NestedStableField1(); + public static A get() { return c.v.next.next.next.next.next.next.next; } + public static double get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; + c.v.a = 1.0; c.v.next.a = 1.0; A val1 = get(); + c.v.a = 2.0; c.v.next.a = 2.0; A val2 = get(); + + assertEquals(val1.a, 2.0); + assertEquals(val2.a, 2.0); + } + + { + c.v = new A(); c.v.next = c.v; + c.v.a = 1.0; double val1 = get1(); + c.v.a = 2.0; double val2 = get1(); + c.v = new A(); c.v.next = c.v; + c.v.a = 3.0; double val3 = get1(); + + assertEquals(val1, 1.0); + assertEquals(val2, (isStableEnabled ? 1.0 : 2.0)); + assertEquals(val3, (isStableEnabled ? 1.0 : 3.0)); + } + } + } + /* ==================================================== */ + + static class NestedStableField2 { + static class A { + public @Stable double a; + public @Stable A left; + public A right; + } + + public @Stable A v; + + public static final NestedStableField2 c = new NestedStableField2(); + public static double get() { return c.v.left.left.left.a; } + public static double get1() { return c.v.left.left.right.left.a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.left = c.v.right = c.v; + c.v.a = 1.0; double val1 = get(); double val2 = get1(); + c.v.a = 2.0; double val3 = get(); double val4 = get1(); + + assertEquals(val1, 1.0); + assertEquals(val3, (isStableEnabled ? 1.0 : 2.0)); + + assertEquals(val2, 1.0); + assertEquals(val4, 2.0); + } + } + } + + /* ==================================================== */ + + static class NestedStableField3 { + static class A { + public @Stable double a; + public @Stable A[] left; + public A[] right; + } + + public @Stable A[] v; + + public static final NestedStableField3 c = new NestedStableField3(); + public static double get() { return c.v[0].left[1].left[0].left[1].a; } + public static double get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } + + public static void test() throws Exception { + { + A elem = new A(); + c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; + elem.a = 1.0; double val1 = get(); double val2 = get1(); + elem.a = 2.0; double val3 = get(); double val4 = get1(); + + assertEquals(val1, 1.0); + assertEquals(val3, (isStableEnabled ? 1.0 : 2.0)); + + assertEquals(val2, 1.0); + assertEquals(val4, 2.0); + } + } + } + + /* ==================================================== */ + // Auxiliary methods + static void assertEquals(double i, double j) { if (i != j) throw new AssertionError(i + " != " + j); } + static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } + + static boolean failed = false; + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + failed = true; + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } + + static final boolean isStableEnabled; + static { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption tmp; + try { + tmp = diagnostic.getVMOption("FoldStableValues"); + } catch (IllegalArgumentException e) { + tmp = null; + } + isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); + } +} diff --git a/hotspot/test/compiler/stable/TestStableFloat.java b/hotspot/test/compiler/stable/TestStableFloat.java new file mode 100644 index 00000000000..ab1c3f0be1f --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableFloat.java @@ -0,0 +1,632 @@ +/* + * 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. + */ + +/* + * @test TestStableFloat + * @summary tests on stable fields and arrays + * @library /testlibrary + * @compile -XDignore.symbol.file TestStableFloat.java + * @run main ClassFileInstaller + * java/lang/invoke/TestStableFloat + * java/lang/invoke/TestStableFloat$FloatStable + * java/lang/invoke/TestStableFloat$StaticFloatStable + * java/lang/invoke/TestStableFloat$VolatileFloatStable + * java/lang/invoke/TestStableFloat$FloatArrayDim1 + * java/lang/invoke/TestStableFloat$FloatArrayDim2 + * java/lang/invoke/TestStableFloat$FloatArrayDim3 + * java/lang/invoke/TestStableFloat$FloatArrayDim4 + * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim0 + * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim1 + * java/lang/invoke/TestStableFloat$NestedStableField + * java/lang/invoke/TestStableFloat$NestedStableField$A + * java/lang/invoke/TestStableFloat$NestedStableField1 + * java/lang/invoke/TestStableFloat$NestedStableField1$A + * java/lang/invoke/TestStableFloat$NestedStableField2 + * java/lang/invoke/TestStableFloat$NestedStableField2$A + * java/lang/invoke/TestStableFloat$NestedStableField3 + * java/lang/invoke/TestStableFloat$NestedStableField3$A + * java/lang/invoke/TestStableFloat$DefaultValue + * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim2 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableFloat + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableFloat + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableFloat + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableFloat + */ +package java.lang.invoke; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import sun.management.ManagementFactoryHelper; +import java.lang.reflect.InvocationTargetException; + +public class TestStableFloat { + public static void main(String[] args) throws Exception { + System.out.println("@Stable enabled: "+isStableEnabled); + System.out.println(); + + run(DefaultValue.class); + run(FloatStable.class); + run(StaticFloatStable.class); + run(VolatileFloatStable.class); + + // @Stable arrays: Dim 1-4 + run(FloatArrayDim1.class); + run(FloatArrayDim2.class); + run(FloatArrayDim3.class); + run(FloatArrayDim4.class); + + // @Stable Object field: dynamic arrays + run(ObjectArrayLowerDim0.class); + run(ObjectArrayLowerDim1.class); + run(ObjectArrayLowerDim2.class); + + // Nested @Stable fields + run(NestedStableField.class); + run(NestedStableField1.class); + run(NestedStableField2.class); + run(NestedStableField3.class); + + if (failed) { + throw new Error("TEST FAILED"); + } + } + + /* ==================================================== */ + + static class DefaultValue { + public @Stable float v; + + public static final DefaultValue c = new DefaultValue(); + public static float get() { return c.v; } + public static void test() throws Exception { + float val1 = get(); + c.v = 1.0F; float val2 = get(); + assertEquals(val1, 0F); + assertEquals(val2, 1.0F); + } + } + + /* ==================================================== */ + + static class FloatStable { + public @Stable float v; + + public static final FloatStable c = new FloatStable(); + public static float get() { return c.v; } + public static void test() throws Exception { + c.v = 1.0F; float val1 = get(); + c.v = 2.0F; float val2 = get(); + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + } + } + + /* ==================================================== */ + + static class StaticFloatStable { + public static @Stable float v; + + public static final StaticFloatStable c = new StaticFloatStable(); + public static float get() { return c.v; } + public static void test() throws Exception { + c.v = 1.0F; float val1 = get(); + c.v = 2.0F; float val2 = get(); + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + } + } + + /* ==================================================== */ + + static class VolatileFloatStable { + public @Stable volatile float v; + + public static final VolatileFloatStable c = new VolatileFloatStable(); + public static float get() { return c.v; } + public static void test() throws Exception { + c.v = 1.0F; float val1 = get(); + c.v = 2.0F; float val2 = get(); + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + } + } + + /* ==================================================== */ + // @Stable array == field && all components are stable + + static class FloatArrayDim1 { + public @Stable float[] v; + + public static final FloatArrayDim1 c = new FloatArrayDim1(); + public static float get() { return c.v[0]; } + public static float get1() { return c.v[10]; } + public static float[] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new float[1]; c.v[0] = 1.0F; float val1 = get(); + c.v[0] = 2.0F; float val2 = get(); + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + + c.v = new float[1]; c.v[0] = 3.0F; float val3 = get(); + assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F)); + } + + { + c.v = new float[20]; c.v[10] = 1.0F; float val1 = get1(); + c.v[10] = 2.0F; float val2 = get1(); + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + + c.v = new float[20]; c.v[10] = 3.0F; float val3 = get1(); + assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F)); + } + + { + c.v = new float[1]; float[] val1 = get2(); + c.v = new float[1]; float[] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class FloatArrayDim2 { + public @Stable float[][] v; + + public static final FloatArrayDim2 c = new FloatArrayDim2(); + public static float get() { return c.v[0][0]; } + public static float[] get1() { return c.v[0]; } + public static float[][] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new float[1][1]; c.v[0][0] = 1.0F; float val1 = get(); + c.v[0][0] = 2.0F; float val2 = get(); + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + + c.v = new float[1][1]; c.v[0][0] = 3.0F; float val3 = get(); + assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F)); + + c.v[0] = new float[1]; c.v[0][0] = 4.0F; float val4 = get(); + assertEquals(val4, (isStableEnabled ? 1.0F : 4.0F)); + } + + { + c.v = new float[1][1]; float[] val1 = get1(); + c.v[0] = new float[1]; float[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new float[1][1]; float[][] val1 = get2(); + c.v = new float[1][1]; float[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class FloatArrayDim3 { + public @Stable float[][][] v; + + public static final FloatArrayDim3 c = new FloatArrayDim3(); + public static float get() { return c.v[0][0][0]; } + public static float[] get1() { return c.v[0][0]; } + public static float[][] get2() { return c.v[0]; } + public static float[][][] get3() { return c.v; } + public static void test() throws Exception { + { + c.v = new float[1][1][1]; c.v[0][0][0] = 1.0F; float val1 = get(); + c.v[0][0][0] = 2.0F; float val2 = get(); + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + + c.v = new float[1][1][1]; c.v[0][0][0] = 3.0F; float val3 = get(); + assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F)); + + c.v[0] = new float[1][1]; c.v[0][0][0] = 4.0F; float val4 = get(); + assertEquals(val4, (isStableEnabled ? 1.0F : 4.0F)); + + c.v[0][0] = new float[1]; c.v[0][0][0] = 5.0F; float val5 = get(); + assertEquals(val5, (isStableEnabled ? 1.0F : 5.0F)); + } + + { + c.v = new float[1][1][1]; float[] val1 = get1(); + c.v[0][0] = new float[1]; float[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new float[1][1][1]; float[][] val1 = get2(); + c.v[0] = new float[1][1]; float[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new float[1][1][1]; float[][][] val1 = get3(); + c.v = new float[1][1][1]; float[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class FloatArrayDim4 { + public @Stable float[][][][] v; + + public static final FloatArrayDim4 c = new FloatArrayDim4(); + public static float get() { return c.v[0][0][0][0]; } + public static float[] get1() { return c.v[0][0][0]; } + public static float[][] get2() { return c.v[0][0]; } + public static float[][][] get3() { return c.v[0]; } + public static float[][][][] get4() { return c.v; } + public static void test() throws Exception { + { + c.v = new float[1][1][1][1]; c.v[0][0][0][0] = 1.0F; float val1 = get(); + c.v[0][0][0][0] = 2.0F; float val2 = get(); + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + + c.v = new float[1][1][1][1]; c.v[0][0][0][0] = 3.0F; float val3 = get(); + assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F)); + + c.v[0] = new float[1][1][1]; c.v[0][0][0][0] = 4.0F; float val4 = get(); + assertEquals(val4, (isStableEnabled ? 1.0F : 4.0F)); + + c.v[0][0] = new float[1][1]; c.v[0][0][0][0] = 5.0F; float val5 = get(); + assertEquals(val5, (isStableEnabled ? 1.0F : 5.0F)); + + c.v[0][0][0] = new float[1]; c.v[0][0][0][0] = 6.0F; float val6 = get(); + assertEquals(val6, (isStableEnabled ? 1.0F : 6.0F)); + } + + { + c.v = new float[1][1][1][1]; float[] val1 = get1(); + c.v[0][0][0] = new float[1]; float[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new float[1][1][1][1]; float[][] val1 = get2(); + c.v[0][0] = new float[1][1]; float[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new float[1][1][1][1]; float[][][] val1 = get3(); + c.v[0] = new float[1][1][1]; float[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new float[1][1][1][1]; float[][][][] val1 = get4(); + c.v = new float[1][1][1][1]; float[][][][] val2 = get4(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + } + } + + /* ==================================================== */ + // Dynamic Dim is higher than static + + static class ObjectArrayLowerDim0 { + public @Stable Object v; + + public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); + public static float get() { return ((float[])c.v)[0]; } + public static float[] get1() { return (float[])c.v; } + + public static void test() throws Exception { + { + c.v = new float[1]; ((float[])c.v)[0] = 1.0F; float val1 = get(); + ((float[])c.v)[0] = 2.0F; float val2 = get(); + + assertEquals(val1, 1.0F); + assertEquals(val2, 2.0F); + } + + { + c.v = new float[1]; float[] val1 = get1(); + c.v = new float[1]; float[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim1 { + public @Stable Object[] v; + + public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); + public static float get() { return ((float[][])c.v)[0][0]; } + public static float[] get1() { return (float[])(c.v[0]); } + public static Object[] get2() { return c.v; } + + public static void test() throws Exception { + { + c.v = new float[1][1]; ((float[][])c.v)[0][0] = 1.0F; float val1 = get(); + ((float[][])c.v)[0][0] = 2.0F; float val2 = get(); + + assertEquals(val1, 1.0F); + assertEquals(val2, 2.0F); + } + + { + c.v = new float[1][1]; c.v[0] = new float[0]; float[] val1 = get1(); + c.v[0] = new float[0]; float[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new float[0][0]; Object[] val1 = get2(); + c.v = new float[0][0]; Object[] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); + public static float get() { return ((float[][][])c.v)[0][0][0]; } + public static float[] get1() { return (float[])(c.v[0][0]); } + public static float[][] get2() { return (float[][])(c.v[0]); } + public static Object[][] get3() { return c.v; } + + public static void test() throws Exception { + { + c.v = new float[1][1][1]; ((float[][][])c.v)[0][0][0] = 1.0F; float val1 = get(); + ((float[][][])c.v)[0][0][0] = 2.0F; float val2 = get(); + + assertEquals(val1, 1.0F); + assertEquals(val2, 2.0F); + } + + { + c.v = new float[1][1][1]; c.v[0][0] = new float[0]; float[] val1 = get1(); + c.v[0][0] = new float[0]; float[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new float[1][1][1]; c.v[0] = new float[0][0]; float[][] val1 = get2(); + c.v[0] = new float[0][0]; float[][] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new float[0][0][0]; Object[][] val1 = get3(); + c.v = new float[0][0][0]; Object[][] val2 = get3(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class NestedStableField { + static class A { + public @Stable float a; + + } + public @Stable A v; + + public static final NestedStableField c = new NestedStableField(); + public static A get() { return c.v; } + public static float get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.a = 1.0F; A val1 = get(); + c.v.a = 2.0F; A val2 = get(); + + assertEquals(val1.a, 2.0F); + assertEquals(val2.a, 2.0F); + } + + { + c.v = new A(); c.v.a = 1.0F; float val1 = get1(); + c.v.a = 2.0F; float val2 = get1(); + c.v = new A(); c.v.a = 3.0F; float val3 = get1(); + + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F)); + } + } + } + + /* ==================================================== */ + + static class NestedStableField1 { + static class A { + public @Stable float a; + public @Stable A next; + } + public @Stable A v; + + public static final NestedStableField1 c = new NestedStableField1(); + public static A get() { return c.v.next.next.next.next.next.next.next; } + public static float get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; + c.v.a = 1.0F; c.v.next.a = 1.0F; A val1 = get(); + c.v.a = 2.0F; c.v.next.a = 2.0F; A val2 = get(); + + assertEquals(val1.a, 2.0F); + assertEquals(val2.a, 2.0F); + } + + { + c.v = new A(); c.v.next = c.v; + c.v.a = 1.0F; float val1 = get1(); + c.v.a = 2.0F; float val2 = get1(); + c.v = new A(); c.v.next = c.v; + c.v.a = 3.0F; float val3 = get1(); + + assertEquals(val1, 1.0F); + assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); + assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F)); + } + } + } + /* ==================================================== */ + + static class NestedStableField2 { + static class A { + public @Stable float a; + public @Stable A left; + public A right; + } + + public @Stable A v; + + public static final NestedStableField2 c = new NestedStableField2(); + public static float get() { return c.v.left.left.left.a; } + public static float get1() { return c.v.left.left.right.left.a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.left = c.v.right = c.v; + c.v.a = 1.0F; float val1 = get(); float val2 = get1(); + c.v.a = 2.0F; float val3 = get(); float val4 = get1(); + + assertEquals(val1, 1.0F); + assertEquals(val3, (isStableEnabled ? 1.0F : 2.0F)); + + assertEquals(val2, 1.0F); + assertEquals(val4, 2.0F); + } + } + } + + /* ==================================================== */ + + static class NestedStableField3 { + static class A { + public @Stable float a; + public @Stable A[] left; + public A[] right; + } + + public @Stable A[] v; + + public static final NestedStableField3 c = new NestedStableField3(); + public static float get() { return c.v[0].left[1].left[0].left[1].a; } + public static float get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } + + public static void test() throws Exception { + { + A elem = new A(); + c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; + elem.a = 1.0F; float val1 = get(); float val2 = get1(); + elem.a = 2.0F; float val3 = get(); float val4 = get1(); + + assertEquals(val1, 1.0F); + assertEquals(val3, (isStableEnabled ? 1.0F : 2.0F)); + + assertEquals(val2, 1.0F); + assertEquals(val4, 2.0F); + } + } + } + + /* ==================================================== */ + // Auxiliary methods + static void assertEquals(float i, float j) { if (i != j) throw new AssertionError(i + " != " + j); } + static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } + + static boolean failed = false; + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + failed = true; + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } + + static final boolean isStableEnabled; + static { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption tmp; + try { + tmp = diagnostic.getVMOption("FoldStableValues"); + } catch (IllegalArgumentException e) { + tmp = null; + } + isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); + } +} diff --git a/hotspot/test/compiler/stable/TestStableInt.java b/hotspot/test/compiler/stable/TestStableInt.java new file mode 100644 index 00000000000..9632a8dc39d --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableInt.java @@ -0,0 +1,632 @@ +/* + * 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. + */ + +/* + * @test TestStableInt + * @summary tests on stable fields and arrays + * @library /testlibrary + * @compile -XDignore.symbol.file TestStableInt.java + * @run main ClassFileInstaller + * java/lang/invoke/TestStableInt + * java/lang/invoke/TestStableInt$IntStable + * java/lang/invoke/TestStableInt$StaticIntStable + * java/lang/invoke/TestStableInt$VolatileIntStable + * java/lang/invoke/TestStableInt$IntArrayDim1 + * java/lang/invoke/TestStableInt$IntArrayDim2 + * java/lang/invoke/TestStableInt$IntArrayDim3 + * java/lang/invoke/TestStableInt$IntArrayDim4 + * java/lang/invoke/TestStableInt$ObjectArrayLowerDim0 + * java/lang/invoke/TestStableInt$ObjectArrayLowerDim1 + * java/lang/invoke/TestStableInt$NestedStableField + * java/lang/invoke/TestStableInt$NestedStableField$A + * java/lang/invoke/TestStableInt$NestedStableField1 + * java/lang/invoke/TestStableInt$NestedStableField1$A + * java/lang/invoke/TestStableInt$NestedStableField2 + * java/lang/invoke/TestStableInt$NestedStableField2$A + * java/lang/invoke/TestStableInt$NestedStableField3 + * java/lang/invoke/TestStableInt$NestedStableField3$A + * java/lang/invoke/TestStableInt$DefaultValue + * java/lang/invoke/TestStableInt$ObjectArrayLowerDim2 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableInt + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableInt + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableInt + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableInt + */ +package java.lang.invoke; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import sun.management.ManagementFactoryHelper; +import java.lang.reflect.InvocationTargetException; + +public class TestStableInt { + public static void main(String[] args) throws Exception { + System.out.println("@Stable enabled: "+isStableEnabled); + System.out.println(); + + run(DefaultValue.class); + run(IntStable.class); + run(StaticIntStable.class); + run(VolatileIntStable.class); + + // @Stable arrays: Dim 1-4 + run(IntArrayDim1.class); + run(IntArrayDim2.class); + run(IntArrayDim3.class); + run(IntArrayDim4.class); + + // @Stable Object field: dynamic arrays + run(ObjectArrayLowerDim0.class); + run(ObjectArrayLowerDim1.class); + run(ObjectArrayLowerDim2.class); + + // Nested @Stable fields + run(NestedStableField.class); + run(NestedStableField1.class); + run(NestedStableField2.class); + run(NestedStableField3.class); + + if (failed) { + throw new Error("TEST FAILED"); + } + } + + /* ==================================================== */ + + static class DefaultValue { + public @Stable int v; + + public static final DefaultValue c = new DefaultValue(); + public static int get() { return c.v; } + public static void test() throws Exception { + int val1 = get(); + c.v = 1; int val2 = get(); + assertEquals(val1, 0); + assertEquals(val2, 1); + } + } + + /* ==================================================== */ + + static class IntStable { + public @Stable int v; + + public static final IntStable c = new IntStable(); + public static int get() { return c.v; } + public static void test() throws Exception { + c.v = 1; int val1 = get(); + c.v = 2; int val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + } + } + + /* ==================================================== */ + + static class StaticIntStable { + public static @Stable int v; + + public static final StaticIntStable c = new StaticIntStable(); + public static int get() { return c.v; } + public static void test() throws Exception { + c.v = 1; int val1 = get(); + c.v = 2; int val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + } + } + + /* ==================================================== */ + + static class VolatileIntStable { + public @Stable volatile int v; + + public static final VolatileIntStable c = new VolatileIntStable(); + public static int get() { return c.v; } + public static void test() throws Exception { + c.v = 1; int val1 = get(); + c.v = 2; int val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + } + } + + /* ==================================================== */ + // @Stable array == field && all components are stable + + static class IntArrayDim1 { + public @Stable int[] v; + + public static final IntArrayDim1 c = new IntArrayDim1(); + public static int get() { return c.v[0]; } + public static int get1() { return c.v[10]; } + public static int[] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new int[1]; c.v[0] = 1; int val1 = get(); + c.v[0] = 2; int val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new int[1]; c.v[0] = 3; int val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + + { + c.v = new int[20]; c.v[10] = 1; int val1 = get1(); + c.v[10] = 2; int val2 = get1(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new int[20]; c.v[10] = 3; int val3 = get1(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + + { + c.v = new int[1]; int[] val1 = get2(); + c.v = new int[1]; int[] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class IntArrayDim2 { + public @Stable int[][] v; + + public static final IntArrayDim2 c = new IntArrayDim2(); + public static int get() { return c.v[0][0]; } + public static int[] get1() { return c.v[0]; } + public static int[][] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new int[1][1]; c.v[0][0] = 1; int val1 = get(); + c.v[0][0] = 2; int val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new int[1][1]; c.v[0][0] = 3; int val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new int[1]; c.v[0][0] = 4; int val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + } + + { + c.v = new int[1][1]; int[] val1 = get1(); + c.v[0] = new int[1]; int[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new int[1][1]; int[][] val1 = get2(); + c.v = new int[1][1]; int[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class IntArrayDim3 { + public @Stable int[][][] v; + + public static final IntArrayDim3 c = new IntArrayDim3(); + public static int get() { return c.v[0][0][0]; } + public static int[] get1() { return c.v[0][0]; } + public static int[][] get2() { return c.v[0]; } + public static int[][][] get3() { return c.v; } + public static void test() throws Exception { + { + c.v = new int[1][1][1]; c.v[0][0][0] = 1; int val1 = get(); + c.v[0][0][0] = 2; int val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new int[1][1][1]; c.v[0][0][0] = 3; int val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new int[1][1]; c.v[0][0][0] = 4; int val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + + c.v[0][0] = new int[1]; c.v[0][0][0] = 5; int val5 = get(); + assertEquals(val5, (isStableEnabled ? 1 : 5)); + } + + { + c.v = new int[1][1][1]; int[] val1 = get1(); + c.v[0][0] = new int[1]; int[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new int[1][1][1]; int[][] val1 = get2(); + c.v[0] = new int[1][1]; int[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new int[1][1][1]; int[][][] val1 = get3(); + c.v = new int[1][1][1]; int[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class IntArrayDim4 { + public @Stable int[][][][] v; + + public static final IntArrayDim4 c = new IntArrayDim4(); + public static int get() { return c.v[0][0][0][0]; } + public static int[] get1() { return c.v[0][0][0]; } + public static int[][] get2() { return c.v[0][0]; } + public static int[][][] get3() { return c.v[0]; } + public static int[][][][] get4() { return c.v; } + public static void test() throws Exception { + { + c.v = new int[1][1][1][1]; c.v[0][0][0][0] = 1; int val1 = get(); + c.v[0][0][0][0] = 2; int val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new int[1][1][1][1]; c.v[0][0][0][0] = 3; int val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new int[1][1][1]; c.v[0][0][0][0] = 4; int val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + + c.v[0][0] = new int[1][1]; c.v[0][0][0][0] = 5; int val5 = get(); + assertEquals(val5, (isStableEnabled ? 1 : 5)); + + c.v[0][0][0] = new int[1]; c.v[0][0][0][0] = 6; int val6 = get(); + assertEquals(val6, (isStableEnabled ? 1 : 6)); + } + + { + c.v = new int[1][1][1][1]; int[] val1 = get1(); + c.v[0][0][0] = new int[1]; int[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new int[1][1][1][1]; int[][] val1 = get2(); + c.v[0][0] = new int[1][1]; int[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new int[1][1][1][1]; int[][][] val1 = get3(); + c.v[0] = new int[1][1][1]; int[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new int[1][1][1][1]; int[][][][] val1 = get4(); + c.v = new int[1][1][1][1]; int[][][][] val2 = get4(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + } + } + + /* ==================================================== */ + // Dynamic Dim is higher than static + + static class ObjectArrayLowerDim0 { + public @Stable Object v; + + public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); + public static int get() { return ((int[])c.v)[0]; } + public static int[] get1() { return (int[])c.v; } + + public static void test() throws Exception { + { + c.v = new int[1]; ((int[])c.v)[0] = 1; int val1 = get(); + ((int[])c.v)[0] = 2; int val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new int[1]; int[] val1 = get1(); + c.v = new int[1]; int[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim1 { + public @Stable Object[] v; + + public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); + public static int get() { return ((int[][])c.v)[0][0]; } + public static int[] get1() { return (int[])(c.v[0]); } + public static Object[] get2() { return c.v; } + + public static void test() throws Exception { + { + c.v = new int[1][1]; ((int[][])c.v)[0][0] = 1; int val1 = get(); + ((int[][])c.v)[0][0] = 2; int val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new int[1][1]; c.v[0] = new int[0]; int[] val1 = get1(); + c.v[0] = new int[0]; int[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new int[0][0]; Object[] val1 = get2(); + c.v = new int[0][0]; Object[] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); + public static int get() { return ((int[][][])c.v)[0][0][0]; } + public static int[] get1() { return (int[])(c.v[0][0]); } + public static int[][] get2() { return (int[][])(c.v[0]); } + public static Object[][] get3() { return c.v; } + + public static void test() throws Exception { + { + c.v = new int[1][1][1]; ((int[][][])c.v)[0][0][0] = 1; int val1 = get(); + ((int[][][])c.v)[0][0][0] = 2; int val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new int[1][1][1]; c.v[0][0] = new int[0]; int[] val1 = get1(); + c.v[0][0] = new int[0]; int[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new int[1][1][1]; c.v[0] = new int[0][0]; int[][] val1 = get2(); + c.v[0] = new int[0][0]; int[][] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new int[0][0][0]; Object[][] val1 = get3(); + c.v = new int[0][0][0]; Object[][] val2 = get3(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class NestedStableField { + static class A { + public @Stable int a; + + } + public @Stable A v; + + public static final NestedStableField c = new NestedStableField(); + public static A get() { return c.v; } + public static int get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.a = 1; A val1 = get(); + c.v.a = 2; A val2 = get(); + + assertEquals(val1.a, 2); + assertEquals(val2.a, 2); + } + + { + c.v = new A(); c.v.a = 1; int val1 = get1(); + c.v.a = 2; int val2 = get1(); + c.v = new A(); c.v.a = 3; int val3 = get1(); + + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + } + } + + /* ==================================================== */ + + static class NestedStableField1 { + static class A { + public @Stable int a; + public @Stable A next; + } + public @Stable A v; + + public static final NestedStableField1 c = new NestedStableField1(); + public static A get() { return c.v.next.next.next.next.next.next.next; } + public static int get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; + c.v.a = 1; c.v.next.a = 1; A val1 = get(); + c.v.a = 2; c.v.next.a = 2; A val2 = get(); + + assertEquals(val1.a, 2); + assertEquals(val2.a, 2); + } + + { + c.v = new A(); c.v.next = c.v; + c.v.a = 1; int val1 = get1(); + c.v.a = 2; int val2 = get1(); + c.v = new A(); c.v.next = c.v; + c.v.a = 3; int val3 = get1(); + + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + } + } + /* ==================================================== */ + + static class NestedStableField2 { + static class A { + public @Stable int a; + public @Stable A left; + public A right; + } + + public @Stable A v; + + public static final NestedStableField2 c = new NestedStableField2(); + public static int get() { return c.v.left.left.left.a; } + public static int get1() { return c.v.left.left.right.left.a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.left = c.v.right = c.v; + c.v.a = 1; int val1 = get(); int val2 = get1(); + c.v.a = 2; int val3 = get(); int val4 = get1(); + + assertEquals(val1, 1); + assertEquals(val3, (isStableEnabled ? 1 : 2)); + + assertEquals(val2, 1); + assertEquals(val4, 2); + } + } + } + + /* ==================================================== */ + + static class NestedStableField3 { + static class A { + public @Stable int a; + public @Stable A[] left; + public A[] right; + } + + public @Stable A[] v; + + public static final NestedStableField3 c = new NestedStableField3(); + public static int get() { return c.v[0].left[1].left[0].left[1].a; } + public static int get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } + + public static void test() throws Exception { + { + A elem = new A(); + c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; + elem.a = 1; int val1 = get(); int val2 = get1(); + elem.a = 2; int val3 = get(); int val4 = get1(); + + assertEquals(val1, 1); + assertEquals(val3, (isStableEnabled ? 1 : 2)); + + assertEquals(val2, 1); + assertEquals(val4, 2); + } + } + } + + /* ==================================================== */ + // Auxiliary methods + static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); } + static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } + + static boolean failed = false; + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + failed = true; + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } + + static final boolean isStableEnabled; + static { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption tmp; + try { + tmp = diagnostic.getVMOption("FoldStableValues"); + } catch (IllegalArgumentException e) { + tmp = null; + } + isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); + } +} diff --git a/hotspot/test/compiler/stable/TestStableLong.java b/hotspot/test/compiler/stable/TestStableLong.java new file mode 100644 index 00000000000..d1c72f5609c --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableLong.java @@ -0,0 +1,632 @@ +/* + * 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. + */ + +/* + * @test TestStableLong + * @summary tests on stable fields and arrays + * @library /testlibrary + * @compile -XDignore.symbol.file TestStableLong.java + * @run main ClassFileInstaller + * java/lang/invoke/TestStableLong + * java/lang/invoke/TestStableLong$LongStable + * java/lang/invoke/TestStableLong$StaticLongStable + * java/lang/invoke/TestStableLong$VolatileLongStable + * java/lang/invoke/TestStableLong$LongArrayDim1 + * java/lang/invoke/TestStableLong$LongArrayDim2 + * java/lang/invoke/TestStableLong$LongArrayDim3 + * java/lang/invoke/TestStableLong$LongArrayDim4 + * java/lang/invoke/TestStableLong$ObjectArrayLowerDim0 + * java/lang/invoke/TestStableLong$ObjectArrayLowerDim1 + * java/lang/invoke/TestStableLong$NestedStableField + * java/lang/invoke/TestStableLong$NestedStableField$A + * java/lang/invoke/TestStableLong$NestedStableField1 + * java/lang/invoke/TestStableLong$NestedStableField1$A + * java/lang/invoke/TestStableLong$NestedStableField2 + * java/lang/invoke/TestStableLong$NestedStableField2$A + * java/lang/invoke/TestStableLong$NestedStableField3 + * java/lang/invoke/TestStableLong$NestedStableField3$A + * java/lang/invoke/TestStableLong$DefaultValue + * java/lang/invoke/TestStableLong$ObjectArrayLowerDim2 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableLong + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableLong + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableLong + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableLong + */ +package java.lang.invoke; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import sun.management.ManagementFactoryHelper; +import java.lang.reflect.InvocationTargetException; + +public class TestStableLong { + public static void main(String[] args) throws Exception { + System.out.println("@Stable enabled: "+isStableEnabled); + System.out.println(); + + run(DefaultValue.class); + run(LongStable.class); + run(StaticLongStable.class); + run(VolatileLongStable.class); + + // @Stable arrays: Dim 1-4 + run(LongArrayDim1.class); + run(LongArrayDim2.class); + run(LongArrayDim3.class); + run(LongArrayDim4.class); + + // @Stable Object field: dynamic arrays + run(ObjectArrayLowerDim0.class); + run(ObjectArrayLowerDim1.class); + run(ObjectArrayLowerDim2.class); + + // Nested @Stable fields + run(NestedStableField.class); + run(NestedStableField1.class); + run(NestedStableField2.class); + run(NestedStableField3.class); + + if (failed) { + throw new Error("TEST FAILED"); + } + } + + /* ==================================================== */ + + static class DefaultValue { + public @Stable long v; + + public static final DefaultValue c = new DefaultValue(); + public static long get() { return c.v; } + public static void test() throws Exception { + long val1 = get(); + c.v = 1L; long val2 = get(); + assertEquals(val1, 0); + assertEquals(val2, 1L); + } + } + + /* ==================================================== */ + + static class LongStable { + public @Stable long v; + + public static final LongStable c = new LongStable(); + public static long get() { return c.v; } + public static void test() throws Exception { + c.v = 5; long val1 = get(); + c.v = Long.MAX_VALUE; long val2 = get(); + assertEquals(val1, 5); + assertEquals(val2, (isStableEnabled ? 5 : Long.MAX_VALUE)); + } + } + + /* ==================================================== */ + + static class StaticLongStable { + public static @Stable long v; + + public static final StaticLongStable c = new StaticLongStable(); + public static long get() { return c.v; } + public static void test() throws Exception { + c.v = 5; long val1 = get(); + c.v = Long.MAX_VALUE; long val2 = get(); + assertEquals(val1, 5); + assertEquals(val2, (isStableEnabled ? 5 : Long.MAX_VALUE)); + } + } + + /* ==================================================== */ + + static class VolatileLongStable { + public @Stable volatile long v; + + public static final VolatileLongStable c = new VolatileLongStable(); + public static long get() { return c.v; } + public static void test() throws Exception { + c.v = 5; long val1 = get(); + c.v = Long.MAX_VALUE; long val2 = get(); + assertEquals(val1, 5); + assertEquals(val2, (isStableEnabled ? 5 : Long.MAX_VALUE)); + } + } + + /* ==================================================== */ + // @Stable array == field && all components are stable + + static class LongArrayDim1 { + public @Stable long[] v; + + public static final LongArrayDim1 c = new LongArrayDim1(); + public static long get() { return c.v[0]; } + public static long get1() { return c.v[10]; } + public static long[] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new long[1]; c.v[0] = 1; long val1 = get(); + c.v[0] = 2; long val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new long[1]; c.v[0] = 3; long val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + + { + c.v = new long[20]; c.v[10] = 1; long val1 = get1(); + c.v[10] = 2; long val2 = get1(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new long[20]; c.v[10] = 3; long val3 = get1(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + + { + c.v = new long[1]; long[] val1 = get2(); + c.v = new long[1]; long[] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class LongArrayDim2 { + public @Stable long[][] v; + + public static final LongArrayDim2 c = new LongArrayDim2(); + public static long get() { return c.v[0][0]; } + public static long[] get1() { return c.v[0]; } + public static long[][] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new long[1][1]; c.v[0][0] = 1; long val1 = get(); + c.v[0][0] = 2; long val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new long[1][1]; c.v[0][0] = 3; long val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new long[1]; c.v[0][0] = 4; long val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + } + + { + c.v = new long[1][1]; long[] val1 = get1(); + c.v[0] = new long[1]; long[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new long[1][1]; long[][] val1 = get2(); + c.v = new long[1][1]; long[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class LongArrayDim3 { + public @Stable long[][][] v; + + public static final LongArrayDim3 c = new LongArrayDim3(); + public static long get() { return c.v[0][0][0]; } + public static long[] get1() { return c.v[0][0]; } + public static long[][] get2() { return c.v[0]; } + public static long[][][] get3() { return c.v; } + public static void test() throws Exception { + { + c.v = new long[1][1][1]; c.v[0][0][0] = 1; long val1 = get(); + c.v[0][0][0] = 2; long val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new long[1][1][1]; c.v[0][0][0] = 3; long val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new long[1][1]; c.v[0][0][0] = 4; long val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + + c.v[0][0] = new long[1]; c.v[0][0][0] = 5; long val5 = get(); + assertEquals(val5, (isStableEnabled ? 1 : 5)); + } + + { + c.v = new long[1][1][1]; long[] val1 = get1(); + c.v[0][0] = new long[1]; long[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new long[1][1][1]; long[][] val1 = get2(); + c.v[0] = new long[1][1]; long[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new long[1][1][1]; long[][][] val1 = get3(); + c.v = new long[1][1][1]; long[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class LongArrayDim4 { + public @Stable long[][][][] v; + + public static final LongArrayDim4 c = new LongArrayDim4(); + public static long get() { return c.v[0][0][0][0]; } + public static long[] get1() { return c.v[0][0][0]; } + public static long[][] get2() { return c.v[0][0]; } + public static long[][][] get3() { return c.v[0]; } + public static long[][][][] get4() { return c.v; } + public static void test() throws Exception { + { + c.v = new long[1][1][1][1]; c.v[0][0][0][0] = 1; long val1 = get(); + c.v[0][0][0][0] = 2; long val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new long[1][1][1][1]; c.v[0][0][0][0] = 3; long val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new long[1][1][1]; c.v[0][0][0][0] = 4; long val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + + c.v[0][0] = new long[1][1]; c.v[0][0][0][0] = 5; long val5 = get(); + assertEquals(val5, (isStableEnabled ? 1 : 5)); + + c.v[0][0][0] = new long[1]; c.v[0][0][0][0] = 6; long val6 = get(); + assertEquals(val6, (isStableEnabled ? 1 : 6)); + } + + { + c.v = new long[1][1][1][1]; long[] val1 = get1(); + c.v[0][0][0] = new long[1]; long[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new long[1][1][1][1]; long[][] val1 = get2(); + c.v[0][0] = new long[1][1]; long[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new long[1][1][1][1]; long[][][] val1 = get3(); + c.v[0] = new long[1][1][1]; long[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new long[1][1][1][1]; long[][][][] val1 = get4(); + c.v = new long[1][1][1][1]; long[][][][] val2 = get4(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + } + } + + /* ==================================================== */ + // Dynamic Dim is higher than static + + static class ObjectArrayLowerDim0 { + public @Stable Object v; + + public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); + public static long get() { return ((long[])c.v)[0]; } + public static long[] get1() { return (long[])c.v; } + + public static void test() throws Exception { + { + c.v = new long[1]; ((long[])c.v)[0] = 1; long val1 = get(); + ((long[])c.v)[0] = 2; long val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new long[1]; long[] val1 = get1(); + c.v = new long[1]; long[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim1 { + public @Stable Object[] v; + + public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); + public static long get() { return ((long[][])c.v)[0][0]; } + public static long[] get1() { return (long[])(c.v[0]); } + public static Object[] get2() { return c.v; } + + public static void test() throws Exception { + { + c.v = new long[1][1]; ((long[][])c.v)[0][0] = 1; long val1 = get(); + ((long[][])c.v)[0][0] = 2; long val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new long[1][1]; c.v[0] = new long[0]; long[] val1 = get1(); + c.v[0] = new long[0]; long[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new long[0][0]; Object[] val1 = get2(); + c.v = new long[0][0]; Object[] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); + public static long get() { return ((long[][][])c.v)[0][0][0]; } + public static long[] get1() { return (long[])(c.v[0][0]); } + public static long[][] get2() { return (long[][])(c.v[0]); } + public static Object[][] get3() { return c.v; } + + public static void test() throws Exception { + { + c.v = new long[1][1][1]; ((long[][][])c.v)[0][0][0] = 1L; long val1 = get(); + ((long[][][])c.v)[0][0][0] = 2L; long val2 = get(); + + assertEquals(val1, 1L); + assertEquals(val2, 2L); + } + + { + c.v = new long[1][1][1]; c.v[0][0] = new long[0]; long[] val1 = get1(); + c.v[0][0] = new long[0]; long[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new long[1][1][1]; c.v[0] = new long[0][0]; long[][] val1 = get2(); + c.v[0] = new long[0][0]; long[][] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new long[0][0][0]; Object[][] val1 = get3(); + c.v = new long[0][0][0]; Object[][] val2 = get3(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class NestedStableField { + static class A { + public @Stable long a; + + } + public @Stable A v; + + public static final NestedStableField c = new NestedStableField(); + public static A get() { return c.v; } + public static long get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.a = 1; A val1 = get(); + c.v.a = 2; A val2 = get(); + + assertEquals(val1.a, 2); + assertEquals(val2.a, 2); + } + + { + c.v = new A(); c.v.a = 1; long val1 = get1(); + c.v.a = 2; long val2 = get1(); + c.v = new A(); c.v.a = 3; long val3 = get1(); + + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + } + } + + /* ==================================================== */ + + static class NestedStableField1 { + static class A { + public @Stable long a; + public @Stable A next; + } + public @Stable A v; + + public static final NestedStableField1 c = new NestedStableField1(); + public static A get() { return c.v.next.next.next.next.next.next.next; } + public static long get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; + c.v.a = 1; c.v.next.a = 1; A val1 = get(); + c.v.a = 2; c.v.next.a = 2; A val2 = get(); + + assertEquals(val1.a, 2); + assertEquals(val2.a, 2); + } + + { + c.v = new A(); c.v.next = c.v; + c.v.a = 1; long val1 = get1(); + c.v.a = 2; long val2 = get1(); + c.v = new A(); c.v.next = c.v; + c.v.a = 3; long val3 = get1(); + + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + } + } + /* ==================================================== */ + + static class NestedStableField2 { + static class A { + public @Stable long a; + public @Stable A left; + public A right; + } + + public @Stable A v; + + public static final NestedStableField2 c = new NestedStableField2(); + public static long get() { return c.v.left.left.left.a; } + public static long get1() { return c.v.left.left.right.left.a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.left = c.v.right = c.v; + c.v.a = 1; long val1 = get(); long val2 = get1(); + c.v.a = 2; long val3 = get(); long val4 = get1(); + + assertEquals(val1, 1); + assertEquals(val3, (isStableEnabled ? 1 : 2)); + + assertEquals(val2, 1); + assertEquals(val4, 2); + } + } + } + + /* ==================================================== */ + + static class NestedStableField3 { + static class A { + public @Stable long a; + public @Stable A[] left; + public A[] right; + } + + public @Stable A[] v; + + public static final NestedStableField3 c = new NestedStableField3(); + public static long get() { return c.v[0].left[1].left[0].left[1].a; } + public static long get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } + + public static void test() throws Exception { + { + A elem = new A(); + c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; + elem.a = 1; long val1 = get(); long val2 = get1(); + elem.a = 2; long val3 = get(); long val4 = get1(); + + assertEquals(val1, 1); + assertEquals(val3, (isStableEnabled ? 1 : 2)); + + assertEquals(val2, 1); + assertEquals(val4, 2); + } + } + } + + /* ==================================================== */ + // Auxiliary methods + static void assertEquals(long i, long j) { if (i != j) throw new AssertionError(i + " != " + j); } + static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } + + static boolean failed = false; + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + failed = true; + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } + + static final boolean isStableEnabled; + static { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption tmp; + try { + tmp = diagnostic.getVMOption("FoldStableValues"); + } catch (IllegalArgumentException e) { + tmp = null; + } + isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); + } +} diff --git a/hotspot/test/compiler/stable/TestStableObject.java b/hotspot/test/compiler/stable/TestStableObject.java new file mode 100644 index 00000000000..7958c6500c4 --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableObject.java @@ -0,0 +1,635 @@ +/* + * 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. + */ + +/* + * @test TestStableObject + * @summary tests on stable fields and arrays + * @library /testlibrary + * @compile -XDignore.symbol.file TestStableObject.java + * @run main ClassFileInstaller + * java/lang/invoke/TestStableObject + * java/lang/invoke/TestStableObject$ObjectStable + * java/lang/invoke/TestStableObject$StaticObjectStable + * java/lang/invoke/TestStableObject$VolatileObjectStable + * java/lang/invoke/TestStableObject$ObjectArrayDim1 + * java/lang/invoke/TestStableObject$ObjectArrayDim2 + * java/lang/invoke/TestStableObject$ObjectArrayDim3 + * java/lang/invoke/TestStableObject$ObjectArrayDim4 + * java/lang/invoke/TestStableObject$ObjectArrayLowerDim0 + * java/lang/invoke/TestStableObject$ObjectArrayLowerDim1 + * java/lang/invoke/TestStableObject$NestedStableField + * java/lang/invoke/TestStableObject$NestedStableField$A + * java/lang/invoke/TestStableObject$NestedStableField1 + * java/lang/invoke/TestStableObject$NestedStableField1$A + * java/lang/invoke/TestStableObject$NestedStableField2 + * java/lang/invoke/TestStableObject$NestedStableField2$A + * java/lang/invoke/TestStableObject$NestedStableField3 + * java/lang/invoke/TestStableObject$NestedStableField3$A + * java/lang/invoke/TestStableObject$Values + * java/lang/invoke/TestStableObject$DefaultValue + * java/lang/invoke/TestStableObject$ObjectArrayLowerDim2 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableObject + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableObject + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableObject + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableObject + */ +package java.lang.invoke; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import sun.management.ManagementFactoryHelper; +import java.lang.reflect.InvocationTargetException; + +public class TestStableObject { + public static void main(String[] args) throws Exception { + System.out.println("@Stable enabled: "+isStableEnabled); + System.out.println(); + + run(DefaultValue.class); + run(ObjectStable.class); + run(StaticObjectStable.class); + run(VolatileObjectStable.class); + + // @Stable arrays: Dim 1-4 + run(ObjectArrayDim1.class); + run(ObjectArrayDim2.class); + run(ObjectArrayDim3.class); + run(ObjectArrayDim4.class); + + // @Stable Object field: dynamic arrays + run(ObjectArrayLowerDim0.class); + run(ObjectArrayLowerDim1.class); + run(ObjectArrayLowerDim2.class); + + // Nested @Stable fields + run(NestedStableField.class); + run(NestedStableField1.class); + run(NestedStableField2.class); + run(NestedStableField3.class); + + if (failed) { + throw new Error("TEST FAILED"); + } + } + + /* ==================================================== */ + + enum Values {A, B, C, D, E, F} + + static class DefaultValue { + public @Stable Object v; + + public static final DefaultValue c = new DefaultValue(); + public static Object get() { return c.v; } + public static void test() throws Exception { + Object val1 = get(); + c.v = Values.A; Object val2 = get(); + assertEquals(val1, null); + assertEquals(val2, Values.A); + } + } + + /* ==================================================== */ + + static class ObjectStable { + public @Stable Values v; + + public static final ObjectStable c = new ObjectStable (); + public static Values get() { return c.v; } + public static void test() throws Exception { + c.v = Values.A; Values val1 = get(); + c.v = Values.B; Values val2 = get(); + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + } + } + + /* ==================================================== */ + + static class StaticObjectStable { + public static @Stable Values v; + + public static final ObjectStable c = new ObjectStable (); + public static Values get() { return c.v; } + public static void test() throws Exception { + c.v = Values.A; Values val1 = get(); + c.v = Values.B; Values val2 = get(); + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + } + } + + /* ==================================================== */ + + static class VolatileObjectStable { + public @Stable volatile Values v; + + public static final VolatileObjectStable c = new VolatileObjectStable (); + public static Values get() { return c.v; } + public static void test() throws Exception { + c.v = Values.A; Values val1 = get(); + c.v = Values.B; Values val2 = get(); + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + } + } + + /* ==================================================== */ + // @Stable array == field && all components are stable + + static class ObjectArrayDim1 { + public @Stable Object[] v; + + public static final ObjectArrayDim1 c = new ObjectArrayDim1(); + public static Object get() { return c.v[0]; } + public static Object get1() { return c.v[10]; } + public static Object[] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new Object[1]; c.v[0] = Values.A; Object val1 = get(); + c.v[0] = Values.B; Object val2 = get(); + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + + c.v = new Object[1]; c.v[0] = Values.C; Object val3 = get(); + assertEquals(val3, (isStableEnabled ? Values.A : Values.C)); + } + + { + c.v = new Object[20]; c.v[10] = Values.A; Object val1 = get1(); + c.v[10] = Values.B; Object val2 = get1(); + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + + c.v = new Object[20]; c.v[10] = Values.C; Object val3 = get1(); + assertEquals(val3, (isStableEnabled ? Values.A : Values.C)); + } + + { + c.v = new Object[1]; Object[] val1 = get2(); + c.v = new Object[1]; Object[] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayDim2 c = new ObjectArrayDim2(); + public static Object get() { return c.v[0][0]; } + public static Object[] get1() { return c.v[0]; } + public static Object[][] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new Object[1][1]; c.v[0][0] = Values.A; Object val1 = get(); + c.v[0][0] = Values.B; Object val2 = get(); + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + + c.v = new Object[1][1]; c.v[0][0] = Values.C; Object val3 = get(); + assertEquals(val3, (isStableEnabled ? Values.A : Values.C)); + + c.v[0] = new Object[1]; c.v[0][0] = Values.D; Object val4 = get(); + assertEquals(val4, (isStableEnabled ? Values.A : Values.D)); + } + + { + c.v = new Object[1][1]; Object[] val1 = get1(); + c.v[0] = new Object[1]; Object[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new Object[1][1]; Object[][] val1 = get2(); + c.v = new Object[1][1]; Object[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayDim3 { + public @Stable Object[][][] v; + + public static final ObjectArrayDim3 c = new ObjectArrayDim3(); + public static Object get() { return c.v[0][0][0]; } + public static Object[] get1() { return c.v[0][0]; } + public static Object[][] get2() { return c.v[0]; } + public static Object[][][] get3() { return c.v; } + public static void test() throws Exception { + { + c.v = new Object[1][1][1]; c.v[0][0][0] = Values.A; Object val1 = get(); + c.v[0][0][0] = Values.B; Object val2 = get(); + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + + c.v = new Object[1][1][1]; c.v[0][0][0] = Values.C; Object val3 = get(); + assertEquals(val3, (isStableEnabled ? Values.A : Values.C)); + + c.v[0] = new Object[1][1]; c.v[0][0][0] = Values.D; Object val4 = get(); + assertEquals(val4, (isStableEnabled ? Values.A : Values.D)); + + c.v[0][0] = new Object[1]; c.v[0][0][0] = Values.E; Object val5 = get(); + assertEquals(val5, (isStableEnabled ? Values.A : Values.E)); + } + + { + c.v = new Object[1][1][1]; Object[] val1 = get1(); + c.v[0][0] = new Object[1]; Object[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new Object[1][1][1]; Object[][] val1 = get2(); + c.v[0] = new Object[1][1]; Object[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new Object[1][1][1]; Object[][][] val1 = get3(); + c.v = new Object[1][1][1]; Object[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayDim4 { + public @Stable Object[][][][] v; + + public static final ObjectArrayDim4 c = new ObjectArrayDim4(); + public static Object get() { return c.v[0][0][0][0]; } + public static Object[] get1() { return c.v[0][0][0]; } + public static Object[][] get2() { return c.v[0][0]; } + public static Object[][][] get3() { return c.v[0]; } + public static Object[][][][] get4() { return c.v; } + public static void test() throws Exception { + { + c.v = new Object[1][1][1][1]; c.v[0][0][0][0] = Values.A; Object val1 = get(); + c.v[0][0][0][0] = Values.B; Object val2 = get(); + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + + c.v = new Object[1][1][1][1]; c.v[0][0][0][0] = Values.C; Object val3 = get(); + assertEquals(val3, (isStableEnabled ? Values.A : Values.C)); + + c.v[0] = new Object[1][1][1]; c.v[0][0][0][0] = Values.D; Object val4 = get(); + assertEquals(val4, (isStableEnabled ? Values.A : Values.D)); + + c.v[0][0] = new Object[1][1]; c.v[0][0][0][0] = Values.E; Object val5 = get(); + assertEquals(val5, (isStableEnabled ? Values.A : Values.E)); + + c.v[0][0][0] = new Object[1]; c.v[0][0][0][0] = Values.F; Object val6 = get(); + assertEquals(val6, (isStableEnabled ? Values.A : Values.F)); + } + + { + c.v = new Object[1][1][1][1]; Object[] val1 = get1(); + c.v[0][0][0] = new Object[1]; Object[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new Object[1][1][1][1]; Object[][] val1 = get2(); + c.v[0][0] = new Object[1][1]; Object[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new Object[1][1][1][1]; Object[][][] val1 = get3(); + c.v[0] = new Object[1][1][1]; Object[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new Object[1][1][1][1]; Object[][][][] val1 = get4(); + c.v = new Object[1][1][1][1]; Object[][][][] val2 = get4(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + } + } + + /* ==================================================== */ + // Dynamic Dim is higher than static + + static class ObjectArrayLowerDim0 { + public @Stable Object v; + + public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); + public static Object get() { return ((Object[])c.v)[0]; } + public static Object[] get1() { return (Object[])c.v; } + + public static void test() throws Exception { + { + c.v = new Object[1]; ((Object[])c.v)[0] = Values.A; Object val1 = get(); + ((Object[])c.v)[0] = Values.B; Object val2 = get(); + + assertEquals(val1, Values.A); + assertEquals(val2, Values.B); + } + + { + c.v = new Object[1]; Object[] val1 = get1(); + c.v = new Object[1]; Object[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim1 { + public @Stable Object[] v; + + public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); + public static Object get() { return ((Object[][])c.v)[0][0]; } + public static Object[] get1() { return (Object[])(c.v[0]); } + public static Object[] get2() { return c.v; } + + public static void test() throws Exception { + { + c.v = new Object[1][1]; ((Object[][])c.v)[0][0] = Values.A; Object val1 = get(); + ((Object[][])c.v)[0][0] = Values.B; Object val2 = get(); + + assertEquals(val1, Values.A); + assertEquals(val2, Values.B); + } + + { + c.v = new Object[1][1]; c.v[0] = new Object[0]; Object[] val1 = get1(); + c.v[0] = new Object[0]; Object[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new Object[0][0]; Object[] val1 = get2(); + c.v = new Object[0][0]; Object[] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); + public static Object get() { return ((Object[][][])c.v)[0][0][0]; } + public static Object[] get1() { return (Object[])(c.v[0][0]); } + public static Object[][] get2() { return (Object[][])(c.v[0]); } + public static Object[][] get3() { return c.v; } + + public static void test() throws Exception { + { + c.v = new Object[1][1][1]; ((Object[][][])c.v)[0][0][0] = Values.A; Object val1 = get(); + ((Object[][][])c.v)[0][0][0] = Values.B; Object val2 = get(); + + assertEquals(val1, Values.A); + assertEquals(val2, Values.B); + } + + { + c.v = new Object[1][1][1]; c.v[0][0] = new Object[0]; Object[] val1 = get1(); + c.v[0][0] = new Object[0]; Object[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new Object[1][1][1]; c.v[0] = new Object[0][0]; Object[][] val1 = get2(); + c.v[0] = new Object[0][0]; Object[][] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new Object[0][0][0]; Object[][] val1 = get3(); + c.v = new Object[0][0][0]; Object[][] val2 = get3(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class NestedStableField { + static class A { + public @Stable Object a; + + } + public @Stable A v; + + public static final NestedStableField c = new NestedStableField(); + public static A get() { return c.v; } + public static Object get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.a = Values.A; A val1 = get(); + c.v.a = Values.B; A val2 = get(); + + assertEquals(val1.a, Values.B); + assertEquals(val2.a, Values.B); + } + + { + c.v = new A(); c.v.a = Values.A; Object val1 = get1(); + c.v.a = Values.B; Object val2 = get1(); + c.v = new A(); c.v.a = Values.C; Object val3 = get1(); + + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + assertEquals(val3, (isStableEnabled ? Values.A : Values.C)); + } + } + } + + /* ==================================================== */ + + static class NestedStableField1 { + static class A { + public @Stable Object a; + public @Stable A next; + } + public @Stable A v; + + public static final NestedStableField1 c = new NestedStableField1(); + public static A get() { return c.v.next.next.next.next.next.next.next; } + public static Object get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; + c.v.a = Values.A; c.v.next.a = Values.A; A val1 = get(); + c.v.a = Values.B; c.v.next.a = Values.B; A val2 = get(); + + assertEquals(val1.a, Values.B); + assertEquals(val2.a, Values.B); + } + + { + c.v = new A(); c.v.next = c.v; + c.v.a = Values.A; Object val1 = get1(); + c.v.a = Values.B; Object val2 = get1(); + c.v = new A(); c.v.next = c.v; + c.v.a = Values.C; Object val3 = get1(); + + assertEquals(val1, Values.A); + assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); + assertEquals(val3, (isStableEnabled ? Values.A : Values.C)); + } + } + } + /* ==================================================== */ + + static class NestedStableField2 { + static class A { + public @Stable Object a; + public @Stable A left; + public A right; + } + + public @Stable A v; + + public static final NestedStableField2 c = new NestedStableField2(); + public static Object get() { return c.v.left.left.left.a; } + public static Object get1() { return c.v.left.left.right.left.a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.left = c.v.right = c.v; + c.v.a = Values.A; Object val1 = get(); Object val2 = get1(); + c.v.a = Values.B; Object val3 = get(); Object val4 = get1(); + + assertEquals(val1, Values.A); + assertEquals(val3, (isStableEnabled ? Values.A : Values.B)); + + assertEquals(val2, Values.A); + assertEquals(val4, Values.B); + } + } + } + + /* ==================================================== */ + + static class NestedStableField3 { + static class A { + public @Stable Object a; + public @Stable A[] left; + public A[] right; + } + + public @Stable A[] v; + + public static final NestedStableField3 c = new NestedStableField3(); + public static Object get() { return c.v[0].left[1].left[0].left[1].a; } + public static Object get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } + + public static void test() throws Exception { + { + A elem = new A(); + c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; + elem.a = Values.A; Object val1 = get(); Object val2 = get1(); + elem.a = Values.B; Object val3 = get(); Object val4 = get1(); + + assertEquals(val1, Values.A); + assertEquals(val3, (isStableEnabled ? Values.A : Values.B)); + + assertEquals(val2, Values.A); + assertEquals(val4, Values.B); + } + } + } + + /* ==================================================== */ + // Auxiliary methods + static void assertEquals(Object i, Object j) { if (i != j) throw new AssertionError(i + " != " + j); } + static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } + + static boolean failed = false; + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + failed = true; + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } + + static final boolean isStableEnabled; + static { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption tmp; + try { + tmp = diagnostic.getVMOption("FoldStableValues"); + } catch (IllegalArgumentException e) { + tmp = null; + } + isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); + } +} diff --git a/hotspot/test/compiler/stable/TestStableShort.java b/hotspot/test/compiler/stable/TestStableShort.java new file mode 100644 index 00000000000..a80d0726db6 --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableShort.java @@ -0,0 +1,632 @@ +/* + * 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. + */ + +/* + * @test TestStableShort + * @summary tests on stable fields and arrays + * @library /testlibrary + * @compile -XDignore.symbol.file TestStableShort.java + * @run main ClassFileInstaller + * java/lang/invoke/TestStableShort + * java/lang/invoke/TestStableShort$ShortStable + * java/lang/invoke/TestStableShort$StaticShortStable + * java/lang/invoke/TestStableShort$VolatileShortStable + * java/lang/invoke/TestStableShort$ShortArrayDim1 + * java/lang/invoke/TestStableShort$ShortArrayDim2 + * java/lang/invoke/TestStableShort$ShortArrayDim3 + * java/lang/invoke/TestStableShort$ShortArrayDim4 + * java/lang/invoke/TestStableShort$ObjectArrayLowerDim0 + * java/lang/invoke/TestStableShort$ObjectArrayLowerDim1 + * java/lang/invoke/TestStableShort$NestedStableField + * java/lang/invoke/TestStableShort$NestedStableField$A + * java/lang/invoke/TestStableShort$NestedStableField1 + * java/lang/invoke/TestStableShort$NestedStableField1$A + * java/lang/invoke/TestStableShort$NestedStableField2 + * java/lang/invoke/TestStableShort$NestedStableField2$A + * java/lang/invoke/TestStableShort$NestedStableField3 + * java/lang/invoke/TestStableShort$NestedStableField3$A + * java/lang/invoke/TestStableShort$DefaultValue + * java/lang/invoke/TestStableShort$ObjectArrayLowerDim2 + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableShort + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableShort + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableShort + * + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop + * -server -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * java.lang.invoke.TestStableShort + */ +package java.lang.invoke; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import sun.management.ManagementFactoryHelper; +import java.lang.reflect.InvocationTargetException; + +public class TestStableShort { + public static void main(String[] args) throws Exception { + System.out.println("@Stable enabled: "+isStableEnabled); + System.out.println(); + + run(DefaultValue.class); + run(ShortStable.class); + run(StaticShortStable.class); + run(VolatileShortStable.class); + + // @Stable arrays: Dim 1-4 + run(ShortArrayDim1.class); + run(ShortArrayDim2.class); + run(ShortArrayDim3.class); + run(ShortArrayDim4.class); + + // @Stable Object field: dynamic arrays + run(ObjectArrayLowerDim0.class); + run(ObjectArrayLowerDim1.class); + run(ObjectArrayLowerDim2.class); + + // Nested @Stable fields + run(NestedStableField.class); + run(NestedStableField1.class); + run(NestedStableField2.class); + run(NestedStableField3.class); + + if (failed) { + throw new Error("TEST FAILED"); + } + } + + /* ==================================================== */ + + static class DefaultValue { + public @Stable short v; + + public static final DefaultValue c = new DefaultValue(); + public static short get() { return c.v; } + public static void test() throws Exception { + short val1 = get(); + c.v = 1; short val2 = get(); + assertEquals(val1, 0); + assertEquals(val2, 1); + } + } + + /* ==================================================== */ + + static class ShortStable { + public @Stable short v; + + public static final ShortStable c = new ShortStable(); + public static short get() { return c.v; } + public static void test() throws Exception { + c.v = 1; short val1 = get(); + c.v = 32767; short val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 32767)); + } + } + + /* ==================================================== */ + + static class StaticShortStable { + public static @Stable short v; + + public static final StaticShortStable c = new StaticShortStable(); + public static short get() { return c.v; } + public static void test() throws Exception { + c.v = 1; short val1 = get(); + c.v = 32767; short val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 32767)); + } + } + + /* ==================================================== */ + + static class VolatileShortStable { + public @Stable volatile short v; + + public static final VolatileShortStable c = new VolatileShortStable(); + public static short get() { return c.v; } + public static void test() throws Exception { + c.v = 1; short val1 = get(); + c.v = 32767; short val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 32767)); + } + } + + /* ==================================================== */ + // @Stable array == field && all components are stable + + static class ShortArrayDim1 { + public @Stable short[] v; + + public static final ShortArrayDim1 c = new ShortArrayDim1(); + public static short get() { return c.v[0]; } + public static short get1() { return c.v[10]; } + public static short[] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new short[1]; c.v[0] = 1; short val1 = get(); + c.v[0] = 2; short val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new short[1]; c.v[0] = 3; short val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + + { + c.v = new short[20]; c.v[10] = 1; short val1 = get1(); + c.v[10] = 2; short val2 = get1(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new short[20]; c.v[10] = 3; short val3 = get1(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + + { + c.v = new short[1]; short[] val1 = get2(); + c.v = new short[1]; short[] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ShortArrayDim2 { + public @Stable short[][] v; + + public static final ShortArrayDim2 c = new ShortArrayDim2(); + public static short get() { return c.v[0][0]; } + public static short[] get1() { return c.v[0]; } + public static short[][] get2() { return c.v; } + public static void test() throws Exception { + { + c.v = new short[1][1]; c.v[0][0] = 1; short val1 = get(); + c.v[0][0] = 2; short val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new short[1][1]; c.v[0][0] = 3; short val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new short[1]; c.v[0][0] = 4; short val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + } + + { + c.v = new short[1][1]; short[] val1 = get1(); + c.v[0] = new short[1]; short[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new short[1][1]; short[][] val1 = get2(); + c.v = new short[1][1]; short[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ShortArrayDim3 { + public @Stable short[][][] v; + + public static final ShortArrayDim3 c = new ShortArrayDim3(); + public static short get() { return c.v[0][0][0]; } + public static short[] get1() { return c.v[0][0]; } + public static short[][] get2() { return c.v[0]; } + public static short[][][] get3() { return c.v; } + public static void test() throws Exception { + { + c.v = new short[1][1][1]; c.v[0][0][0] = 1; short val1 = get(); + c.v[0][0][0] = 2; short val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new short[1][1][1]; c.v[0][0][0] = 3; short val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new short[1][1]; c.v[0][0][0] = 4; short val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + + c.v[0][0] = new short[1]; c.v[0][0][0] = 5; short val5 = get(); + assertEquals(val5, (isStableEnabled ? 1 : 5)); + } + + { + c.v = new short[1][1][1]; short[] val1 = get1(); + c.v[0][0] = new short[1]; short[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new short[1][1][1]; short[][] val1 = get2(); + c.v[0] = new short[1][1]; short[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new short[1][1][1]; short[][][] val1 = get3(); + c.v = new short[1][1][1]; short[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ShortArrayDim4 { + public @Stable short[][][][] v; + + public static final ShortArrayDim4 c = new ShortArrayDim4(); + public static short get() { return c.v[0][0][0][0]; } + public static short[] get1() { return c.v[0][0][0]; } + public static short[][] get2() { return c.v[0][0]; } + public static short[][][] get3() { return c.v[0]; } + public static short[][][][] get4() { return c.v; } + public static void test() throws Exception { + { + c.v = new short[1][1][1][1]; c.v[0][0][0][0] = 1; short val1 = get(); + c.v[0][0][0][0] = 2; short val2 = get(); + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + + c.v = new short[1][1][1][1]; c.v[0][0][0][0] = 3; short val3 = get(); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + + c.v[0] = new short[1][1][1]; c.v[0][0][0][0] = 4; short val4 = get(); + assertEquals(val4, (isStableEnabled ? 1 : 4)); + + c.v[0][0] = new short[1][1]; c.v[0][0][0][0] = 5; short val5 = get(); + assertEquals(val5, (isStableEnabled ? 1 : 5)); + + c.v[0][0][0] = new short[1]; c.v[0][0][0][0] = 6; short val6 = get(); + assertEquals(val6, (isStableEnabled ? 1 : 6)); + } + + { + c.v = new short[1][1][1][1]; short[] val1 = get1(); + c.v[0][0][0] = new short[1]; short[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new short[1][1][1][1]; short[][] val1 = get2(); + c.v[0][0] = new short[1][1]; short[][] val2 = get2(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new short[1][1][1][1]; short[][][] val1 = get3(); + c.v[0] = new short[1][1][1]; short[][][] val2 = get3(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new short[1][1][1][1]; short[][][][] val1 = get4(); + c.v = new short[1][1][1][1]; short[][][][] val2 = get4(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + } + } + + /* ==================================================== */ + // Dynamic Dim is higher than static + + static class ObjectArrayLowerDim0 { + public @Stable Object v; + + public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); + public static short get() { return ((short[])c.v)[0]; } + public static short[] get1() { return (short[])c.v; } + + public static void test() throws Exception { + { + c.v = new short[1]; ((short[])c.v)[0] = 1; short val1 = get(); + ((short[])c.v)[0] = 2; short val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new short[1]; short[] val1 = get1(); + c.v = new short[1]; short[] val2 = get1(); + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim1 { + public @Stable Object[] v; + + public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); + public static short get() { return ((short[][])c.v)[0][0]; } + public static short[] get1() { return (short[])(c.v[0]); } + public static Object[] get2() { return c.v; } + + public static void test() throws Exception { + { + c.v = new short[1][1]; ((short[][])c.v)[0][0] = 1; short val1 = get(); + ((short[][])c.v)[0][0] = 2; short val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new short[1][1]; c.v[0] = new short[0]; short[] val1 = get1(); + c.v[0] = new short[0]; short[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new short[0][0]; Object[] val1 = get2(); + c.v = new short[0][0]; Object[] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class ObjectArrayLowerDim2 { + public @Stable Object[][] v; + + public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); + public static short get() { return ((short[][][])c.v)[0][0][0]; } + public static short[] get1() { return (short[])(c.v[0][0]); } + public static short[][] get2() { return (short[][])(c.v[0]); } + public static Object[][] get3() { return c.v; } + + public static void test() throws Exception { + { + c.v = new short[1][1][1]; ((short[][][])c.v)[0][0][0] = 1; short val1 = get(); + ((short[][][])c.v)[0][0][0] = 2; short val2 = get(); + + assertEquals(val1, 1); + assertEquals(val2, 2); + } + + { + c.v = new short[1][1][1]; c.v[0][0] = new short[0]; short[] val1 = get1(); + c.v[0][0] = new short[0]; short[] val2 = get1(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new short[1][1][1]; c.v[0] = new short[0][0]; short[][] val1 = get2(); + c.v[0] = new short[0][0]; short[][] val2 = get2(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + + { + c.v = new short[0][0][0]; Object[][] val1 = get3(); + c.v = new short[0][0][0]; Object[][] val2 = get3(); + + assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); + } + } + } + + /* ==================================================== */ + + static class NestedStableField { + static class A { + public @Stable short a; + + } + public @Stable A v; + + public static final NestedStableField c = new NestedStableField(); + public static A get() { return c.v; } + public static short get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.a = 1; A val1 = get(); + c.v.a = 2; A val2 = get(); + + assertEquals(val1.a, 2); + assertEquals(val2.a, 2); + } + + { + c.v = new A(); c.v.a = 1; short val1 = get1(); + c.v.a = 2; short val2 = get1(); + c.v = new A(); c.v.a = 3; short val3 = get1(); + + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + } + } + + /* ==================================================== */ + + static class NestedStableField1 { + static class A { + public @Stable short a; + public @Stable A next; + } + public @Stable A v; + + public static final NestedStableField1 c = new NestedStableField1(); + public static A get() { return c.v.next.next.next.next.next.next.next; } + public static short get1() { return get().a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; + c.v.a = 1; c.v.next.a = 1; A val1 = get(); + c.v.a = 2; c.v.next.a = 2; A val2 = get(); + + assertEquals(val1.a, 2); + assertEquals(val2.a, 2); + } + + { + c.v = new A(); c.v.next = c.v; + c.v.a = 1; short val1 = get1(); + c.v.a = 2; short val2 = get1(); + c.v = new A(); c.v.next = c.v; + c.v.a = 3; short val3 = get1(); + + assertEquals(val1, 1); + assertEquals(val2, (isStableEnabled ? 1 : 2)); + assertEquals(val3, (isStableEnabled ? 1 : 3)); + } + } + } + /* ==================================================== */ + + static class NestedStableField2 { + static class A { + public @Stable short a; + public @Stable A left; + public A right; + } + + public @Stable A v; + + public static final NestedStableField2 c = new NestedStableField2(); + public static short get() { return c.v.left.left.left.a; } + public static short get1() { return c.v.left.left.right.left.a; } + + public static void test() throws Exception { + { + c.v = new A(); c.v.left = c.v.right = c.v; + c.v.a = 1; short val1 = get(); short val2 = get1(); + c.v.a = 2; short val3 = get(); short val4 = get1(); + + assertEquals(val1, 1); + assertEquals(val3, (isStableEnabled ? 1 : 2)); + + assertEquals(val2, 1); + assertEquals(val4, 2); + } + } + } + + /* ==================================================== */ + + static class NestedStableField3 { + static class A { + public @Stable short a; + public @Stable A[] left; + public A[] right; + } + + public @Stable A[] v; + + public static final NestedStableField3 c = new NestedStableField3(); + public static short get() { return c.v[0].left[1].left[0].left[1].a; } + public static short get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } + + public static void test() throws Exception { + { + A elem = new A(); + c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; + elem.a = 1; short val1 = get(); short val2 = get1(); + elem.a = 2; short val3 = get(); short val4 = get1(); + + assertEquals(val1, 1); + assertEquals(val3, (isStableEnabled ? 1 : 2)); + + assertEquals(val2, 1); + assertEquals(val4, 2); + } + } + } + + /* ==================================================== */ + // Auxiliary methods + static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); } + static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } + + static boolean failed = false; + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + failed = true; + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } + + static final boolean isStableEnabled; + static { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption tmp; + try { + tmp = diagnostic.getVMOption("FoldStableValues"); + } catch (IllegalArgumentException e) { + tmp = null; + } + isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); + } +} diff --git a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java index 715d32a8944..13411a0dd73 100644 --- a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java +++ b/hotspot/test/compiler/tiered/NonTieredLevelsTest.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 @@ -70,6 +70,9 @@ public class NonTieredLevelsTest extends CompLevelsTest { @Override protected void test() throws Exception { + if (skipXcompOSR()) { + return; + } checkNotCompiled(); compile(); checkCompiled(); diff --git a/hotspot/test/compiler/tiered/TieredLevelsTest.java b/hotspot/test/compiler/tiered/TieredLevelsTest.java index 675a394498a..9fb2254d0b5 100644 --- a/hotspot/test/compiler/tiered/TieredLevelsTest.java +++ b/hotspot/test/compiler/tiered/TieredLevelsTest.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 @@ -51,6 +51,9 @@ public class TieredLevelsTest extends CompLevelsTest { @Override protected void test() throws Exception { + if (skipXcompOSR()) { + return; + } checkNotCompiled(); compile(); checkCompiled(); diff --git a/hotspot/test/compiler/types/TestMeetTopArrayExactConstantArray.java b/hotspot/test/compiler/types/TestMeetTopArrayExactConstantArray.java index 56b19b31713..4ec6e7b03af 100644 --- a/hotspot/test/compiler/types/TestMeetTopArrayExactConstantArray.java +++ b/hotspot/test/compiler/types/TestMeetTopArrayExactConstantArray.java @@ -25,7 +25,7 @@ * @test * @bug 8027571 * @summary meet of TopPTR exact array with constant array is not symmetric - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestMeetTopArrayExactConstantArray + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestMeetTopArrayExactConstantArray * */ diff --git a/hotspot/test/compiler/types/TestSpeculationFailedHigherEqual.java b/hotspot/test/compiler/types/TestSpeculationFailedHigherEqual.java index 9579dce6e40..70d5566ad33 100644 --- a/hotspot/test/compiler/types/TestSpeculationFailedHigherEqual.java +++ b/hotspot/test/compiler/types/TestSpeculationFailedHigherEqual.java @@ -25,7 +25,7 @@ * @test * @bug 8027422 * @summary type methods shouldn't always operate on speculative part - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestSpeculationFailedHigherEqual + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestSpeculationFailedHigherEqual * */ diff --git a/hotspot/test/compiler/types/TypeSpeculation.java b/hotspot/test/compiler/types/TypeSpeculation.java index 0a9c8e94d95..6f146b84ede 100644 --- a/hotspot/test/compiler/types/TypeSpeculation.java +++ b/hotspot/test/compiler/types/TypeSpeculation.java @@ -25,7 +25,7 @@ * @test * @bug 8024070 * @summary Test that type speculation doesn't cause incorrect execution - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation TypeSpeculation + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation TypeSpeculation * */ diff --git a/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java b/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java index 11572672afe..fcdd592263d 100644 --- a/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java +++ b/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java @@ -25,7 +25,7 @@ * @test * @bug 8031752 * @summary speculative traps need to be cleaned up at GC - * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx1M TestSpecTrapClassUnloading + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx1M TestSpecTrapClassUnloading * */ diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java index e47231e29f5..c199c2a6a67 100644 --- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.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 @@ -195,6 +195,29 @@ public abstract class CompilerWhiteBoxTest { printInfo(); } + /** + * Checks, that {@linkplain #method} is not compiled at the given compilation + * level or above. + * + * @param compLevel + * + * @throws RuntimeException if {@linkplain #method} is in compiler queue or + * is compiled, or if {@linkplain #method} has zero + * compilation level. + */ + + protected final void checkNotCompiled(int compLevel) { + if (WHITE_BOX.isMethodQueuedForCompilation(method)) { + throw new RuntimeException(method + " must not be in queue"); + } + if (WHITE_BOX.getMethodCompilationLevel(method, false) >= compLevel) { + throw new RuntimeException(method + " comp_level must be >= maxCompLevel"); + } + if (WHITE_BOX.getMethodCompilationLevel(method, true) >= compLevel) { + throw new RuntimeException(method + " osr_comp_level must be >= maxCompLevel"); + } + } + /** * Checks, that {@linkplain #method} is not compiled. * @@ -380,6 +403,20 @@ public abstract class CompilerWhiteBoxTest { /** flag for OSR test case */ boolean isOsr(); } + + /** + * @return {@code true} if the current test case is OSR and the mode is + * Xcomp, otherwise {@code false} + */ + protected boolean skipXcompOSR() { + boolean result = testCase.isOsr() + && CompilerWhiteBoxTest.MODE.startsWith("compiled "); + if (result && IS_VERBOSE) { + System.err.printf("Warning: %s is not applicable in %s%n", + testCase.name(), CompilerWhiteBoxTest.MODE); + } + return result; + } } enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase { diff --git a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java index 350c99c8f5c..ea4e36400eb 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.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 @@ -51,11 +51,8 @@ public class DeoptimizeAllTest extends CompilerWhiteBoxTest { */ @Override protected void test() throws Exception { - if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith( - "compiled ")) { - System.err.printf("Warning: %s is not applicable in %s%n", - testCase.name(), CompilerWhiteBoxTest.MODE); - return; + if (skipXcompOSR()) { + return; } compile(); checkCompiled(); diff --git a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java index 565a5b91cd7..0b9ffd2d9db 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.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 @@ -51,11 +51,8 @@ public class DeoptimizeMethodTest extends CompilerWhiteBoxTest { */ @Override protected void test() throws Exception { - if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith( - "compiled ")) { - System.err.printf("Warning: %s is not applicable in %s%n", - testCase.name(), CompilerWhiteBoxTest.MODE); - return; + if (skipXcompOSR()) { + return; } compile(); checkCompiled(); diff --git a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java index bd5916a7ca8..88e5cd835e4 100644 --- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java +++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,13 +24,17 @@ /* * @test IsMethodCompilableTest * @bug 8007270 8006683 8007288 8022832 - * @library /testlibrary /testlibrary/whitebox + * @library /testlibrary /testlibrary/whitebox /testlibrary/com/oracle/java/testlibrary * @build IsMethodCompilableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest + * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform + * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest * @summary testing of WB::isMethodCompilable() * @author igor.ignatyev@oracle.com */ + +import com.oracle.java.testlibrary.Platform; + public class IsMethodCompilableTest extends CompilerWhiteBoxTest { /** * Value of {@code -XX:PerMethodRecompilationCutoff} @@ -43,7 +47,7 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { if (tmp == -1) { PER_METHOD_RECOMPILATION_CUTOFF = -1 /* Inf */; } else { - PER_METHOD_RECOMPILATION_CUTOFF = 1 + (0xFFFFFFFFL & tmp); + PER_METHOD_RECOMPILATION_CUTOFF = (0xFFFFFFFFL & tmp); } } @@ -60,19 +64,23 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { /** * Tests {@code WB::isMethodCompilable()} by recompilation of tested method * 'PerMethodRecompilationCutoff' times and checks compilation status. Also - * checks that WB::clearMethodState() clears no-compilable flags. + * checks that WB::clearMethodState() clears no-compilable flags. Only + * applicable to c2 compiled methods. * * @throws Exception if one of the checks fails. */ @Override protected void test() throws Exception { - if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith( - "compiled ")) { - System.err.printf("Warning: %s is not applicable in %s%n", - testCase.name(), CompilerWhiteBoxTest.MODE); - return; + + // Only c2 compilations can be disabled through PerMethodRecompilationCutoff + if (!Platform.isServer()) { + return; } - if (!isCompilable()) { + + if (skipXcompOSR()) { + return; + } + if (!isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) { throw new RuntimeException(method + " must be compilable"); } System.out.println("PerMethodRecompilationCutoff = " @@ -83,39 +91,37 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { return; } - // deoptimize 'PerMethodRecompilationCutoff' times and clear state - for (long i = 0L, n = PER_METHOD_RECOMPILATION_CUTOFF - 1; i < n; ++i) { - compileAndDeoptimize(); + // deoptimize 'PerMethodRecompilationCutoff' times + for (long attempts = 0, successes = 0; + (successes < PER_METHOD_RECOMPILATION_CUTOFF) && + (attempts < PER_METHOD_RECOMPILATION_CUTOFF*2) && + isCompilable(COMP_LEVEL_FULL_OPTIMIZATION); attempts++) { + if (compileAndDeoptimize() == COMP_LEVEL_FULL_OPTIMIZATION) { + successes++; + } } - if (!testCase.isOsr() && !isCompilable()) { - // in osr test case count of deopt maybe more than iterations - throw new RuntimeException(method + " is not compilable after " - + (PER_METHOD_RECOMPILATION_CUTOFF - 1) + " iterations"); - } - WHITE_BOX.clearMethodState(method); - // deoptimize 'PerMethodRecompilationCutoff' + 1 times - long i; - for (i = 0L; i < PER_METHOD_RECOMPILATION_CUTOFF - && isCompilable(); ++i) { - compileAndDeoptimize(); - } - if (!testCase.isOsr() && i != PER_METHOD_RECOMPILATION_CUTOFF) { + if (!testCase.isOsr() && !isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) { // in osr test case count of deopt maybe more than iterations throw new RuntimeException(method + " is not compilable after " - + i + " iterations, but must only after " - + PER_METHOD_RECOMPILATION_CUTOFF); + + PER_METHOD_RECOMPILATION_CUTOFF + " iterations"); } - if (isCompilable()) { + + // Now compile once more + compileAndDeoptimize(); + + if (isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) { throw new RuntimeException(method + " is still compilable after " + PER_METHOD_RECOMPILATION_CUTOFF + " iterations"); } - compile(); checkNotCompiled(); + compile(); + waitBackgroundCompilation(); + checkNotCompiled(COMP_LEVEL_FULL_OPTIMIZATION); // WB.clearMethodState() must reset no-compilable flags WHITE_BOX.clearMethodState(method); - if (!isCompilable()) { + if (!isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) { throw new RuntimeException(method + " is not compilable after clearMethodState()"); } @@ -123,9 +129,11 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { checkCompiled(); } - private void compileAndDeoptimize() throws Exception { + private int compileAndDeoptimize() throws Exception { compile(); waitBackgroundCompilation(); + int compLevel = getCompLevel(); deoptimize(); + return compLevel; } } diff --git a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java index cbd65da45bd..d6586879778 100644 --- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java +++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.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 @@ -53,11 +53,8 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { */ @Override protected void test() throws Exception { - if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith( - "compiled ")) { - System.err.printf("Warning: %s is not applicable in %s%n", - testCase.name(), CompilerWhiteBoxTest.MODE); - return; + if (skipXcompOSR()) { + return; } checkNotCompiled(); if (!isCompilable()) { diff --git a/hotspot/test/runtime/6294277/SourceDebugExtension.java b/hotspot/test/runtime/6294277/SourceDebugExtension.java index e8cc8a8bb50..bb650e673ca 100644 --- a/hotspot/test/runtime/6294277/SourceDebugExtension.java +++ b/hotspot/test/runtime/6294277/SourceDebugExtension.java @@ -25,7 +25,7 @@ * @test * @bug 6294277 * @summary java -Xdebug crashes on SourceDebugExtension attribute larger than 64K - * @run main/othervm -Xdebug -Xrunjdwp:transport=dt_socket,address=8888,server=y,suspend=n SourceDebugExtension + * @run main/othervm -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n SourceDebugExtension */ import java.io.*; diff --git a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java index e801d5b87df..bb68a6ff074 100644 --- a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java +++ b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java @@ -83,8 +83,8 @@ public class CompressedClassPointers { public static void heapBaseMinAddressTest() throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:HeapBaseMinAddress=1m", - "-XX:+PrintMiscellaneous", - "-XX:+Verbose", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintCompressedOopsMode", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("HeapBaseMinAddress must be at least"); diff --git a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java new file mode 100644 index 00000000000..4f929c49af6 --- /dev/null +++ b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java @@ -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. + */ + +/* + * @test + * @summary Redefine a class with an UnresolvedClass reference in the constant pool. + * @bug 8035150 + * @library /testlibrary + * @build UnresolvedClassAgent com.oracle.java.testlibrary.ProcessTools com.oracle.java.testlibrary.OutputAnalyzer + * @run main TestRedefineWithUnresolvedClass + */ + +import java.io.File; +import java.util.Arrays; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestRedefineWithUnresolvedClass { + + final static String slash = File.separator; + final static String testClasses = System.getProperty("test.classes") + slash; + + public static void main(String... args) throws Throwable { + // delete this class to cause a NoClassDefFoundError + File unresolved = new File(testClasses, "MyUnresolvedClass.class"); + if (unresolved.exists() && !unresolved.delete()) { + throw new Exception("Could not delete: " + unresolved); + } + + // build the javaagent + buildJar("UnresolvedClassAgent"); + + // launch a VM with the javaagent + launchTest(); + } + + private static void buildJar(String jarName) throws Throwable { + String testSrc = System.getProperty("test.src", "?") + slash; + + String jarPath = String.format("%s%s.jar", testClasses, jarName); + String manifestPath = String.format("%s%s.mf", testSrc, jarName); + String className = String.format("%s.class", jarName); + + String[] args = new String[] {"-cfm", jarPath, manifestPath, "-C", testClasses, className}; + + System.out.println("Running jar " + Arrays.toString(args)); + sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar"); + if (!jarTool.run(args)) { + throw new Exception("jar failed: args=" + Arrays.toString(args)); + } + } + + private static void launchTest() throws Throwable { + String[] args = { + "-javaagent:" + testClasses + "UnresolvedClassAgent.jar", + "-Dtest.classes=" + testClasses, + "UnresolvedClassAgent" }; + OutputAnalyzer output = ProcessTools.executeTestJvm(args); + output.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.java b/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.java new file mode 100644 index 00000000000..efe7b25a1aa --- /dev/null +++ b/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.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. + */ + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.Instrumentation; + +/* + * This class is present during compilation, but will be deleted before execution. + */ +class MyUnresolvedClass { + static void bar() { + } +} + +class MyRedefinedClass { + static void foo() { + MyUnresolvedClass.bar(); + } +} + +public class UnresolvedClassAgent { + public static void main(String... args) { + } + + public static void premain(String args, Instrumentation inst) throws Exception { + try { + MyRedefinedClass.foo(); + } catch(NoClassDefFoundError err) { + System.out.println("NoClassDefFoundError (expected)"); + } + + File f = new File(System.getProperty("test.classes"), "MyRedefinedClass.class"); + byte[] buf = new byte[(int)f.length()]; + try (DataInputStream dis = new DataInputStream(new FileInputStream(f))) { + dis.readFully(buf); + } + ClassDefinition cd = new ClassDefinition(MyRedefinedClass.class, buf); + inst.redefineClasses(new ClassDefinition[] {cd}); + + try { + MyRedefinedClass.foo(); + } catch(NoClassDefFoundError err) { + System.out.println("NoClassDefFoundError (expected again)"); + } + } +} diff --git a/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.mf b/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.mf new file mode 100644 index 00000000000..5570570cd11 --- /dev/null +++ b/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Premain-Class: UnresolvedClassAgent +Can-Redefine-Classes: true diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java index a2e5f82ad71..34b2f20f9a3 100644 --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java @@ -28,6 +28,15 @@ public class Platform { private static final String dataModel = System.getProperty("sun.arch.data.model"); private static final String vmVersion = System.getProperty("java.vm.version"); private static final String osArch = System.getProperty("os.arch"); + private static final String vmName = System.getProperty("java.vm.name"); + + public static boolean isClient() { + return vmName.endsWith(" Client VM"); + } + + public static boolean isServer() { + return vmName.endsWith(" Server VM"); + } public static boolean is32bit() { return dataModel.equals("32"); diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java index 04293905824..649b7a1b38a 100644 --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java @@ -163,10 +163,87 @@ public final class ProcessTools { // Reporting StringBuilder cmdLine = new StringBuilder(); - for (String cmd : args) - cmdLine.append(cmd).append(' '); + for (String cmd : args) { + cmdLine.append(cmd).append(' '); + } System.out.println("Command line: [" + cmdLine.toString() + "]"); return new ProcessBuilder(args.toArray(new String[args.size()])); } + + /** + * Executes a test jvm process, waits for it to finish and returns the process output. + * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. + * The java from the test.jdk is used to execute the command. + * + * The command line will be like: + * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds + * + * @param cmds User specifed arguments. + * @return The output from the process. + */ + public static OutputAnalyzer executeTestJvm(String... cmds) throws Throwable { + ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds)); + return executeProcess(pb); + } + + /** + * Executes a process, waits for it to finish and returns the process output. + * @param pb The ProcessBuilder to execute. + * @return The output from the process. + */ + public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Throwable { + OutputAnalyzer output = null; + try { + output = new OutputAnalyzer(pb.start()); + return output; + } catch (Throwable t) { + System.out.println("executeProcess() failed: " + t); + throw t; + } finally { + System.out.println(getProcessLog(pb, output)); + } + } + + /** + * Executes a process, waits for it to finish and returns the process output. + * @param cmds The command line to execute. + * @return The output from the process. + */ + public static OutputAnalyzer executeProcess(String... cmds) throws Throwable { + return executeProcess(new ProcessBuilder(cmds)); + } + + /** + * Used to log command line, stdout, stderr and exit code from an executed process. + * @param pb The executed process. + * @param output The output from the process. + */ + public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) { + String stderr = output == null ? "null" : output.getStderr(); + String stdout = output == null ? "null" : output.getStdout(); + String exitValue = output == null ? "null": Integer.toString(output.getExitValue()); + StringBuilder logMsg = new StringBuilder(); + final String nl = System.getProperty("line.separator"); + logMsg.append("--- ProcessLog ---" + nl); + logMsg.append("cmd: " + getCommandLine(pb) + nl); + logMsg.append("exitvalue: " + exitValue + nl); + logMsg.append("stderr: " + stderr + nl); + logMsg.append("stdout: " + stdout + nl); + return logMsg.toString(); + } + + /** + * @return The full command line for the ProcessBuilder. + */ + public static String getCommandLine(ProcessBuilder pb) { + if (pb == null) { + return "null"; + } + StringBuilder cmd = new StringBuilder(); + for (String s : pb.command()) { + cmd.append(s).append(" "); + } + return cmd.toString().trim(); + } } diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java new file mode 100644 index 00000000000..a0031e706ec --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.java.testlibrary; + +import static com.oracle.java.testlibrary.Asserts.assertTrue; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.Arrays; +import java.util.Collections; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * Common library for various test helper functions. + */ +public final class Utils { + + /** + * Returns the sequence used by operating system to separate lines. + */ + public static final String NEW_LINE = System.getProperty("line.separator"); + + /** + * Returns the value of 'test.vm.opts'system property. + */ + public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim(); + + /** + * Returns the value of 'test.java.opts'system property. + */ + public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); + + /** + * Returns the value of 'test.timeout.factor' system property + * converted to {@code double}. + */ + public static final double TIMEOUT_FACTOR; + static { + String toFactor = System.getProperty("test.timeout.factor", "1.0"); + TIMEOUT_FACTOR = Double.parseDouble(toFactor); + } + + private Utils() { + // Private constructor to prevent class instantiation + } + + /** + * Returns the list of VM options. + * + * @return List of VM options + */ + public static List getVmOptions() { + return Arrays.asList(safeSplitString(VM_OPTIONS)); + } + + /** + * Returns the list of VM options with -J prefix. + * + * @return The list of VM options with -J prefix + */ + public static List getForwardVmOptions() { + String[] opts = safeSplitString(VM_OPTIONS); + for (int i = 0; i < opts.length; i++) { + opts[i] = "-J" + opts[i]; + } + return Arrays.asList(opts); + } + + /** + * Returns the default JTReg arguments for a jvm running a test. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts. + * @return An array of options, or an empty array if no opptions. + */ + public static String[] getTestJavaOpts() { + List opts = new ArrayList(); + Collections.addAll(opts, safeSplitString(VM_OPTIONS)); + Collections.addAll(opts, safeSplitString(JAVA_OPTIONS)); + return opts.toArray(new String[0]); + } + + /** + * 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 + * @return The combination of JTReg test java options and user args. + */ + public static String[] addTestJavaOpts(String... userArgs) { + List opts = new ArrayList(); + Collections.addAll(opts, getTestJavaOpts()); + Collections.addAll(opts, userArgs); + return opts.toArray(new String[0]); + } + + /** + * Splits a string by white space. + * Works like String.split(), but returns an empty array + * if the string is null or empty. + */ + private static String[] safeSplitString(String s) { + if (s == null || s.trim().isEmpty()) { + return new String[] {}; + } + return s.trim().split("\\s+"); + } + + /** + * @return The full command line for the ProcessBuilder. + */ + public static String getCommandLine(ProcessBuilder pb) { + StringBuilder cmd = new StringBuilder(); + for (String s : pb.command()) { + cmd.append(s).append(" "); + } + return cmd.toString(); + } + + /** + * Returns the free port on the local host. + * The function will spin until a valid port number is found. + * + * @return The port number + * @throws InterruptedException if any thread has interrupted the current thread + * @throws IOException if an I/O error occurs when opening the socket + */ + public static int getFreePort() throws InterruptedException, IOException { + int port = -1; + + while (port <= 0) { + Thread.sleep(100); + + ServerSocket serverSocket = null; + try { + serverSocket = new ServerSocket(0); + port = serverSocket.getLocalPort(); + } finally { + serverSocket.close(); + } + } + + return port; + } + + /** + * Returns the name of the local host. + * + * @return The host name + * @throws UnknownHostException if IP address of a host could not be determined + */ + public static String getHostname() throws UnknownHostException { + InetAddress inetAddress = InetAddress.getLocalHost(); + String hostName = inetAddress.getHostName(); + + assertTrue((hostName != null && !hostName.isEmpty()), + "Cannot get hostname"); + + return hostName; + } + + /** + * Uses "jcmd -l" to search for a jvm pid. This function will wait + * forever (until jtreg timeout) for the pid to be found. + * @param key Regular expression to search for + * @return The found pid. + */ + public static int waitForJvmPid(String key) throws Throwable { + final long iterationSleepMillis = 250; + System.out.println("waitForJvmPid: Waiting for key '" + key + "'"); + System.out.flush(); + while (true) { + int pid = tryFindJvmPid(key); + if (pid >= 0) { + return pid; + } + Thread.sleep(iterationSleepMillis); + } + } + + /** + * Searches for a jvm pid in the output from "jcmd -l". + * + * Example output from jcmd is: + * 12498 sun.tools.jcmd.JCmd -l + * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar + * + * @param key A regular expression to search for. + * @return The found pid, or -1 if Enot found. + * @throws Exception If multiple matching jvms are found. + */ + public static int tryFindJvmPid(String key) throws Throwable { + OutputAnalyzer output = null; + try { + JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd"); + jcmdLauncher.addToolArg("-l"); + output = ProcessTools.executeProcess(jcmdLauncher.getCommand()); + output.shouldHaveExitValue(0); + + // Search for a line starting with numbers (pid), follwed by the key. + Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n"); + Matcher matcher = pattern.matcher(output.getStdout()); + + int pid = -1; + if (matcher.find()) { + pid = Integer.parseInt(matcher.group(1)); + System.out.println("findJvmPid.pid: " + pid); + if (matcher.find()) { + throw new Exception("Found multiple JVM pids for key: " + key); + } + } + return pid; + } catch (Throwable t) { + System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t)); + throw t; + } + } + + /** + * Returns file content as a list of strings + * + * @param file File to operate on + * @return List of strings + * @throws IOException + */ + public static List fileAsList(File file) throws IOException { + assertTrue(file.exists() && file.isFile(), + file.getAbsolutePath() + " does not exist or not a file"); + List output = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(file.getAbsolutePath()))) { + while (reader.ready()) { + output.add(reader.readLine().replace(NEW_LINE, "")); + } + } + return output; + } + +} diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 89dfe4cfb54..81af574266a 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -246,3 +246,5 @@ e4e5069250e717defcb556e2f6be291460988c51 jdk8-b118 e5256f530a9b5f2d677ca245de44a617ffb58f52 jdk9-b01 02f60a253e15240087c043bad77a106792e4d56a jdk9-b02 fb92ed0399424193f444489ad49a16748816dc12 jdk9-b03 +2846d8fc31490897817a122a668af4f44fc913d0 jdk9-b04 +b92a20e303d24c74078888cd7084b14d7626d48f jdk9-b05 diff --git a/jaxp/make/BuildJaxp.gmk b/jaxp/make/BuildJaxp.gmk index 7950b0cf8a1..57c184bc4ee 100644 --- a/jaxp/make/BuildJaxp.gmk +++ b/jaxp/make/BuildJaxp.gmk @@ -45,27 +45,11 @@ $(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG, \ $(eval $(call SetupJavaCompilation,BUILD_JAXP, \ SETUP := GENERATE_NEWBYTECODE_DEBUG, \ SRC := $(JAXP_TOPDIR)/src, \ + CLEAN := .properties, \ BIN := $(JAXP_OUTPUTDIR)/classes, \ - SRCZIP := $(JAXP_OUTPUTDIR)/dist/lib/src.zip)) - -# Imitate the property cleaning mechanism in the old build. This will likely be replaced -# by the unified functionality in JavaCompilation.gmk, but keep it the same as old build -# for now, even though it actually breaks properties containing # in the value. -# Using nawk to avoid solaris sed. -$(JAXP_OUTPUTDIR)/classes/%.properties: $(JAXP_TOPDIR)/src/%.properties - $(MKDIR) -p $(@D) - $(RM) $@ $@.tmp - $(CAT) $< | LANG=C $(NAWK) '{ sub(/#.*$$/,"#"); print }' > $@.tmp - $(MV) $@.tmp $@ - -SRC_PROP_FILES := $(shell $(FIND) $(JAXP_TOPDIR)/src -name "*.properties") -TARGET_PROP_FILES := $(patsubst $(JAXP_TOPDIR)/src/%, $(JAXP_OUTPUTDIR)/classes/%, $(SRC_PROP_FILES)) - -$(eval $(call SetupArchive,ARCHIVE_JAXP, $(BUILD_JAXP) $(TARGET_PROP_FILES), \ - SRCS := $(JAXP_OUTPUTDIR)/classes, \ - SUFFIXES := .class .properties, \ + SRCZIP := $(JAXP_OUTPUTDIR)/dist/lib/src.zip, \ JAR := $(JAXP_OUTPUTDIR)/dist/lib/classes.jar)) -all: $(JAXP_OUTPUTDIR)/dist/lib/classes.jar $(JAXP_OUTPUTDIR)/dist/lib/src.zip +all: $(BUILD_JAXP) .PHONY: default all diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 8e843fe4b59..27f4734f0bd 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -249,3 +249,5 @@ bc622ba563f9316f981c11c3a260f4c3fdc5ef07 jdk8-b122 9c9fabbcd3d526d7ca29165169155f49a107533a jdk9-b01 efe2bc258c78af49de9517a4a5699d3a2e630c44 jdk9-b02 1cd9786257ed4f82a3371fd606b162e5bb6fcd81 jdk9-b03 +da44a8bdf1f3fdd518e7d785d60cc1b15983b176 jdk9-b04 +eae966c8133fec0a8bf9e16d1274a4ede3c0fb52 jdk9-b05 diff --git a/jaxws/make/BuildJaxws.gmk b/jaxws/make/BuildJaxws.gmk index 204dd47fb53..1c159965dd3 100644 --- a/jaxws/make/BuildJaxws.gmk +++ b/jaxws/make/BuildJaxws.gmk @@ -42,11 +42,10 @@ $(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG, \ SERVER_DIR := $(SJAVAC_SERVER_DIR), \ SERVER_JVM := $(SJAVAC_SERVER_JAVA))) -# Dummy here is needed to trigger copying of META-INF $(eval $(call SetupJavaCompilation,BUILD_JAF, \ SETUP := GENERATE_NEWBYTECODE_DEBUG, \ SRC := $(JAXWS_TOPDIR)/src/share/jaf_classes, \ - COPY := "dummy", \ + CLEAN := .properties, \ BIN := $(JAXWS_OUTPUTDIR)/jaf_classes)) $(eval $(call SetupJavaCompilation,BUILD_JAXWS, \ @@ -57,6 +56,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JAXWS, \ COPY_FILES := $(JAXWS_TOPDIR)/src/share/jaxws_classes/com/sun/tools/internal/xjc/runtime/JAXBContextFactory.java \ $(JAXWS_TOPDIR)/src/share/jaxws_classes/com/sun/tools/internal/xjc/runtime/ZeroOneBooleanAdapter.java \ $(JAXWS_TOPDIR)/src/share/jaxws_classes/com/sun/xml/internal/ws/assembler/jaxws-tubes-default.xml, \ + CLEAN := .properties, \ ADD_JAVAC_FLAGS = -Xbootclasspath/p:$(OUTPUT_ROOT)/jaxp/dist/lib/classes.jar)) $(JAXWS_OUTPUTDIR)/jaxws_classes/META-INF/services/com.sun.tools.internal.ws.wscompile.Plugin: \ @@ -73,30 +73,6 @@ $(JAXWS_OUTPUTDIR)/jaxws_classes/META-INF/services/com.sun.tools.internal.xjc.Pl BUILD_JAXWS += $(JAXWS_OUTPUTDIR)/jaxws_classes/META-INF/services/com.sun.tools.internal.ws.wscompile.Plugin \ $(JAXWS_OUTPUTDIR)/jaxws_classes/META-INF/services/com.sun.tools.internal.xjc.Plugin -# Imitate the property cleaning mechanism in the old build. This will likely be replaced -# by the unified functionality in JavaCompilation.gmk, but keep it the same as old build -# for now, even though it actually breaks properties containing # in the value. -# Using nawk to avoid solaris sed. -$(JAXWS_OUTPUTDIR)/jaxws_classes/%.properties: $(JAXWS_TOPDIR)/src/share/jaxws_classes/%.properties - $(MKDIR) -p $(@D) - $(RM) $@ $@.tmp - $(CAT) $< | LANG=C $(NAWK) '{ sub(/#.*$$/,"#"); print }' > $@.tmp - $(MV) $@.tmp $@ - -JAXWS_SRC_PROP_FILES := $(shell $(FIND) $(JAXWS_TOPDIR)/src/share/jaxws_classes -name "*.properties") -TARGET_PROP_FILES := $(patsubst $(JAXWS_TOPDIR)/src/share/jaxws_classes/%, \ - $(JAXWS_OUTPUTDIR)/jaxws_classes/%, $(JAXWS_SRC_PROP_FILES)) - -$(JAXWS_OUTPUTDIR)/jaf_classes/%.properties: $(JAXWS_TOPDIR)/src/share/jaf_classes/%.properties - $(MKDIR) -p $(@D) - $(RM) $@ $@.tmp - $(CAT) $< | LANG=C $(NAWK) '{ sub(/#.*$$/,"#"); print }' > $@.tmp - $(MV) $@.tmp $@ - -JAF_SRC_PROP_FILES := $(shell $(FIND) $(JAXWS_TOPDIR)/src/share/jaf_classes -name "*.properties") -TARGET_PROP_FILES += $(patsubst $(JAXWS_TOPDIR)/src/share/jaf_classes/%, \ - $(JAXWS_OUTPUTDIR)/jaf_classes/%, $(JAF_SRC_PROP_FILES)) - $(eval $(call SetupArchive,ARCHIVE_JAXWS, $(BUILD_JAXWS) $(BUILD_JAF) $(TARGET_PROP_FILES), \ SRCS := $(JAXWS_OUTPUTDIR)/jaxws_classes $(JAXWS_OUTPUTDIR)/jaf_classes, \ SUFFIXES := .class .properties .xsd .xml .java \ diff --git a/jdk/.hgtags b/jdk/.hgtags index 950784a2233..e4c040d37a1 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -246,3 +246,5 @@ d31cd980e1da31fa496a359caaf1a165aeb5791a jdk8-b120 3b4ac8d1b76fc6bec9815f0ab714f15b552e4c7b jdk9-b01 8c8275426a3207d91393354f7a7f9bc362ec25cf jdk9-b02 4111af6151ed8ca8e3f5603c69729a68427e1d5b jdk9-b03 +627deed79b595a4789fc9151455b663a47381257 jdk9-b04 +263198a1d8f1f4cb97d35f40c61704b08ebd3686 jdk9-b05 diff --git a/langtools/.hgtags b/langtools/.hgtags index ab6c1e2e32a..6488f7e10e4 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -246,3 +246,5 @@ afe63d41c699e0e2ee910ef20c41b60603c852a1 jdk9-b00 077c12d527fb5531c59666c1f84000fc1245a260 jdk9-b01 f2c58a337c8aaa1ce84dfa8a8e8c5d4c8c1e12fa jdk9-b02 151222468d1d04ce6613d33efa3d45bfaf53e3e5 jdk9-b03 +fa2ec6b6b1697ae4a78b03b609664dc6b47dee86 jdk9-b04 +1d5e6fc88a4cca287090c16b0530a0d5849a5603 jdk9-b05 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 a5195caa8ee..1af2b332cc0 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 @@ -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 @@ -467,11 +467,24 @@ public abstract class Symbol extends AnnoConstruct implements Element { private boolean hiddenIn(ClassSymbol clazz, Types types) { Symbol sym = hiddenInInternal(clazz, types); - return sym != null && sym != this; + Assert.check(sym != null, "the result of hiddenInInternal() can't be null"); + /* If we find the current symbol then there is no symbol hiding it + */ + return sym != this; } - private Symbol hiddenInInternal(ClassSymbol c, Types types) { - Scope.Entry e = c.members().lookup(name); + /** This method looks in the supertypes graph that has the current class as the + * initial node, till it finds the current symbol or another symbol that hides it. + * If the current class has more than one supertype (extends one class and + * implements one or more interfaces) then null can be returned, meaning that + * a wrong path in the supertypes graph was selected. Null can only be returned + * as a temporary value, as a result of the recursive call. + */ + private Symbol hiddenInInternal(ClassSymbol currentClass, Types types) { + if (currentClass == owner) { + return this; + } + Scope.Entry e = currentClass.members().lookup(name); while (e.scope != null) { if (e.sym.kind == kind && (kind != MTH || @@ -481,18 +494,19 @@ public abstract class Symbol extends AnnoConstruct implements Element { } e = e.next(); } - List hiddenSyms = List.nil(); - for (Type st : types.interfaces(c.type).prepend(types.supertype(c.type))) { + Symbol hiddenSym = null; + for (Type st : types.interfaces(currentClass.type) + .prepend(types.supertype(currentClass.type))) { if (st != null && (st.hasTag(CLASS))) { Symbol sym = hiddenInInternal((ClassSymbol)st.tsym, types); - if (sym != null) { - hiddenSyms = hiddenSyms.prepend(hiddenInInternal((ClassSymbol)st.tsym, types)); + if (sym == this) { + return this; + } else if (sym != null) { + hiddenSym = sym; } } } - return hiddenSyms.contains(this) ? - this : - (hiddenSyms.isEmpty() ? null : hiddenSyms.head); + return hiddenSym; } /** Is this symbol inherited into a given class? diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java index da87eee67e0..0b57e21cbae 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.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 @@ -1481,8 +1481,21 @@ public abstract class Type extends AnnoConstruct implements TypeMirror { } public String toString() { - if (inst != null) return inst.toString(); - else return qtype + "?"; + return (inst == null) ? qtype + "?" : inst.toString(); + } + + public String debugString() { + String result = "inference var = " + qtype + "\n"; + if (inst != null) { + result += "inst = " + inst + '\n'; + } + for (InferenceBound bound: InferenceBound.values()) { + List aboundList = bounds.get(bound); + if (aboundList.size() > 0) { + result += bound + " = " + aboundList + '\n'; + } + } + return result; } @Override @@ -1492,8 +1505,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror { @Override public Type baseType() { - if (inst != null) return inst.baseType(); - else return this; + return (inst == null) ? this : inst.baseType(); } /** get all bounds of a given kind */ 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 acc3ccbff29..4e011f04368 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 @@ -3208,6 +3208,7 @@ public class Types { return tvar.rank_field; } case ERROR: + case NONE: return 0; default: throw new AssertionError(); 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 cd1383b3b0a..1a9e0626b1c 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 @@ -808,9 +808,7 @@ public class Annotate { Attribute.TypeCompound tc = enterTypeAnnotation(a, syms.annotationType, env); - if (tc == null) { - continue; - } + Assert.checkNonNull(tc, "Failed to create type annotation"); if (annotated.containsKey(a.type.tsym)) { if (!allowRepeatedAnnos) { @@ -827,10 +825,9 @@ public class Annotate { } } - if (s != null) { - s.appendTypeAttributesWithCompletion( - new AnnotateRepeatedContext<>(env, annotated, pos, log, true)); - } + Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is null"); + s.appendTypeAttributesWithCompletion( + new AnnotateRepeatedContext<>(env, annotated, pos, log, true)); } finally { if (prevLintPos != null) deferredLintHandler.setPos(prevLintPos); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java index 7fa54fc374c..1fe49587172 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java @@ -2173,6 +2173,12 @@ public class Infer { //back-door to infer return Infer.this; } + + @Override + public String toString() { + return "Inference vars: " + inferencevars + '\n' + + "Undet vars: " + undetvars; + } } final InferenceContext emptyContext = new InferenceContext(List.nil()); diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java index 5e7293d74d3..13e910ce559 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java @@ -1037,7 +1037,7 @@ public class ClassWriter extends ClassFile { } databuf.appendChar(pool.get(inner)); databuf.appendChar( - inner.owner.kind == TYP ? pool.get(inner.owner) : 0); + inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0); databuf.appendChar( !inner.name.isEmpty() ? pool.get(inner.name) : 0); databuf.appendChar(flags); diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java index 0f2cbcf1ed7..e1bda1c736d 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -1910,6 +1910,7 @@ public class Gen extends JCTree.Visitor { if (!c.isFalse()) { code.resolve(c.trueJumps); int startpc = genCrt ? code.curCP() : 0; + code.statBegin(tree.truepart.pos); genExpr(tree.truepart, pt).load(); code.state.forceStackTop(tree.type); if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET, @@ -1919,6 +1920,7 @@ public class Gen extends JCTree.Visitor { if (elseChain != null) { code.resolve(elseChain); int startpc = genCrt ? code.curCP() : 0; + code.statBegin(tree.falsepart.pos); genExpr(tree.falsepart, pt).load(); code.state.forceStackTop(tree.type); if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET, diff --git a/langtools/src/share/classes/javax/lang/model/type/MirroredTypeException.java b/langtools/src/share/classes/javax/lang/model/type/MirroredTypeException.java index fd79f04e62d..21af5070a76 100644 --- a/langtools/src/share/classes/javax/lang/model/type/MirroredTypeException.java +++ b/langtools/src/share/classes/javax/lang/model/type/MirroredTypeException.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 @@ -70,6 +70,10 @@ public class MirroredTypeException extends MirroredTypesException { /** * Explicitly set all transient fields. + * @param s the serial stream + * @throws ClassNotFoundException for a missing class during + * deserialization + * @throws IOException for an IO problem during deserialization */ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { diff --git a/langtools/src/share/classes/javax/lang/model/type/MirroredTypesException.java b/langtools/src/share/classes/javax/lang/model/type/MirroredTypesException.java index e385241a378..2cff3ffdaf6 100644 --- a/langtools/src/share/classes/javax/lang/model/type/MirroredTypesException.java +++ b/langtools/src/share/classes/javax/lang/model/type/MirroredTypesException.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 @@ -85,6 +85,10 @@ public class MirroredTypesException extends RuntimeException { /** * Explicitly set all transient fields. + * @param s the serial stream + * @throws ClassNotFoundException for a missing class during + * deserialization + * @throws IOException for an IO problem during deserialization */ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { diff --git a/langtools/test/tools/javac/6464451/BigFinally.java b/langtools/test/tools/javac/6464451/BigFinally.java deleted file mode 100644 index 8f89e7d870f..00000000000 --- a/langtools/test/tools/javac/6464451/BigFinally.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6464451 - * @summary javac in 5.0ux can not compile try-finally block which has a lot of "return" - * @author Wei Tao - * @compile -source 5 -target 5 BigFinally.java - * @clean BigFinally - * @compile/fail BigFinally.java - */ - -public class BigFinally { - static public int func(int i) { - try { - if(i == 1) return 1; - } finally { - try { - if(i == 2) return 2; - if(i == 3 ) return 3; - if(i == 4 ) return 4; - if(i == 5 ) return 5; - if(i == 6 ) return 6; - if(i == 7 ) return 7; - if(i == 8 ) return 8; - if(i == 9 ) return 9; - if(i == 10 ) return 10; - if(i == 11 ) return 11; - if(i == 12 ) return 12; - if(i == 13 ) return 13; - if(i == 14 ) return 14; - if(i == 15 ) return 15; - if(i == 16 ) return 16; - if(i == 17 ) return 17; - if(i == 18 ) return 18; - if(i == 19 ) return 19; - if(i == 20 ) return 20; - if(i == 21 ) return 21; - if(i == 22 ) return 22; - if(i == 23 ) return 23; - if(i == 24 ) return 24; - if(i == 25 ) return 25; - if(i == 26 ) return 26; - if(i == 27 ) return 27; - if(i == 28 ) return 28; - if(i == 29 ) return 29; - if(i == 30 ) return 30; - if(i == 31 ) return 31; - if(i == 32 ) return 32; - if(i == 33 ) return 33; - if(i == 34 ) return 34; - if(i == 35 ) return 35; - if(i == 36 ) return 36; - if(i == 37 ) return 37; - if(i == 38 ) return 38; - if(i == 39 ) return 39; - if(i == 40 ) return 40; - if(i == 41 ) return 41; - if(i == 42 ) return 42; - if(i == 43 ) return 43; - if(i == 44 ) return 44; - if(i == 45 ) return 45; - if(i == 46 ) return 46; - if(i == 47 ) return 47; - if(i == 48 ) return 48; - if(i == 49 ) return 49; - if(i == 50 ) return 50; - if(i == 51 ) return 51; - if(i == 52 ) return 52; - if(i == 53 ) return 53; - if(i == 54 ) return 54; - if(i == 55 ) return 55; - if(i == 56 ) return 56; - if(i == 57 ) return 57; - if(i == 58 ) return 58; - if(i == 59 ) return 59; - if(i == 60 ) return 60; - if(i == 61 ) return 61; - if(i == 62 ) return 62; - if(i == 63 ) return 63; - if(i == 64 ) return 64; - if(i == 65 ) return 65; - if(i == 66 ) return 66; - if(i == 67 ) return 67; - if(i == 68 ) return 68; - if(i == 69 ) return 69; - if(i == 70 ) return 70; - if(i == 71 ) return 71; - if(i == 72 ) return 72; - if(i == 73 ) return 73; - if(i == 74 ) return 74; - if(i == 75 ) return 75; - if(i == 76 ) return 76; - if(i == 77 ) return 77; - if(i == 78 ) return 78; - if(i == 79 ) return 79; - if(i == 80 ) return 80; - if(i == 81 ) return 81; - if(i == 82 ) return 82; - if(i == 83 ) return 83; - if(i == 84 ) return 84; - if(i == 85 ) return 85; - if(i == 86 ) return 86; - if(i == 87 ) return 87; - if(i == 88 ) return 88; - if(i == 89 ) return 89; - if(i == 90 ) return 90; - if(i == 91 ) return 91; - if(i == 92 ) return 92; - if(i == 93 ) return 93; - if(i == 94 ) return 94; - if(i == 95 ) return 95; - if(i == 96 ) return 96; - if(i == 97 ) return 97; - if(i == 98 ) return 98; - if(i == 99 ) return 99; - if(i == 100 ) return 100; - } finally { - int x = 0; - x += 1; - x += 2; - x += 3; - x += 4; - x += 5; - x += 6; - x += 7; - x += 8; - x += 9; - x += 10; - x += 11; - x += 12; - x += 13; - x += 14; - x += 15; - x += 16; - x += 17; - x += 18; - x += 19; - x += 20; - x += 21; - x += 22; - x += 23; - x += 24; - x += 25; - x += 26; - x += 27; - x += 28; - x += 29; - x += 30; - x += 31; - x += 32; - x += 33; - x += 34; - x += 35; - x += 36; - x += 37; - x += 38; - x += 39; - x += 40; - x += 41; - x += 42; - x += 43; - x += 44; - x += 45; - x += 46; - x += 47; - x += 48; - x += 49; - x += 50; - x += 51; - x += 52; - x += 53; - x += 54; - x += 55; - x += 56; - x += 57; - x += 58; - x += 59; - x += 60; - x += 61; - x += 62; - x += 63; - x += 64; - x += 65; - x += 66; - x += 67; - x += 68; - x += 69; - x += 70; - x += 71; - x += 72; - x += 73; - x += 74; - x += 75; - x += 76; - x += 77; - x += 78; - x += 79; - x += 80; - x += 81; - x += 82; - x += 83; - x += 84; - x += 85; - x += 86; - x += 87; - x += 88; - x += 89; - x += 90; - x += 91; - x += 92; - x += 93; - x += 94; - x += 95; - x += 96; - x += 97; - x += 98; - x += 99; - x += 100; - } - } - return 0; - } -} diff --git a/langtools/test/tools/javac/6464451/DeepNestedFinally.java b/langtools/test/tools/javac/6464451/DeepNestedFinally.java deleted file mode 100644 index fc6253cd975..00000000000 --- a/langtools/test/tools/javac/6464451/DeepNestedFinally.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6464451 - * @summary javac in 5.0ux can not compile try-finally block which has a lot of "return" - * @author Wei Tao - * @compile -source 5 -target 5 DeepNestedFinally.java - * @clean DeepNestedFinally - * @compile/fail DeepNestedFinally.java - */ - -public class DeepNestedFinally { - static public int func(int i) { - try { - if(i == 1) return 1; - } finally { - try { - if(i == 2) return 2; - } finally { - try { - if(i == 3) return 3; - } finally { - try { - if(i == 4) return 4; - } finally { - try { - if(i == 5) return 5; - } finally { - try { - if(i == 6) return 6; - } finally { - try { - if (i == 7) return 7; - } finally { - int x = 0; - x += 1; - x += 2; - x += 3; - x += 4; - x += 5; - x += 6; - x += 7; - x += 8; - x += 9; - } - } - } - } - } - } - } - return 0; - } -} diff --git a/langtools/test/tools/javac/6464451/ManyExitsInTry.java b/langtools/test/tools/javac/6464451/ManyExitsInTry.java deleted file mode 100644 index 95eb2ffadef..00000000000 --- a/langtools/test/tools/javac/6464451/ManyExitsInTry.java +++ /dev/null @@ -1,2051 +0,0 @@ -/* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6464451 - * @summary javac in 5.0ux can not compile try-finally block which has a lot of "return" - * @author Wei Tao - * @compile -source 5 -target 5 ManyExitsInTry.java - * @clean ManyExitsInTry - * @compile/fail ManyExitsInTry.java - */ - -public class ManyExitsInTry { - static public int func(int i) { - try { - if(i == 0 ) return 0; - if(i == 1 ) return 1; - if(i == 2 ) return 2; - if(i == 3 ) return 3; - if(i == 4 ) return 4; - if(i == 5 ) return 5; - if(i == 6 ) return 6; - if(i == 7 ) return 7; - if(i == 8 ) return 8; - if(i == 9 ) return 9; - if(i == 10 ) return 10; - if(i == 11 ) return 11; - if(i == 12 ) return 12; - if(i == 13 ) return 13; - if(i == 14 ) return 14; - if(i == 15 ) return 15; - if(i == 16 ) return 16; - if(i == 17 ) return 17; - if(i == 18 ) return 18; - if(i == 19 ) return 19; - if(i == 20 ) return 20; - if(i == 21 ) return 21; - if(i == 22 ) return 22; - if(i == 23 ) return 23; - if(i == 24 ) return 24; - if(i == 25 ) return 25; - if(i == 26 ) return 26; - if(i == 27 ) return 27; - if(i == 28 ) return 28; - if(i == 29 ) return 29; - if(i == 30 ) return 30; - if(i == 31 ) return 31; - if(i == 32 ) return 32; - if(i == 33 ) return 33; - if(i == 34 ) return 34; - if(i == 35 ) return 35; - if(i == 36 ) return 36; - if(i == 37 ) return 37; - if(i == 38 ) return 38; - if(i == 39 ) return 39; - if(i == 40 ) return 40; - if(i == 41 ) return 41; - if(i == 42 ) return 42; - if(i == 43 ) return 43; - if(i == 44 ) return 44; - if(i == 45 ) return 45; - if(i == 46 ) return 46; - if(i == 47 ) return 47; - if(i == 48 ) return 48; - if(i == 49 ) return 49; - if(i == 50 ) return 50; - if(i == 51 ) return 51; - if(i == 52 ) return 52; - if(i == 53 ) return 53; - if(i == 54 ) return 54; - if(i == 55 ) return 55; - if(i == 56 ) return 56; - if(i == 57 ) return 57; - if(i == 58 ) return 58; - if(i == 59 ) return 59; - if(i == 60 ) return 60; - if(i == 61 ) return 61; - if(i == 62 ) return 62; - if(i == 63 ) return 63; - if(i == 64 ) return 64; - if(i == 65 ) return 65; - if(i == 66 ) return 66; - if(i == 67 ) return 67; - if(i == 68 ) return 68; - if(i == 69 ) return 69; - if(i == 70 ) return 70; - if(i == 71 ) return 71; - if(i == 72 ) return 72; - if(i == 73 ) return 73; - if(i == 74 ) return 74; - if(i == 75 ) return 75; - if(i == 76 ) return 76; - if(i == 77 ) return 77; - if(i == 78 ) return 78; - if(i == 79 ) return 79; - if(i == 80 ) return 80; - if(i == 81 ) return 81; - if(i == 82 ) return 82; - if(i == 83 ) return 83; - if(i == 84 ) return 84; - if(i == 85 ) return 85; - if(i == 86 ) return 86; - if(i == 87 ) return 87; - if(i == 88 ) return 88; - if(i == 89 ) return 89; - if(i == 90 ) return 90; - if(i == 91 ) return 91; - if(i == 92 ) return 92; - if(i == 93 ) return 93; - if(i == 94 ) return 94; - if(i == 95 ) return 95; - if(i == 96 ) return 96; - if(i == 97 ) return 97; - if(i == 98 ) return 98; - if(i == 99 ) return 99; - if(i == 100 ) return 100; - if(i == 101 ) return 101; - if(i == 102 ) return 102; - if(i == 103 ) return 103; - if(i == 104 ) return 104; - if(i == 105 ) return 105; - if(i == 106 ) return 106; - if(i == 107 ) return 107; - if(i == 108 ) return 108; - if(i == 109 ) return 109; - if(i == 110 ) return 110; - if(i == 111 ) return 111; - if(i == 112 ) return 112; - if(i == 113 ) return 113; - if(i == 114 ) return 114; - if(i == 115 ) return 115; - if(i == 116 ) return 116; - if(i == 117 ) return 117; - if(i == 118 ) return 118; - if(i == 119 ) return 119; - if(i == 120 ) return 120; - if(i == 121 ) return 121; - if(i == 122 ) return 122; - if(i == 123 ) return 123; - if(i == 124 ) return 124; - if(i == 125 ) return 125; - if(i == 126 ) return 126; - if(i == 127 ) return 127; - if(i == 128 ) return 128; - if(i == 129 ) return 129; - if(i == 130 ) return 130; - if(i == 131 ) return 131; - if(i == 132 ) return 132; - if(i == 133 ) return 133; - if(i == 134 ) return 134; - if(i == 135 ) return 135; - if(i == 136 ) return 136; - if(i == 137 ) return 137; - if(i == 138 ) return 138; - if(i == 139 ) return 139; - if(i == 140 ) return 140; - if(i == 141 ) return 141; - if(i == 142 ) return 142; - if(i == 143 ) return 143; - if(i == 144 ) return 144; - if(i == 145 ) return 145; - if(i == 146 ) return 146; - if(i == 147 ) return 147; - if(i == 148 ) return 148; - if(i == 149 ) return 149; - if(i == 150 ) return 150; - if(i == 151 ) return 151; - if(i == 152 ) return 152; - if(i == 153 ) return 153; - if(i == 154 ) return 154; - if(i == 155 ) return 155; - if(i == 156 ) return 156; - if(i == 157 ) return 157; - if(i == 158 ) return 158; - if(i == 159 ) return 159; - if(i == 160 ) return 160; - if(i == 161 ) return 161; - if(i == 162 ) return 162; - if(i == 163 ) return 163; - if(i == 164 ) return 164; - if(i == 165 ) return 165; - if(i == 166 ) return 166; - if(i == 167 ) return 167; - if(i == 168 ) return 168; - if(i == 169 ) return 169; - if(i == 170 ) return 170; - if(i == 171 ) return 171; - if(i == 172 ) return 172; - if(i == 173 ) return 173; - if(i == 174 ) return 174; - if(i == 175 ) return 175; - if(i == 176 ) return 176; - if(i == 177 ) return 177; - if(i == 178 ) return 178; - if(i == 179 ) return 179; - if(i == 180 ) return 180; - if(i == 181 ) return 181; - if(i == 182 ) return 182; - if(i == 183 ) return 183; - if(i == 184 ) return 184; - if(i == 185 ) return 185; - if(i == 186 ) return 186; - if(i == 187 ) return 187; - if(i == 188 ) return 188; - if(i == 189 ) return 189; - if(i == 190 ) return 190; - if(i == 191 ) return 191; - if(i == 192 ) return 192; - if(i == 193 ) return 193; - if(i == 194 ) return 194; - if(i == 195 ) return 195; - if(i == 196 ) return 196; - if(i == 197 ) return 197; - if(i == 198 ) return 198; - if(i == 199 ) return 199; - if(i == 200 ) return 200; - if(i == 201 ) return 201; - if(i == 202 ) return 202; - if(i == 203 ) return 203; - if(i == 204 ) return 204; - if(i == 205 ) return 205; - if(i == 206 ) return 206; - if(i == 207 ) return 207; - if(i == 208 ) return 208; - if(i == 209 ) return 209; - if(i == 210 ) return 210; - if(i == 211 ) return 211; - if(i == 212 ) return 212; - if(i == 213 ) return 213; - if(i == 214 ) return 214; - if(i == 215 ) return 215; - if(i == 216 ) return 216; - if(i == 217 ) return 217; - if(i == 218 ) return 218; - if(i == 219 ) return 219; - if(i == 220 ) return 220; - if(i == 221 ) return 221; - if(i == 222 ) return 222; - if(i == 223 ) return 223; - if(i == 224 ) return 224; - if(i == 225 ) return 225; - if(i == 226 ) return 226; - if(i == 227 ) return 227; - if(i == 228 ) return 228; - if(i == 229 ) return 229; - if(i == 230 ) return 230; - if(i == 231 ) return 231; - if(i == 232 ) return 232; - if(i == 233 ) return 233; - if(i == 234 ) return 234; - if(i == 235 ) return 235; - if(i == 236 ) return 236; - if(i == 237 ) return 237; - if(i == 238 ) return 238; - if(i == 239 ) return 239; - if(i == 240 ) return 240; - if(i == 241 ) return 241; - if(i == 242 ) return 242; - if(i == 243 ) return 243; - if(i == 244 ) return 244; - if(i == 245 ) return 245; - if(i == 246 ) return 246; - if(i == 247 ) return 247; - if(i == 248 ) return 248; - if(i == 249 ) return 249; - if(i == 250 ) return 250; - if(i == 251 ) return 251; - if(i == 252 ) return 252; - if(i == 253 ) return 253; - if(i == 254 ) return 254; - if(i == 255 ) return 255; - if(i == 256 ) return 256; - if(i == 257 ) return 257; - if(i == 258 ) return 258; - if(i == 259 ) return 259; - if(i == 260 ) return 260; - if(i == 261 ) return 261; - if(i == 262 ) return 262; - if(i == 263 ) return 263; - if(i == 264 ) return 264; - if(i == 265 ) return 265; - if(i == 266 ) return 266; - if(i == 267 ) return 267; - if(i == 268 ) return 268; - if(i == 269 ) return 269; - if(i == 270 ) return 270; - if(i == 271 ) return 271; - if(i == 272 ) return 272; - if(i == 273 ) return 273; - if(i == 274 ) return 274; - if(i == 275 ) return 275; - if(i == 276 ) return 276; - if(i == 277 ) return 277; - if(i == 278 ) return 278; - if(i == 279 ) return 279; - if(i == 280 ) return 280; - if(i == 281 ) return 281; - if(i == 282 ) return 282; - if(i == 283 ) return 283; - if(i == 284 ) return 284; - if(i == 285 ) return 285; - if(i == 286 ) return 286; - if(i == 287 ) return 287; - if(i == 288 ) return 288; - if(i == 289 ) return 289; - if(i == 290 ) return 290; - if(i == 291 ) return 291; - if(i == 292 ) return 292; - if(i == 293 ) return 293; - if(i == 294 ) return 294; - if(i == 295 ) return 295; - if(i == 296 ) return 296; - if(i == 297 ) return 297; - if(i == 298 ) return 298; - if(i == 299 ) return 299; - if(i == 300 ) return 300; - if(i == 301 ) return 301; - if(i == 302 ) return 302; - if(i == 303 ) return 303; - if(i == 304 ) return 304; - if(i == 305 ) return 305; - if(i == 306 ) return 306; - if(i == 307 ) return 307; - if(i == 308 ) return 308; - if(i == 309 ) return 309; - if(i == 310 ) return 310; - if(i == 311 ) return 311; - if(i == 312 ) return 312; - if(i == 313 ) return 313; - if(i == 314 ) return 314; - if(i == 315 ) return 315; - if(i == 316 ) return 316; - if(i == 317 ) return 317; - if(i == 318 ) return 318; - if(i == 319 ) return 319; - if(i == 320 ) return 320; - if(i == 321 ) return 321; - if(i == 322 ) return 322; - if(i == 323 ) return 323; - if(i == 324 ) return 324; - if(i == 325 ) return 325; - if(i == 326 ) return 326; - if(i == 327 ) return 327; - if(i == 328 ) return 328; - if(i == 329 ) return 329; - if(i == 330 ) return 330; - if(i == 331 ) return 331; - if(i == 332 ) return 332; - if(i == 333 ) return 333; - if(i == 334 ) return 334; - if(i == 335 ) return 335; - if(i == 336 ) return 336; - if(i == 337 ) return 337; - if(i == 338 ) return 338; - if(i == 339 ) return 339; - if(i == 340 ) return 340; - if(i == 341 ) return 341; - if(i == 342 ) return 342; - if(i == 343 ) return 343; - if(i == 344 ) return 344; - if(i == 345 ) return 345; - if(i == 346 ) return 346; - if(i == 347 ) return 347; - if(i == 348 ) return 348; - if(i == 349 ) return 349; - if(i == 350 ) return 350; - if(i == 351 ) return 351; - if(i == 352 ) return 352; - if(i == 353 ) return 353; - if(i == 354 ) return 354; - if(i == 355 ) return 355; - if(i == 356 ) return 356; - if(i == 357 ) return 357; - if(i == 358 ) return 358; - if(i == 359 ) return 359; - if(i == 360 ) return 360; - if(i == 361 ) return 361; - if(i == 362 ) return 362; - if(i == 363 ) return 363; - if(i == 364 ) return 364; - if(i == 365 ) return 365; - if(i == 366 ) return 366; - if(i == 367 ) return 367; - if(i == 368 ) return 368; - if(i == 369 ) return 369; - if(i == 370 ) return 370; - if(i == 371 ) return 371; - if(i == 372 ) return 372; - if(i == 373 ) return 373; - if(i == 374 ) return 374; - if(i == 375 ) return 375; - if(i == 376 ) return 376; - if(i == 377 ) return 377; - if(i == 378 ) return 378; - if(i == 379 ) return 379; - if(i == 380 ) return 380; - if(i == 381 ) return 381; - if(i == 382 ) return 382; - if(i == 383 ) return 383; - if(i == 384 ) return 384; - if(i == 385 ) return 385; - if(i == 386 ) return 386; - if(i == 387 ) return 387; - if(i == 388 ) return 388; - if(i == 389 ) return 389; - if(i == 390 ) return 390; - if(i == 391 ) return 391; - if(i == 392 ) return 392; - if(i == 393 ) return 393; - if(i == 394 ) return 394; - if(i == 395 ) return 395; - if(i == 396 ) return 396; - if(i == 397 ) return 397; - if(i == 398 ) return 398; - if(i == 399 ) return 399; - if(i == 400 ) return 400; - if(i == 401 ) return 401; - if(i == 402 ) return 402; - if(i == 403 ) return 403; - if(i == 404 ) return 404; - if(i == 405 ) return 405; - if(i == 406 ) return 406; - if(i == 407 ) return 407; - if(i == 408 ) return 408; - if(i == 409 ) return 409; - if(i == 410 ) return 410; - if(i == 411 ) return 411; - if(i == 412 ) return 412; - if(i == 413 ) return 413; - if(i == 414 ) return 414; - if(i == 415 ) return 415; - if(i == 416 ) return 416; - if(i == 417 ) return 417; - if(i == 418 ) return 418; - if(i == 419 ) return 419; - if(i == 420 ) return 420; - if(i == 421 ) return 421; - if(i == 422 ) return 422; - if(i == 423 ) return 423; - if(i == 424 ) return 424; - if(i == 425 ) return 425; - if(i == 426 ) return 426; - if(i == 427 ) return 427; - if(i == 428 ) return 428; - if(i == 429 ) return 429; - if(i == 430 ) return 430; - if(i == 431 ) return 431; - if(i == 432 ) return 432; - if(i == 433 ) return 433; - if(i == 434 ) return 434; - if(i == 435 ) return 435; - if(i == 436 ) return 436; - if(i == 437 ) return 437; - if(i == 438 ) return 438; - if(i == 439 ) return 439; - if(i == 440 ) return 440; - if(i == 441 ) return 441; - if(i == 442 ) return 442; - if(i == 443 ) return 443; - if(i == 444 ) return 444; - if(i == 445 ) return 445; - if(i == 446 ) return 446; - if(i == 447 ) return 447; - if(i == 448 ) return 448; - if(i == 449 ) return 449; - if(i == 450 ) return 450; - if(i == 451 ) return 451; - if(i == 452 ) return 452; - if(i == 453 ) return 453; - if(i == 454 ) return 454; - if(i == 455 ) return 455; - if(i == 456 ) return 456; - if(i == 457 ) return 457; - if(i == 458 ) return 458; - if(i == 459 ) return 459; - if(i == 460 ) return 460; - if(i == 461 ) return 461; - if(i == 462 ) return 462; - if(i == 463 ) return 463; - if(i == 464 ) return 464; - if(i == 465 ) return 465; - if(i == 466 ) return 466; - if(i == 467 ) return 467; - if(i == 468 ) return 468; - if(i == 469 ) return 469; - if(i == 470 ) return 470; - if(i == 471 ) return 471; - if(i == 472 ) return 472; - if(i == 473 ) return 473; - if(i == 474 ) return 474; - if(i == 475 ) return 475; - if(i == 476 ) return 476; - if(i == 477 ) return 477; - if(i == 478 ) return 478; - if(i == 479 ) return 479; - if(i == 480 ) return 480; - if(i == 481 ) return 481; - if(i == 482 ) return 482; - if(i == 483 ) return 483; - if(i == 484 ) return 484; - if(i == 485 ) return 485; - if(i == 486 ) return 486; - if(i == 487 ) return 487; - if(i == 488 ) return 488; - if(i == 489 ) return 489; - if(i == 490 ) return 490; - if(i == 491 ) return 491; - if(i == 492 ) return 492; - if(i == 493 ) return 493; - if(i == 494 ) return 494; - if(i == 495 ) return 495; - if(i == 496 ) return 496; - if(i == 497 ) return 497; - if(i == 498 ) return 498; - if(i == 499 ) return 499; - if(i == 500 ) return 500; - if(i == 501 ) return 501; - if(i == 502 ) return 502; - if(i == 503 ) return 503; - if(i == 504 ) return 504; - if(i == 505 ) return 505; - if(i == 506 ) return 506; - if(i == 507 ) return 507; - if(i == 508 ) return 508; - if(i == 509 ) return 509; - if(i == 510 ) return 510; - if(i == 511 ) return 511; - if(i == 512 ) return 512; - if(i == 513 ) return 513; - if(i == 514 ) return 514; - if(i == 515 ) return 515; - if(i == 516 ) return 516; - if(i == 517 ) return 517; - if(i == 518 ) return 518; - if(i == 519 ) return 519; - if(i == 520 ) return 520; - if(i == 521 ) return 521; - if(i == 522 ) return 522; - if(i == 523 ) return 523; - if(i == 524 ) return 524; - if(i == 525 ) return 525; - if(i == 526 ) return 526; - if(i == 527 ) return 527; - if(i == 528 ) return 528; - if(i == 529 ) return 529; - if(i == 530 ) return 530; - if(i == 531 ) return 531; - if(i == 532 ) return 532; - if(i == 533 ) return 533; - if(i == 534 ) return 534; - if(i == 535 ) return 535; - if(i == 536 ) return 536; - if(i == 537 ) return 537; - if(i == 538 ) return 538; - if(i == 539 ) return 539; - if(i == 540 ) return 540; - if(i == 541 ) return 541; - if(i == 542 ) return 542; - if(i == 543 ) return 543; - if(i == 544 ) return 544; - if(i == 545 ) return 545; - if(i == 546 ) return 546; - if(i == 547 ) return 547; - if(i == 548 ) return 548; - if(i == 549 ) return 549; - if(i == 550 ) return 550; - if(i == 551 ) return 551; - if(i == 552 ) return 552; - if(i == 553 ) return 553; - if(i == 554 ) return 554; - if(i == 555 ) return 555; - if(i == 556 ) return 556; - if(i == 557 ) return 557; - if(i == 558 ) return 558; - if(i == 559 ) return 559; - if(i == 560 ) return 560; - if(i == 561 ) return 561; - if(i == 562 ) return 562; - if(i == 563 ) return 563; - if(i == 564 ) return 564; - if(i == 565 ) return 565; - if(i == 566 ) return 566; - if(i == 567 ) return 567; - if(i == 568 ) return 568; - if(i == 569 ) return 569; - if(i == 570 ) return 570; - if(i == 571 ) return 571; - if(i == 572 ) return 572; - if(i == 573 ) return 573; - if(i == 574 ) return 574; - if(i == 575 ) return 575; - if(i == 576 ) return 576; - if(i == 577 ) return 577; - if(i == 578 ) return 578; - if(i == 579 ) return 579; - if(i == 580 ) return 580; - if(i == 581 ) return 581; - if(i == 582 ) return 582; - if(i == 583 ) return 583; - if(i == 584 ) return 584; - if(i == 585 ) return 585; - if(i == 586 ) return 586; - if(i == 587 ) return 587; - if(i == 588 ) return 588; - if(i == 589 ) return 589; - if(i == 590 ) return 590; - if(i == 591 ) return 591; - if(i == 592 ) return 592; - if(i == 593 ) return 593; - if(i == 594 ) return 594; - if(i == 595 ) return 595; - if(i == 596 ) return 596; - if(i == 597 ) return 597; - if(i == 598 ) return 598; - if(i == 599 ) return 599; - if(i == 600 ) return 600; - if(i == 601 ) return 601; - if(i == 602 ) return 602; - if(i == 603 ) return 603; - if(i == 604 ) return 604; - if(i == 605 ) return 605; - if(i == 606 ) return 606; - if(i == 607 ) return 607; - if(i == 608 ) return 608; - if(i == 609 ) return 609; - if(i == 610 ) return 610; - if(i == 611 ) return 611; - if(i == 612 ) return 612; - if(i == 613 ) return 613; - if(i == 614 ) return 614; - if(i == 615 ) return 615; - if(i == 616 ) return 616; - if(i == 617 ) return 617; - if(i == 618 ) return 618; - if(i == 619 ) return 619; - if(i == 620 ) return 620; - if(i == 621 ) return 621; - if(i == 622 ) return 622; - if(i == 623 ) return 623; - if(i == 624 ) return 624; - if(i == 625 ) return 625; - if(i == 626 ) return 626; - if(i == 627 ) return 627; - if(i == 628 ) return 628; - if(i == 629 ) return 629; - if(i == 630 ) return 630; - if(i == 631 ) return 631; - if(i == 632 ) return 632; - if(i == 633 ) return 633; - if(i == 634 ) return 634; - if(i == 635 ) return 635; - if(i == 636 ) return 636; - if(i == 637 ) return 637; - if(i == 638 ) return 638; - if(i == 639 ) return 639; - if(i == 640 ) return 640; - if(i == 641 ) return 641; - if(i == 642 ) return 642; - if(i == 643 ) return 643; - if(i == 644 ) return 644; - if(i == 645 ) return 645; - if(i == 646 ) return 646; - if(i == 647 ) return 647; - if(i == 648 ) return 648; - if(i == 649 ) return 649; - if(i == 650 ) return 650; - if(i == 651 ) return 651; - if(i == 652 ) return 652; - if(i == 653 ) return 653; - if(i == 654 ) return 654; - if(i == 655 ) return 655; - if(i == 656 ) return 656; - if(i == 657 ) return 657; - if(i == 658 ) return 658; - if(i == 659 ) return 659; - if(i == 660 ) return 660; - if(i == 661 ) return 661; - if(i == 662 ) return 662; - if(i == 663 ) return 663; - if(i == 664 ) return 664; - if(i == 665 ) return 665; - if(i == 666 ) return 666; - if(i == 667 ) return 667; - if(i == 668 ) return 668; - if(i == 669 ) return 669; - if(i == 670 ) return 670; - if(i == 671 ) return 671; - if(i == 672 ) return 672; - if(i == 673 ) return 673; - if(i == 674 ) return 674; - if(i == 675 ) return 675; - if(i == 676 ) return 676; - if(i == 677 ) return 677; - if(i == 678 ) return 678; - if(i == 679 ) return 679; - if(i == 680 ) return 680; - if(i == 681 ) return 681; - if(i == 682 ) return 682; - if(i == 683 ) return 683; - if(i == 684 ) return 684; - if(i == 685 ) return 685; - if(i == 686 ) return 686; - if(i == 687 ) return 687; - if(i == 688 ) return 688; - if(i == 689 ) return 689; - if(i == 690 ) return 690; - if(i == 691 ) return 691; - if(i == 692 ) return 692; - if(i == 693 ) return 693; - if(i == 694 ) return 694; - if(i == 695 ) return 695; - if(i == 696 ) return 696; - if(i == 697 ) return 697; - if(i == 698 ) return 698; - if(i == 699 ) return 699; - if(i == 700 ) return 700; - if(i == 701 ) return 701; - if(i == 702 ) return 702; - if(i == 703 ) return 703; - if(i == 704 ) return 704; - if(i == 705 ) return 705; - if(i == 706 ) return 706; - if(i == 707 ) return 707; - if(i == 708 ) return 708; - if(i == 709 ) return 709; - if(i == 710 ) return 710; - if(i == 711 ) return 711; - if(i == 712 ) return 712; - if(i == 713 ) return 713; - if(i == 714 ) return 714; - if(i == 715 ) return 715; - if(i == 716 ) return 716; - if(i == 717 ) return 717; - if(i == 718 ) return 718; - if(i == 719 ) return 719; - if(i == 720 ) return 720; - if(i == 721 ) return 721; - if(i == 722 ) return 722; - if(i == 723 ) return 723; - if(i == 724 ) return 724; - if(i == 725 ) return 725; - if(i == 726 ) return 726; - if(i == 727 ) return 727; - if(i == 728 ) return 728; - if(i == 729 ) return 729; - if(i == 730 ) return 730; - if(i == 731 ) return 731; - if(i == 732 ) return 732; - if(i == 733 ) return 733; - if(i == 734 ) return 734; - if(i == 735 ) return 735; - if(i == 736 ) return 736; - if(i == 737 ) return 737; - if(i == 738 ) return 738; - if(i == 739 ) return 739; - if(i == 740 ) return 740; - if(i == 741 ) return 741; - if(i == 742 ) return 742; - if(i == 743 ) return 743; - if(i == 744 ) return 744; - if(i == 745 ) return 745; - if(i == 746 ) return 746; - if(i == 747 ) return 747; - if(i == 748 ) return 748; - if(i == 749 ) return 749; - if(i == 750 ) return 750; - if(i == 751 ) return 751; - if(i == 752 ) return 752; - if(i == 753 ) return 753; - if(i == 754 ) return 754; - if(i == 755 ) return 755; - if(i == 756 ) return 756; - if(i == 757 ) return 757; - if(i == 758 ) return 758; - if(i == 759 ) return 759; - if(i == 760 ) return 760; - if(i == 761 ) return 761; - if(i == 762 ) return 762; - if(i == 763 ) return 763; - if(i == 764 ) return 764; - if(i == 765 ) return 765; - if(i == 766 ) return 766; - if(i == 767 ) return 767; - if(i == 768 ) return 768; - if(i == 769 ) return 769; - if(i == 770 ) return 770; - if(i == 771 ) return 771; - if(i == 772 ) return 772; - if(i == 773 ) return 773; - if(i == 774 ) return 774; - if(i == 775 ) return 775; - if(i == 776 ) return 776; - if(i == 777 ) return 777; - if(i == 778 ) return 778; - if(i == 779 ) return 779; - if(i == 780 ) return 780; - if(i == 781 ) return 781; - if(i == 782 ) return 782; - if(i == 783 ) return 783; - if(i == 784 ) return 784; - if(i == 785 ) return 785; - if(i == 786 ) return 786; - if(i == 787 ) return 787; - if(i == 788 ) return 788; - if(i == 789 ) return 789; - if(i == 790 ) return 790; - if(i == 791 ) return 791; - if(i == 792 ) return 792; - if(i == 793 ) return 793; - if(i == 794 ) return 794; - if(i == 795 ) return 795; - if(i == 796 ) return 796; - if(i == 797 ) return 797; - if(i == 798 ) return 798; - if(i == 799 ) return 799; - if(i == 800 ) return 800; - if(i == 801 ) return 801; - if(i == 802 ) return 802; - if(i == 803 ) return 803; - if(i == 804 ) return 804; - if(i == 805 ) return 805; - if(i == 806 ) return 806; - if(i == 807 ) return 807; - if(i == 808 ) return 808; - if(i == 809 ) return 809; - if(i == 810 ) return 810; - if(i == 811 ) return 811; - if(i == 812 ) return 812; - if(i == 813 ) return 813; - if(i == 814 ) return 814; - if(i == 815 ) return 815; - if(i == 816 ) return 816; - if(i == 817 ) return 817; - if(i == 818 ) return 818; - if(i == 819 ) return 819; - if(i == 820 ) return 820; - if(i == 821 ) return 821; - if(i == 822 ) return 822; - if(i == 823 ) return 823; - if(i == 824 ) return 824; - if(i == 825 ) return 825; - if(i == 826 ) return 826; - if(i == 827 ) return 827; - if(i == 828 ) return 828; - if(i == 829 ) return 829; - if(i == 830 ) return 830; - if(i == 831 ) return 831; - if(i == 832 ) return 832; - if(i == 833 ) return 833; - if(i == 834 ) return 834; - if(i == 835 ) return 835; - if(i == 836 ) return 836; - if(i == 837 ) return 837; - if(i == 838 ) return 838; - if(i == 839 ) return 839; - if(i == 840 ) return 840; - if(i == 841 ) return 841; - if(i == 842 ) return 842; - if(i == 843 ) return 843; - if(i == 844 ) return 844; - if(i == 845 ) return 845; - if(i == 846 ) return 846; - if(i == 847 ) return 847; - if(i == 848 ) return 848; - if(i == 849 ) return 849; - if(i == 850 ) return 850; - if(i == 851 ) return 851; - if(i == 852 ) return 852; - if(i == 853 ) return 853; - if(i == 854 ) return 854; - if(i == 855 ) return 855; - if(i == 856 ) return 856; - if(i == 857 ) return 857; - if(i == 858 ) return 858; - if(i == 859 ) return 859; - if(i == 860 ) return 860; - if(i == 861 ) return 861; - if(i == 862 ) return 862; - if(i == 863 ) return 863; - if(i == 864 ) return 864; - if(i == 865 ) return 865; - if(i == 866 ) return 866; - if(i == 867 ) return 867; - if(i == 868 ) return 868; - if(i == 869 ) return 869; - if(i == 870 ) return 870; - if(i == 871 ) return 871; - if(i == 872 ) return 872; - if(i == 873 ) return 873; - if(i == 874 ) return 874; - if(i == 875 ) return 875; - if(i == 876 ) return 876; - if(i == 877 ) return 877; - if(i == 878 ) return 878; - if(i == 879 ) return 879; - if(i == 880 ) return 880; - if(i == 881 ) return 881; - if(i == 882 ) return 882; - if(i == 883 ) return 883; - if(i == 884 ) return 884; - if(i == 885 ) return 885; - if(i == 886 ) return 886; - if(i == 887 ) return 887; - if(i == 888 ) return 888; - if(i == 889 ) return 889; - if(i == 890 ) return 890; - if(i == 891 ) return 891; - if(i == 892 ) return 892; - if(i == 893 ) return 893; - if(i == 894 ) return 894; - if(i == 895 ) return 895; - if(i == 896 ) return 896; - if(i == 897 ) return 897; - if(i == 898 ) return 898; - if(i == 899 ) return 899; - if(i == 900 ) return 900; - if(i == 901 ) return 901; - if(i == 902 ) return 902; - if(i == 903 ) return 903; - if(i == 904 ) return 904; - if(i == 905 ) return 905; - if(i == 906 ) return 906; - if(i == 907 ) return 907; - if(i == 908 ) return 908; - if(i == 909 ) return 909; - if(i == 910 ) return 910; - if(i == 911 ) return 911; - if(i == 912 ) return 912; - if(i == 913 ) return 913; - if(i == 914 ) return 914; - if(i == 915 ) return 915; - if(i == 916 ) return 916; - if(i == 917 ) return 917; - if(i == 918 ) return 918; - if(i == 919 ) return 919; - if(i == 920 ) return 920; - if(i == 921 ) return 921; - if(i == 922 ) return 922; - if(i == 923 ) return 923; - if(i == 924 ) return 924; - if(i == 925 ) return 925; - if(i == 926 ) return 926; - if(i == 927 ) return 927; - if(i == 928 ) return 928; - if(i == 929 ) return 929; - if(i == 930 ) return 930; - if(i == 931 ) return 931; - if(i == 932 ) return 932; - if(i == 933 ) return 933; - if(i == 934 ) return 934; - if(i == 935 ) return 935; - if(i == 936 ) return 936; - if(i == 937 ) return 937; - if(i == 938 ) return 938; - if(i == 939 ) return 939; - if(i == 940 ) return 940; - if(i == 941 ) return 941; - if(i == 942 ) return 942; - if(i == 943 ) return 943; - if(i == 944 ) return 944; - if(i == 945 ) return 945; - if(i == 946 ) return 946; - if(i == 947 ) return 947; - if(i == 948 ) return 948; - if(i == 949 ) return 949; - if(i == 950 ) return 950; - if(i == 951 ) return 951; - if(i == 952 ) return 952; - if(i == 953 ) return 953; - if(i == 954 ) return 954; - if(i == 955 ) return 955; - if(i == 956 ) return 956; - if(i == 957 ) return 957; - if(i == 958 ) return 958; - if(i == 959 ) return 959; - if(i == 960 ) return 960; - if(i == 961 ) return 961; - if(i == 962 ) return 962; - if(i == 963 ) return 963; - if(i == 964 ) return 964; - if(i == 965 ) return 965; - if(i == 966 ) return 966; - if(i == 967 ) return 967; - if(i == 968 ) return 968; - if(i == 969 ) return 969; - if(i == 970 ) return 970; - if(i == 971 ) return 971; - if(i == 972 ) return 972; - if(i == 973 ) return 973; - if(i == 974 ) return 974; - if(i == 975 ) return 975; - if(i == 976 ) return 976; - if(i == 977 ) return 977; - if(i == 978 ) return 978; - if(i == 979 ) return 979; - if(i == 980 ) return 980; - if(i == 981 ) return 981; - if(i == 982 ) return 982; - if(i == 983 ) return 983; - if(i == 984 ) return 984; - if(i == 985 ) return 985; - if(i == 986 ) return 986; - if(i == 987 ) return 987; - if(i == 988 ) return 988; - if(i == 989 ) return 989; - if(i == 990 ) return 990; - if(i == 991 ) return 991; - if(i == 992 ) return 992; - if(i == 993 ) return 993; - if(i == 994 ) return 994; - if(i == 995 ) return 995; - if(i == 996 ) return 996; - if(i == 997 ) return 997; - if(i == 998 ) return 998; - if(i == 999 ) return 999; - if(i == 1000 ) return 1000; - if(i == 1001 ) return 1001; - if(i == 1002 ) return 1002; - if(i == 1003 ) return 1003; - if(i == 1004 ) return 1004; - if(i == 1005 ) return 1005; - if(i == 1006 ) return 1006; - if(i == 1007 ) return 1007; - if(i == 1008 ) return 1008; - if(i == 1009 ) return 1009; - if(i == 1010 ) return 1010; - if(i == 1011 ) return 1011; - if(i == 1012 ) return 1012; - if(i == 1013 ) return 1013; - if(i == 1014 ) return 1014; - if(i == 1015 ) return 1015; - if(i == 1016 ) return 1016; - if(i == 1017 ) return 1017; - if(i == 1018 ) return 1018; - if(i == 1019 ) return 1019; - if(i == 1020 ) return 1020; - if(i == 1021 ) return 1021; - if(i == 1022 ) return 1022; - if(i == 1023 ) return 1023; - if(i == 1024 ) return 1024; - if(i == 1025 ) return 1025; - if(i == 1026 ) return 1026; - if(i == 1027 ) return 1027; - if(i == 1028 ) return 1028; - if(i == 1029 ) return 1029; - if(i == 1030 ) return 1030; - if(i == 1031 ) return 1031; - if(i == 1032 ) return 1032; - if(i == 1033 ) return 1033; - if(i == 1034 ) return 1034; - if(i == 1035 ) return 1035; - if(i == 1036 ) return 1036; - if(i == 1037 ) return 1037; - if(i == 1038 ) return 1038; - if(i == 1039 ) return 1039; - if(i == 1040 ) return 1040; - if(i == 1041 ) return 1041; - if(i == 1042 ) return 1042; - if(i == 1043 ) return 1043; - if(i == 1044 ) return 1044; - if(i == 1045 ) return 1045; - if(i == 1046 ) return 1046; - if(i == 1047 ) return 1047; - if(i == 1048 ) return 1048; - if(i == 1049 ) return 1049; - if(i == 1050 ) return 1050; - if(i == 1051 ) return 1051; - if(i == 1052 ) return 1052; - if(i == 1053 ) return 1053; - if(i == 1054 ) return 1054; - if(i == 1055 ) return 1055; - if(i == 1056 ) return 1056; - if(i == 1057 ) return 1057; - if(i == 1058 ) return 1058; - if(i == 1059 ) return 1059; - if(i == 1060 ) return 1060; - if(i == 1061 ) return 1061; - if(i == 1062 ) return 1062; - if(i == 1063 ) return 1063; - if(i == 1064 ) return 1064; - if(i == 1065 ) return 1065; - if(i == 1066 ) return 1066; - if(i == 1067 ) return 1067; - if(i == 1068 ) return 1068; - if(i == 1069 ) return 1069; - if(i == 1070 ) return 1070; - if(i == 1071 ) return 1071; - if(i == 1072 ) return 1072; - if(i == 1073 ) return 1073; - if(i == 1074 ) return 1074; - if(i == 1075 ) return 1075; - if(i == 1076 ) return 1076; - if(i == 1077 ) return 1077; - if(i == 1078 ) return 1078; - if(i == 1079 ) return 1079; - if(i == 1080 ) return 1080; - if(i == 1081 ) return 1081; - if(i == 1082 ) return 1082; - if(i == 1083 ) return 1083; - if(i == 1084 ) return 1084; - if(i == 1085 ) return 1085; - if(i == 1086 ) return 1086; - if(i == 1087 ) return 1087; - if(i == 1088 ) return 1088; - if(i == 1089 ) return 1089; - if(i == 1090 ) return 1090; - if(i == 1091 ) return 1091; - if(i == 1092 ) return 1092; - if(i == 1093 ) return 1093; - if(i == 1094 ) return 1094; - if(i == 1095 ) return 1095; - if(i == 1096 ) return 1096; - if(i == 1097 ) return 1097; - if(i == 1098 ) return 1098; - if(i == 1099 ) return 1099; - if(i == 1100 ) return 1100; - if(i == 1101 ) return 1101; - if(i == 1102 ) return 1102; - if(i == 1103 ) return 1103; - if(i == 1104 ) return 1104; - if(i == 1105 ) return 1105; - if(i == 1106 ) return 1106; - if(i == 1107 ) return 1107; - if(i == 1108 ) return 1108; - if(i == 1109 ) return 1109; - if(i == 1110 ) return 1110; - if(i == 1111 ) return 1111; - if(i == 1112 ) return 1112; - if(i == 1113 ) return 1113; - if(i == 1114 ) return 1114; - if(i == 1115 ) return 1115; - if(i == 1116 ) return 1116; - if(i == 1117 ) return 1117; - if(i == 1118 ) return 1118; - if(i == 1119 ) return 1119; - if(i == 1120 ) return 1120; - if(i == 1121 ) return 1121; - if(i == 1122 ) return 1122; - if(i == 1123 ) return 1123; - if(i == 1124 ) return 1124; - if(i == 1125 ) return 1125; - if(i == 1126 ) return 1126; - if(i == 1127 ) return 1127; - if(i == 1128 ) return 1128; - if(i == 1129 ) return 1129; - if(i == 1130 ) return 1130; - if(i == 1131 ) return 1131; - if(i == 1132 ) return 1132; - if(i == 1133 ) return 1133; - if(i == 1134 ) return 1134; - if(i == 1135 ) return 1135; - if(i == 1136 ) return 1136; - if(i == 1137 ) return 1137; - if(i == 1138 ) return 1138; - if(i == 1139 ) return 1139; - if(i == 1140 ) return 1140; - if(i == 1141 ) return 1141; - if(i == 1142 ) return 1142; - if(i == 1143 ) return 1143; - if(i == 1144 ) return 1144; - if(i == 1145 ) return 1145; - if(i == 1146 ) return 1146; - if(i == 1147 ) return 1147; - if(i == 1148 ) return 1148; - if(i == 1149 ) return 1149; - if(i == 1150 ) return 1150; - if(i == 1151 ) return 1151; - if(i == 1152 ) return 1152; - if(i == 1153 ) return 1153; - if(i == 1154 ) return 1154; - if(i == 1155 ) return 1155; - if(i == 1156 ) return 1156; - if(i == 1157 ) return 1157; - if(i == 1158 ) return 1158; - if(i == 1159 ) return 1159; - if(i == 1160 ) return 1160; - if(i == 1161 ) return 1161; - if(i == 1162 ) return 1162; - if(i == 1163 ) return 1163; - if(i == 1164 ) return 1164; - if(i == 1165 ) return 1165; - if(i == 1166 ) return 1166; - if(i == 1167 ) return 1167; - if(i == 1168 ) return 1168; - if(i == 1169 ) return 1169; - if(i == 1170 ) return 1170; - if(i == 1171 ) return 1171; - if(i == 1172 ) return 1172; - if(i == 1173 ) return 1173; - if(i == 1174 ) return 1174; - if(i == 1175 ) return 1175; - if(i == 1176 ) return 1176; - if(i == 1177 ) return 1177; - if(i == 1178 ) return 1178; - if(i == 1179 ) return 1179; - if(i == 1180 ) return 1180; - if(i == 1181 ) return 1181; - if(i == 1182 ) return 1182; - if(i == 1183 ) return 1183; - if(i == 1184 ) return 1184; - if(i == 1185 ) return 1185; - if(i == 1186 ) return 1186; - if(i == 1187 ) return 1187; - if(i == 1188 ) return 1188; - if(i == 1189 ) return 1189; - if(i == 1190 ) return 1190; - if(i == 1191 ) return 1191; - if(i == 1192 ) return 1192; - if(i == 1193 ) return 1193; - if(i == 1194 ) return 1194; - if(i == 1195 ) return 1195; - if(i == 1196 ) return 1196; - if(i == 1197 ) return 1197; - if(i == 1198 ) return 1198; - if(i == 1199 ) return 1199; - if(i == 1200 ) return 1200; - if(i == 1201 ) return 1201; - if(i == 1202 ) return 1202; - if(i == 1203 ) return 1203; - if(i == 1204 ) return 1204; - if(i == 1205 ) return 1205; - if(i == 1206 ) return 1206; - if(i == 1207 ) return 1207; - if(i == 1208 ) return 1208; - if(i == 1209 ) return 1209; - if(i == 1210 ) return 1210; - if(i == 1211 ) return 1211; - if(i == 1212 ) return 1212; - if(i == 1213 ) return 1213; - if(i == 1214 ) return 1214; - if(i == 1215 ) return 1215; - if(i == 1216 ) return 1216; - if(i == 1217 ) return 1217; - if(i == 1218 ) return 1218; - if(i == 1219 ) return 1219; - if(i == 1220 ) return 1220; - if(i == 1221 ) return 1221; - if(i == 1222 ) return 1222; - if(i == 1223 ) return 1223; - if(i == 1224 ) return 1224; - if(i == 1225 ) return 1225; - if(i == 1226 ) return 1226; - if(i == 1227 ) return 1227; - if(i == 1228 ) return 1228; - if(i == 1229 ) return 1229; - if(i == 1230 ) return 1230; - if(i == 1231 ) return 1231; - if(i == 1232 ) return 1232; - if(i == 1233 ) return 1233; - if(i == 1234 ) return 1234; - if(i == 1235 ) return 1235; - if(i == 1236 ) return 1236; - if(i == 1237 ) return 1237; - if(i == 1238 ) return 1238; - if(i == 1239 ) return 1239; - if(i == 1240 ) return 1240; - if(i == 1241 ) return 1241; - if(i == 1242 ) return 1242; - if(i == 1243 ) return 1243; - if(i == 1244 ) return 1244; - if(i == 1245 ) return 1245; - if(i == 1246 ) return 1246; - if(i == 1247 ) return 1247; - if(i == 1248 ) return 1248; - if(i == 1249 ) return 1249; - if(i == 1250 ) return 1250; - if(i == 1251 ) return 1251; - if(i == 1252 ) return 1252; - if(i == 1253 ) return 1253; - if(i == 1254 ) return 1254; - if(i == 1255 ) return 1255; - if(i == 1256 ) return 1256; - if(i == 1257 ) return 1257; - if(i == 1258 ) return 1258; - if(i == 1259 ) return 1259; - if(i == 1260 ) return 1260; - if(i == 1261 ) return 1261; - if(i == 1262 ) return 1262; - if(i == 1263 ) return 1263; - if(i == 1264 ) return 1264; - if(i == 1265 ) return 1265; - if(i == 1266 ) return 1266; - if(i == 1267 ) return 1267; - if(i == 1268 ) return 1268; - if(i == 1269 ) return 1269; - if(i == 1270 ) return 1270; - if(i == 1271 ) return 1271; - if(i == 1272 ) return 1272; - if(i == 1273 ) return 1273; - if(i == 1274 ) return 1274; - if(i == 1275 ) return 1275; - if(i == 1276 ) return 1276; - if(i == 1277 ) return 1277; - if(i == 1278 ) return 1278; - if(i == 1279 ) return 1279; - if(i == 1280 ) return 1280; - if(i == 1281 ) return 1281; - if(i == 1282 ) return 1282; - if(i == 1283 ) return 1283; - if(i == 1284 ) return 1284; - if(i == 1285 ) return 1285; - if(i == 1286 ) return 1286; - if(i == 1287 ) return 1287; - if(i == 1288 ) return 1288; - if(i == 1289 ) return 1289; - if(i == 1290 ) return 1290; - if(i == 1291 ) return 1291; - if(i == 1292 ) return 1292; - if(i == 1293 ) return 1293; - if(i == 1294 ) return 1294; - if(i == 1295 ) return 1295; - if(i == 1296 ) return 1296; - if(i == 1297 ) return 1297; - if(i == 1298 ) return 1298; - if(i == 1299 ) return 1299; - if(i == 1300 ) return 1300; - if(i == 1301 ) return 1301; - if(i == 1302 ) return 1302; - if(i == 1303 ) return 1303; - if(i == 1304 ) return 1304; - if(i == 1305 ) return 1305; - if(i == 1306 ) return 1306; - if(i == 1307 ) return 1307; - if(i == 1308 ) return 1308; - if(i == 1309 ) return 1309; - if(i == 1310 ) return 1310; - if(i == 1311 ) return 1311; - if(i == 1312 ) return 1312; - if(i == 1313 ) return 1313; - if(i == 1314 ) return 1314; - if(i == 1315 ) return 1315; - if(i == 1316 ) return 1316; - if(i == 1317 ) return 1317; - if(i == 1318 ) return 1318; - if(i == 1319 ) return 1319; - if(i == 1320 ) return 1320; - if(i == 1321 ) return 1321; - if(i == 1322 ) return 1322; - if(i == 1323 ) return 1323; - if(i == 1324 ) return 1324; - if(i == 1325 ) return 1325; - if(i == 1326 ) return 1326; - if(i == 1327 ) return 1327; - if(i == 1328 ) return 1328; - if(i == 1329 ) return 1329; - if(i == 1330 ) return 1330; - if(i == 1331 ) return 1331; - if(i == 1332 ) return 1332; - if(i == 1333 ) return 1333; - if(i == 1334 ) return 1334; - if(i == 1335 ) return 1335; - if(i == 1336 ) return 1336; - if(i == 1337 ) return 1337; - if(i == 1338 ) return 1338; - if(i == 1339 ) return 1339; - if(i == 1340 ) return 1340; - if(i == 1341 ) return 1341; - if(i == 1342 ) return 1342; - if(i == 1343 ) return 1343; - if(i == 1344 ) return 1344; - if(i == 1345 ) return 1345; - if(i == 1346 ) return 1346; - if(i == 1347 ) return 1347; - if(i == 1348 ) return 1348; - if(i == 1349 ) return 1349; - if(i == 1350 ) return 1350; - if(i == 1351 ) return 1351; - if(i == 1352 ) return 1352; - if(i == 1353 ) return 1353; - if(i == 1354 ) return 1354; - if(i == 1355 ) return 1355; - if(i == 1356 ) return 1356; - if(i == 1357 ) return 1357; - if(i == 1358 ) return 1358; - if(i == 1359 ) return 1359; - if(i == 1360 ) return 1360; - if(i == 1361 ) return 1361; - if(i == 1362 ) return 1362; - if(i == 1363 ) return 1363; - if(i == 1364 ) return 1364; - if(i == 1365 ) return 1365; - if(i == 1366 ) return 1366; - if(i == 1367 ) return 1367; - if(i == 1368 ) return 1368; - if(i == 1369 ) return 1369; - if(i == 1370 ) return 1370; - if(i == 1371 ) return 1371; - if(i == 1372 ) return 1372; - if(i == 1373 ) return 1373; - if(i == 1374 ) return 1374; - if(i == 1375 ) return 1375; - if(i == 1376 ) return 1376; - if(i == 1377 ) return 1377; - if(i == 1378 ) return 1378; - if(i == 1379 ) return 1379; - if(i == 1380 ) return 1380; - if(i == 1381 ) return 1381; - if(i == 1382 ) return 1382; - if(i == 1383 ) return 1383; - if(i == 1384 ) return 1384; - if(i == 1385 ) return 1385; - if(i == 1386 ) return 1386; - if(i == 1387 ) return 1387; - if(i == 1388 ) return 1388; - if(i == 1389 ) return 1389; - if(i == 1390 ) return 1390; - if(i == 1391 ) return 1391; - if(i == 1392 ) return 1392; - if(i == 1393 ) return 1393; - if(i == 1394 ) return 1394; - if(i == 1395 ) return 1395; - if(i == 1396 ) return 1396; - if(i == 1397 ) return 1397; - if(i == 1398 ) return 1398; - if(i == 1399 ) return 1399; - if(i == 1400 ) return 1400; - if(i == 1401 ) return 1401; - if(i == 1402 ) return 1402; - if(i == 1403 ) return 1403; - if(i == 1404 ) return 1404; - if(i == 1405 ) return 1405; - if(i == 1406 ) return 1406; - if(i == 1407 ) return 1407; - if(i == 1408 ) return 1408; - if(i == 1409 ) return 1409; - if(i == 1410 ) return 1410; - if(i == 1411 ) return 1411; - if(i == 1412 ) return 1412; - if(i == 1413 ) return 1413; - if(i == 1414 ) return 1414; - if(i == 1415 ) return 1415; - if(i == 1416 ) return 1416; - if(i == 1417 ) return 1417; - if(i == 1418 ) return 1418; - if(i == 1419 ) return 1419; - if(i == 1420 ) return 1420; - if(i == 1421 ) return 1421; - if(i == 1422 ) return 1422; - if(i == 1423 ) return 1423; - if(i == 1424 ) return 1424; - if(i == 1425 ) return 1425; - if(i == 1426 ) return 1426; - if(i == 1427 ) return 1427; - if(i == 1428 ) return 1428; - if(i == 1429 ) return 1429; - if(i == 1430 ) return 1430; - if(i == 1431 ) return 1431; - if(i == 1432 ) return 1432; - if(i == 1433 ) return 1433; - if(i == 1434 ) return 1434; - if(i == 1435 ) return 1435; - if(i == 1436 ) return 1436; - if(i == 1437 ) return 1437; - if(i == 1438 ) return 1438; - if(i == 1439 ) return 1439; - if(i == 1440 ) return 1440; - if(i == 1441 ) return 1441; - if(i == 1442 ) return 1442; - if(i == 1443 ) return 1443; - if(i == 1444 ) return 1444; - if(i == 1445 ) return 1445; - if(i == 1446 ) return 1446; - if(i == 1447 ) return 1447; - if(i == 1448 ) return 1448; - if(i == 1449 ) return 1449; - if(i == 1450 ) return 1450; - if(i == 1451 ) return 1451; - if(i == 1452 ) return 1452; - if(i == 1453 ) return 1453; - if(i == 1454 ) return 1454; - if(i == 1455 ) return 1455; - if(i == 1456 ) return 1456; - if(i == 1457 ) return 1457; - if(i == 1458 ) return 1458; - if(i == 1459 ) return 1459; - if(i == 1460 ) return 1460; - if(i == 1461 ) return 1461; - if(i == 1462 ) return 1462; - if(i == 1463 ) return 1463; - if(i == 1464 ) return 1464; - if(i == 1465 ) return 1465; - if(i == 1466 ) return 1466; - if(i == 1467 ) return 1467; - if(i == 1468 ) return 1468; - if(i == 1469 ) return 1469; - if(i == 1470 ) return 1470; - if(i == 1471 ) return 1471; - if(i == 1472 ) return 1472; - if(i == 1473 ) return 1473; - if(i == 1474 ) return 1474; - if(i == 1475 ) return 1475; - if(i == 1476 ) return 1476; - if(i == 1477 ) return 1477; - if(i == 1478 ) return 1478; - if(i == 1479 ) return 1479; - if(i == 1480 ) return 1480; - if(i == 1481 ) return 1481; - if(i == 1482 ) return 1482; - if(i == 1483 ) return 1483; - if(i == 1484 ) return 1484; - if(i == 1485 ) return 1485; - if(i == 1486 ) return 1486; - if(i == 1487 ) return 1487; - if(i == 1488 ) return 1488; - if(i == 1489 ) return 1489; - if(i == 1490 ) return 1490; - if(i == 1491 ) return 1491; - if(i == 1492 ) return 1492; - if(i == 1493 ) return 1493; - if(i == 1494 ) return 1494; - if(i == 1495 ) return 1495; - if(i == 1496 ) return 1496; - if(i == 1497 ) return 1497; - if(i == 1498 ) return 1498; - if(i == 1499 ) return 1499; - if(i == 1500 ) return 1500; - if(i == 1501 ) return 1501; - if(i == 1502 ) return 1502; - if(i == 1503 ) return 1503; - if(i == 1504 ) return 1504; - if(i == 1505 ) return 1505; - if(i == 1506 ) return 1506; - if(i == 1507 ) return 1507; - if(i == 1508 ) return 1508; - if(i == 1509 ) return 1509; - if(i == 1510 ) return 1510; - if(i == 1511 ) return 1511; - if(i == 1512 ) return 1512; - if(i == 1513 ) return 1513; - if(i == 1514 ) return 1514; - if(i == 1515 ) return 1515; - if(i == 1516 ) return 1516; - if(i == 1517 ) return 1517; - if(i == 1518 ) return 1518; - if(i == 1519 ) return 1519; - if(i == 1520 ) return 1520; - if(i == 1521 ) return 1521; - if(i == 1522 ) return 1522; - if(i == 1523 ) return 1523; - if(i == 1524 ) return 1524; - if(i == 1525 ) return 1525; - if(i == 1526 ) return 1526; - if(i == 1527 ) return 1527; - if(i == 1528 ) return 1528; - if(i == 1529 ) return 1529; - if(i == 1530 ) return 1530; - if(i == 1531 ) return 1531; - if(i == 1532 ) return 1532; - if(i == 1533 ) return 1533; - if(i == 1534 ) return 1534; - if(i == 1535 ) return 1535; - if(i == 1536 ) return 1536; - if(i == 1537 ) return 1537; - if(i == 1538 ) return 1538; - if(i == 1539 ) return 1539; - if(i == 1540 ) return 1540; - if(i == 1541 ) return 1541; - if(i == 1542 ) return 1542; - if(i == 1543 ) return 1543; - if(i == 1544 ) return 1544; - if(i == 1545 ) return 1545; - if(i == 1546 ) return 1546; - if(i == 1547 ) return 1547; - if(i == 1548 ) return 1548; - if(i == 1549 ) return 1549; - if(i == 1550 ) return 1550; - if(i == 1551 ) return 1551; - if(i == 1552 ) return 1552; - if(i == 1553 ) return 1553; - if(i == 1554 ) return 1554; - if(i == 1555 ) return 1555; - if(i == 1556 ) return 1556; - if(i == 1557 ) return 1557; - if(i == 1558 ) return 1558; - if(i == 1559 ) return 1559; - if(i == 1560 ) return 1560; - if(i == 1561 ) return 1561; - if(i == 1562 ) return 1562; - if(i == 1563 ) return 1563; - if(i == 1564 ) return 1564; - if(i == 1565 ) return 1565; - if(i == 1566 ) return 1566; - if(i == 1567 ) return 1567; - if(i == 1568 ) return 1568; - if(i == 1569 ) return 1569; - if(i == 1570 ) return 1570; - if(i == 1571 ) return 1571; - if(i == 1572 ) return 1572; - if(i == 1573 ) return 1573; - if(i == 1574 ) return 1574; - if(i == 1575 ) return 1575; - if(i == 1576 ) return 1576; - if(i == 1577 ) return 1577; - if(i == 1578 ) return 1578; - if(i == 1579 ) return 1579; - if(i == 1580 ) return 1580; - if(i == 1581 ) return 1581; - if(i == 1582 ) return 1582; - if(i == 1583 ) return 1583; - if(i == 1584 ) return 1584; - if(i == 1585 ) return 1585; - if(i == 1586 ) return 1586; - if(i == 1587 ) return 1587; - if(i == 1588 ) return 1588; - if(i == 1589 ) return 1589; - if(i == 1590 ) return 1590; - if(i == 1591 ) return 1591; - if(i == 1592 ) return 1592; - if(i == 1593 ) return 1593; - if(i == 1594 ) return 1594; - if(i == 1595 ) return 1595; - if(i == 1596 ) return 1596; - if(i == 1597 ) return 1597; - if(i == 1598 ) return 1598; - if(i == 1599 ) return 1599; - if(i == 1600 ) return 1600; - if(i == 1601 ) return 1601; - if(i == 1602 ) return 1602; - if(i == 1603 ) return 1603; - if(i == 1604 ) return 1604; - if(i == 1605 ) return 1605; - if(i == 1606 ) return 1606; - if(i == 1607 ) return 1607; - if(i == 1608 ) return 1608; - if(i == 1609 ) return 1609; - if(i == 1610 ) return 1610; - if(i == 1611 ) return 1611; - if(i == 1612 ) return 1612; - if(i == 1613 ) return 1613; - if(i == 1614 ) return 1614; - if(i == 1615 ) return 1615; - if(i == 1616 ) return 1616; - if(i == 1617 ) return 1617; - if(i == 1618 ) return 1618; - if(i == 1619 ) return 1619; - if(i == 1620 ) return 1620; - if(i == 1621 ) return 1621; - if(i == 1622 ) return 1622; - if(i == 1623 ) return 1623; - if(i == 1624 ) return 1624; - if(i == 1625 ) return 1625; - if(i == 1626 ) return 1626; - if(i == 1627 ) return 1627; - if(i == 1628 ) return 1628; - if(i == 1629 ) return 1629; - if(i == 1630 ) return 1630; - if(i == 1631 ) return 1631; - if(i == 1632 ) return 1632; - if(i == 1633 ) return 1633; - if(i == 1634 ) return 1634; - if(i == 1635 ) return 1635; - if(i == 1636 ) return 1636; - if(i == 1637 ) return 1637; - if(i == 1638 ) return 1638; - if(i == 1639 ) return 1639; - if(i == 1640 ) return 1640; - if(i == 1641 ) return 1641; - if(i == 1642 ) return 1642; - if(i == 1643 ) return 1643; - if(i == 1644 ) return 1644; - if(i == 1645 ) return 1645; - if(i == 1646 ) return 1646; - if(i == 1647 ) return 1647; - if(i == 1648 ) return 1648; - if(i == 1649 ) return 1649; - if(i == 1650 ) return 1650; - if(i == 1651 ) return 1651; - if(i == 1652 ) return 1652; - if(i == 1653 ) return 1653; - if(i == 1654 ) return 1654; - if(i == 1655 ) return 1655; - if(i == 1656 ) return 1656; - if(i == 1657 ) return 1657; - if(i == 1658 ) return 1658; - if(i == 1659 ) return 1659; - if(i == 1660 ) return 1660; - if(i == 1661 ) return 1661; - if(i == 1662 ) return 1662; - if(i == 1663 ) return 1663; - if(i == 1664 ) return 1664; - if(i == 1665 ) return 1665; - if(i == 1666 ) return 1666; - if(i == 1667 ) return 1667; - if(i == 1668 ) return 1668; - if(i == 1669 ) return 1669; - if(i == 1670 ) return 1670; - if(i == 1671 ) return 1671; - if(i == 1672 ) return 1672; - if(i == 1673 ) return 1673; - if(i == 1674 ) return 1674; - if(i == 1675 ) return 1675; - if(i == 1676 ) return 1676; - if(i == 1677 ) return 1677; - if(i == 1678 ) return 1678; - if(i == 1679 ) return 1679; - if(i == 1680 ) return 1680; - if(i == 1681 ) return 1681; - if(i == 1682 ) return 1682; - if(i == 1683 ) return 1683; - if(i == 1684 ) return 1684; - if(i == 1685 ) return 1685; - if(i == 1686 ) return 1686; - if(i == 1687 ) return 1687; - if(i == 1688 ) return 1688; - if(i == 1689 ) return 1689; - if(i == 1690 ) return 1690; - if(i == 1691 ) return 1691; - if(i == 1692 ) return 1692; - if(i == 1693 ) return 1693; - if(i == 1694 ) return 1694; - if(i == 1695 ) return 1695; - if(i == 1696 ) return 1696; - if(i == 1697 ) return 1697; - if(i == 1698 ) return 1698; - if(i == 1699 ) return 1699; - if(i == 1700 ) return 1700; - if(i == 1701 ) return 1701; - if(i == 1702 ) return 1702; - if(i == 1703 ) return 1703; - if(i == 1704 ) return 1704; - if(i == 1705 ) return 1705; - if(i == 1706 ) return 1706; - if(i == 1707 ) return 1707; - if(i == 1708 ) return 1708; - if(i == 1709 ) return 1709; - if(i == 1710 ) return 1710; - if(i == 1711 ) return 1711; - if(i == 1712 ) return 1712; - if(i == 1713 ) return 1713; - if(i == 1714 ) return 1714; - if(i == 1715 ) return 1715; - if(i == 1716 ) return 1716; - if(i == 1717 ) return 1717; - if(i == 1718 ) return 1718; - if(i == 1719 ) return 1719; - if(i == 1720 ) return 1720; - if(i == 1721 ) return 1721; - if(i == 1722 ) return 1722; - if(i == 1723 ) return 1723; - if(i == 1724 ) return 1724; - if(i == 1725 ) return 1725; - if(i == 1726 ) return 1726; - if(i == 1727 ) return 1727; - if(i == 1728 ) return 1728; - if(i == 1729 ) return 1729; - if(i == 1730 ) return 1730; - if(i == 1731 ) return 1731; - if(i == 1732 ) return 1732; - if(i == 1733 ) return 1733; - if(i == 1734 ) return 1734; - if(i == 1735 ) return 1735; - if(i == 1736 ) return 1736; - if(i == 1737 ) return 1737; - if(i == 1738 ) return 1738; - if(i == 1739 ) return 1739; - if(i == 1740 ) return 1740; - if(i == 1741 ) return 1741; - if(i == 1742 ) return 1742; - if(i == 1743 ) return 1743; - if(i == 1744 ) return 1744; - if(i == 1745 ) return 1745; - if(i == 1746 ) return 1746; - if(i == 1747 ) return 1747; - if(i == 1748 ) return 1748; - if(i == 1749 ) return 1749; - if(i == 1750 ) return 1750; - if(i == 1751 ) return 1751; - if(i == 1752 ) return 1752; - if(i == 1753 ) return 1753; - if(i == 1754 ) return 1754; - if(i == 1755 ) return 1755; - if(i == 1756 ) return 1756; - if(i == 1757 ) return 1757; - if(i == 1758 ) return 1758; - if(i == 1759 ) return 1759; - if(i == 1760 ) return 1760; - if(i == 1761 ) return 1761; - if(i == 1762 ) return 1762; - if(i == 1763 ) return 1763; - if(i == 1764 ) return 1764; - if(i == 1765 ) return 1765; - if(i == 1766 ) return 1766; - if(i == 1767 ) return 1767; - if(i == 1768 ) return 1768; - if(i == 1769 ) return 1769; - if(i == 1770 ) return 1770; - if(i == 1771 ) return 1771; - if(i == 1772 ) return 1772; - if(i == 1773 ) return 1773; - if(i == 1774 ) return 1774; - if(i == 1775 ) return 1775; - if(i == 1776 ) return 1776; - if(i == 1777 ) return 1777; - if(i == 1778 ) return 1778; - if(i == 1779 ) return 1779; - if(i == 1780 ) return 1780; - if(i == 1781 ) return 1781; - if(i == 1782 ) return 1782; - if(i == 1783 ) return 1783; - if(i == 1784 ) return 1784; - if(i == 1785 ) return 1785; - if(i == 1786 ) return 1786; - if(i == 1787 ) return 1787; - if(i == 1788 ) return 1788; - if(i == 1789 ) return 1789; - if(i == 1790 ) return 1790; - if(i == 1791 ) return 1791; - if(i == 1792 ) return 1792; - if(i == 1793 ) return 1793; - if(i == 1794 ) return 1794; - if(i == 1795 ) return 1795; - if(i == 1796 ) return 1796; - if(i == 1797 ) return 1797; - if(i == 1798 ) return 1798; - if(i == 1799 ) return 1799; - if(i == 1800 ) return 1800; - if(i == 1801 ) return 1801; - if(i == 1802 ) return 1802; - if(i == 1803 ) return 1803; - if(i == 1804 ) return 1804; - if(i == 1805 ) return 1805; - if(i == 1806 ) return 1806; - if(i == 1807 ) return 1807; - if(i == 1808 ) return 1808; - if(i == 1809 ) return 1809; - if(i == 1810 ) return 1810; - if(i == 1811 ) return 1811; - if(i == 1812 ) return 1812; - if(i == 1813 ) return 1813; - if(i == 1814 ) return 1814; - if(i == 1815 ) return 1815; - if(i == 1816 ) return 1816; - if(i == 1817 ) return 1817; - if(i == 1818 ) return 1818; - if(i == 1819 ) return 1819; - if(i == 1820 ) return 1820; - if(i == 1821 ) return 1821; - if(i == 1822 ) return 1822; - if(i == 1823 ) return 1823; - if(i == 1824 ) return 1824; - if(i == 1825 ) return 1825; - if(i == 1826 ) return 1826; - if(i == 1827 ) return 1827; - if(i == 1828 ) return 1828; - if(i == 1829 ) return 1829; - if(i == 1830 ) return 1830; - if(i == 1831 ) return 1831; - if(i == 1832 ) return 1832; - if(i == 1833 ) return 1833; - if(i == 1834 ) return 1834; - if(i == 1835 ) return 1835; - if(i == 1836 ) return 1836; - if(i == 1837 ) return 1837; - if(i == 1838 ) return 1838; - if(i == 1839 ) return 1839; - if(i == 1840 ) return 1840; - if(i == 1841 ) return 1841; - if(i == 1842 ) return 1842; - if(i == 1843 ) return 1843; - if(i == 1844 ) return 1844; - if(i == 1845 ) return 1845; - if(i == 1846 ) return 1846; - if(i == 1847 ) return 1847; - if(i == 1848 ) return 1848; - if(i == 1849 ) return 1849; - if(i == 1850 ) return 1850; - if(i == 1851 ) return 1851; - if(i == 1852 ) return 1852; - if(i == 1853 ) return 1853; - if(i == 1854 ) return 1854; - if(i == 1855 ) return 1855; - if(i == 1856 ) return 1856; - if(i == 1857 ) return 1857; - if(i == 1858 ) return 1858; - if(i == 1859 ) return 1859; - if(i == 1860 ) return 1860; - if(i == 1861 ) return 1861; - if(i == 1862 ) return 1862; - if(i == 1863 ) return 1863; - if(i == 1864 ) return 1864; - if(i == 1865 ) return 1865; - if(i == 1866 ) return 1866; - if(i == 1867 ) return 1867; - if(i == 1868 ) return 1868; - if(i == 1869 ) return 1869; - if(i == 1870 ) return 1870; - if(i == 1871 ) return 1871; - if(i == 1872 ) return 1872; - if(i == 1873 ) return 1873; - if(i == 1874 ) return 1874; - if(i == 1875 ) return 1875; - if(i == 1876 ) return 1876; - if(i == 1877 ) return 1877; - if(i == 1878 ) return 1878; - if(i == 1879 ) return 1879; - if(i == 1880 ) return 1880; - if(i == 1881 ) return 1881; - if(i == 1882 ) return 1882; - if(i == 1883 ) return 1883; - if(i == 1884 ) return 1884; - if(i == 1885 ) return 1885; - if(i == 1886 ) return 1886; - if(i == 1887 ) return 1887; - if(i == 1888 ) return 1888; - if(i == 1889 ) return 1889; - if(i == 1890 ) return 1890; - if(i == 1891 ) return 1891; - if(i == 1892 ) return 1892; - if(i == 1893 ) return 1893; - if(i == 1894 ) return 1894; - if(i == 1895 ) return 1895; - if(i == 1896 ) return 1896; - if(i == 1897 ) return 1897; - if(i == 1898 ) return 1898; - if(i == 1899 ) return 1899; - if(i == 1900 ) return 1900; - if(i == 1901 ) return 1901; - if(i == 1902 ) return 1902; - if(i == 1903 ) return 1903; - if(i == 1904 ) return 1904; - if(i == 1905 ) return 1905; - if(i == 1906 ) return 1906; - if(i == 1907 ) return 1907; - if(i == 1908 ) return 1908; - if(i == 1909 ) return 1909; - if(i == 1910 ) return 1910; - if(i == 1911 ) return 1911; - if(i == 1912 ) return 1912; - if(i == 1913 ) return 1913; - if(i == 1914 ) return 1914; - if(i == 1915 ) return 1915; - if(i == 1916 ) return 1916; - if(i == 1917 ) return 1917; - if(i == 1918 ) return 1918; - if(i == 1919 ) return 1919; - if(i == 1920 ) return 1920; - if(i == 1921 ) return 1921; - if(i == 1922 ) return 1922; - if(i == 1923 ) return 1923; - if(i == 1924 ) return 1924; - if(i == 1925 ) return 1925; - if(i == 1926 ) return 1926; - if(i == 1927 ) return 1927; - if(i == 1928 ) return 1928; - if(i == 1929 ) return 1929; - if(i == 1930 ) return 1930; - if(i == 1931 ) return 1931; - if(i == 1932 ) return 1932; - if(i == 1933 ) return 1933; - if(i == 1934 ) return 1934; - if(i == 1935 ) return 1935; - if(i == 1936 ) return 1936; - if(i == 1937 ) return 1937; - if(i == 1938 ) return 1938; - if(i == 1939 ) return 1939; - if(i == 1940 ) return 1940; - if(i == 1941 ) return 1941; - if(i == 1942 ) return 1942; - if(i == 1943 ) return 1943; - if(i == 1944 ) return 1944; - if(i == 1945 ) return 1945; - if(i == 1946 ) return 1946; - if(i == 1947 ) return 1947; - if(i == 1948 ) return 1948; - if(i == 1949 ) return 1949; - if(i == 1950 ) return 1950; - if(i == 1951 ) return 1951; - if(i == 1952 ) return 1952; - if(i == 1953 ) return 1953; - if(i == 1954 ) return 1954; - if(i == 1955 ) return 1955; - if(i == 1956 ) return 1956; - if(i == 1957 ) return 1957; - if(i == 1958 ) return 1958; - if(i == 1959 ) return 1959; - if(i == 1960 ) return 1960; - if(i == 1961 ) return 1961; - if(i == 1962 ) return 1962; - if(i == 1963 ) return 1963; - if(i == 1964 ) return 1964; - if(i == 1965 ) return 1965; - if(i == 1966 ) return 1966; - if(i == 1967 ) return 1967; - if(i == 1968 ) return 1968; - if(i == 1969 ) return 1969; - if(i == 1970 ) return 1970; - if(i == 1971 ) return 1971; - if(i == 1972 ) return 1972; - if(i == 1973 ) return 1973; - if(i == 1974 ) return 1974; - if(i == 1975 ) return 1975; - if(i == 1976 ) return 1976; - if(i == 1977 ) return 1977; - if(i == 1978 ) return 1978; - if(i == 1979 ) return 1979; - if(i == 1980 ) return 1980; - if(i == 1981 ) return 1981; - if(i == 1982 ) return 1982; - if(i == 1983 ) return 1983; - if(i == 1984 ) return 1984; - if(i == 1985 ) return 1985; - if(i == 1986 ) return 1986; - if(i == 1987 ) return 1987; - if(i == 1988 ) return 1988; - if(i == 1989 ) return 1989; - if(i == 1990 ) return 1990; - if(i == 1991 ) return 1991; - if(i == 1992 ) return 1992; - if(i == 1993 ) return 1993; - if(i == 1994 ) return 1994; - if(i == 1995 ) return 1995; - if(i == 1996 ) return 1996; - if(i == 1997 ) return 1997; - if(i == 1998 ) return 1998; - if(i == 1999 ) return 1999; - } finally { - int x = 0; - x += 1; - x += 2; - x += 3; - x += 4; - x += 5; - x += 6; - x += 7; - x += 8; - x += 9; - } - return 0; - } -} diff --git a/langtools/test/tools/javac/ClassLit.java b/langtools/test/tools/javac/ClassLit.java index 4e26c9c43eb..9145ae23c6e 100644 --- a/langtools/test/tools/javac/ClassLit.java +++ b/langtools/test/tools/javac/ClassLit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 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 @@ -26,9 +26,6 @@ * @bug 4884387 * @summary Use ldc instruction for class literals * @author gafter - * - * @compile -source 1.5 -target 1.5 ClassLit.java - * @run main ClassLit */ public class ClassLit { diff --git a/langtools/test/tools/javac/ConditionalArgTypes_2.java b/langtools/test/tools/javac/ConditionalArgTypes_2.java index b0fc6759b01..e5f5b0b7d69 100644 --- a/langtools/test/tools/javac/ConditionalArgTypes_2.java +++ b/langtools/test/tools/javac/ConditionalArgTypes_2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, 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 @@ -27,7 +27,6 @@ * @summary Verify that both branches of a conditional expression must agree in type. * @author maddox * - * @compile/fail -source 1.4 ConditionalArgTypes_2.java * @compile ConditionalArgTypes_2.java */ diff --git a/langtools/test/tools/javac/IncorrectInheritance/IncorrectInheritanceTest.java b/langtools/test/tools/javac/IncorrectInheritance/IncorrectInheritanceTest.java new file mode 100644 index 00000000000..a447d22fe15 --- /dev/null +++ b/langtools/test/tools/javac/IncorrectInheritance/IncorrectInheritanceTest.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 8034924 + * @summary Incorrect inheritance of inaccessible static method + * @library /tools/javac/lib + * @build ToolBox + * @run main IncorrectInheritanceTest + */ + +public class IncorrectInheritanceTest { + private static final String ASrc = + "package pkg;\n" + + "\n" + + "public class A {\n" + + " static void foo(Object o) {}\n" + + " private static void bar(Object o) {}\n" + + "}"; + + private static final String BSrc = + "import pkg.A;\n" + + "class B extends A {\n" + + " public void foo(Object o) {}\n" + + " public void bar(Object o) {}\n" + + "}"; + + private static final String CSrc = + "class C extends B {\n" + + " public void m(Object o) {\n" + + " foo(o);\n" + + " bar(o);\n" + + " }\n" + + "}"; + + public static void main(String[] args) throws Exception { + new IncorrectInheritanceTest().test(); + } + + public void test() throws Exception { + ToolBox.JavaToolArgs javacParams = + new ToolBox.JavaToolArgs() + .setSources(ASrc, BSrc, CSrc); + ToolBox.javac(javacParams); + } + +} diff --git a/langtools/test/tools/javac/JsrRet.java b/langtools/test/tools/javac/JsrRet.java index 5158b6ac49e..576f9b3b83a 100644 --- a/langtools/test/tools/javac/JsrRet.java +++ b/langtools/test/tools/javac/JsrRet.java @@ -27,7 +27,7 @@ * @summary StackOverflowError from javac * @author gafter * - * @compile -source 1.5 -target 1.5 JsrRet.java + * @compile JsrRet.java */ package jsr.ret; diff --git a/langtools/test/tools/javac/T6266772.java b/langtools/test/tools/javac/T6266772.java index 76f2f39fd88..8a5e5133766 100644 --- a/langtools/test/tools/javac/T6266772.java +++ b/langtools/test/tools/javac/T6266772.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, 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 @@ -26,9 +26,6 @@ * @bug 6266772 * @summary javac crashes, assertion failure in Lower.java * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 T6266772.java - * @compile T6266772.java - * @run main T6266772 */ public class T6266772 { diff --git a/langtools/test/tools/javac/T6557865.java b/langtools/test/tools/javac/T6557865.java deleted file mode 100644 index 3ac154b52b2..00000000000 --- a/langtools/test/tools/javac/T6557865.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6557865 - * @summary -source 5 -target 5 should not put ACC_SYNTHETIC on package-info - * @author Wei Tao - * @compile T6557865.java - * @compile -source 5 -target 5 T6232928/package-info.java - * @run main T6557865 - */ - -import java.io.*; -import java.lang.reflect.Modifier; - -public class T6557865 { - public static void main(String... args) throws Exception { - Class pkginfo_cls = Class.forName("T6232928.package-info"); - int mod = pkginfo_cls.getModifiers(); - if ((mod & 0x1000) != 0) { - throw new AssertionError("Test failed: interface package-info shouldn't be synthetic in -target 5."); - } - } -} diff --git a/langtools/test/tools/javac/UplevelFromAnonInSuperCall.java b/langtools/test/tools/javac/UplevelFromAnonInSuperCall.java index c17fd3eb6fd..bd40fc7426d 100644 --- a/langtools/test/tools/javac/UplevelFromAnonInSuperCall.java +++ b/langtools/test/tools/javac/UplevelFromAnonInSuperCall.java @@ -29,7 +29,6 @@ * @author maddox (cribbed from bracha/lillibridge) gafter * * @compile UplevelFromAnonInSuperCall.java - * @compile/fail -source 1.4 UplevelFromAnonInSuperCall.java */ class UplevelFromAnonInSuperCall { diff --git a/langtools/test/tools/javac/annotations/neg/Dep.java b/langtools/test/tools/javac/annotations/neg/Dep.java index 4493366af78..ff83dc761fd 100644 --- a/langtools/test/tools/javac/annotations/neg/Dep.java +++ b/langtools/test/tools/javac/annotations/neg/Dep.java @@ -27,7 +27,6 @@ * @summary Please add annotation Deprecated to supplant the javadoc tag * @author gafter * - * @compile -source 1.4 -Xlint:-options -Xlint:dep-ann -Werror Dep.java * @compile/fail -Xlint:dep-ann -Werror Dep.java * @compile -Xlint:dep-ann Dep.java */ diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java index 22280b44109..6beae3afd8f 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java +++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.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 @@ -49,7 +49,7 @@ public class ClassfileTestHelper { File compile(File f) { int rc = com.sun.tools.javac.Main.compile(new String[] { - "-source", "1.8", "-g", f.getPath() }); + "-g", f.getPath() }); if (rc != 0) throw new Error("compilation failed. rc=" + rc); String path = f.getPath(); diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java index ccc3a0db1a5..d33e3d9ebe0 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java +++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,7 +146,7 @@ public class NoTargetAnnotations { } File compileTestFile(File f) { - int rc = com.sun.tools.javac.Main.compile(new String[] { "-XDTA:writer", "-source", "1.8", "-g", f.getPath() }); + int rc = com.sun.tools.javac.Main.compile(new String[] { "-XDTA:writer", "-g", f.getPath() }); if (rc != 0) throw new Error("compilation failed. rc=" + rc); String path = f.getPath(); diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java index cb1ceafaa53..c1d226a3b78 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java @@ -180,7 +180,6 @@ public class Driver { protected File compileTestFile(File f, String testClass, String... extraParams) { List options = new ArrayList<>(); - options.addAll(Arrays.asList("-source", "1.8")); options.addAll(Arrays.asList(extraParams)); options.add(f.getPath()); int rc = com.sun.tools.javac.Main.compile(options.toArray(new String[options.size()])); diff --git a/langtools/test/tools/javac/api/T6265137.java b/langtools/test/tools/javac/api/T6265137.java index 9eabaf6b605..1b86c565359 100644 --- a/langtools/test/tools/javac/api/T6265137.java +++ b/langtools/test/tools/javac/api/T6265137.java @@ -49,6 +49,6 @@ public class T6265137 { String srcdir = System.getProperty("test.src"); Iterable files = fm.getJavaFileObjectsFromFiles(Arrays.asList(new File(srcdir, "T6265137a.java"))); - javac.getTask(null, fm, dl, Arrays.asList("-target","1.5"), null, files).call(); + javac.getTask(null, fm, dl, Arrays.asList("-target","9"), null, files).call(); } } diff --git a/langtools/test/tools/javac/boxing/NoBoxingBool.java b/langtools/test/tools/javac/boxing/NoBoxingBool.java deleted file mode 100644 index 5fc1d6dfb1d..00000000000 --- a/langtools/test/tools/javac/boxing/NoBoxingBool.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6177400 - * @summary Boxing allowed with -source 1.4 - * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 NoBoxingBool.java - */ - -public class NoBoxingBool { - Boolean b = false; -} diff --git a/langtools/test/tools/javac/boxing/NoBoxingByte.java b/langtools/test/tools/javac/boxing/NoBoxingByte.java deleted file mode 100644 index b4bbf41aa64..00000000000 --- a/langtools/test/tools/javac/boxing/NoBoxingByte.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6177400 - * @summary Boxing allowed with -source 1.4 - * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 NoBoxingByte.java - */ - -public class NoBoxingByte { - Byte b = 0; -} diff --git a/langtools/test/tools/javac/boxing/NoBoxingChar.java b/langtools/test/tools/javac/boxing/NoBoxingChar.java deleted file mode 100644 index f8b757e4bb5..00000000000 --- a/langtools/test/tools/javac/boxing/NoBoxingChar.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6177400 - * @summary Boxing allowed with -source 1.4 - * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 NoBoxingChar.java - */ - -public class NoBoxingChar { - Character c = '\u0000'; -} diff --git a/langtools/test/tools/javac/boxing/NoBoxingDouble.java b/langtools/test/tools/javac/boxing/NoBoxingDouble.java deleted file mode 100644 index faac03163e1..00000000000 --- a/langtools/test/tools/javac/boxing/NoBoxingDouble.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6177400 - * @summary Boxing allowed with -source 1.4 - * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 NoBoxingDouble.java - */ - -public class NoBoxingDouble { - Double d = 0D; -} diff --git a/langtools/test/tools/javac/boxing/NoBoxingFloat.java b/langtools/test/tools/javac/boxing/NoBoxingFloat.java deleted file mode 100644 index 8c81b985aa9..00000000000 --- a/langtools/test/tools/javac/boxing/NoBoxingFloat.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6177400 - * @summary Boxing allowed with -source 1.4 - * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 NoBoxingFloat.java - */ - -public class NoBoxingFloat { - Float f = 0F; -} diff --git a/langtools/test/tools/javac/boxing/NoBoxingInt.java b/langtools/test/tools/javac/boxing/NoBoxingInt.java deleted file mode 100644 index c66b6e33a11..00000000000 --- a/langtools/test/tools/javac/boxing/NoBoxingInt.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6177400 - * @summary Boxing allowed with -source 1.4 - * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 NoBoxingInt.java - */ - -public class NoBoxingInt { - Integer i = 0; -} diff --git a/langtools/test/tools/javac/boxing/NoBoxingLong.java b/langtools/test/tools/javac/boxing/NoBoxingLong.java deleted file mode 100644 index afc51498105..00000000000 --- a/langtools/test/tools/javac/boxing/NoBoxingLong.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6177400 - * @summary Boxing allowed with -source 1.4 - * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 NoBoxingLong.java - */ - -public class NoBoxingLong { - Long l = 0L; -} diff --git a/langtools/test/tools/javac/boxing/NoBoxingShort.java b/langtools/test/tools/javac/boxing/NoBoxingShort.java deleted file mode 100644 index 70c50f8defd..00000000000 --- a/langtools/test/tools/javac/boxing/NoBoxingShort.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 6177400 - * @summary Boxing allowed with -source 1.4 - * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 NoBoxingShort.java - */ - -public class NoBoxingShort { - Short s = 0; -} diff --git a/langtools/test/tools/javac/classfiles/ClassVersionChecker.java b/langtools/test/tools/javac/classfiles/ClassVersionChecker.java index f08d850d035..2fa5a7ed799 100644 --- a/langtools/test/tools/javac/classfiles/ClassVersionChecker.java +++ b/langtools/test/tools/javac/classfiles/ClassVersionChecker.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 @@ -37,7 +37,7 @@ import java.util.regex.*; public class ClassVersionChecker { int errors; - String[] jdk = {"","1.2","1.3","1.4","1.5","1.6","1.7","1.8"}; + String[] jdk = {"","1.6","1.7","1.8"}; File javaFile = null; public static void main(String[] args) throws Throwable { @@ -47,7 +47,7 @@ public class ClassVersionChecker { void run() throws Exception { writeTestFile(); /* Rules applicable for -source and -target combinations - * 1. If both empty, version num is for 1.7 + * 1. If both empty, version num is for the current release * 2. If source is not empty and target is empty, version is based on source * 3. If both non-empty, version is based on target */ @@ -57,14 +57,10 @@ public class ClassVersionChecker { * -1 => invalid combinations */ int[][] ver = - {{52, -1, -1, -1, -1, -1, -1, -1}, - {48, 46, 47, 48, 49, 50, 51, 52}, - {48, 46, 47, 48, 49, 50, 51, 52}, - {48, -1, -1, 48, 49, 50, 51, 52}, - {52, -1, -1, -1, 49, 50, 51, 52}, - {52, -1, -1, -1, -1, 50, 51, 52}, - {52, -1, -1, -1, -1, -1, 51, 52}, - {52, -1, -1, -1, -1, -1, -1, 52}}; + {{52, -1, -1, -1}, + {52, 50, 51, 52}, + {52, -1, 51, 52}, + {52, -1, -1, 52}}; // Loop to run all possible combinations of source/target values for (int i = 0; i< ver.length; i++) { diff --git a/langtools/test/tools/javac/classfiles/InnerClasses/SyntheticClasses.java b/langtools/test/tools/javac/classfiles/InnerClasses/SyntheticClasses.java new file mode 100644 index 00000000000..58a8f9aa186 --- /dev/null +++ b/langtools/test/tools/javac/classfiles/InnerClasses/SyntheticClasses.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** @test + * @bug 8034854 + * @summary Verify that the InnerClasses attribute has outer_class_info_index zero if it has + * inner_name_index zero (for synthetic classes) + * @compile SyntheticClasses.java + * @run main SyntheticClasses + */ + +import java.io.*; +import java.util.*; +import com.sun.tools.classfile.*; + +public class SyntheticClasses { + + public static void main(String[] args) throws IOException, ConstantPoolException { + new SyntheticClasses().run(); + } + + private void run() throws IOException, ConstantPoolException { + File testClasses = new File(System.getProperty("test.classes")); + for (File classFile : testClasses.listFiles()) { + ClassFile cf = ClassFile.read(classFile); + if (cf.getName().matches(".*\\$[0-9]+")) { + EnclosingMethod_attribute encl = + (EnclosingMethod_attribute) cf.getAttribute(Attribute.EnclosingMethod); + if (encl != null) { + if (encl.method_index != 0) + throw new IllegalStateException("Invalid EnclosingMethod.method_index: " + + encl.method_index + "."); + } + } + InnerClasses_attribute attr = + (InnerClasses_attribute) cf.getAttribute(Attribute.InnerClasses); + if (attr != null) { + for (InnerClasses_attribute.Info info : attr.classes) { + if (cf.major_version < 51) + throw new IllegalStateException(); + if (info.inner_name_index == 0 && info.outer_class_info_index != 0) + throw new IllegalStateException("Invalid outer_class_info_index=" + + info.outer_class_info_index + + "; inner_name_index=" + + info.inner_name_index + "."); + } + } + } + } +} + +class SyntheticConstructorAccessTag { + + private static class A { + private A(){} + } + + public void test() { + new A(); + } +} + +class SyntheticEnumMapping { + private int convert(E e) { + switch (e) { + case A: return 0; + default: return -1; + } + } + enum E { A } +} + +interface SyntheticAssertionsDisabled { + public default void test() { + assert false; + } +} diff --git a/langtools/test/tools/javac/enum/6384542/T6384542.java b/langtools/test/tools/javac/enum/6384542/T6384542.java deleted file mode 100644 index 234ba485864..00000000000 --- a/langtools/test/tools/javac/enum/6384542/T6384542.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @test /nodynamiccopyright/ - * @bug 6384542 - * @summary crash: test/tools/javac/versions/check.sh - * @author Peter von der Ah\u00e9 - * @compile/fail -source 1.4 -Xlint:-options T6384542.java - * @compile/fail/ref=T6384542.out -source 1.4 -Xlint:-options -XDrawDiagnostics T6384542.java - */ - -import static java.lang.Math.sin; - -public enum A { } -class B { - int i = 0xCafe.BabeP1; - List l; - public static void main(String... args) { - for (String arg : args) { - System.out.println(arg); - } - } - @Override - public String toString() { return null; } -} -public klass C { } diff --git a/langtools/test/tools/javac/enum/6384542/T6384542.out b/langtools/test/tools/javac/enum/6384542/T6384542.out deleted file mode 100644 index 98480841e69..00000000000 --- a/langtools/test/tools/javac/enum/6384542/T6384542.out +++ /dev/null @@ -1,9 +0,0 @@ -T6384542.java:10:8: compiler.err.static.import.not.supported.in.source: 1.4 -T6384542.java:12:8: compiler.err.enums.not.supported.in.source: 1.4 -T6384542.java:14:13: compiler.err.unsupported.fp.lit: 1.4 -T6384542.java:15:9: compiler.err.generics.not.supported.in.source: 1.4 -T6384542.java:16:35: compiler.err.varargs.not.supported.in.source: 1.4 -T6384542.java:17:25: compiler.err.foreach.not.supported.in.source: 1.4 -T6384542.java:21:6: compiler.err.annotations.not.supported.in.source: 1.4 -T6384542.java:24:8: compiler.err.expected3: class, interface, enum -8 errors diff --git a/langtools/test/tools/javac/enum/6384542/T6384542a.java b/langtools/test/tools/javac/enum/6384542/T6384542a.java deleted file mode 100644 index f313b73f167..00000000000 --- a/langtools/test/tools/javac/enum/6384542/T6384542a.java +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @test /nodynamiccopyright/ - * @bug 6384542 - * @summary crash: test/tools/javac/versions/check.sh - * @author Peter von der Ah\u00e9 - * @compile/fail -source 5 T6384542a.java - * @compile -source 1.4 T6384542a.java - * @compile/fail/ref=T6384542a_5.out -source 5 -Xlint:-options -XDrawDiagnostics T6384542a.java - * @compile/ref=T6384542a_1_4.out -source 1.4 -Xlint:-options -XDrawDiagnostics T6384542a.java - */ - -public class T6384542a { - T6384542a enum = null; -} diff --git a/langtools/test/tools/javac/enum/6384542/T6384542a_1_4.out b/langtools/test/tools/javac/enum/6384542/T6384542a_1_4.out deleted file mode 100644 index 85671926d23..00000000000 --- a/langtools/test/tools/javac/enum/6384542/T6384542a_1_4.out +++ /dev/null @@ -1,2 +0,0 @@ -T6384542a.java:13:15: compiler.warn.enum.as.identifier -1 warning diff --git a/langtools/test/tools/javac/enum/6384542/T6384542a_5.out b/langtools/test/tools/javac/enum/6384542/T6384542a_5.out deleted file mode 100644 index 0ed7fa6a530..00000000000 --- a/langtools/test/tools/javac/enum/6384542/T6384542a_5.out +++ /dev/null @@ -1,2 +0,0 @@ -T6384542a.java:13:15: compiler.err.enum.as.identifier -1 error diff --git a/langtools/test/tools/javac/enum/EnumAsIdentifier.java b/langtools/test/tools/javac/enum/EnumAsIdentifier.java index 30bc822e49b..65392ba1a95 100644 --- a/langtools/test/tools/javac/enum/EnumAsIdentifier.java +++ b/langtools/test/tools/javac/enum/EnumAsIdentifier.java @@ -3,8 +3,6 @@ * @bug 8025537 * @author sogoel * @summary enum keyword used as an identifier - * @compile/ref=EnumAsIdentifier4.out -XDrawDiagnostics -source 1.4 EnumAsIdentifier.java - * @compile/fail/ref=EnumAsIdentifier5.out -XDrawDiagnostics -source 1.5 EnumAsIdentifier.java * @compile/fail/ref=EnumAsIdentifier.out -XDrawDiagnostics EnumAsIdentifier.java */ diff --git a/langtools/test/tools/javac/enum/EnumAsIdentifier.out b/langtools/test/tools/javac/enum/EnumAsIdentifier.out index eeb9e842600..35051fd092c 100644 --- a/langtools/test/tools/javac/enum/EnumAsIdentifier.out +++ b/langtools/test/tools/javac/enum/EnumAsIdentifier.out @@ -1,2 +1,2 @@ -EnumAsIdentifier.java:13:9: compiler.err.enum.as.identifier +EnumAsIdentifier.java:11:9: compiler.err.enum.as.identifier 1 error diff --git a/langtools/test/tools/javac/enum/EnumAsIdentifier4.out b/langtools/test/tools/javac/enum/EnumAsIdentifier4.out deleted file mode 100644 index 40c72a84629..00000000000 --- a/langtools/test/tools/javac/enum/EnumAsIdentifier4.out +++ /dev/null @@ -1,6 +0,0 @@ -- compiler.warn.source.no.bootclasspath: 1.4 -- compiler.warn.option.obsolete.source: 1.4 -- compiler.warn.option.obsolete.target: 1.4 -- compiler.warn.option.obsolete.suppression -EnumAsIdentifier.java:13:9: compiler.warn.enum.as.identifier -5 warnings diff --git a/langtools/test/tools/javac/enum/EnumAsIdentifier5.out b/langtools/test/tools/javac/enum/EnumAsIdentifier5.out deleted file mode 100644 index dead5c41a2b..00000000000 --- a/langtools/test/tools/javac/enum/EnumAsIdentifier5.out +++ /dev/null @@ -1,6 +0,0 @@ -- compiler.warn.source.no.bootclasspath: 1.5 -- compiler.warn.option.obsolete.source: 1.5 -- compiler.warn.option.obsolete.suppression -EnumAsIdentifier.java:13:9: compiler.err.enum.as.identifier -1 error -3 warnings diff --git a/langtools/test/tools/javac/enum/FauxEnum2.java b/langtools/test/tools/javac/enum/FauxEnum2.java deleted file mode 100644 index dea62615a83..00000000000 --- a/langtools/test/tools/javac/enum/FauxEnum2.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 5009574 - * @summary verify java.lang.Enum can't be directly subclassed - * @author Joseph D. Darcy - * - * @compile/fail -source 1.4 FauxEnum2.java - */ - -public class FauxEnum2 extends java.lang.Enum { - FauxEnum2() { - super("", 0); - } -} diff --git a/langtools/test/tools/javac/generics/RefEqual.java b/langtools/test/tools/javac/generics/RefEqual.java index ba696d3a673..c3ff88f76ae 100644 --- a/langtools/test/tools/javac/generics/RefEqual.java +++ b/langtools/test/tools/javac/generics/RefEqual.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 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,7 +27,6 @@ * @summary casting conversion checks changed for covariant returns * @author gafter * - * @compile -source 1.4 RefEqual.java * @compile/fail RefEqual.java */ diff --git a/langtools/test/tools/javac/generics/T5094318.java b/langtools/test/tools/javac/generics/T5094318.java index 31d8fef2624..a9b3d792b6c 100644 --- a/langtools/test/tools/javac/generics/T5094318.java +++ b/langtools/test/tools/javac/generics/T5094318.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved. * 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,8 +26,6 @@ * @bug 5094318 * @summary REGRESSION: Array cloning is not backwards compatible * - * @compile -source 1.4 T5094318.java - * @run main T5094318 * @compile T5094318.java * @run main/fail T5094318 */ diff --git a/langtools/test/tools/javac/generics/compat/CovariantCompat1.java b/langtools/test/tools/javac/generics/compat/CovariantCompat1.java deleted file mode 100644 index ce79d005fc4..00000000000 --- a/langtools/test/tools/javac/generics/compat/CovariantCompat1.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4836051 - * @summary generics: non-generic code should be able to call covariant method - * @author gafter - * - * @compile CovariantCompat1.java - * @compile -source 1.4 CovariantCompat2.java - */ - -class CovariantCompat1 { - static class A { - public A foo() { return this; } - } - static class B extends A { - public B foo() { return this; } - } -} diff --git a/langtools/test/tools/javac/generics/compat/CovariantCompat2.java b/langtools/test/tools/javac/generics/compat/CovariantCompat2.java deleted file mode 100644 index 955fd83474a..00000000000 --- a/langtools/test/tools/javac/generics/compat/CovariantCompat2.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -class CovariantCompat2 { - static { - CovariantCompat1.B x = new CovariantCompat1.B(); - CovariantCompat1.B o = x.foo(); - } -} diff --git a/langtools/test/tools/javac/generics/compat/OverrideBridge3.java b/langtools/test/tools/javac/generics/compat/OverrideBridge3.java deleted file mode 100644 index 87a9e2cb251..00000000000 --- a/langtools/test/tools/javac/generics/compat/OverrideBridge3.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -class OverrideBridge3 { - static class C extends OverrideBridge2.B { - } -} diff --git a/langtools/test/tools/javac/generics/compat/VisibleBridge.java b/langtools/test/tools/javac/generics/compat/VisibleBridge.java deleted file mode 100644 index 334eb251529..00000000000 --- a/langtools/test/tools/javac/generics/compat/VisibleBridge.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4830291 - * @summary javac makes String non-backward compatible - * @author gafter - * - * @compile -source 1.4 VisibleBridge.java - */ - -// Ensure that bridge methods are visible for maximum -// backward compatibility. - -class VisibleBridge { - static { - Object o = "b"; - if ("a".compareTo(o) > 0) {} - } -} diff --git a/langtools/test/tools/javac/limits/FinallyNesting.java b/langtools/test/tools/javac/limits/FinallyNesting.java deleted file mode 100644 index baabd698fa5..00000000000 --- a/langtools/test/tools/javac/limits/FinallyNesting.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4739388 - * @summary regression: javac generates too much bytecode for deply nested try-finally - * @author gafter - * - * @compile -source 1.4 -target 1.4 FinallyNesting.java - */ -// Source and target 1.4 are needed for the test to pass with default memory sizes. -class FinallyNesting { - public static void main(String[] args) { - int x; - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - try { x = 1; } finally { - x = 2; - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } -} diff --git a/langtools/test/tools/javac/linenumbers/ConditionalLineNumberTest.java b/langtools/test/tools/javac/linenumbers/ConditionalLineNumberTest.java new file mode 100644 index 00000000000..a1af968e806 --- /dev/null +++ b/langtools/test/tools/javac/linenumbers/ConditionalLineNumberTest.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 8034091 + * @summary Add LineNumberTable attributes for conditional operator (?:) split across several lines. + */ + +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.Method; +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.LineNumberTable_attribute; +import com.sun.tools.classfile.LineNumberTable_attribute.Entry; + +import java.io.File; +import java.io.IOException; + +public class ConditionalLineNumberTest { + public static void main(String[] args) throws Exception { + // check that we have 5 consecutive entries for method() + Entry[] lines = findEntries(); + if (lines == null || lines.length != 5) + throw new Exception("conditional line number table incorrect"); + + int current = lines[0].line_number; + for (Entry e : lines) { + if (e.line_number != current) + throw new Exception("conditional line number table incorrect"); + current++; + } + } + + static Entry[] findEntries() throws IOException, ConstantPoolException { + ClassFile self = ClassFile.read(ConditionalLineNumberTest.class.getResourceAsStream("ConditionalLineNumberTest.class")); + for (Method m : self.methods) { + if ("method".equals(m.getName(self.constant_pool))) { + Code_attribute code_attribute = (Code_attribute)m.attributes.get(Attribute.Code); + for (Attribute at : code_attribute.attributes) { + if (Attribute.LineNumberTable.equals(at.getName(self.constant_pool))) { + return ((LineNumberTable_attribute)at).line_number_table; + } + } + } + } + return null; + } + + // This method should get one LineNumberTable entry per line + // in the method body. + public static String method(int field) { + String s = field % 2 == 0 ? + (field == 0 ? "false" + : "true" + field) : //Breakpoint + "false" + field; //Breakpoint + return s; + } +} diff --git a/langtools/test/tools/javac/meth/InvokeMH.java b/langtools/test/tools/javac/meth/InvokeMH.java index 4d72b71c992..d96532825c8 100644 --- a/langtools/test/tools/javac/meth/InvokeMH.java +++ b/langtools/test/tools/javac/meth/InvokeMH.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, 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 @@ -27,7 +27,7 @@ * @summary Generate call sites for method handle * @author jrose * - * @compile -source 7 -target 7 -XDallowTransitionalJSR292=no InvokeMH.java + * @compile InvokeMH.java */ /* diff --git a/langtools/test/tools/javac/miranda/T4711325.java b/langtools/test/tools/javac/miranda/T4711325.java index 4989debc58a..8889989563c 100644 --- a/langtools/test/tools/javac/miranda/T4711325.java +++ b/langtools/test/tools/javac/miranda/T4711325.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ * @author gafter * * @compile T4711325.java - * @compile/fail -source 1.4 T4711325.java */ interface A { diff --git a/langtools/test/tools/javac/missingSuperRecovery/MissingInterfaceTest.java b/langtools/test/tools/javac/missingSuperRecovery/MissingInterfaceTest.java new file mode 100644 index 00000000000..d71df0664ea --- /dev/null +++ b/langtools/test/tools/javac/missingSuperRecovery/MissingInterfaceTest.java @@ -0,0 +1,15 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8036007 + * @summary javac crashes when encountering an unresolvable interface + * @build MissingInterfaceTestDep + * @clean Closeable + * @compile/fail/ref=MissingInterfaceTest.out -XDrawDiagnostics MissingInterfaceTest.java + */ + +public class MissingInterfaceTest { + void test(MissingInterfaceTestDep s) { + s.call(); + s.another(); + } +} diff --git a/langtools/test/tools/javac/missingSuperRecovery/MissingInterfaceTest.out b/langtools/test/tools/javac/missingSuperRecovery/MissingInterfaceTest.out new file mode 100644 index 00000000000..0956ba6fb05 --- /dev/null +++ b/langtools/test/tools/javac/missingSuperRecovery/MissingInterfaceTest.out @@ -0,0 +1,3 @@ +MissingInterfaceTest.java:12:10: compiler.err.cant.access: Closeable, (compiler.misc.class.file.not.found: Closeable) +MissingInterfaceTest.java:13:10: compiler.err.cant.resolve.location.args: kindname.method, another, , , (compiler.misc.location.1: kindname.variable, s, MissingInterfaceTestDep) +2 errors diff --git a/langtools/test/tools/javac/generics/compat/OverrideBridge2.java b/langtools/test/tools/javac/missingSuperRecovery/MissingInterfaceTestDep.java similarity index 83% rename from langtools/test/tools/javac/generics/compat/OverrideBridge2.java rename to langtools/test/tools/javac/missingSuperRecovery/MissingInterfaceTestDep.java index 57edb5348a7..b8379d9fbe1 100644 --- a/langtools/test/tools/javac/generics/compat/OverrideBridge2.java +++ b/langtools/test/tools/javac/missingSuperRecovery/MissingInterfaceTestDep.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 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 @@ -21,8 +21,6 @@ * questions. */ -class OverrideBridge2 { - static class B extends OverrideBridge1.B { - public void foo(Object o) { } - } -} +public class MissingInterfaceTestDep implements Intermediate {} +interface Intermediate extends Closeable { } +interface Closeable {} diff --git a/langtools/test/tools/javac/parser/T4910483.java b/langtools/test/tools/javac/parser/T4910483.java index 7d80e0ade5d..b29115518a9 100644 --- a/langtools/test/tools/javac/parser/T4910483.java +++ b/langtools/test/tools/javac/parser/T4910483.java @@ -21,10 +21,10 @@ * questions. */ -/** +/* * @test * @bug 4910483 - * @summary javac shouldn't throw NPE while compiling invalid RuntimeInvisibleParameterAnnotations + * @summary Javadoc renders the string ".*\\.pdf" as ".\*\.pdf" * @run main T4910483 */ diff --git a/langtools/test/tools/javac/proprietary/WarnClass.java b/langtools/test/tools/javac/proprietary/WarnClass.java index a3333c54104..ceeea45649e 100644 --- a/langtools/test/tools/javac/proprietary/WarnClass.java +++ b/langtools/test/tools/javac/proprietary/WarnClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 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 @@ -28,7 +28,6 @@ * @author Peter von der Ah\u00e9 * @compile WarnClass.java * @compile/fail -Werror WarnClass.java - * @compile/fail -Werror -source 1.4 -nowarn WarnClass.java * @compile/fail -Werror -nowarn WarnClass.java * @compile/fail -Werror -Xlint:none WarnClass.java */ diff --git a/langtools/test/tools/javac/proprietary/WarnImport.java b/langtools/test/tools/javac/proprietary/WarnImport.java index 7d5d66a3906..7a0c25960eb 100644 --- a/langtools/test/tools/javac/proprietary/WarnImport.java +++ b/langtools/test/tools/javac/proprietary/WarnImport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 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 @@ -28,7 +28,6 @@ * @author Peter von der Ah\u00e9 * @compile WarnImport.java * @compile/fail -Werror WarnImport.java - * @compile/fail -Werror -source 1.4 -nowarn WarnImport.java * @compile/fail -Werror -nowarn WarnImport.java * @compile/fail -Werror -Xlint:none WarnImport.java */ diff --git a/langtools/test/tools/javac/proprietary/WarnMethod.java b/langtools/test/tools/javac/proprietary/WarnMethod.java index 76218abf3d6..4e06100676e 100644 --- a/langtools/test/tools/javac/proprietary/WarnMethod.java +++ b/langtools/test/tools/javac/proprietary/WarnMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 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 @@ -28,7 +28,6 @@ * @author Peter von der Ah\u00e9 * @compile WarnMethod.java * @compile/fail -Werror WarnMethod.java - * @compile/fail -Werror -source 1.4 -nowarn WarnMethod.java * @compile/fail -Werror -nowarn WarnMethod.java * @compile/fail -Werror -Xlint:none WarnMethod.java */ diff --git a/langtools/test/tools/javac/proprietary/WarnStaticImport.java b/langtools/test/tools/javac/proprietary/WarnStaticImport.java index a5ff4442bd4..43ce3afd8fc 100644 --- a/langtools/test/tools/javac/proprietary/WarnStaticImport.java +++ b/langtools/test/tools/javac/proprietary/WarnStaticImport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 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 @@ -28,7 +28,6 @@ * @author Peter von der Ah\u00e9 * @compile WarnStaticImport.java * @compile/fail -Werror WarnStaticImport.java - * @compile/fail -Werror -source 1.4 -nowarn WarnStaticImport.java * @compile/fail -Werror -nowarn WarnStaticImport.java * @compile/fail -Werror -Xlint:none WarnStaticImport.java */ diff --git a/langtools/test/tools/javac/proprietary/WarnVariable.java b/langtools/test/tools/javac/proprietary/WarnVariable.java index 0061b1c766f..8dda29aee39 100644 --- a/langtools/test/tools/javac/proprietary/WarnVariable.java +++ b/langtools/test/tools/javac/proprietary/WarnVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 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 @@ -28,7 +28,6 @@ * @author Peter von der Ah\u00e9 * @compile WarnVariable.java * @compile/fail -Werror WarnVariable.java - * @compile/fail -Werror -source 1.4 -nowarn WarnVariable.java * @compile/fail -Werror -nowarn WarnVariable.java * @compile/fail -Werror -Xlint:none WarnVariable.java */ diff --git a/langtools/test/tools/javac/proprietary/WarnWildcard.java b/langtools/test/tools/javac/proprietary/WarnWildcard.java index 509815eb5c5..1fee47632a2 100644 --- a/langtools/test/tools/javac/proprietary/WarnWildcard.java +++ b/langtools/test/tools/javac/proprietary/WarnWildcard.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 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 @@ -28,7 +28,6 @@ * @author Peter von der Ah\u00e9 * @compile WarnWildcard.java * @compile/fail -Werror WarnWildcard.java - * @compile/fail -Werror -source 1.4 -nowarn WarnWildcard.java * @compile/fail -Werror -nowarn WarnWildcard.java * @compile/fail -Werror -Xlint:none WarnWildcard.java */ diff --git a/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.java b/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.java index f8e61e1afb4..ae6c15790c4 100644 --- a/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.java +++ b/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.java @@ -25,7 +25,6 @@ * @test * @bug 7038363 * @summary cast from object to primitive should be for source >= 1.7 - * @compile/fail/ref=CastObjectToPrimitiveTest.out -XDrawDiagnostics -Xlint:-options -source 5 CastObjectToPrimitiveTest.java * @compile/fail/ref=CastObjectToPrimitiveTest.out -XDrawDiagnostics -Xlint:-options -source 6 CastObjectToPrimitiveTest.java * @compile CastObjectToPrimitiveTest.java */ diff --git a/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out b/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out index f57047f99d9..80f12654b24 100644 --- a/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out +++ b/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out @@ -1,2 +1,2 @@ -CastObjectToPrimitiveTest.java:36:23: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Object, int) +CastObjectToPrimitiveTest.java:35:23: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Object, int) 1 error diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index c2dd54b2be5..5b3f23741dd 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -143,6 +143,9 @@ define SetupArchive ifneq (,$2) $1_DEPS:=$2 else + # Add all source roots to the find cache since we are likely going to run find + # on these more than once. The cache will only be updated if necessary. + $$(eval $$(call FillCacheFind, $$($1_FIND_LIST))) $1_DEPS:=$$(filter $$(addprefix %,$$($1_SUFFIXES)), \ $$(call CacheFind,$$($1_SRCS))) ifneq (,$$($1_GREP_INCLUDE_PATTERNS)) @@ -158,6 +161,10 @@ define SetupArchive $1_DEPS+=$$(call CacheFind,$$(wildcard $$(addsuffix /META-INF,$$($1_SRCS)))) endif endif + # The dependency list should never be empty + ifeq ($$(strip $$($1_DEPS)), ) + $$(warning No dependencies found for $1) + endif # Utility macros, to make the shell script receipt somewhat easier to decipher. @@ -336,7 +343,20 @@ endef # Previously this was inconsistently done in different repositories. # This is the new clean standard. Though it is to be superseded by # a standard annotation processor from with sjavac. -define add_file_to_copy_and_clean +# +# The sed expression does this: +# 1. Add a backslash before any :, = or ! that do not have a backslash already. +# 2. Apply the file unicode2x.sed which does a whole bunch of \u00XX to \xXX +# conversions. +# 3. Delete all lines starting with #. +# 4. Delete empty lines. +# 5. Append lines ending with \ with the next line. +# 6. Remove leading and trailing white space. +# 7. Replace the first \= with just =. +# 8. Finally it's all sorted to create a stable output. +# +# It is assumed that = is the character used for separating names and values. +define add_file_to_clean # param 1 = BUILD_MYPACKAGE # parma 2 = The source file to copy and clean. $2_TARGET:=$2 @@ -345,12 +365,13 @@ define add_file_to_copy_and_clean # Now we can setup the depency that will trigger the copying. $$($1_BIN)$$($2_TARGET) : $2 $(MKDIR) -p $$(@D) - $(CAT) $$< | $(SED) -e 's/\([^\\]\):/\1\\:/g' -e 's/\([^\\]\)=/\1\\=/g' -e 's/#.*/#/g' \ + $(CAT) $$< | $(SED) -e 's/\([^\\]\):/\1\\:/g' -e 's/\([^\\]\)=/\1\\=/g' \ + -e 's/\([^\\]\)!/\1\\!/g' -e 's/#.*/#/g' \ | $(SED) -f "$(SRC_ROOT)/make/common/support/unicode2x.sed" \ | $(SED) -e '/^#/d' -e '/^$$$$/d' \ -e :a -e '/\\$$$$/N; s/\\\n//; ta' \ -e 's/^[ \t]*//;s/[ \t]*$$$$//' \ - -e 's/\\=/=/' | LANG=C $(SORT) > $$@ + -e 's/\\=/=/' | LC_ALL=C $(SORT) > $$@ $(CHMOD) -f ug+w $$@ # And do not forget this target @@ -376,8 +397,9 @@ define SetupJavaCompilation # INCLUDES:=myapp.foo means will only compile java files in myapp.foo or any of its sub-packages. # EXCLUDES:=myapp.foo means will do not compile java files in myapp.foo or any of its sub-packages. # COPY:=.prp means copy all prp files to the corresponding package in BIN. - # CLEAN:=.properties means copy and clean all properties file to the corresponding package in BIN. # COPY_FILES:=myapp/foo/setting.txt means copy this file over to the package myapp/foo + # CLEAN:=.properties means copy and clean all properties file to the corresponding package in BIN. + # CLEAN_FILES:=myapp/foo/setting.txt means clean this file over to the package myapp/foo # SRCZIP:=Create a src.zip based on the found sources and copied files. # INCLUDE_FILES:="com/sun/SolarisFoobar.java" means only compile this file! # EXCLUDE_FILES:="com/sun/SolarisFoobar.java" means do not compile this particular file! @@ -405,6 +427,9 @@ define SetupJavaCompilation # Make sure the dirs exist. $$(foreach d,$$($1_SRC), $$(if $$(wildcard $$d),,$$(error SRC specified to SetupJavaCompilation $1 contains missing directory $$d))) $$(eval $$(call MakeDir,$$($1_BIN))) + # Add all source roots to the find cache since we are likely going to run find + # on these more than once. The cache will only be updated if necessary. + $$(eval $$(call FillCacheFind,$$($1_SRC))) # Find all files in the source trees. $1_ALL_SRCS += $$(filter-out $(OVR_SRCS),$$(call CacheFind,$$($1_SRC))) # Extract the java files. @@ -437,7 +462,7 @@ define SetupJavaCompilation endif # Find all files to be copied from source to bin. - ifneq (,$$($1_COPY)) + ifneq (,$$($1_COPY)$$($1_COPY_FILES)) # Search for all files to be copied. $1_ALL_COPIES := $$(filter $$(addprefix %,$$($1_COPY)),$$($1_ALL_SRCS)) # Copy these explicitly @@ -452,20 +477,22 @@ define SetupJavaCompilation ifneq (,$$($1_EXCLUDE_FILES)) $1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_FILES_PATTERN),$$($1_ALL_COPIES)) endif - # All files below META-INF are always copied. - $1_ALL_COPIES += $$(filter $$(addsuffix /META-INF%,$$($1_SRC)),$$($1_ALL_SRCS)) - ifneq (,$$($1_ALL_COPIES)) - # Yep, there are files to be copied! - $1_ALL_COPY_TARGETS:= - $$(foreach i,$$($1_ALL_COPIES),$$(eval $$(call add_file_to_copy,$1,$$i))) - # Now we can depend on $$($1_ALL_COPY_TARGETS) to copy all files! - endif + endif + # All files below META-INF are always copied. + $1_ALL_COPIES += $$(filter $$(addsuffix /META-INF%,$$($1_SRC)),$$($1_ALL_SRCS)) + ifneq (,$$($1_ALL_COPIES)) + # Yep, there are files to be copied! + $1_ALL_COPY_TARGETS:= + $$(foreach i,$$($1_ALL_COPIES),$$(eval $$(call add_file_to_copy,$1,$$i))) + # Now we can depend on $$($1_ALL_COPY_TARGETS) to copy all files! endif # Find all property files to be copied and cleaned from source to bin. - ifneq (,$$($1_CLEAN)) + ifneq (,$$($1_CLEAN)$$($1_CLEAN_FILES)) # Search for all files to be copied. $1_ALL_CLEANS := $$(filter $$(addprefix %,$$($1_CLEAN)),$$($1_ALL_SRCS)) + # Clean these explicitly + $1_ALL_CLEANS += $$($1_CLEAN_FILES) # Copy and clean must also respect filters. ifneq (,$$($1_INCLUDES)) $1_ALL_CLEANS := $$(filter $$($1_SRC_INCLUDES),$$($1_ALL_CLEANS)) @@ -479,7 +506,7 @@ define SetupJavaCompilation ifneq (,$$($1_ALL_CLEANS)) # Yep, there are files to be copied and cleaned! $1_ALL_COPY_CLEAN_TARGETS:= - $$(foreach i,$$($1_ALL_CLEANS),$$(eval $$(call add_file_to_copy_and_clean,$1,$$i))) + $$(foreach i,$$($1_ALL_CLEANS),$$(eval $$(call add_file_to_clean,$1,$$i))) # Now we can depend on $$($1_ALL_COPY_CLEAN_TARGETS) to copy all files! endif endif diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index 2b276c6f1fb..ca183ad3b86 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -380,11 +380,23 @@ ifeq ($(OPENJDK_TARGET_OS),solaris) # On Solaris, if the target is a symlink and exists, cp won't overwrite. # Cp has to operate in recursive mode to allow for -P flag, to preserve soft links. If the # name of the target file differs from the source file, rename after copy. + # If the source and target parent directories are the same, recursive copy doesn't work + # so we fall back on regular copy, which isn't preserving symlinks. define install-file $(MKDIR) -p $(@D) $(RM) '$@' - $(CP) -f -r -P '$<' '$(@D)' - if [ "$(@F)" != "$( + @@ -243,6 +244,7 @@ + @@ -253,6 +255,10 @@ + + + + diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties index d51e72e4180..5af728794e2 100644 --- a/nashorn/make/project.properties +++ b/nashorn/make/project.properties @@ -206,7 +206,7 @@ test262-test-sys-prop.test.failed.list.file=${build.dir}/test/failedTests # test262 test frameworks test262-test-sys-prop.test.js.framework=\ - --class-cache-size=0 \ + --class-cache-size=10 \ --no-java \ --no-typed-arrays \ -timezone=PST \ diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index 3c4d29fc025..9c14359ec4e 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -57,9 +57,9 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptException; import javax.script.SimpleBindings; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; -import jdk.nashorn.internal.runtime.GlobalObject; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; @@ -99,7 +99,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C private final boolean _global_per_engine; // This is the initial default Nashorn global object. // This is used as "shared" global if above option is true. - private final ScriptObject global; + private final Global global; // initialized bit late to be made 'final'. // Property object for "context" property of global object. private volatile Property contextProperty; @@ -264,7 +264,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) { if (ctxt != null) { final int scope = ctxt.getAttributesScope(name); - final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt); + final Global ctxtGlobal = getNashornGlobalFrom(ctxt); if (scope != -1) { return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal); } @@ -317,7 +317,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } ScriptObject realSelf = null; - ScriptObject realGlobal = null; + Global realGlobal = null; if(thiz == null) { // making interface out of global functions realSelf = realGlobal = getNashornGlobalFrom(context); @@ -346,7 +346,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } try { - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != realGlobal); try { if (globalChanged) { @@ -371,7 +371,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } // Retrieve nashorn Global object for a given ScriptContext object - private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) { + private Global getNashornGlobalFrom(final ScriptContext ctxt) { if (_global_per_engine) { // shared single global object for all ENGINE_SCOPE Bindings return global; @@ -380,18 +380,18 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE); // is this Nashorn's own Bindings implementation? if (bindings instanceof ScriptObjectMirror) { - final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)bindings); - if (sobj != null) { - return sobj; + final Global glob = globalFromMirror((ScriptObjectMirror)bindings); + if (glob != null) { + return glob; } } // Arbitrary user Bindings implementation. Look for NASHORN_GLOBAL in it! Object scope = bindings.get(NASHORN_GLOBAL); if (scope instanceof ScriptObjectMirror) { - final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)scope); - if (sobj != null) { - return sobj; + final Global glob = globalFromMirror((ScriptObjectMirror)scope); + if (glob != null) { + return glob; } } @@ -399,14 +399,14 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C // Create new global instance mirror and associate with the Bindings. final ScriptObjectMirror mirror = createGlobalMirror(ctxt); bindings.put(NASHORN_GLOBAL, mirror); - return mirror.getScriptObject(); + return mirror.getHomeGlobal(); } // Retrieve nashorn Global object from a given ScriptObjectMirror - private ScriptObject globalFromMirror(final ScriptObjectMirror mirror) { + private Global globalFromMirror(final ScriptObjectMirror mirror) { ScriptObject sobj = mirror.getScriptObject(); - if (sobj instanceof GlobalObject && isOfContext(sobj, nashornContext)) { - return sobj; + if (sobj instanceof Global && isOfContext((Global)sobj, nashornContext)) { + return (Global)sobj; } return null; @@ -414,15 +414,15 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C // Create a new ScriptObjectMirror wrapping a newly created Nashorn Global object private ScriptObjectMirror createGlobalMirror(final ScriptContext ctxt) { - final ScriptObject newGlobal = createNashornGlobal(ctxt); + final Global newGlobal = createNashornGlobal(ctxt); return new ScriptObjectMirror(newGlobal, newGlobal); } // Create a new Nashorn Global object - private ScriptObject createNashornGlobal(final ScriptContext ctxt) { - final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction() { + private Global createNashornGlobal(final ScriptContext ctxt) { + final Global newGlobal = AccessController.doPrivileged(new PrivilegedAction() { @Override - public ScriptObject run() { + public Global run() { try { return nashornContext.newGlobal(); } catch (final RuntimeException e) { @@ -460,7 +460,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } // scripts should see "context" and "engine" as variables in the given global object - private void setContextVariables(final ScriptObject ctxtGlobal, final ScriptContext ctxt) { + private void setContextVariables(final Global ctxtGlobal, final ScriptContext ctxt) { // set "context" global variable via contextProperty - because this // property is non-writable contextProperty.setObjectValue(ctxtGlobal, ctxtGlobal, ctxt, false); @@ -470,7 +470,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } // if no arguments passed, expose it if (! (args instanceof ScriptObject)) { - args = ((GlobalObject)ctxtGlobal).wrapAsObject(args); + args = ctxtGlobal.wrapAsObject(args); ctxtGlobal.set("arguments", args, false); } } @@ -478,7 +478,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException { name.getClass(); // null check - ScriptObject invokeGlobal = null; + Global invokeGlobal = null; ScriptObjectMirror selfMirror = null; if (selfObject instanceof ScriptObjectMirror) { selfMirror = (ScriptObjectMirror)selfObject; @@ -489,7 +489,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } else if (selfObject instanceof ScriptObject) { // invokeMethod called from script code - in which case we may get 'naked' ScriptObject // Wrap it with oldGlobal to make a ScriptObjectMirror for the same. - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); invokeGlobal = oldGlobal; if (oldGlobal == null) { throw new IllegalArgumentException(getMessage("no.current.nashorn.global")); @@ -502,7 +502,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(selfObject, oldGlobal); } else if (selfObject == null) { // selfObject is null => global function call - final ScriptObject ctxtGlobal = getNashornGlobalFrom(context); + final Global ctxtGlobal = getNashornGlobalFrom(context); invokeGlobal = ctxtGlobal; selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(ctxtGlobal, ctxtGlobal); } @@ -532,11 +532,11 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt)); } - private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final ScriptObject ctxtGlobal) throws ScriptException { + private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException { if (script == null) { return null; } - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != ctxtGlobal); try { if (globalChanged) { @@ -558,7 +558,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } } - private static void throwAsScriptException(final Exception e, final ScriptObject global) throws ScriptException { + private static void throwAsScriptException(final Exception e, final Global global) throws ScriptException { if (e instanceof ScriptException) { throw (ScriptException)e; } else if (e instanceof NashornException) { @@ -582,7 +582,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C return new CompiledScript() { @Override public Object eval(final ScriptContext ctxt) throws ScriptException { - final ScriptObject globalObject = getNashornGlobalFrom(ctxt); + final Global globalObject = getNashornGlobalFrom(ctxt); // Are we running the script in the correct global? if (func.getScope() == globalObject) { return evalImpl(func, ctxt, globalObject); @@ -602,8 +602,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C return compileImpl(source, getNashornGlobalFrom(ctxt)); } - private ScriptFunction compileImpl(final Source source, final ScriptObject newGlobal) throws ScriptException { - final ScriptObject oldGlobal = Context.getGlobal(); + private ScriptFunction compileImpl(final Source source, final Global newGlobal) throws ScriptException { + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != newGlobal); try { if (globalChanged) { @@ -641,8 +641,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C return true; } - private static boolean isOfContext(final ScriptObject global, final Context context) { - assert global instanceof GlobalObject: "Not a Global object"; - return ((GlobalObject)global).isOfContext(context); + private static boolean isOfContext(final Global global, final Context context) { + return global.isOfContext(context); } } diff --git a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index 7a9792df19c..b12553369d4 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -42,10 +42,10 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import javax.script.Bindings; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.arrays.ArrayData; import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.Context; -import jdk.nashorn.internal.runtime.GlobalObject; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; @@ -64,7 +64,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin private static final AccessControlContext GET_CONTEXT_ACC_CTXT = getContextAccCtxt(); private final ScriptObject sobj; - private final ScriptObject global; + private final Global global; private final boolean strict; @Override @@ -95,7 +95,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin @Override public Object call(final Object thiz, final Object... args) { - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { @@ -125,7 +125,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin @Override public Object newObject(final Object... args) { - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { @@ -171,7 +171,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin public Object callMember(final String functionName, final Object... args) { functionName.getClass(); // null check - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { @@ -642,7 +642,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin */ public static Object wrap(final Object obj, final Object homeGlobal) { if(obj instanceof ScriptObject) { - return homeGlobal instanceof ScriptObject ? new ScriptObjectMirror((ScriptObject)obj, (ScriptObject)homeGlobal) : obj; + return homeGlobal instanceof Global ? new ScriptObjectMirror((ScriptObject)obj, (Global)homeGlobal) : obj; } if(obj instanceof ConsString) { return obj.toString(); @@ -710,13 +710,13 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin // package-privates below this. - ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) { + ScriptObjectMirror(final ScriptObject sobj, final Global global) { assert sobj != null : "ScriptObjectMirror on null!"; - assert global instanceof GlobalObject : "global is not a GlobalObject"; + assert global != null : "home Global is null"; this.sobj = sobj; this.global = global; - this.strict = ((GlobalObject)global).isStrictContext(); + this.strict = global.isStrictContext(); } // accessors for script engine @@ -724,7 +724,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin return sobj; } - ScriptObject getHomeGlobal() { + Global getHomeGlobal() { return global; } @@ -734,7 +734,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin // internals only below this. private V inGlobal(final Callable callable) { - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); if (globalChanged) { Context.setGlobal(global); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java index 177cfef4e4b..61ccb712772 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -375,10 +375,11 @@ final class Attr extends NodeOperatorVisitor { * @return Symbol for given name or null for redefinition. */ private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) { - int flags = symbolFlags; - Symbol symbol = findSymbol(block, name); // Locate symbol. + int flags = symbolFlags; + Symbol symbol = findSymbol(block, name); // Locate symbol. + boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL; - if ((flags & KINDMASK) == IS_GLOBAL) { + if (isGlobal) { flags |= IS_SCOPE; } @@ -414,6 +415,8 @@ final class Attr extends NodeOperatorVisitor { // Determine where to create it. if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) { symbolBlock = block; //internal vars are always defined in the block closest to them + } else if (isGlobal) { + symbolBlock = lc.getOutermostFunction().getBody(); } else { symbolBlock = lc.getFunctionBody(function); } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 6ad92829bfe..e0ca67a4a92 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -685,7 +685,7 @@ final class CodeGenerator extends NodeOperatorVisitor 0) { - classCache = new ClassCache(cacheSize); - } } /** @@ -439,11 +432,9 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { * @return the global singleton */ public static Global instance() { - ScriptObject global = Context.getGlobal(); - if (! (global instanceof Global)) { - throw new IllegalStateException("no current global instance"); - } - return (Global)global; + Global global = Context.getGlobal(); + global.getClass(); // null check + return global; } /** @@ -464,19 +455,30 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { return instance().getContext(); } - // GlobalObject interface implementation + // Runtime interface to Global - @Override + /** + * Is this global of the given Context? + * @param ctxt the context + * @return true if this global belongs to the given Context + */ public boolean isOfContext(final Context ctxt) { return this.context == ctxt; } - @Override + /** + * Does this global belong to a strict Context? + * @return true if this global belongs to a strict Context + */ public boolean isStrictContext() { return context.getEnv()._strict; } - @Override + /** + * Initialize standard builtin objects like "Object", "Array", "Function" etc. + * as well as our extension builtin objects like "Java", "JSAdapter" as properties + * of the global scope object. + */ public void initBuiltinObjects() { if (this.builtinObject != null) { // already initialized, just return @@ -486,12 +488,26 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { init(); } - @Override + /** + * Create a new ScriptFunction object + * + * @param name function name + * @param handle invocation handle for function + * @param scope the scope + * @param strict are we in strict mode + * + * @return new script function + */ public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) { - return new ScriptFunctionImpl(name, handle, scope, null, strict, false, true); + return new ScriptFunctionImpl(name, handle, scope, null, strict ? ScriptFunctionData.IS_STRICT_CONSTRUCTOR : ScriptFunctionData.IS_CONSTRUCTOR); } - @Override + /** + * Wrap a Java object as corresponding script object + * + * @param obj object to wrap + * @return wrapped object + */ public Object wrapAsObject(final Object obj) { if (obj instanceof Boolean) { return new NativeBoolean((Boolean)obj, this); @@ -513,7 +529,14 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { } } - @Override + /** + * Lookup helper for JS primitive types + * + * @param request the link request for the dynamic call site. + * @param self self reference + * + * @return guarded invocation + */ public GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) { if (self instanceof String || self instanceof ConsString) { return NativeString.lookupPrimitive(request, self); @@ -525,12 +548,23 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { throw new IllegalArgumentException("Unsupported primitive: " + self); } - @Override + /** + * Create a new empty script object + * + * @return the new ScriptObject + */ public ScriptObject newObject() { return new JO(getObjectPrototype(), JO.getInitialMap()); } - @Override + /** + * Default value of given type + * + * @param sobj script object + * @param typeHint type hint + * + * @return default value + */ public Object getDefaultValue(final ScriptObject sobj, final Class typeHint) { // When the [[DefaultValue]] internal method of O is called with no hint, // then it behaves as if the hint were Number, unless O is a Date object @@ -590,7 +624,12 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { return UNDEFINED; } - @Override + /** + * Is the given ScriptObject an ECMAScript Error object? + * + * @param sobj the object being checked + * @return true if sobj is an Error object + */ public boolean isError(final ScriptObject sobj) { final ScriptObject errorProto = getErrorPrototype(); ScriptObject proto = sobj.getProto(); @@ -603,52 +642,108 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { return false; } - @Override + /** + * Create a new ECMAScript Error object. + * + * @param msg error message + * @return newly created Error object + */ public ScriptObject newError(final String msg) { return new NativeError(msg, this); } - @Override + /** + * Create a new ECMAScript EvalError object. + * + * @param msg error message + * @return newly created EvalError object + */ public ScriptObject newEvalError(final String msg) { return new NativeEvalError(msg, this); } - @Override + /** + * Create a new ECMAScript RangeError object. + * + * @param msg error message + * @return newly created RangeError object + */ public ScriptObject newRangeError(final String msg) { return new NativeRangeError(msg, this); } - @Override + /** + * Create a new ECMAScript ReferenceError object. + * + * @param msg error message + * @return newly created ReferenceError object + */ public ScriptObject newReferenceError(final String msg) { return new NativeReferenceError(msg, this); } - @Override + /** + * Create a new ECMAScript SyntaxError object. + * + * @param msg error message + * @return newly created SyntaxError object + */ public ScriptObject newSyntaxError(final String msg) { return new NativeSyntaxError(msg, this); } - @Override + /** + * Create a new ECMAScript TypeError object. + * + * @param msg error message + * @return newly created TypeError object + */ public ScriptObject newTypeError(final String msg) { return new NativeTypeError(msg, this); } - @Override + /** + * Create a new ECMAScript URIError object. + * + * @param msg error message + * @return newly created URIError object + */ public ScriptObject newURIError(final String msg) { return new NativeURIError(msg, this); } - @Override + /** + * Create a new ECMAScript GenericDescriptor object. + * + * @param configurable is the property configurable? + * @param enumerable is the property enumerable? + * @return newly created GenericDescriptor object + */ public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) { return new GenericPropertyDescriptor(configurable, enumerable, this); } - @Override + /** + * Create a new ECMAScript DatePropertyDescriptor object. + * + * @param value of the data property + * @param configurable is the property configurable? + * @param enumerable is the property enumerable? + * @return newly created DataPropertyDescriptor object + */ public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) { return new DataPropertyDescriptor(configurable, enumerable, writable, value, this); } - @Override + /** + * Create a new ECMAScript AccessorPropertyDescriptor object. + * + * @param get getter function of the user accessor property + * @param set setter function of the user accessor property + * @param configurable is the property configurable? + * @param enumerable is the property enumerable? + * @return newly created AccessorPropertyDescriptor object + */ public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) { final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this); @@ -664,62 +759,6 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { } - /** - * Cache for compiled script classes. - */ - @SuppressWarnings("serial") - private static class ClassCache extends LinkedHashMap { - private final int size; - private final ReferenceQueue> queue; - - ClassCache(int size) { - super(size, 0.75f, true); - this.size = size; - this.queue = new ReferenceQueue<>(); - } - - void cache(final Source source, final Class clazz) { - put(source, new ClassReference(clazz, queue, source)); - } - - @Override - protected boolean removeEldestEntry(final Map.Entry eldest) { - return size() > size; - } - - @Override - public ClassReference get(Object key) { - for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) { - remove(ref.source); - } - return super.get(key); - } - - } - - private static class ClassReference extends SoftReference> { - private final Source source; - - ClassReference(final Class clazz, final ReferenceQueue> queue, final Source source) { - super(clazz, queue); - this.source = source; - } - } - - // Class cache management - @Override - public Class findCachedClass(final Source source) { - assert classCache != null : "Class cache used without being initialized"; - ClassReference ref = classCache.get(source); - return ref != null ? ref.get() : null; - } - - @Override - public void cacheClass(final Source source, final Class clazz) { - assert classCache != null : "Class cache used without being initialized"; - classCache.cache(source, clazz); - } - private static T getLazilyCreatedValue(final Object key, final Callable creator, final Map map) { final T obj = map.get(key); if (obj != null) { @@ -737,14 +776,25 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { private final Map namedInvokers = new ConcurrentHashMap<>(); - @Override + + /** + * Get cached InvokeByName object for the given key + * @param key key to be associated with InvokeByName object + * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init) + * @return InvokeByName object associated with the key. + */ public InvokeByName getInvokeByName(final Object key, final Callable creator) { return getLazilyCreatedValue(key, creator, namedInvokers); } private final Map dynamicInvokers = new ConcurrentHashMap<>(); - @Override + /** + * Get cached dynamic method handle for the given key + * @param key key to be associated with dynamic method handle + * @param creator if method handle is absent 'creator' is called to make one (lazy init) + * @return dynamic method handle associated with the key. + */ public MethodHandle getDynamicInvoker(final Object key, final Callable creator) { return getLazilyCreatedValue(key, creator, dynamicInvokers); } @@ -933,6 +983,10 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { return ScriptFunction.getPrototype(builtinArrayBuffer); } + ScriptObject getDataViewPrototype() { + return ScriptFunction.getPrototype(builtinDataView); + } + ScriptObject getInt8ArrayPrototype() { return ScriptFunction.getPrototype(builtinInt8Array); } @@ -1701,6 +1755,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { private void initTypedArray() { this.builtinArrayBuffer = initConstructor("ArrayBuffer"); + this.builtinDataView = initConstructor("DataView"); this.builtinInt8Array = initConstructor("Int8Array"); this.builtinUint8Array = initConstructor("Uint8Array"); this.builtinUint8ClampedArray = initConstructor("Uint8ClampedArray"); @@ -1741,6 +1796,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { this.typeError = this.builtinTypeError; this.uriError = this.builtinURIError; this.arrayBuffer = this.builtinArrayBuffer; + this.dataView = this.builtinDataView; this.int8Array = this.builtinInt8Array; this.uint8Array = this.builtinUint8Array; this.uint8ClampedArray = this.builtinUint8ClampedArray; @@ -1838,7 +1894,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { anon.deleteOwnProperty(anon.getMap().findProperty("prototype")); // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3 - this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, false, false, false); + this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, 0); typeErrorThrower.setPrototype(UNDEFINED); // Non-constructor built-in functions do not have "prototype" property typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype")); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java index cc62d23cc1f..168a2f8a9ec 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java @@ -156,10 +156,6 @@ public final class NativeArray extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - /* * Constructors. */ @@ -208,7 +204,7 @@ public final class NativeArray extends ScriptObject { } NativeArray(final ArrayData arrayData, final Global global) { - super(global.getArrayPrototype(), getInitialMap()); + super(global.getArrayPrototype(), $nasgenmap$); this.setArray(arrayData); this.setIsArray(); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java index dbc1b24b2cb..49a61c96df3 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java @@ -25,6 +25,7 @@ package jdk.nashorn.internal.objects; +import java.nio.ByteBuffer; import java.util.Arrays; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; @@ -43,10 +44,6 @@ final class NativeArrayBuffer extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - @Constructor(arity = 1) public static Object constructor(final boolean newObj, final Object self, final Object... args) { if (args.length == 0) { @@ -57,7 +54,7 @@ final class NativeArrayBuffer extends ScriptObject { } protected NativeArrayBuffer(final byte[] byteArray, final Global global) { - super(global.getArrayBufferPrototype(), getInitialMap()); + super(global.getArrayBufferPrototype(), $nasgenmap$); this.buffer = byteArray; } @@ -128,4 +125,16 @@ final class NativeArrayBuffer extends ScriptObject { public int getByteLength() { return buffer.length; } + + ByteBuffer getBuffer() { + return ByteBuffer.wrap(buffer); + } + + ByteBuffer getBuffer(final int offset) { + return ByteBuffer.wrap(buffer, offset, buffer.length - offset); + } + + ByteBuffer getBuffer(final int offset, final int length) { + return ByteBuffer.wrap(buffer, offset, length); + } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java index bd955079830..f737a6c898b 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java @@ -30,6 +30,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.annotations.Attribute; @@ -50,22 +51,21 @@ import jdk.nashorn.internal.runtime.linker.PrimitiveLookup; public final class NativeBoolean extends ScriptObject { private final boolean value; - final static MethodHandle WRAPFILTER = findWrapFilter(); + // Method handle to create an object wrapper for a primitive boolean + private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class)); + // Method handle to retrieve the Boolean prototype object + private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class)); // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - private NativeBoolean(final boolean value, final ScriptObject proto, final PropertyMap map) { super(proto, map); this.value = value; } NativeBoolean(final boolean flag, final Global global) { - this(flag, global.getBooleanPrototype(), getInitialMap()); + this(flag, global.getBooleanPrototype(), $nasgenmap$); } NativeBoolean(final boolean flag) { @@ -164,7 +164,7 @@ public final class NativeBoolean extends ScriptObject { * @return Link to be invoked at call site. */ public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) { - return PrimitiveLookup.lookupPrimitive(request, Boolean.class, new NativeBoolean((Boolean)receiver), WRAPFILTER); + return PrimitiveLookup.lookupPrimitive(request, Boolean.class, new NativeBoolean((Boolean)receiver), WRAPFILTER, PROTOFILTER); } /** @@ -178,7 +178,12 @@ public final class NativeBoolean extends ScriptObject { return new NativeBoolean((Boolean)receiver); } - private static MethodHandle findWrapFilter() { - return MH.findStatic(MethodHandles.lookup(), NativeBoolean.class, "wrapFilter", MH.type(NativeBoolean.class, Object.class)); + @SuppressWarnings("unused") + private static Object protoFilter(final Object object) { + return Global.instance().getBooleanPrototype(); + } + + private static MethodHandle findOwnMH(final String name, final MethodType type) { + return MH.findStatic(MethodHandles.lookup(), NativeBoolean.class, name, type); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java new file mode 100644 index 00000000000..93b5f09f90c --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java @@ -0,0 +1,1015 @@ +/* + * 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.objects; + +import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; +import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError; +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import jdk.nashorn.internal.objects.annotations.Attribute; +import jdk.nashorn.internal.objects.annotations.Constructor; +import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; +import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; +import jdk.nashorn.internal.objects.annotations.SpecializedFunction; +import jdk.nashorn.internal.runtime.JSType; +import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.ScriptRuntime; + +/** + *

      + * DataView builtin constructor. Based on the specification here: + * http://www.khronos.org/registry/typedarray/specs/latest/#8 + *

      + *

      + * An ArrayBuffer is a useful object for representing an arbitrary chunk of data. + * In many cases, such data will be read from disk or from the network, and will + * not follow the alignment restrictions that are imposed on the typed array views + * described earlier. In addition, the data will often be heterogeneous in nature + * and have a defined byte order. The DataView view provides a low-level interface + * for reading such data from and writing it to an ArrayBuffer. + *

      + *

      + * Regardless of the host computer's endianness, DataView reads or writes values + * to or from main memory with a specified endianness: big or little. + *

      + */ +@ScriptClass("DataView") +public class NativeDataView extends ScriptObject { + // initialized by nasgen + private static PropertyMap $nasgenmap$; + + // inherited ArrayBufferView properties + + /** + * Underlying ArrayBuffer storage object + */ + @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) + public final Object buffer; + + /** + * The offset in bytes from the start of the ArrayBuffer + */ + @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) + public final int byteOffset; + + /** + * The number of bytes from the offset that this DataView will reference + */ + @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) + public final int byteLength; + + // underlying ByteBuffer + private final ByteBuffer buf; + + private NativeDataView(NativeArrayBuffer arrBuf) { + this(arrBuf, arrBuf.getBuffer(), 0); + } + + private NativeDataView(NativeArrayBuffer arrBuf, int offset) { + this(arrBuf, bufferFrom(arrBuf, offset), offset); + } + + private NativeDataView(NativeArrayBuffer arrBuf, int offset, int length) { + this(arrBuf, bufferFrom(arrBuf, offset, length), offset, length); + } + + private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset) { + this(arrBuf, buf, offset, buf.capacity() - offset); + } + + private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset, final int length) { + super(Global.instance().getDataViewPrototype(), $nasgenmap$); + this.buffer = arrBuf; + this.byteOffset = offset; + this.byteLength = length; + this.buf = buf; + } + + /** + * Create a new DataView object using the passed ArrayBuffer for its + * storage. Optional byteOffset and byteLength can be used to limit the + * section of the buffer referenced. The byteOffset indicates the offset in + * bytes from the start of the ArrayBuffer, and the byteLength is the number + * of bytes from the offset that this DataView will reference. If both + * byteOffset and byteLength are omitted, the DataView spans the entire + * ArrayBuffer range. If the byteLength is omitted, the DataView extends from + * the given byteOffset until the end of the ArrayBuffer. + * + * If the given byteOffset and byteLength references an area beyond the end + * of the ArrayBuffer an exception is raised. + + * @param newObj if this constructor was invoked with 'new' or not + * @param self constructor function object + * @param args arguments to the constructor + * @return newly constructed DataView object + */ + @Constructor(arity = 1) + public static Object 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"); + } + + final NativeArrayBuffer arrBuf = (NativeArrayBuffer) args[0]; + switch (args.length) { + case 1: + return new NativeDataView(arrBuf); + case 2: + return new NativeDataView(arrBuf, JSType.toInt32(args[1])); + default: + return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2])); + } + } + + /** + * Specialized version of DataView constructor + * + * @param newObj if this constructor was invoked with 'new' or not + * @param self constructor function object + * @param arrBuf underlying ArrayBuffer storage object + * @param offset offset in bytes from the start of the ArrayBuffer + * @return newly constructed DataView object + */ + @SpecializedConstructor + public static Object constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) { + if (!(arrBuf instanceof NativeArrayBuffer)) { + throw typeError("not.an.arraybuffer.in.dataview"); + } + return new NativeDataView((NativeArrayBuffer) arrBuf, offset); + } + + /** + * Specialized version of DataView constructor + * + * @param newObj if this constructor was invoked with 'new' or not + * @param self constructor function object + * @param arrBuf underlying ArrayBuffer storage object + * @param offset in bytes from the start of the ArrayBuffer + * @param length is the number of bytes from the offset that this DataView will reference + * @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) { + if (!(arrBuf instanceof NativeArrayBuffer)) { + throw typeError("not.an.arraybuffer.in.dataview"); + } + return new NativeDataView((NativeArrayBuffer) arrBuf, offset, length); + } + + // Gets the value of the given type at the specified byte offset + // from the start of the view. There is no alignment constraint; + // multi-byte values may be fetched from any offset. + // + // For multi-byte values, the optional littleEndian argument + // indicates whether a big-endian or little-endian value should be + // read. If false or undefined, a big-endian value is read. + // + // These methods raise an exception if they would read + // beyond the end of the view. + + /** + * Get 8-bit signed int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 8-bit signed int value at the byteOffset + */ + @Function(attributes = Attribute.NOT_ENUMERABLE) + public static int getInt8(final Object self, final Object byteOffset) { + try { + return getBuffer(self).get(JSType.toInt32(byteOffset)); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 8-bit signed int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 8-bit signed int value at the byteOffset + */ + @SpecializedFunction + public static int getInt8(final Object self, final int byteOffset) { + try { + return getBuffer(self).get(byteOffset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 8-bit unsigned int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 8-bit unsigned int value at the byteOffset + */ + @Function(attributes = Attribute.NOT_ENUMERABLE) + public static int getUint8(final Object self, final Object byteOffset) { + try { + return (0xFF & getBuffer(self).get(JSType.toInt32(byteOffset))); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 8-bit unsigned int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 8-bit unsigned int value at the byteOffset + */ + @SpecializedFunction + public static int getUint8(final Object self, final int byteOffset) { + try { + return (0xFF & getBuffer(self).get(byteOffset)); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 16-bit signed int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 16-bit signed int value at the byteOffset + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) + public static int getInt16(final Object self, final Object byteOffset, final Object littleEndian) { + try { + return getBuffer(self, littleEndian).getShort(JSType.toInt32(byteOffset)); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 16-bit signed int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 16-bit signed int value at the byteOffset + */ + @SpecializedFunction + public static int getInt16(final Object self, final int byteOffset) { + try { + return getBuffer(self, false).getShort(byteOffset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 16-bit signed int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 16-bit signed int value at the byteOffset + */ + @SpecializedFunction + public static int getInt16(final Object self, final int byteOffset, final boolean littleEndian) { + try { + return getBuffer(self, littleEndian).getShort(byteOffset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 16-bit unsigned int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 16-bit unsigned int value at the byteOffset + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) + public static int getUint16(final Object self, final Object byteOffset, final Object littleEndian) { + try { + return (int) (0xFFFF & getBuffer(self, littleEndian).getShort(JSType.toInt32(byteOffset))); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 16-bit unsigned int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 16-bit unsigned int value at the byteOffset + */ + @SpecializedFunction + public static int getUint16(final Object self, final int byteOffset) { + try { + return (int) (0xFFFF & getBuffer(self, false).getShort(byteOffset)); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 16-bit unsigned int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 16-bit unsigned int value at the byteOffset + */ + @SpecializedFunction + public static int getUint16(final Object self, final int byteOffset, final boolean littleEndian) { + try { + return (int) (0xFFFF & getBuffer(self, littleEndian).getShort(byteOffset)); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 32-bit signed int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 32-bit signed int value at the byteOffset + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) + public static int getInt32(final Object self, final Object byteOffset, final Object littleEndian) { + try { + return getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset)); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 32-bit signed int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 32-bit signed int value at the byteOffset + */ + @SpecializedFunction + public static int getInt32(final Object self, final int byteOffset) { + try { + return getBuffer(self, false).getInt(byteOffset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 32-bit signed int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 32-bit signed int value at the byteOffset + */ + @SpecializedFunction + public static int getInt32(final Object self, final int byteOffset, final boolean littleEndian) { + try { + return getBuffer(self, littleEndian).getInt(byteOffset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 32-bit unsigned int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 32-bit unsigned int value at the byteOffset + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) + public static long getUint32(final Object self, final Object byteOffset, final Object littleEndian) { + try { + return (long) (0xFFFFFFFFL & getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset))); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 32-bit unsigned int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 32-bit unsigned int value at the byteOffset + */ + @SpecializedFunction + public static long getUint32(final Object self, final int byteOffset) { + try { + return (long) (0xFFFFFFFFL & getBuffer(self, false).getInt(JSType.toInt32(byteOffset))); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 32-bit unsigned int from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 32-bit unsigned int value at the byteOffset + */ + @SpecializedFunction + public static long getUint32(final Object self, final int byteOffset, final boolean littleEndian) { + try { + return (long) (0xFFFFFFFFL & getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset))); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 32-bit float value from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 32-bit float value at the byteOffset + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) + public static double getFloat32(final Object self, final Object byteOffset, final Object littleEndian) { + try { + return getBuffer(self, littleEndian).getFloat(JSType.toInt32(byteOffset)); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 32-bit float value from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 32-bit float value at the byteOffset + */ + @SpecializedFunction + public static double getFloat32(final Object self, final int byteOffset) { + try { + return getBuffer(self, false).getFloat(byteOffset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 32-bit float value from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 32-bit float value at the byteOffset + */ + @SpecializedFunction + public static double getFloat32(final Object self, final int byteOffset, final boolean littleEndian) { + try { + return getBuffer(self, littleEndian).getFloat(byteOffset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 64-bit float value from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 64-bit float value at the byteOffset + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) + public static double getFloat64(final Object self, final Object byteOffset, final Object littleEndian) { + try { + return getBuffer(self, littleEndian).getDouble(JSType.toInt32(byteOffset)); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 64-bit float value from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @return 64-bit float value at the byteOffset + */ + @SpecializedFunction + public static double getFloat64(final Object self, final int byteOffset) { + try { + return getBuffer(self, false).getDouble(byteOffset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Get 64-bit float value from given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param littleEndian (optional) flag indicating whether to read in little endian order + * @return 64-bit float value at the byteOffset + */ + @SpecializedFunction + public static double getFloat64(final Object self, final int byteOffset, final boolean littleEndian) { + try { + return getBuffer(self, littleEndian).getDouble(byteOffset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + // Stores a value of the given type at the specified byte offset + // from the start of the view. There is no alignment constraint; + // multi-byte values may be stored at any offset. + // + // For multi-byte values, the optional littleEndian argument + // indicates whether the value should be stored in big-endian or + // little-endian byte order. If false or undefined, the value is + // stored in big-endian byte order. + // + // These methods raise an exception if they would write + // beyond the end of the view. + + /** + * Set 8-bit signed int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param value byte value to set + * @return undefined + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) + public static Object setInt8(final Object self, final Object byteOffset, final Object value) { + try { + getBuffer(self).put(JSType.toInt32(byteOffset), (byte)JSType.toInt32(value)); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 8-bit signed int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to read from + * @param value byte value to set + * @return undefined + */ + @SpecializedFunction + public static Object setInt8(final Object self, final int byteOffset, final int value) { + try { + getBuffer(self).put(byteOffset, (byte)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 8-bit unsigned int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value byte value to set + * @return undefined + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) + public static Object setUint8(final Object self, final Object byteOffset, final Object value) { + try { + getBuffer(self).put(JSType.toInt32(byteOffset), (byte)JSType.toInt32(value)); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 8-bit unsigned int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value byte value to set + * @return undefined + */ + @SpecializedFunction + public static Object setUint8(final Object self, final int byteOffset, final int value) { + try { + getBuffer(self).put(byteOffset, (byte)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 16-bit signed int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value short value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) + public static Object setInt16(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { + try { + getBuffer(self, littleEndian).putShort(JSType.toInt32(byteOffset), (short)JSType.toInt32(value)); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 16-bit signed int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value short value to set + * @return undefined + */ + @SpecializedFunction + public static Object setInt16(final Object self, final int byteOffset, final int value) { + try { + getBuffer(self, false).putShort(byteOffset, (short)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 16-bit signed int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value short value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @SpecializedFunction + public static Object setInt16(final Object self, final int byteOffset, final int value, final boolean littleEndian) { + try { + getBuffer(self, littleEndian).putShort(byteOffset, (short)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 16-bit unsigned int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value short value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) + public static Object setUint16(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { + try { + getBuffer(self, littleEndian).putShort(JSType.toInt32(byteOffset), (short)JSType.toInt32(value)); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 16-bit unsigned int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value short value to set + * @return undefined + */ + @SpecializedFunction + public static Object setUint16(final Object self, final int byteOffset, final int value) { + try { + getBuffer(self, false).putShort(byteOffset, (short)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 16-bit unsigned int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value short value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @SpecializedFunction + public static Object setUint16(final Object self, final int byteOffset, final int value, final boolean littleEndian) { + try { + getBuffer(self, littleEndian).putShort(byteOffset, (short)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 32-bit signed int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value int value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) + public static Object setInt32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { + try { + getBuffer(self, littleEndian).putInt(JSType.toInt32(byteOffset), (int)JSType.toInt32(value)); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 32-bit signed int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value int value to set + * @return undefined + */ + @SpecializedFunction + public static Object setInt32(final Object self, final int byteOffset, final int value) { + try { + getBuffer(self, false).putInt(byteOffset, value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 32-bit signed int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value int value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @SpecializedFunction + public static Object setInt32(final Object self, final int byteOffset, final int value, final boolean littleEndian) { + try { + getBuffer(self, littleEndian).putInt(byteOffset, value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 32-bit unsigned int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value int value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) + public static Object setUint32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { + try { + getBuffer(self, littleEndian).putInt(JSType.toInt32(byteOffset), (int)JSType.toUint32(value)); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 32-bit unsigned int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value int value to set + * @return undefined + */ + @SpecializedFunction + public static Object setUint32(final Object self, final int byteOffset, final long value) { + try { + getBuffer(self, false).putInt(byteOffset, (int)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 32-bit unsigned int at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value int value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @SpecializedFunction + public static Object setUint32(final Object self, final int byteOffset, final long value, final boolean littleEndian) { + try { + getBuffer(self, littleEndian).putInt(byteOffset, (int)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 32-bit float at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value float value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) + public static Object setFloat32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { + try { + getBuffer(self, littleEndian).putFloat((int)JSType.toUint32(byteOffset), (float)JSType.toNumber(value)); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 32-bit float at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value float value to set + * @return undefined + */ + @SpecializedFunction + public static Object setFloat32(final Object self, final int byteOffset, final double value) { + try { + getBuffer(self, false).putFloat(byteOffset, (float)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 32-bit float at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value float value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @SpecializedFunction + public static Object setFloat32(final Object self, final int byteOffset, final double value, final boolean littleEndian) { + try { + getBuffer(self, littleEndian).putFloat(byteOffset, (float)value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 64-bit float at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value double value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) + public static Object setFloat64(final Object self, final Object byteOffset, final Object value, final Object littleEndian) { + try { + getBuffer(self, littleEndian).putDouble((int)JSType.toUint32(byteOffset), JSType.toNumber(value)); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 64-bit float at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value double value to set + * @return undefined + */ + @SpecializedFunction + public static Object setFloat64(final Object self, final int byteOffset, final double value) { + try { + getBuffer(self, false).putDouble(byteOffset, value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + /** + * Set 64-bit float at the given byteOffset + * + * @param self DataView object + * @param byteOffset byte offset to write at + * @param value double value to set + * @param littleEndian (optional) flag indicating whether to write in little endian order + * @return undefined + */ + @SpecializedFunction + public static Object setFloat64(final Object self, final int byteOffset, final double value, final boolean littleEndian) { + try { + getBuffer(self, littleEndian).putDouble(byteOffset, value); + return UNDEFINED; + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.offset"); + } + } + + // internals only below this point + private static ByteBuffer bufferFrom(final NativeArrayBuffer nab, final int offset) { + try { + return nab.getBuffer(offset); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.constructor.offset"); + } + } + + private static ByteBuffer bufferFrom(final NativeArrayBuffer nab, final int offset, final int length) { + try { + return nab.getBuffer(offset, length); + } catch (final IndexOutOfBoundsException ioe) { + throw rangeError(ioe, "dataview.constructor.offset"); + } + } + + private static NativeDataView checkSelf(final Object self) { + if (!(self instanceof NativeDataView)) { + throw typeError("not.an.arraybuffer", ScriptRuntime.safeToString(self)); + } + return (NativeDataView)self; + } + + private static ByteBuffer getBuffer(final Object self) { + return checkSelf(self).buf; + } + + private static ByteBuffer getBuffer(final Object self, final Object littleEndian) { + return getBuffer(self, JSType.toBoolean(littleEndian)); + } + + private static ByteBuffer getBuffer(final Object self, final boolean littleEndian) { + return getBuffer(self).order(littleEndian? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); + } +} diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java index b0d120222a9..34e27f173ac 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java @@ -114,10 +114,6 @@ public final class NativeDate extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - private NativeDate(final double time, final ScriptObject proto, final PropertyMap map) { super(proto, map); final ScriptEnvironment env = Global.getEnv(); @@ -127,7 +123,7 @@ public final class NativeDate extends ScriptObject { } NativeDate(final double time, final Global global) { - this(time, global.getDatePrototype(), getInitialMap()); + this(time, global.getDatePrototype(), $nasgenmap$); } private NativeDate (final double time) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java index e1a4730d553..3dea27288b0 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java @@ -92,10 +92,6 @@ public final class NativeError extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - @SuppressWarnings("LeakingThisInConstructor") private NativeError(final Object msg, final ScriptObject proto, final PropertyMap map) { super(proto, map); @@ -108,7 +104,7 @@ public final class NativeError extends ScriptObject { } NativeError(final Object msg, final Global global) { - this(msg, global.getErrorPrototype(), getInitialMap()); + this(msg, global.getErrorPrototype(), $nasgenmap$); } private NativeError(final Object msg) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java index bb11ef6c354..2b343ede673 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java @@ -62,10 +62,6 @@ public final class NativeEvalError extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - @SuppressWarnings("LeakingThisInConstructor") private NativeEvalError(final Object msg, final ScriptObject proto, final PropertyMap map) { super(proto, map); @@ -78,7 +74,7 @@ public final class NativeEvalError extends ScriptObject { } NativeEvalError(final Object msg, final Global global) { - this(msg, global.getEvalErrorPrototype(), getInitialMap()); + this(msg, global.getEvalErrorPrototype(), $nasgenmap$); } private NativeEvalError(final Object msg) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java index c77b2fe0fa9..b71b4276cd8 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java @@ -146,10 +146,6 @@ public final class NativeJSAdapter extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - NativeJSAdapter(final Object overrides, final ScriptObject adaptee, final ScriptObject proto, final PropertyMap map) { super(proto, map); this.adaptee = wrapAdaptee(adaptee); @@ -577,7 +573,7 @@ public final class NativeJSAdapter extends ScriptObject { proto = global.getJSAdapterPrototype(); } - return new NativeJSAdapter(overrides, (ScriptObject)adaptee, (ScriptObject)proto, getInitialMap()); + return new NativeJSAdapter(overrides, (ScriptObject)adaptee, (ScriptObject)proto, $nasgenmap$); } @Override @@ -622,7 +618,7 @@ public final class NativeJSAdapter extends ScriptObject { case "getMethod": final FindProperty find = adaptee.findProperty(__call__, true); if (find != null) { - final Object value = getObjectValue(find); + final Object value = find.getObjectValue(); if (value instanceof ScriptFunction) { final ScriptFunctionImpl func = (ScriptFunctionImpl)value; // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound @@ -691,7 +687,7 @@ public final class NativeJSAdapter extends ScriptObject { final MethodType type = desc.getMethodType(); if (findData != null) { final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null; - final Object value = getObjectValue(findData); + final Object value = findData.getObjectValue(); if (value instanceof ScriptFunction) { final ScriptFunction func = (ScriptFunction)value; diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java index c86f3053526..49be8a7c473 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java @@ -60,17 +60,13 @@ public final class NativeJavaImporter extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - private NativeJavaImporter(final Object[] args, final ScriptObject proto, final PropertyMap map) { super(proto, map); this.args = args; } private NativeJavaImporter(final Object[] args, final Global global) { - this(args, global.getJavaImporterPrototype(), getInitialMap()); + this(args, global.getJavaImporterPrototype(), $nasgenmap$); } private NativeJavaImporter(final Object[] args) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java index 09289a015d0..4181d205051 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java @@ -34,6 +34,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.text.NumberFormat; import java.util.Locale; import jdk.internal.dynalink.linker.GuardedInvocation; @@ -57,7 +58,10 @@ import jdk.nashorn.internal.runtime.linker.PrimitiveLookup; @ScriptClass("Number") public final class NativeNumber extends ScriptObject { - static final MethodHandle WRAPFILTER = findWrapFilter(); + // Method handle to create an object wrapper for a primitive number + private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class)); + // Method handle to retrieve the Number prototype object + private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class)); /** ECMA 15.7.3.2 largest positive finite value */ @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR) @@ -86,10 +90,6 @@ public final class NativeNumber extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - private NativeNumber(final double value, final ScriptObject proto, final PropertyMap map) { super(proto, map); this.value = value; @@ -98,7 +98,7 @@ public final class NativeNumber extends ScriptObject { } NativeNumber(final double value, final Global global) { - this(value, global.getNumberPrototype(), getInitialMap()); + this(value, global.getNumberPrototype(), $nasgenmap$); } private NativeNumber(final double value) { @@ -322,7 +322,7 @@ public final class NativeNumber extends ScriptObject { * @return Link to be invoked at call site. */ public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) { - return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER); + return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER, PROTOFILTER); } @SuppressWarnings("unused") @@ -330,6 +330,11 @@ public final class NativeNumber extends ScriptObject { return new NativeNumber(((Number)receiver).doubleValue()); } + @SuppressWarnings("unused") + private static Object protoFilter(final Object object) { + return Global.instance().getNumberPrototype(); + } + private static double getNumberValue(final Object self) { if (self instanceof Number) { return ((Number)self).doubleValue(); @@ -378,7 +383,7 @@ public final class NativeNumber extends ScriptObject { return str; } - private static MethodHandle findWrapFilter() { - return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, "wrapFilter", MH.type(NativeNumber.class, Object.class)); + private static MethodHandle findOwnMH(final String name, final MethodType type) { + return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, name, type); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java index 6e0d954bc7c..4b2bebcfd2d 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java @@ -62,10 +62,6 @@ public final class NativeRangeError extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - @SuppressWarnings("LeakingThisInConstructor") private NativeRangeError(final Object msg, final ScriptObject proto, final PropertyMap map) { super(proto, map); @@ -78,7 +74,7 @@ public final class NativeRangeError extends ScriptObject { } NativeRangeError(final Object msg, final Global global) { - this(msg, global.getRangeErrorPrototype(), getInitialMap()); + this(msg, global.getRangeErrorPrototype(), $nasgenmap$); } private NativeRangeError(final Object msg) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java index 052950c6d24..504f16ecd6c 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java @@ -62,10 +62,6 @@ public final class NativeReferenceError extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - @SuppressWarnings("LeakingThisInConstructor") private NativeReferenceError(final Object msg, final ScriptObject proto, final PropertyMap map) { super(proto, map); @@ -78,7 +74,7 @@ public final class NativeReferenceError extends ScriptObject { } NativeReferenceError(final Object msg, final Global global) { - this(msg, global.getReferenceErrorPrototype(), getInitialMap()); + this(msg, global.getReferenceErrorPrototype(), $nasgenmap$); } private NativeReferenceError(final Object msg) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java index abc3366d353..04b828bfc21 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java @@ -70,12 +70,8 @@ public final class NativeRegExp extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - private NativeRegExp(final Global global) { - super(global.getRegExpPrototype(), getInitialMap()); + super(global.getRegExpPrototype(), $nasgenmap$); this.globalObject = global; } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java index 5d79699e2ae..f12cea12c13 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java @@ -53,12 +53,8 @@ public final class NativeRegExpExecResult extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - NativeRegExpExecResult(final RegExpResult result, final Global global) { - super(global.getArrayPrototype(), getInitialMap()); + super(global.getArrayPrototype(), $nasgenmap$); setIsArray(); this.setArray(ArrayData.allocate(result.getGroups().clone())); this.index = result.getIndex(); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java index 2370f514518..c75b2b00362 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java @@ -32,6 +32,7 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; @@ -69,21 +70,20 @@ public final class NativeString extends ScriptObject { private final CharSequence value; - static final MethodHandle WRAPFILTER = findWrapFilter(); + // Method handle to create an object wrapper for a primitive string + private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class)); + // Method handle to retrieve the String prototype object + private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class)); // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - private NativeString(final CharSequence value) { this(value, Global.instance()); } NativeString(final CharSequence value, final Global global) { - this(value, global.getStringPrototype(), getInitialMap()); + this(value, global.getStringPrototype(), $nasgenmap$); } private NativeString(final CharSequence value, final ScriptObject proto, final PropertyMap map) { @@ -1199,7 +1199,7 @@ public final class NativeString extends ScriptObject { */ public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) { final MethodHandle guard = NashornGuards.getInstanceOf2Guard(String.class, ConsString.class); - return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER); + return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER, PROTOFILTER); } @SuppressWarnings("unused") @@ -1207,6 +1207,11 @@ public final class NativeString extends ScriptObject { return new NativeString((CharSequence)receiver); } + @SuppressWarnings("unused") + private static Object protoFilter(final Object object) { + return Global.instance().getStringPrototype(); + } + private static CharSequence getCharSequence(final Object self) { if (self instanceof String || self instanceof ConsString) { return (CharSequence)self; @@ -1254,7 +1259,7 @@ public final class NativeString extends ScriptObject { return key >= 0 && key < value.length(); } - private static MethodHandle findWrapFilter() { - return MH.findStatic(MethodHandles.lookup(), NativeString.class, "wrapFilter", MH.type(NativeString.class, Object.class)); + private static MethodHandle findOwnMH(final String name, final MethodType type) { + return MH.findStatic(MethodHandles.lookup(), NativeString.class, name, type); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java index ffe1b0a7432..6515f3cc2e6 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java @@ -62,13 +62,9 @@ public final class NativeSyntaxError extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - @SuppressWarnings("LeakingThisInConstructor") NativeSyntaxError(final Object msg, final Global global) { - super(global.getSyntaxErrorPrototype(), getInitialMap()); + super(global.getSyntaxErrorPrototype(), $nasgenmap$); if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java index 067139cda3d..f799b1767d0 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java @@ -62,13 +62,9 @@ public final class NativeTypeError extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - @SuppressWarnings("LeakingThisInConstructor") NativeTypeError(final Object msg, final Global global) { - super(global.getTypeErrorPrototype(), getInitialMap()); + super(global.getTypeErrorPrototype(), $nasgenmap$); if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java index 382e23f4b65..fd59bc8a209 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java @@ -61,13 +61,9 @@ public final class NativeURIError extends ScriptObject { // initialized by nasgen private static PropertyMap $nasgenmap$; - static PropertyMap getInitialMap() { - return $nasgenmap$; - } - @SuppressWarnings("LeakingThisInConstructor") NativeURIError(final Object msg, final Global global) { - super(global.getURIErrorPrototype(), getInitialMap()); + super(global.getURIErrorPrototype(), $nasgenmap$); if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { diff --git a/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java b/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java index 1fd4f60d5a0..483f6174702 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java +++ b/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java @@ -57,10 +57,6 @@ public class PrototypeObject extends ScriptObject { map$ = PropertyMap.newMap(properties); } - static PropertyMap getInitialMap() { - return map$; - } - private PrototypeObject(final Global global, final PropertyMap map) { super(global.getObjectPrototype(), map != map$? map.addAll(map$) : map$); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index 9852c96273d..dcbc7da99c8 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -55,27 +55,11 @@ public class ScriptFunctionImpl extends ScriptFunction { // property map for non-strict, non-bound functions. private static final PropertyMap map$; - static PropertyMap getInitialMap() { - return map$; - } - - static PropertyMap getInitialAnonymousMap() { - return AnonymousFunction.getInitialMap(); - } - - static PropertyMap getInitialStrictMap() { - return strictmodemap$; - } - - static PropertyMap getInitialBoundMap() { - return boundfunctionmap$; - } - // Marker object for lazily initialized prototype object private static final Object LAZY_PROTOTYPE = new Object(); private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs, final Global global) { - super(name, invokeHandle, getInitialMap(), null, specs, false, true, true); + super(name, invokeHandle, map$, null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR); init(global); } @@ -92,7 +76,7 @@ public class ScriptFunctionImpl extends ScriptFunction { } private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs, final Global global) { - super(name, invokeHandle, map.addAll(getInitialMap()), null, specs, false, true, true); + super(name, invokeHandle, map.addAll(map$), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR); init(global); } @@ -109,8 +93,8 @@ public class ScriptFunctionImpl extends ScriptFunction { this(name, invokeHandle, map, specs, Global.instance()); } - private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor, final Global global) { - super(name, methodHandle, getMap(global, isStrict), scope, specs, isStrict, isBuiltin, isConstructor); + private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags, final Global global) { + super(name, methodHandle, getMap(isStrict(flags)), scope, specs, flags); init(global); } @@ -121,16 +105,14 @@ public class ScriptFunctionImpl extends ScriptFunction { * @param methodHandle handle for invocation * @param scope scope object * @param specs specialized versions of this method, if available, null otherwise - * @param isStrict are we in strict mode - * @param isBuiltin is this a built-in function - * @param isConstructor can the function be used as a constructor (most can; some built-ins are restricted). + * @param flags {@link ScriptFunctionData} flags */ - ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { - this(name, methodHandle, scope, specs, isStrict, isBuiltin, isConstructor, Global.instance()); + ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags) { + this(name, methodHandle, scope, specs, flags, Global.instance()); } private ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope, final Global global) { - super(data, getMap(global, data.isStrict()), scope); + super(data, getMap(data.isStrict()), scope); init(global); } @@ -150,7 +132,7 @@ public class ScriptFunctionImpl extends ScriptFunction { * @param global the global object */ ScriptFunctionImpl(final ScriptFunctionData data, final Global global) { - super(data, getInitialBoundMap(), null); + super(data, boundfunctionmap$, null); init(global); } @@ -173,9 +155,13 @@ public class ScriptFunctionImpl extends ScriptFunction { return newMap; } + private static boolean isStrict(final int flags) { + return (flags & ScriptFunctionData.IS_STRICT) != 0; + } + // Choose the map based on strict mode! - private static PropertyMap getMap(final Global global, final boolean strict) { - return strict ? getInitialStrictMap() : getInitialMap(); + private static PropertyMap getMap(final boolean strict) { + return strict ? strictmodemap$ : map$; } private static PropertyMap createBoundFunctionMap(final PropertyMap strictModeMap) { @@ -189,12 +175,8 @@ public class ScriptFunctionImpl extends ScriptFunction { private static class AnonymousFunction extends ScriptFunctionImpl { private static final PropertyMap anonmap$ = PropertyMap.newMap(); - static PropertyMap getInitialMap() { - return anonmap$; - } - AnonymousFunction(final Global global) { - super("", GlobalFunctions.ANONYMOUS, getInitialAnonymousMap(), null); + super("", GlobalFunctions.ANONYMOUS, anonmap$, null); } } @@ -211,7 +193,7 @@ public class ScriptFunctionImpl extends ScriptFunction { * @return new ScriptFunction */ static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) { - final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, false, true, false); + final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, ScriptFunctionData.IS_BUILTIN); func.setPrototype(UNDEFINED); // Non-constructor built-in functions do not have "prototype" property func.deleteOwnProperty(func.getMap().findProperty("prototype")); diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java index 60cbaccb68e..f6b962a93e1 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java @@ -1799,6 +1799,7 @@ loop: case THIS: final String name = type.getName(); next(); + lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_THIS); return new IdentNode(primaryToken, finish, name); case IDENT: final IdentNode ident = getIdent(); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java index 702ca76ba1f..d22a956760b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -141,10 +141,12 @@ public final class AccessorProperty extends Property { private Class currentType; /** - * Delegate constructor. This is used when adding properties to the Global scope, which - * is necessary for outermost levels in a script (the ScriptObject is represented by - * a JO-prefixed ScriptObject class, but the properties need to be in the Global scope - * and are thus rebound with that as receiver + * Delegate constructor for bound properties. This is used for properties created by + * {@link ScriptRuntime#mergeScope} and the Nashorn {@code Object.bindProperties} method. + * The former is used to add a script's defined globals to the current global scope while + * still storing them in a JO-prefixed ScriptObject class. + * + *

      All properties created by this constructor have the {@link #IS_BOUND} flag set.

      * * @param property accessor property to rebind * @param delegate delegate object to rebind receiver to @@ -157,6 +159,8 @@ public final class AccessorProperty extends Property { this.objectGetter = bindTo(property.ensureObjectGetter(), delegate); this.objectSetter = bindTo(property.ensureObjectSetter(), delegate); + // Properties created this way are bound to a delegate + this.flags |= IS_BOUND; setCurrentType(property.getCurrentType()); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 3e6a1488fa3..f3ec08757d1 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -36,6 +36,8 @@ import java.io.IOException; import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; @@ -46,6 +48,7 @@ import java.security.CodeSource; import java.security.Permissions; import java.security.PrivilegedAction; import java.security.ProtectionDomain; +import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import jdk.internal.org.objectweb.asm.ClassReader; @@ -153,16 +156,19 @@ public final class Context { /** Is Context global debug mode enabled ? */ public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug"); - private static final ThreadLocal currentGlobal = new ThreadLocal<>(); + private static final ThreadLocal currentGlobal = new ThreadLocal<>(); + + // class cache + private ClassCache classCache; /** * Get the current global scope * @return the current global scope */ - public static ScriptObject getGlobal() { + public static Global getGlobal() { // This class in a package.access protected package. // Trusted code only can call this method. - return getGlobalTrusted(); + return currentGlobal.get(); } /** @@ -171,10 +177,19 @@ public final class Context { */ public static void setGlobal(final ScriptObject global) { if (global != null && !(global instanceof Global)) { - throw new IllegalArgumentException("global is not an instance of Global!"); + throw new IllegalArgumentException("not a global!"); } + setGlobal((Global)global); + } - setGlobalTrusted(global); + /** + * Set the current global scope + * @param global the global scope + */ + public static void setGlobal(final Global global) { + // This class in a package.access protected package. + // Trusted code only can call this method. + currentGlobal.set(global); } /** @@ -195,7 +210,7 @@ public final class Context { * @return error writer of the current context */ public static PrintWriter getCurrentErr() { - final ScriptObject global = getGlobalTrusted(); + final ScriptObject global = getGlobal(); return (global != null)? global.getContext().getErr() : new PrintWriter(System.err); } @@ -348,6 +363,11 @@ public final class Context { this.classPathLoader = null; } + final int cacheSize = env._class_cache_size; + if (cacheSize > 0) { + classCache = new ClassCache(cacheSize); + } + // print version info if asked. if (env._version) { getErr().println("nashorn " + Version.version()); @@ -395,7 +415,7 @@ public final class Context { * @return the property map of the current global scope */ public static PropertyMap getGlobalMap() { - return Context.getGlobalTrusted().getMap(); + return Context.getGlobal().getMap(); } /** @@ -425,7 +445,7 @@ public final class Context { final String file = (location == UNDEFINED || location == null) ? "" : location.toString(); final Source source = new Source(file, string); final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval? - final ScriptObject global = Context.getGlobalTrusted(); + final Global global = Context.getGlobal(); ScriptObject scope = initialScope; @@ -457,7 +477,7 @@ public final class Context { // in the caller's environment. A new environment is created! if (strictFlag) { // Create a new scope object - final ScriptObject strictEvalScope = ((GlobalObject)global).newObject(); + final ScriptObject strictEvalScope = global.newObject(); // bless it as a "scope" strictEvalScope.setIsScope(); @@ -582,10 +602,10 @@ public final class Context { * @throws IOException if source cannot be found or loaded */ public Object loadWithNewGlobal(final Object from, final Object...args) throws IOException { - final ScriptObject oldGlobal = getGlobalTrusted(); - final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction() { + final Global oldGlobal = getGlobal(); + final Global newGlobal = AccessController.doPrivileged(new PrivilegedAction() { @Override - public ScriptObject run() { + public Global run() { try { return newGlobal(); } catch (final RuntimeException e) { @@ -598,17 +618,17 @@ public final class Context { }, CREATE_GLOBAL_ACC_CTXT); // initialize newly created Global instance initGlobal(newGlobal); - setGlobalTrusted(newGlobal); + setGlobal(newGlobal); final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY : ScriptObjectMirror.wrapArray(args, oldGlobal); - newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped), env._strict); + newGlobal.put("arguments", newGlobal.wrapAsObject(wrapped), env._strict); try { // wrap objects from newGlobal's world as mirrors - but if result // is from oldGlobal's world, unwrap it! return ScriptObjectMirror.unwrap(ScriptObjectMirror.wrap(load(newGlobal, from), newGlobal), oldGlobal); } finally { - setGlobalTrusted(oldGlobal); + setGlobal(oldGlobal); } } @@ -637,7 +657,7 @@ public final class Context { * Checks that the given Class can be accessed from no permissions context. * * @param clazz Class object - * @throw SecurityException if not accessible + * @throws SecurityException if not accessible */ public static void checkPackageAccess(final Class clazz) { final SecurityManager sm = System.getSecurityManager(); @@ -654,12 +674,12 @@ public final class Context { * Checks that the given package name can be accessed from no permissions context. * * @param pkgName package name - * @throw SecurityException if not accessible + * @throws SecurityException if not accessible */ public static void checkPackageAccess(final String pkgName) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - checkPackageAccess(sm, pkgName.endsWith(".")? pkgName : pkgName + "."); + checkPackageAccess(sm, pkgName.endsWith(".") ? pkgName : pkgName + "."); } } @@ -783,7 +803,7 @@ public final class Context { * * @return the initialized global scope object. */ - public ScriptObject createGlobal() { + public Global createGlobal() { return initGlobal(newGlobal()); } @@ -791,7 +811,7 @@ public final class Context { * Create a new uninitialized global scope object * @return the global script object */ - public ScriptObject newGlobal() { + public Global newGlobal() { return new Global(this); } @@ -801,20 +821,16 @@ public final class Context { * @param global the global * @return the initialized global scope object. */ - public ScriptObject initGlobal(final ScriptObject global) { - if (! (global instanceof GlobalObject)) { - throw new IllegalArgumentException("not a global object!"); - } - + public Global initGlobal(final Global global) { // Need only minimal global object, if we are just compiling. if (!env._compile_only) { - final ScriptObject oldGlobal = Context.getGlobalTrusted(); + final Global oldGlobal = Context.getGlobal(); try { - Context.setGlobalTrusted(global); + Context.setGlobal(global); // initialize global scope with builtin global objects - ((GlobalObject)global).initBuiltinObjects(); + global.initBuiltinObjects(); } finally { - Context.setGlobalTrusted(oldGlobal); + Context.setGlobal(oldGlobal); } } @@ -822,30 +838,15 @@ public final class Context { } /** - * Trusted variants - package-private + * Trusted variant - package-private */ - /** - * Return the current global scope - * @return current global scope - */ - static ScriptObject getGlobalTrusted() { - return currentGlobal.get(); - } - - /** - * Set the current global scope - */ - static void setGlobalTrusted(ScriptObject global) { - currentGlobal.set(global); - } - /** * Return the current global's context * @return current global's context */ static Context getContextTrusted() { - return Context.getGlobalTrusted().getContext(); + return ((ScriptObject)Context.getGlobal()).getContext(); } /** @@ -914,7 +915,7 @@ public final class Context { } // Package as a JavaScript function and pass function back to shell. - return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict); + return Context.getGlobal().newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict); } private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) { @@ -925,16 +926,10 @@ public final class Context { // start with no errors, no warnings. errMan.reset(); - GlobalObject global = null; - Class script; - - if (env._class_cache_size > 0) { - global = (GlobalObject)Context.getGlobalTrusted(); - script = global.findCachedClass(source); - if (script != null) { - Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile."); - return script; - } + Class script = findCachedClass(source); + if (script != null) { + Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile."); + return script; } final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse(); @@ -963,10 +958,7 @@ public final class Context { final FunctionNode newFunctionNode = compiler.compile(functionNode); script = compiler.install(newFunctionNode); - - if (global != null) { - global.cacheClass(source, script); - } + cacheClass(source, script); return script; } @@ -988,4 +980,60 @@ public final class Context { private long getUniqueScriptId() { return uniqueScriptId.getAndIncrement(); } + + /** + * Cache for compiled script classes. + */ + @SuppressWarnings("serial") + private static class ClassCache extends LinkedHashMap { + private final int size; + private final ReferenceQueue> queue; + + ClassCache(int size) { + super(size, 0.75f, true); + this.size = size; + this.queue = new ReferenceQueue<>(); + } + + void cache(final Source source, final Class clazz) { + put(source, new ClassReference(clazz, queue, source)); + } + + @Override + protected boolean removeEldestEntry(final Map.Entry eldest) { + return size() > size; + } + + @Override + public ClassReference get(Object key) { + for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) { + remove(ref.source); + } + return super.get(key); + } + + } + + private static class ClassReference extends SoftReference> { + private final Source source; + + ClassReference(final Class clazz, final ReferenceQueue> queue, final Source source) { + super(clazz, queue); + this.source = source; + } + } + + // Class cache management + private Class findCachedClass(final Source source) { + ClassReference ref = classCache == null ? null : classCache.get(source); + return ref != null ? ref.get() : null; + } + + private void cacheClass(final Source source, final Class clazz) { + if (classCache != null) { + classCache.cache(source, clazz); + } + } + + } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java b/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java index c288a963321..261bc0200aa 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java @@ -75,7 +75,7 @@ final class DebuggerSupport { * @return context global. */ static Object getGlobal() { - return Context.getGlobalTrusted(); + return Context.getGlobal(); } /** @@ -87,7 +87,7 @@ final class DebuggerSupport { * @return Result of eval as string, or, an exception or null depending on returnException. */ static Object eval(final ScriptObject scope, final Object self, final String string, final boolean returnException) { - final ScriptObject global = Context.getGlobalTrusted(); + final ScriptObject global = Context.getGlobal(); final ScriptObject initialScope = scope != null ? scope : global; final Object callThis = self != null ? self : global; final Context context = global.getContext(); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java b/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java index 754ebbf955f..affba497b18 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java @@ -31,6 +31,7 @@ import java.util.ResourceBundle; import jdk.nashorn.api.scripting.NashornException; import jdk.nashorn.internal.scripts.JS; import jdk.nashorn.internal.codegen.CompilerConstants; +import jdk.nashorn.internal.objects.Global; /** * Helper class to throw various standard "ECMA error" exceptions such as Error, ReferenceError, TypeError etc. @@ -66,7 +67,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException asEcmaException(final ParserException e) { - return asEcmaException(Context.getGlobalTrusted(), e); + return asEcmaException(Context.getGlobal(), e); } /** @@ -78,11 +79,11 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException asEcmaException(final ScriptObject global, final ParserException e) { + public static ECMAException asEcmaException(final Global global, final ParserException e) { final JSErrorType errorType = e.getErrorType(); assert errorType != null : "error type for " + e + " was null"; - final GlobalObject globalObj = (GlobalObject)global; + final Global globalObj = global; final String msg = e.getMessage(); // translate to ECMAScript Error object using error type @@ -116,7 +117,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException syntaxError(final String msgId, final String... args) { - return syntaxError(Context.getGlobalTrusted(), msgId, args); + return syntaxError(Context.getGlobal(), msgId, args); } /** @@ -128,7 +129,7 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException syntaxError(final ScriptObject global, final String msgId, final String... args) { + public static ECMAException syntaxError(final Global global, final String msgId, final String... args) { return syntaxError(global, null, msgId, args); } @@ -142,7 +143,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException syntaxError(final Throwable cause, final String msgId, final String... args) { - return syntaxError(Context.getGlobalTrusted(), cause, msgId, args); + return syntaxError(Context.getGlobal(), cause, msgId, args); } /** @@ -155,9 +156,9 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException syntaxError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) { + public static ECMAException syntaxError(final Global global, final Throwable cause, final String msgId, final String... args) { final String msg = getMessage("syntax.error." + msgId, args); - return error(((GlobalObject)global).newSyntaxError(msg), cause); + return error(global.newSyntaxError(msg), cause); } /** @@ -169,7 +170,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException typeError(final String msgId, final String... args) { - return typeError(Context.getGlobalTrusted(), msgId, args); + return typeError(Context.getGlobal(), msgId, args); } /** @@ -181,7 +182,7 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException typeError(final ScriptObject global, final String msgId, final String... args) { + public static ECMAException typeError(final Global global, final String msgId, final String... args) { return typeError(global, null, msgId, args); } @@ -195,7 +196,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException typeError(final Throwable cause, final String msgId, final String... args) { - return typeError(Context.getGlobalTrusted(), cause, msgId, args); + return typeError(Context.getGlobal(), cause, msgId, args); } /** @@ -208,9 +209,9 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException typeError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) { + public static ECMAException typeError(final Global global, final Throwable cause, final String msgId, final String... args) { final String msg = getMessage("type.error." + msgId, args); - return error(((GlobalObject)global).newTypeError(msg), cause); + return error(global.newTypeError(msg), cause); } /** @@ -222,7 +223,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException rangeError(final String msgId, final String... args) { - return rangeError(Context.getGlobalTrusted(), msgId, args); + return rangeError(Context.getGlobal(), msgId, args); } /** @@ -234,7 +235,7 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException rangeError(final ScriptObject global, final String msgId, final String... args) { + public static ECMAException rangeError(final Global global, final String msgId, final String... args) { return rangeError(global, null, msgId, args); } @@ -248,7 +249,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException rangeError(final Throwable cause, final String msgId, final String... args) { - return rangeError(Context.getGlobalTrusted(), cause, msgId, args); + return rangeError(Context.getGlobal(), cause, msgId, args); } /** @@ -261,9 +262,9 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException rangeError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) { + public static ECMAException rangeError(final Global global, final Throwable cause, final String msgId, final String... args) { final String msg = getMessage("range.error." + msgId, args); - return error(((GlobalObject)global).newRangeError(msg), cause); + return error(global.newRangeError(msg), cause); } /** @@ -275,7 +276,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException referenceError(final String msgId, final String... args) { - return referenceError(Context.getGlobalTrusted(), msgId, args); + return referenceError(Context.getGlobal(), msgId, args); } /** @@ -287,7 +288,7 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException referenceError(final ScriptObject global, final String msgId, final String... args) { + public static ECMAException referenceError(final Global global, final String msgId, final String... args) { return referenceError(global, null, msgId, args); } @@ -301,7 +302,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException referenceError(final Throwable cause, final String msgId, final String... args) { - return referenceError(Context.getGlobalTrusted(), cause, msgId, args); + return referenceError(Context.getGlobal(), cause, msgId, args); } /** @@ -314,9 +315,9 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException referenceError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) { + public static ECMAException referenceError(final Global global, final Throwable cause, final String msgId, final String... args) { final String msg = getMessage("reference.error." + msgId, args); - return error(((GlobalObject)global).newReferenceError(msg), cause); + return error(global.newReferenceError(msg), cause); } /** @@ -328,7 +329,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException uriError(final String msgId, final String... args) { - return uriError(Context.getGlobalTrusted(), msgId, args); + return uriError(Context.getGlobal(), msgId, args); } /** @@ -340,7 +341,7 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException uriError(final ScriptObject global, final String msgId, final String... args) { + public static ECMAException uriError(final Global global, final String msgId, final String... args) { return uriError(global, null, msgId, args); } @@ -354,7 +355,7 @@ public final class ECMAErrors { * @return the resulting {@link ECMAException} */ public static ECMAException uriError(final Throwable cause, final String msgId, final String... args) { - return uriError(Context.getGlobalTrusted(), cause, msgId, args); + return uriError(Context.getGlobal(), cause, msgId, args); } /** @@ -367,9 +368,9 @@ public final class ECMAErrors { * * @return the resulting {@link ECMAException} */ - public static ECMAException uriError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) { + public static ECMAException uriError(final Global global, final Throwable cause, final String msgId, final String... args) { final String msg = getMessage("uri.error." + msgId, args); - return error(((GlobalObject)global).newURIError(msg), cause); + return error(global.newURIError(msg), cause); } /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java index c7a410ea821..f16cf41c3ab 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java @@ -38,31 +38,27 @@ final class FinalScriptFunctionData extends ScriptFunctionData { /** * Constructor - used for bind * - * @param name name - * @param arity arity - * @param functions precompiled code - * @param isStrict strict - * @param isBuiltin builtin - * @param isConstructor constructor + * @param name name + * @param arity arity + * @param functions precompiled code + * @param flags {@link ScriptFunctionData} flags */ - FinalScriptFunctionData(final String name, int arity, CompiledFunctions functions, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { - super(name, arity, isStrict, isBuiltin, isConstructor); + FinalScriptFunctionData(final String name, final int arity, final CompiledFunctions functions, final int flags) { + super(name, arity, flags); code.addAll(functions); } /** - * Constructor - used from ScriptFunction. This assumes that we have code alraedy for the + * Constructor - used from ScriptFunction. This assumes that we have code already for the * method (typically a native method) and possibly specializations. * - * @param name name - * @param mh method handle for generic version of method - * @param specs specializations - * @param isStrict strict - * @param isBuiltin builtin - * @param isConstructor constructor + * @param name name + * @param mh method handle for generic version of method + * @param specs specializations + * @param flags {@link ScriptFunctionData} flags */ - FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { - super(name, arity(mh), isStrict, isBuiltin, isConstructor); + FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final int flags) { + super(name, arity(mh), flags); addInvoker(mh); if (specs != null) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java deleted file mode 100644 index 3779f3bda9c..00000000000 --- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.runtime; - -import java.lang.invoke.MethodHandle; -import java.util.concurrent.Callable; -import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.linker.LinkRequest; -import jdk.nashorn.internal.runtime.linker.InvokeByName; - -/** - * Runtime interface to the global scope objects. - */ - -public interface GlobalObject { - /** - * Is this global of the given Context? - * @param ctxt the context - * @return true if this global belongs to the given Context - */ - public boolean isOfContext(final Context ctxt); - - /** - * Does this global belong to a strict Context? - * @return true if this global belongs to a strict Context - */ - public boolean isStrictContext(); - - /** - * Initialize standard builtin objects like "Object", "Array", "Function" etc. - * as well as our extension builtin objects like "Java", "JSAdapter" as properties - * of the global scope object. - */ - public void initBuiltinObjects(); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newScriptFunction(String, MethodHandle, ScriptObject, boolean)} - * - * @param name function name - * @param handle invocation handle for function - * @param scope the scope - * @param strict are we in strict mode - * - * @return new script function - */ - public ScriptFunction newScriptFunction(String name, MethodHandle handle, ScriptObject scope, boolean strict); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#wrapAsObject(Object)} - * - * @param obj object to wrap - * @return wrapped object - */ - public Object wrapAsObject(Object obj); - - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#primitiveLookup(LinkRequest, Object)} - * - * @param request the link request for the dynamic call site. - * @param self self reference - * - * @return guarded invocation - */ - public GuardedInvocation primitiveLookup(LinkRequest request, Object self); - - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newObject()} - * - * @return the new ScriptObject - */ - public ScriptObject newObject(); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#isError(ScriptObject)} - * - * @param sobj to check if it is an error object - * @return true if error object - */ - public boolean isError(ScriptObject sobj); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newError(String)} - * - * @param msg the error message - * - * @return the new ScriptObject representing the error - */ - public ScriptObject newError(String msg); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newEvalError(String)} - * - * @param msg the error message - * - * @return the new ScriptObject representing the eval error - */ - public ScriptObject newEvalError(String msg); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newRangeError(String)} - * - * @param msg the error message - * - * @return the new ScriptObject representing the range error - */ - public ScriptObject newRangeError(String msg); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newReferenceError(String)} - * - * @param msg the error message - * - * @return the new ScriptObject representing the reference error - */ - public ScriptObject newReferenceError(String msg); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newSyntaxError(String)} - * - * @param msg the error message - * - * @return the new ScriptObject representing the syntax error - */ - public ScriptObject newSyntaxError(String msg); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newTypeError(String)} - * - * @param msg the error message - * - * @return the new ScriptObject representing the type error - */ - public ScriptObject newTypeError(String msg); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newURIError(String)} - * - * @param msg the error message - * - * @return the new ScriptObject representing the URI error - */ - public ScriptObject newURIError(String msg); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newGenericDescriptor(boolean, boolean)} - * - * @param configurable is the described property configurable - * @param enumerable is the described property enumerable - * - * @return property descriptor - */ - public PropertyDescriptor newGenericDescriptor(boolean configurable, boolean enumerable); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newDataDescriptor(Object, boolean, boolean, boolean)} - * - * @param value data value - * @param configurable is the described property configurable - * @param enumerable is the described property enumerable - * @param writable is the described property writable - * - * @return property descriptor - */ - public PropertyDescriptor newDataDescriptor(Object value, boolean configurable, boolean enumerable, boolean writable); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#newAccessorDescriptor(Object, Object, boolean, boolean)} - * - * @param get property getter, or null if none - * @param set property setter, or null if none - * @param configurable is the described property configurable - * @param enumerable is the described property enumerable - * - * @return property descriptor - */ - public PropertyDescriptor newAccessorDescriptor(Object get, Object set, boolean configurable, boolean enumerable); - - /** - * Wrapper for {@link jdk.nashorn.internal.objects.Global#getDefaultValue(ScriptObject, Class)} - * - * @param sobj script object - * @param typeHint type hint - * - * @return default value - */ - public Object getDefaultValue(ScriptObject sobj, Class typeHint); - - /** - * Find the compiled Class for the given script source, if available - * - * @param source Source object of the script - * @return compiled Class object or null - */ - public Class findCachedClass(Source source); - - /** - * Put the Source associated Class object in the Source-to-Class cache - * - * @param source Source of the script - * @param clazz compiled Class object for the source - */ - public void cacheClass(Source source, Class clazz); - - /** - * Get cached InvokeByName object for the given key - * @param key key to be associated with InvokeByName object - * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init) - * @return InvokeByName object associated with the key. - */ - public InvokeByName getInvokeByName(final Object key, final Callable creator); - - /** - * Get cached dynamic method handle for the given key - * @param key key to be associated with dynamic method handle - * @param creator if method handle is absent 'creator' is called to make one (lazy init) - * @return dynamic method handle associated with the key. - */ - public MethodHandle getDynamicInvoker(final Object key, final Callable creator); -} diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java index 73552cb10df..64863184759 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java @@ -33,6 +33,7 @@ import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; import jdk.nashorn.internal.ir.PropertyNode; import jdk.nashorn.internal.ir.UnaryNode; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.parser.JSONParser; import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.runtime.arrays.ArrayIndex; @@ -47,7 +48,7 @@ public final class JSONFunctions { private static final Object REVIVER_INVOKER = new Object(); private static MethodHandle getREVIVER_INVOKER() { - return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(REVIVER_INVOKER, + return Context.getGlobal().getDynamicInvoker(REVIVER_INVOKER, new Callable() { @Override public MethodHandle call() { @@ -88,7 +89,7 @@ public final class JSONFunctions { throw ECMAErrors.syntaxError(e, "invalid.json", e.getMessage()); } - final ScriptObject global = Context.getGlobalTrusted(); + final Global global = Context.getGlobal(); Object unfiltered = convertNode(global, node); return applyReviver(global, unfiltered, reviver); } @@ -98,10 +99,10 @@ public final class JSONFunctions { // parse helpers // apply 'reviver' function if available - private static Object applyReviver(final ScriptObject global, final Object unfiltered, final Object reviver) { + private static Object applyReviver(final Global global, final Object unfiltered, final Object reviver) { if (reviver instanceof ScriptFunction) { - assert global instanceof GlobalObject; - final ScriptObject root = ((GlobalObject)global).newObject(); + assert global instanceof Global; + final ScriptObject root = global.newObject(); root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered); return walk(root, "", (ScriptFunction)reviver); } @@ -138,8 +139,8 @@ public final class JSONFunctions { } // Converts IR node to runtime value - private static Object convertNode(final ScriptObject global, final Node node) { - assert global instanceof GlobalObject; + private static Object convertNode(final Global global, final Node node) { + assert global instanceof Global; if (node instanceof LiteralNode) { // check for array literal @@ -157,7 +158,7 @@ public final class JSONFunctions { for (final Node elem : elements) { values[index++] = JSType.toNumber(convertNode(global, elem)); } - return ((GlobalObject)global).wrapAsObject(values); + return global.wrapAsObject(values); } final Object[] values = new Object[elements.length]; @@ -167,14 +168,14 @@ public final class JSONFunctions { values[index++] = convertNode(global, elem); } - return ((GlobalObject)global).wrapAsObject(values); + return global.wrapAsObject(values); } return ((LiteralNode)node).getValue(); } else if (node instanceof ObjectNode) { final ObjectNode objNode = (ObjectNode) node; - final ScriptObject object = ((GlobalObject)global).newObject(); + final ScriptObject object = global.newObject(); for (final PropertyNode pNode: objNode.getElements()) { final Node valueNode = pNode.getValue(); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java index 541301960c9..c49de9cf4e6 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java @@ -36,6 +36,7 @@ import java.util.List; import jdk.internal.dynalink.beans.StaticClass; import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.internal.codegen.CompilerConstants.Call; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.parser.Lexer; import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; import jdk.nashorn.internal.runtime.linker.Bootstrap; @@ -852,7 +853,7 @@ public enum JSType { * @return the wrapped object */ public static Object toScriptObject(final Object obj) { - return toScriptObject(Context.getGlobalTrusted(), obj); + return toScriptObject(Context.getGlobal(), obj); } /** @@ -865,7 +866,7 @@ public enum JSType { * * @return the wrapped object */ - public static Object toScriptObject(final ScriptObject global, final Object obj) { + public static Object toScriptObject(final Global global, final Object obj) { if (nullOrUndefined(obj)) { throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj)); } @@ -874,7 +875,7 @@ public enum JSType { return obj; } - return ((GlobalObject)global).wrapAsObject(obj); + return global.wrapAsObject(obj); } /** @@ -984,7 +985,7 @@ public enum JSType { if (obj instanceof ScriptObject) { if (safe) { final ScriptObject sobj = (ScriptObject)obj; - final GlobalObject gobj = (GlobalObject)Context.getGlobalTrusted(); + final Global gobj = Context.getGlobal(); return gobj.isError(sobj) ? ECMAException.safeToString(sobj) : sobj.safeToString(); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java index 26c22c390b9..9a3408fbbd6 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java @@ -34,6 +34,7 @@ import java.util.RandomAccess; import java.util.concurrent.Callable; import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.api.scripting.ScriptObjectMirror; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; @@ -54,7 +55,7 @@ public abstract class ListAdapter extends AbstractList implements Random // These add to the back and front of the list private static final Object PUSH = new Object(); private static InvokeByName getPUSH() { - return ((GlobalObject)Context.getGlobal()).getInvokeByName(PUSH, + return Context.getGlobal().getInvokeByName(PUSH, new Callable() { @Override public InvokeByName call() { @@ -65,7 +66,7 @@ public abstract class ListAdapter extends AbstractList implements Random private static final Object UNSHIFT = new Object(); private static InvokeByName getUNSHIFT() { - return ((GlobalObject)Context.getGlobal()).getInvokeByName(UNSHIFT, + return Context.getGlobal().getInvokeByName(UNSHIFT, new Callable() { @Override public InvokeByName call() { @@ -77,7 +78,7 @@ public abstract class ListAdapter extends AbstractList implements Random // These remove from the back and front of the list private static final Object POP = new Object(); private static InvokeByName getPOP() { - return ((GlobalObject)Context.getGlobal()).getInvokeByName(POP, + return Context.getGlobal().getInvokeByName(POP, new Callable() { @Override public InvokeByName call() { @@ -88,7 +89,7 @@ public abstract class ListAdapter extends AbstractList implements Random private static final Object SHIFT = new Object(); private static InvokeByName getSHIFT() { - return ((GlobalObject)Context.getGlobal()).getInvokeByName(SHIFT, + return Context.getGlobal().getInvokeByName(SHIFT, new Callable() { @Override public InvokeByName call() { @@ -100,7 +101,7 @@ public abstract class ListAdapter extends AbstractList implements Random // These insert and remove in the middle of the list private static final Object SPLICE_ADD = new Object(); private static InvokeByName getSPLICE_ADD() { - return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_ADD, + return Context.getGlobal().getInvokeByName(SPLICE_ADD, new Callable() { @Override public InvokeByName call() { @@ -111,7 +112,7 @@ public abstract class ListAdapter extends AbstractList implements Random private static final Object SPLICE_REMOVE = new Object(); private static InvokeByName getSPLICE_REMOVE() { - return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_REMOVE, + return Context.getGlobal().getInvokeByName(SPLICE_REMOVE, new Callable() { @Override public InvokeByName call() { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java index 591fd327c64..fbca1c340bd 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java @@ -35,7 +35,6 @@ import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.support.Guards; import jdk.nashorn.internal.lookup.MethodHandleFactory; import jdk.nashorn.internal.lookup.MethodHandleFunctionality; -import jdk.nashorn.internal.objects.NativeJava; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Function; @@ -52,7 +51,7 @@ import jdk.nashorn.internal.objects.annotations.Function; * var ArrayList = java.util.ArrayList * var list = new ArrayList * - * You can also use {@link NativeJava#type(Object, Object)} to access Java classes. These two statements are mostly + * You can also use {@link jdk.nashorn.internal.objects.NativeJava#type(Object, Object)} to access Java classes. These two statements are mostly * equivalent: *
        * var listType1 = java.util.ArrayList
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java b/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java
      index 2424bc3f1be..5137d596ee7 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java
      @@ -26,6 +26,7 @@
       package jdk.nashorn.internal.runtime;
       
       import jdk.nashorn.api.scripting.NashornException;
      +import jdk.nashorn.internal.objects.Global;
       import jdk.nashorn.internal.parser.Token;
       
       /**
      @@ -110,7 +111,7 @@ public final class ParserException extends NashornException {
            * Throw this {@code ParserException} as one of the 7 native JavaScript errors
            * @param global global scope object
            */
      -    public void throwAsEcmaException(final ScriptObject global) {
      +    public void throwAsEcmaException(final Global global) {
               throw ECMAErrors.asEcmaException(global, this);
           }
       }
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Property.java b/nashorn/src/jdk/nashorn/internal/runtime/Property.java
      index d1dbe2adb4b..885fa712a13 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java
      @@ -84,9 +84,13 @@ public abstract class Property {
           /** Can this property be undefined? */
           public static final int CAN_BE_UNDEFINED = 1 << 8;
       
      -    /* Is this a function declaration property ? */
      +    /** Is this a function declaration property ? */
           public static final int IS_FUNCTION_DECLARATION = 1 << 9;
       
      +    /** Is this property bound to a receiver? This means get/set operations will be delegated to
      +     *  a statically defined object instead of the object passed as callsite parameter. */
      +    public static final int IS_BOUND = 1 << 10;
      +
           /** Property key. */
           private final String key;
       
      @@ -251,6 +255,16 @@ public abstract class Property {
               return (flags & IS_SPILL) == IS_SPILL;
           }
       
      +    /**
      +     * Is this property bound to a receiver? If this method returns {@code true} get and set operations
      +     * will be delegated to a statically bound object instead of the object passed as parameter.
      +     *
      +     * @return true if this is a bound property
      +     */
      +    public boolean isBound() {
      +        return (flags & IS_BOUND) == IS_BOUND;
      +    }
      +
           /**
            * Does this property use any slots in the spill array described in
            * {@link Property#isSpill}? In that case how many. Currently a property
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
      index 2b18cbc87b6..7e1a516aa6d 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
      @@ -103,9 +103,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
           public RecompilableScriptFunctionData(final FunctionNode functionNode, final CodeInstaller installer, final String allocatorClassName, final PropertyMap allocatorMap) {
               super(functionName(functionNode),
                     functionNode.getParameters().size(),
      -              functionNode.isStrict(),
      -              false,
      -              true);
      +              getFlags(functionNode));
       
               this.functionNode       = functionNode;
               this.source             = functionNode.getSource();
      @@ -129,10 +127,11 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
               final StringBuilder sb = new StringBuilder();
       
               if (source != null) {
      -            sb.append(source.getName())
      -                .append(':')
      -                .append(functionNode.getLineNumber())
      -                .append(' ');
      +            sb.append(source.getName());
      +            if (functionNode != null) {
      +                sb.append(':').append(functionNode.getLineNumber());
      +            }
      +            sb.append(' ');
               }
       
               return sb.toString() + super.toString();
      @@ -159,6 +158,20 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
               return Token.toDesc(TokenType.FUNCTION, position, length);
           }
       
      +    private static int getFlags(final FunctionNode functionNode) {
      +        int flags = IS_CONSTRUCTOR;
      +        if (functionNode.isStrict()) {
      +            flags |= IS_STRICT;
      +        }
      +        if (functionNode.needsCallee()) {
      +            flags |= NEEDS_CALLEE;
      +        }
      +        if (functionNode.usesThis() || functionNode.hasEval()) {
      +            flags |= USES_THIS;
      +        }
      +        return flags;
      +    }
      +
           @Override
           ScriptObject allocate(final PropertyMap map) {
               try {
      @@ -182,41 +195,42 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
               return allocatorMap;
           }
       
      +
      +    @Override
      +    protected void ensureCompiled() {
      +        if (functionNode != null && functionNode.isLazy()) {
      +            Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
      +            final Compiler compiler = new Compiler(installer);
      +            functionNode = compiler.compile(functionNode);
      +            assert !functionNode.isLazy();
      +            compiler.install(functionNode);
      +            flags = getFlags(functionNode);
      +        }
      +    }
      +
           @Override
           protected synchronized void ensureCodeGenerated() {
      -         if (!code.isEmpty()) {
      -             return; // nothing to do, we have code, at least some.
      -         }
      +        if (!code.isEmpty()) {
      +            return; // nothing to do, we have code, at least some.
      +        }
       
      -         if (functionNode.isLazy()) {
      -             Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
      -             final Compiler compiler = new Compiler(installer);
      -             functionNode = compiler.compile(functionNode);
      -             assert !functionNode.isLazy();
      -             compiler.install(functionNode);
      +        ensureCompiled();
       
      -             /*
      -              * We don't need to update any flags - varArgs and needsCallee are instrincic
      -              * in the function world we need to get a destination node from the compile instead
      -              * and replace it with our function node. TODO
      -              */
      -         }
      +        /*
      +         * We can't get to this program point unless we have bytecode, either from
      +         * eager compilation or from running a lazy compile on the lines above
      +         */
       
      -         /*
      -          * We can't get to this program point unless we have bytecode, either from
      -          * 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.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);
       
      -         // code exists - look it up and add it into the automatically sorted invoker list
      -         addCode(functionNode);
      -
      -         if (! functionNode.canSpecialize()) {
      -             // allow GC to claim IR stuff that is not needed anymore
      -             functionNode = null;
      -             installer = null;
      -         }
      +        if (! functionNode.canSpecialize()) {
      +            // allow GC to claim IR stuff that is not needed anymore
      +            functionNode = null;
      +            installer = null;
      +        }
           }
       
           private MethodHandle addCode(final FunctionNode fn) {
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
      index 0f5174ea15b..3d8b4ff288b 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
      @@ -38,6 +38,7 @@ import jdk.internal.dynalink.linker.GuardedInvocation;
       import jdk.internal.dynalink.linker.LinkRequest;
       import jdk.nashorn.internal.codegen.CompilerConstants.Call;
       import jdk.nashorn.internal.lookup.MethodHandleFactory;
      +import jdk.nashorn.internal.objects.Global;
       import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
       import jdk.nashorn.internal.runtime.linker.NashornGuards;
       
      @@ -66,6 +67,8 @@ public abstract class ScriptFunction extends ScriptObject {
       
           private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
       
      +    private static final MethodHandle GLOBALFILTER = findOwnMH("globalFilter", Object.class, Object.class);
      +
           /** method handle to scope getter for this ScriptFunction */
           public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
       
      @@ -91,9 +94,7 @@ public abstract class ScriptFunction extends ScriptObject {
            * @param map           property map
            * @param scope         scope
            * @param specs         specialized version of this function - other method handles
      -     * @param strict        is this a strict mode function?
      -     * @param builtin       is this a built in function?
      -     * @param isConstructor is this a constructor?
      +     * @param flags         {@link ScriptFunctionData} flags
            */
           protected ScriptFunction(
                   final String name,
      @@ -101,11 +102,9 @@ public abstract class ScriptFunction extends ScriptObject {
                   final PropertyMap map,
                   final ScriptObject scope,
                   final MethodHandle[] specs,
      -            final boolean strict,
      -            final boolean builtin,
      -            final boolean isConstructor) {
      +            final int flags) {
       
      -        this(new FinalScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope);
      +        this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
           }
       
           /**
      @@ -477,7 +476,14 @@ public abstract class ScriptFunction extends ScriptObject {
               if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
                   return obj;
               }
      -        return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(obj);
      +        return Context.getGlobal().wrapAsObject(obj);
      +    }
      +
      +
      +    @SuppressWarnings("unused")
      +    private static Object globalFilter(final Object object) {
      +        // replace whatever we get with the current global object
      +        return Context.getGlobal();
           }
       
           /**
      @@ -495,11 +501,11 @@ public abstract class ScriptFunction extends ScriptObject {
           @Override
           protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
               final MethodType type = desc.getMethodType();
      +        final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
       
               if (request.isCallSiteUnstable()) {
      -            // (this, callee, args...) => (this, callee, args[])
      -            final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class,
      -                    type.parameterCount() - 2);
      +            // (callee, this, args...) => (callee, this, args[])
      +            final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2);
       
                   // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a
                   // generic "is this a ScriptFunction?" guard.
      @@ -510,17 +516,12 @@ public abstract class ScriptFunction extends ScriptObject {
               MethodHandle boundHandle;
               MethodHandle guard = null;
       
      -        final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
      -
               if (data.needsCallee()) {
                   final MethodHandle callHandle = getBestInvoker(type, request.getArguments());
      -            if (scopeCall) {
      +            if (scopeCall && needsWrappedThis()) {
                       // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
      -                // (callee, this, args...) => (callee, args...)
      -                boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
      -                // (callee, args...) => (callee, [this], args...)
      -                boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
      -
      +                // (callee, this, args...) => (callee, [this], args...)
      +                boundHandle = MH.filterArguments(callHandle, 1, GLOBALFILTER);
                   } else {
                       // It's already (callee, this, args...), just what we need
                       boundHandle = callHandle;
      @@ -531,12 +532,12 @@ public abstract class ScriptFunction extends ScriptObject {
                       // NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
                       // current lookup as its "this" so it can do security-sensitive creation of adapter classes.
                       boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, Object.class, Object.class);
      -            } else if (scopeCall) {
      +            } else if (scopeCall && needsWrappedThis()) {
                       // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
      -                // (this, args...) => (args...)
      -                boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
      -                // (args...) => ([callee], [this], args...)
      -                boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class);
      +                // (this, args...) => ([this], args...)
      +                boundHandle = MH.filterArguments(callHandle, 0, GLOBALFILTER);
      +                // ([this], args...) => ([callee], [this], args...)
      +                boundHandle = MH.dropArguments(boundHandle, 0, Object.class);
                   } else {
                       // (this, args...) => ([callee], this, args...)
                       boundHandle = MH.dropArguments(callHandle, 0, Object.class);
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
      index f0569937dd0..aee367d65ba 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
      @@ -32,6 +32,7 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
       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;
       
       /**
      @@ -47,33 +48,44 @@ public abstract class ScriptFunctionData {
           /** All versions of this function that have been generated to code */
           protected final CompiledFunctions code;
       
      +    /** Function flags */
      +    protected int flags;
      +
           private int arity;
       
      -    private final boolean isStrict;
      -
      -    private final boolean isBuiltin;
      -
      -    private final boolean isConstructor;
      -
           private static final MethodHandle NEWFILTER     = findOwnMH("newFilter", Object.class, Object.class, Object.class);
           private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
       
      +    /** Is this a strict mode function? */
      +    public static final int IS_STRICT      = 1 << 0;
      +    /** Is this a built-in function? */
      +    public static final int IS_BUILTIN     = 1 << 1;
      +    /** Is this a constructor function? */
      +    public static final int IS_CONSTRUCTOR = 1 << 2;
      +    /** Does this function expect a callee argument? */
      +    public static final int NEEDS_CALLEE   = 1 << 3;
      +    /** Does this function make use of the this-object argument? */
      +    public static final int USES_THIS      = 1 << 4;
      +
      +    /** Flag for strict or built-in functions */
      +    public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN;
      +    /** Flag for built-in constructors */
      +    public static final int IS_BUILTIN_CONSTRUCTOR = IS_BUILTIN | IS_CONSTRUCTOR;
      +    /** Flag for strict constructors */
      +    public static final int IS_STRICT_CONSTRUCTOR = IS_STRICT | IS_CONSTRUCTOR;
      +
           /**
            * Constructor
            *
            * @param name          script function name
            * @param arity         arity
      -     * @param isStrict      is the function strict
      -     * @param isBuiltin     is the function built in
      -     * @param isConstructor is the function a constructor
      +     * @param flags         the function flags
            */
      -    ScriptFunctionData(final String name, final int arity, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
      -        this.name          = name;
      -        this.arity         = arity;
      -        this.code          = new CompiledFunctions();
      -        this.isStrict      = isStrict;
      -        this.isBuiltin     = isBuiltin;
      -        this.isConstructor = isConstructor;
      +    ScriptFunctionData(final String name, final int arity, final int flags) {
      +        this.name  = name;
      +        this.arity = arity;
      +        this.code  = new CompiledFunctions();
      +        this.flags = flags;
           }
       
           final int getArity() {
      @@ -105,21 +117,21 @@ public abstract class ScriptFunctionData {
            * @return true if strict, false otherwise
            */
           public boolean isStrict() {
      -        return isStrict;
      +        return (flags & IS_STRICT) != 0;
           }
       
           boolean isBuiltin() {
      -        return isBuiltin;
      +        return (flags & IS_BUILTIN) != 0;
           }
       
           boolean isConstructor() {
      -        return isConstructor;
      +        return (flags & IS_CONSTRUCTOR) != 0;
           }
       
           boolean needsCallee() {
      -        // we don't know if we need a callee or not unless we are generated
      -        ensureCodeGenerated();
      -        return code.needsCallee();
      +        // we don't know if we need a callee or not unless code has been compiled
      +        ensureCompiled();
      +        return (flags & NEEDS_CALLEE) != 0;
           }
       
           /**
      @@ -128,7 +140,7 @@ public abstract class ScriptFunctionData {
            * @return true if this argument must be an object
            */
           boolean needsWrappedThis() {
      -        return !isStrict && !isBuiltin;
      +        return (flags & USES_THIS) != 0 && (flags & IS_STRICT_OR_BUILTIN) == 0;
           }
       
           String toSource() {
      @@ -201,6 +213,15 @@ public abstract class ScriptFunctionData {
               //empty
           }
       
      +    /**
      +     * If we can have lazy code generation, this is a hook to ensure that the code has been compiled.
      +     * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance;
      +     * use {@link #ensureCodeGenerated()} to install the actual method handles.
      +     */
      +    protected void ensureCompiled() {
      +        //empty
      +    }
      +
           /**
            * Return a generic Object/Object invoker for this method. It will ensure code
            * is generated, get the most generic of all versions of this function and adapt it
      @@ -259,6 +280,8 @@ public abstract class ScriptFunctionData {
       
               final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
               final int length = args == null ? 0 : args.length;
      +        // Clear the callee and this flags
      +        final int boundFlags = flags & ~NEEDS_CALLEE & ~USES_THIS;
       
               CompiledFunctions boundList = new CompiledFunctions();
               if (code.size() == 1) {
      @@ -273,8 +296,7 @@ public abstract class ScriptFunctionData {
                   boundList.add(bind(inv, fn, self, allArgs));
               }
       
      -        ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor());
      -        return boundData;
      +        return new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, boundFlags);
           }
       
           /**
      @@ -351,11 +373,11 @@ public abstract class ScriptFunctionData {
           private Object convertThisObject(final Object thiz) {
               if (!(thiz instanceof ScriptObject) && needsWrappedThis()) {
                   if (JSType.nullOrUndefined(thiz)) {
      -                return Context.getGlobalTrusted();
      +                return Context.getGlobal();
                   }
       
                   if (isPrimitiveThis(thiz)) {
      -                return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz);
      +                return Context.getGlobal().wrapAsObject(thiz);
                   }
               }
       
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
      index b7f9c4c1ed0..05e236e3bd6 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
      @@ -66,6 +66,7 @@ import jdk.nashorn.internal.lookup.Lookup;
       import jdk.nashorn.internal.lookup.MethodHandleFactory;
       import jdk.nashorn.internal.objects.AccessorPropertyDescriptor;
       import jdk.nashorn.internal.objects.DataPropertyDescriptor;
      +import jdk.nashorn.internal.objects.Global;
       import jdk.nashorn.internal.runtime.arrays.ArrayData;
       import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
       import jdk.nashorn.internal.runtime.linker.Bootstrap;
      @@ -131,7 +132,8 @@ public abstract class ScriptObject implements PropertyAccess {
       
           static final MethodHandle GETPROTO           = findOwnMH("getProto", ScriptObject.class);
           static final MethodHandle SETPROTOCHECK      = findOwnMH("setProtoCheck", void.class, Object.class);
      -    static final MethodHandle MEGAMORPHIC_GET    = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class);
      +    static final MethodHandle MEGAMORPHIC_GET    = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class, boolean.class);
      +    static final MethodHandle GLOBALFILTER       = findOwnMH("globalFilter", Object.class, Object.class);
       
           static final MethodHandle SETFIELD           = findOwnMH("setField",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
           static final MethodHandle SETSPILL           = findOwnMH("setSpill",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
      @@ -225,6 +227,7 @@ public abstract class ScriptObject implements PropertyAccess {
                   final Property oldProp = newMap.findProperty(key);
                   if (oldProp == null) {
                       if (property instanceof UserAccessorProperty) {
      +                    // Note: we copy accessor functions to this object which is semantically different from binding.
                           final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source));
                           newMap = newMap.addPropertyNoHistory(prop);
                       } else {
      @@ -322,18 +325,18 @@ public abstract class ScriptObject implements PropertyAccess {
             * @return property descriptor
             */
           public final PropertyDescriptor toPropertyDescriptor() {
      -        final GlobalObject global = (GlobalObject) Context.getGlobalTrusted();
      +        final Global global = Context.getGlobal();
       
               final PropertyDescriptor desc;
               if (isDataDescriptor()) {
                   if (has(SET) || has(GET)) {
      -                throw typeError((ScriptObject)global, "inconsistent.property.descriptor");
      +                throw typeError(global, "inconsistent.property.descriptor");
                   }
       
                   desc = global.newDataDescriptor(UNDEFINED, false, false, false);
               } else if (isAccessorDescriptor()) {
                   if (has(VALUE) || has(WRITABLE)) {
      -                throw typeError((ScriptObject)global, "inconsistent.property.descriptor");
      +                throw typeError(global, "inconsistent.property.descriptor");
                   }
       
                   desc = global.newAccessorDescriptor(UNDEFINED, UNDEFINED, false, false);
      @@ -352,7 +355,7 @@ public abstract class ScriptObject implements PropertyAccess {
            *
            * @return property descriptor
            */
      -    public static PropertyDescriptor toPropertyDescriptor(final ScriptObject global, final Object obj) {
      +    public static PropertyDescriptor toPropertyDescriptor(final Global global, final Object obj) {
               if (obj instanceof ScriptObject) {
                   return ((ScriptObject)obj).toPropertyDescriptor();
               }
      @@ -371,7 +374,7 @@ public abstract class ScriptObject implements PropertyAccess {
           public Object getOwnPropertyDescriptor(final String key) {
               final Property property = getMap().findProperty(key);
       
      -        final GlobalObject global = (GlobalObject)Context.getGlobalTrusted();
      +        final Global global = Context.getGlobal();
       
               if (property != null) {
                   final ScriptFunction get   = property.getGetterFunction(this);
      @@ -436,7 +439,7 @@ public abstract class ScriptObject implements PropertyAccess {
            * @return true if property was successfully defined
            */
           public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
      -        final ScriptObject       global  = Context.getGlobalTrusted();
      +        final Global             global  = Context.getGlobal();
               final PropertyDescriptor desc    = toPropertyDescriptor(global, propertyDesc);
               final Object             current = getOwnPropertyDescriptor(key);
               final String             name    = JSType.toString(key);
      @@ -634,7 +637,7 @@ public abstract class ScriptObject implements PropertyAccess {
               final int propFlags = Property.toFlags(pdesc);
       
               if (pdesc.type() == PropertyDescriptor.GENERIC) {
      -            final GlobalObject global = (GlobalObject) Context.getGlobalTrusted();
      +            final Global global = Context.getGlobal();
                   final PropertyDescriptor dDesc = global.newDataDescriptor(UNDEFINED, false, false, false);
       
                   dDesc.fillFrom((ScriptObject)pdesc);
      @@ -974,17 +977,6 @@ public abstract class ScriptObject implements PropertyAccess {
               return ObjectClassGenerator.UNDEFINED_DOUBLE;
           }
       
      -    /**
      -      * Get the object value of a property
      -      *
      -      * @param find {@link FindProperty} lookup result
      -      *
      -      * @return the value of the property
      -      */
      -    protected static Object getObjectValue(final FindProperty find) {
      -        return find.getObjectValue();
      -    }
      -
           /**
            * Return methodHandle of value function for call.
            *
      @@ -995,7 +987,7 @@ public abstract class ScriptObject implements PropertyAccess {
            * @return value of property as a MethodHandle or null.
            */
           protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
      -        return getCallMethodHandle(getObjectValue(find), type, bindName);
      +        return getCallMethodHandle(find.getObjectValue(), type, bindName);
           }
       
           /**
      @@ -1019,7 +1011,7 @@ public abstract class ScriptObject implements PropertyAccess {
            * @return Value of property.
            */
           public final Object getWithProperty(final Property property) {
      -        return getObjectValue(new FindProperty(this, this, property));
      +        return new FindProperty(this, this, property).getObjectValue();
           }
       
           /**
      @@ -1158,7 +1150,7 @@ public abstract class ScriptObject implements PropertyAccess {
                   }
                   setProto((ScriptObject)newProto);
               } else {
      -            final ScriptObject global = Context.getGlobalTrusted();
      +            final Global global = Context.getGlobal();
                   final Object  newProtoObject = JSType.toScriptObject(global, newProto);
       
                   if (newProtoObject instanceof ScriptObject) {
      @@ -1248,11 +1240,11 @@ public abstract class ScriptObject implements PropertyAccess {
            * @return the default value
            */
           public Object getDefaultValue(final Class typeHint) {
      -        // We delegate to GlobalObject, as the implementation uses dynamic call sites to invoke object's "toString" and
      +        // We delegate to Global, as the implementation uses dynamic call sites to invoke object's "toString" and
               // "valueOf" methods, and in order to avoid those call sites from becoming megamorphic when multiple contexts
               // are being executed in a long-running program, we move the code and their associated dynamic call sites
               // (Global.TO_STRING and Global.VALUE_OF) into per-context code.
      -        return ((GlobalObject)Context.getGlobalTrusted()).getDefaultValue(this, typeHint);
      +        return Context.getGlobal().getDefaultValue(this, typeHint);
           }
       
           /**
      @@ -1740,7 +1732,7 @@ public abstract class ScriptObject implements PropertyAccess {
           protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
               final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
               if (request.isCallSiteUnstable() || hasWithScope()) {
      -            return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
      +            return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator), isScope() && NashornCallSiteDescriptor.isScope(desc));
               }
       
               final FindProperty find = findProperty(name, true);
      @@ -1765,9 +1757,8 @@ public abstract class ScriptObject implements PropertyAccess {
               final Property property = find.getProperty();
               methodHandle = find.getGetter(returnType);
       
      -        final boolean noGuard = ObjectClassGenerator.OBJECT_FIELDS_ONLY && NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType();
      -        // getMap() is fine as we have the prototype switchpoint depending on where the property was found
      -        final MethodHandle guard = noGuard ? null : NashornGuards.getMapGuard(getMap());
      +        // Get the appropriate guard for this callsite and property.
      +        final MethodHandle guard = NashornGuards.getGuard(this, property, desc);
               final ScriptObject owner = find.getOwner();
       
               if (methodHandle != null) {
      @@ -1777,31 +1768,32 @@ public abstract class ScriptObject implements PropertyAccess {
                   }
       
                   if (!property.hasGetterFunction(owner)) {
      -                // If not a scope bind to actual prototype as changing prototype will change the property map.
      -                // For scopes we install a filter that replaces the self object with the prototype owning the property.
      -                methodHandle = isScope() ?
      -                        addProtoFilter(methodHandle, find.getProtoChainLength()) :
      -                        bindTo(methodHandle, owner);
      +                // Add a filter that replaces the self object with the prototype owning the property.
      +                methodHandle = addProtoFilter(methodHandle, find.getProtoChainLength());
                   }
      -            return new GuardedInvocation(methodHandle, noGuard ? null : getProtoSwitchPoint(name, owner), guard);
      +            return new GuardedInvocation(methodHandle, guard == null ? null : getProtoSwitchPoint(name, owner), guard);
               }
       
               assert !NashornCallSiteDescriptor.isFastScope(desc);
               return new GuardedInvocation(Lookup.emptyGetter(returnType), getProtoSwitchPoint(name, owner), guard);
           }
       
      -    private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
      -        final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod);
      +    private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name,
      +                                                              final boolean isMethod, final boolean isScope) {
      +        final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, isScope);
               final MethodHandle guard = getScriptObjectGuard(desc.getMethodType());
               return new GuardedInvocation(invoker, guard);
           }
       
           @SuppressWarnings("unused")
      -    private Object megamorphicGet(final String key, final boolean isMethod) {
      +    private Object megamorphicGet(final String key, final boolean isMethod, final boolean isScope) {
               final FindProperty find = findProperty(key, true);
       
               if (find != null) {
      -            return getObjectValue(find);
      +            return find.getObjectValue();
      +        }
      +        if (isScope) {
      +            throw referenceError("not.defined", key);
               }
       
               return isMethod ? getNoSuchMethod(key) : invokeNoSuchProperty(key);
      @@ -1996,6 +1988,15 @@ public abstract class ScriptObject implements PropertyAccess {
               }
           }
       
      +    @SuppressWarnings("unused")
      +    private static Object globalFilter(final Object object) {
      +        ScriptObject sobj = (ScriptObject) object;
      +        while (sobj != null && !(sobj instanceof Global)) {
      +            sobj = sobj.getProto();
      +        }
      +        return sobj;
      +    }
      +
           private static GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
               final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
               final GuardedInvocation inv = findSetIndexMethod(type, NashornCallSiteDescriptor.isStrict(desc));
      @@ -2041,7 +2042,7 @@ public abstract class ScriptObject implements PropertyAccess {
                   return noSuchProperty(desc, request);
               }
       
      -        final Object value = getObjectValue(find);
      +        final Object value = find.getObjectValue();
               if (! (value instanceof ScriptFunction)) {
                   return createEmptyGetter(desc, name);
               }
      @@ -2067,7 +2068,7 @@ public abstract class ScriptObject implements PropertyAccess {
               final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
       
               if (find != null) {
      -            final Object   value        = getObjectValue(find);
      +            final Object   value        = find.getObjectValue();
                   ScriptFunction func         = null;
                   MethodHandle   methodHandle = null;
       
      @@ -2102,7 +2103,7 @@ public abstract class ScriptObject implements PropertyAccess {
               final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
       
               if (find != null) {
      -            final Object func = getObjectValue(find);
      +            final Object func = find.getObjectValue();
       
                   if (func instanceof ScriptFunction) {
                       return ScriptRuntime.apply((ScriptFunction)func, this, name);
      @@ -2124,7 +2125,7 @@ public abstract class ScriptObject implements PropertyAccess {
                   return invokeNoSuchProperty(name);
               }
       
      -        final Object value = getObjectValue(find);
      +        final Object value = find.getObjectValue();
               if (! (value instanceof ScriptFunction)) {
                   return UNDEFINED;
               }
      @@ -2664,7 +2665,7 @@ public abstract class ScriptObject implements PropertyAccess {
                           final FindProperty find = object.findProperty(key, false, false, this);
       
                           if (find != null) {
      -                        return getObjectValue(find);
      +                        return find.getObjectValue();
                           }
                       }
       
      @@ -2682,7 +2683,7 @@ public abstract class ScriptObject implements PropertyAccess {
                   final FindProperty find = findProperty(key, true);
       
                   if (find != null) {
      -                return getObjectValue(find);
      +                return find.getObjectValue();
                   }
               }
       
      @@ -2823,7 +2824,15 @@ public abstract class ScriptObject implements PropertyAccess {
                       throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
                   }
               } else {
      -            spill(key, value);
      +            ScriptObject sobj = this;
      +            // undefined scope properties are set in the global object.
      +            if (isScope()) {
      +                while (sobj != null && !(sobj instanceof Global)) {
      +                    sobj = sobj.getProto();
      +                }
      +                assert sobj != null : "no parent global object in scope";
      +            }
      +            sobj.spill(key, value);
               }
           }
       
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
      index d9705676111..6df047d85a5 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
      @@ -474,7 +474,7 @@ public final class ScriptRuntime {
            * @return {@link WithObject} that is the new scope
            */
           public static ScriptObject openWith(final ScriptObject scope, final Object expression) {
      -        final ScriptObject global = Context.getGlobalTrusted();
      +        final Global global = Context.getGlobal();
               if (expression == UNDEFINED) {
                   throw typeError(global, "cant.apply.with.to.undefined");
               } else if (expression == null) {
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
      index bdbc8ec8b9a..edee3748b7a 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
      @@ -31,7 +31,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
       import java.lang.invoke.MethodHandle;
       import jdk.internal.dynalink.CallSiteDescriptor;
       import jdk.internal.dynalink.linker.GuardedInvocation;
      -import jdk.nashorn.internal.codegen.ObjectClassGenerator;
       import jdk.nashorn.internal.lookup.Lookup;
       import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
       import jdk.nashorn.internal.runtime.linker.NashornGuards;
      @@ -104,21 +103,9 @@ final class SetMethodCreator {
                * @return the composed guarded invocation that represents the dynamic setter method for the property.
                */
               GuardedInvocation createGuardedInvocation() {
      -            return new GuardedInvocation(methodHandle, getGuard());
      +            return new GuardedInvocation(methodHandle, NashornGuards.getGuard(sobj, property, desc));
               }
       
      -        private MethodHandle getGuard() {
      -            return needsNoGuard() ? null : NashornGuards.getMapGuard(getMap());
      -        }
      -
      -        private boolean needsNoGuard() {
      -            return NashornCallSiteDescriptor.isFastScope(desc) &&
      -                    (ObjectClassGenerator.OBJECT_FIELDS_ONLY || isPropertyTypeStable());
      -        }
      -
      -        private boolean isPropertyTypeStable() {
      -            return property == null || !property.canChangeType();
      -        }
           }
       
           private SetMethod createSetMethod() {
      @@ -153,10 +140,7 @@ final class SetMethodCreator {
       
               final MethodHandle boundHandle;
               if (!property.hasSetterFunction(find.getOwner()) && find.isInherited()) {
      -            // Bind or add prototype filter depending on whether this is a scope object.
      -            boundHandle = sobj.isScope() ?
      -                    ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength()):
      -                    ScriptObject.bindTo(methodHandle, find.getOwner());
      +            boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
               } else {
                   boundHandle = methodHandle;
               }
      @@ -164,8 +148,8 @@ final class SetMethodCreator {
           }
       
           private SetMethod createGlobalPropertySetter() {
      -        final ScriptObject global = Context.getGlobalTrusted();
      -        return new SetMethod(ScriptObject.bindTo(global.addSpill(getName()), global), null);
      +        final ScriptObject global = Context.getGlobal();
      +        return new SetMethod(MH.filterArguments(global.addSpill(getName()), 0, ScriptObject.GLOBALFILTER), null);
           }
       
           private SetMethod createNewPropertySetter() {
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
      index 931d712b9aa..a69de45ca3d 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
      @@ -34,6 +34,7 @@ import jdk.nashorn.internal.lookup.Lookup;
       import jdk.nashorn.internal.runtime.linker.Bootstrap;
       
       import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
      +import jdk.nashorn.internal.objects.Global;
       import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
       import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
       
      @@ -73,7 +74,7 @@ public final class UserAccessorProperty extends Property {
       
           private static MethodHandle getINVOKE_UA_GETTER() {
       
      -        return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(INVOKE_UA_GETTER,
      +        return Context.getGlobal().getDynamicInvoker(INVOKE_UA_GETTER,
                       new Callable() {
                           @Override
                           public MethodHandle call() {
      @@ -86,7 +87,7 @@ public final class UserAccessorProperty extends Property {
           /** Dynamic invoker for setter */
           private static Object INVOKE_UA_SETTER = new Object();
           private static MethodHandle getINVOKE_UA_SETTER() {
      -        return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(INVOKE_UA_SETTER,
      +        return Context.getGlobal().getDynamicInvoker(INVOKE_UA_SETTER,
                       new Callable() {
                           @Override
                           public MethodHandle call() {
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
      index d4a28cd7fb4..dc48d727e48 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
      @@ -88,6 +88,11 @@ public final class WithObject extends ScriptObject implements Scope {
       
           @Override
           public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) {
      +        if (request.isCallSiteUnstable()) {
      +            // Fall back to megamorphic invocation which performs a complete lookup each time without further relinking.
      +            return super.lookup(desc, request);
      +        }
      +
               // With scopes can never be observed outside of Nashorn code, so all call sites that can address it will of
               // necessity have a Nashorn descriptor - it is safe to cast.
               final NashornCallSiteDescriptor ndesc = (NashornCallSiteDescriptor)desc;
      @@ -265,7 +270,7 @@ public final class WithObject extends ScriptObject implements Scope {
           }
       
           private static MethodHandle filter(final MethodHandle mh, final MethodHandle filter) {
      -        return MH.filterArguments(mh, 0, filter);
      +        return MH.filterArguments(mh, 0, filter.asType(filter.type().changeReturnType(mh.type().parameterType(0))));
           }
       
           /**
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
      index 0aa1d9ebfcc..58f329682e0 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
      @@ -27,7 +27,7 @@ package jdk.nashorn.internal.runtime.arrays;
       
       import java.lang.invoke.MethodHandle;
       import java.nio.ByteBuffer;
      -import jdk.nashorn.internal.runtime.GlobalObject;
      +import jdk.nashorn.internal.objects.Global;
       import jdk.nashorn.internal.runtime.JSType;
       import jdk.nashorn.internal.runtime.PropertyDescriptor;
       
      @@ -399,7 +399,7 @@ public abstract class ArrayData {
            *
            * @return property descriptor for element
            */
      -    public PropertyDescriptor getDescriptor(final GlobalObject global, final int index) {
      +    public PropertyDescriptor getDescriptor(final Global global, final int index) {
               return global.newDataDescriptor(getObject(index), true, true, true);
           }
       
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
      index 58ea1318f53..33c8679f7f7 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
      @@ -27,7 +27,7 @@ package jdk.nashorn.internal.runtime.arrays;
       import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
       
       import java.nio.ByteBuffer;
      -import jdk.nashorn.internal.runtime.GlobalObject;
      +import jdk.nashorn.internal.objects.Global;
       import jdk.nashorn.internal.runtime.PropertyDescriptor;
       import jdk.nashorn.internal.runtime.ScriptRuntime;
       
      @@ -60,7 +60,8 @@ final class ByteBufferArrayData extends ArrayData {
            *
            * @return property descriptor for element
            */
      -    public PropertyDescriptor getDescriptor(final GlobalObject global, final int index) {
      +    @Override
      +    public PropertyDescriptor getDescriptor(final Global global, final int index) {
               // make the index properties not configurable
               return global.newDataDescriptor(getObject(index), false, true, true);
           }
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java
      index a1f772b8bae..e15541db95f 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java
      @@ -25,9 +25,9 @@
       
       package jdk.nashorn.internal.runtime.arrays;
       
      +import jdk.nashorn.internal.objects.Global;
       import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
       
      -import jdk.nashorn.internal.runtime.GlobalObject;
       import jdk.nashorn.internal.runtime.PropertyDescriptor;
       
       /**
      @@ -44,7 +44,7 @@ final class FrozenArrayFilter extends SealedArrayFilter {
           }
       
           @Override
      -    public PropertyDescriptor getDescriptor(final GlobalObject global, final int index) {
      +    public PropertyDescriptor getDescriptor(final Global global, final int index) {
               return global.newDataDescriptor(getObject(index), false, true, false);
           }
       
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java
      index 6f77ddc02e6..bc6de9f04ac 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java
      @@ -25,9 +25,9 @@
       
       package jdk.nashorn.internal.runtime.arrays;
       
      +import jdk.nashorn.internal.objects.Global;
       import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
       
      -import jdk.nashorn.internal.runtime.GlobalObject;
       import jdk.nashorn.internal.runtime.PropertyDescriptor;
       
       /**
      @@ -62,7 +62,7 @@ class SealedArrayFilter extends ArrayFilter {
           }
       
           @Override
      -    public PropertyDescriptor getDescriptor(final GlobalObject global, final int index) {
      +    public PropertyDescriptor getDescriptor(final Global global, final int index) {
               return global.newDataDescriptor(getObject(index), false, true, true);
           }
       }
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
      index 5aceb206331..4951dad6cf1 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
      @@ -64,6 +64,7 @@ import jdk.internal.org.objectweb.asm.Label;
       import jdk.internal.org.objectweb.asm.Opcodes;
       import jdk.internal.org.objectweb.asm.Type;
       import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
      +import jdk.nashorn.internal.objects.Global;
       import jdk.nashorn.internal.runtime.Context;
       import jdk.nashorn.internal.runtime.ScriptFunction;
       import jdk.nashorn.internal.runtime.ScriptObject;
      @@ -134,6 +135,7 @@ final class JavaAdapterBytecodeGenerator {
           static final Type CONTEXT_TYPE       = Type.getType(Context.class);
           static final Type OBJECT_TYPE        = Type.getType(Object.class);
           static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
      +    static final Type GLOBAL_TYPE        = Type.getType(Global.class);
       
           static final String CONTEXT_TYPE_NAME = CONTEXT_TYPE.getInternalName();
           static final String OBJECT_TYPE_NAME  = OBJECT_TYPE.getInternalName();
      @@ -143,8 +145,10 @@ final class JavaAdapterBytecodeGenerator {
           static final String GLOBAL_FIELD_NAME = "global";
       
           static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor();
      +    static final String GLOBAL_TYPE_DESCRIPTOR = GLOBAL_TYPE.getDescriptor();
       
      -    static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, SCRIPT_OBJECT_TYPE);
      +
      +    static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, GLOBAL_TYPE);
           static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
       
           private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
      @@ -167,7 +171,7 @@ final class JavaAdapterBytecodeGenerator {
           private static final String UNSUPPORTED_OPERATION_TYPE_NAME = UNSUPPORTED_OPERATION_TYPE.getInternalName();
       
           private static final String METHOD_HANDLE_TYPE_DESCRIPTOR = METHOD_HANDLE_TYPE.getDescriptor();
      -    private static final String GET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE);
      +    private static final String GET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(GLOBAL_TYPE);
           private static final String GET_CLASS_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Class.class));
       
           // Package used when the adapter can't be defined in the adaptee's package (either because it's sealed, or because
      @@ -259,7 +263,7 @@ final class JavaAdapterBytecodeGenerator {
           }
       
           private void generateGlobalFields() {
      -        cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd();
      +        cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR, null, null).visitEnd();
               usedFieldNames.add(GLOBAL_FIELD_NAME);
           }
       
      @@ -363,7 +367,7 @@ final class JavaAdapterBytecodeGenerator {
               }
               // Assign "global = Context.getGlobal()"
               invokeGetGlobalWithNullCheck(mv);
      -        mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
      +        mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
       
               endInitMethod(mv);
           }
      @@ -508,7 +512,7 @@ final class JavaAdapterBytecodeGenerator {
               // Assign "this.global = Context.getGlobal()"
               mv.visitVarInsn(ALOAD, 0);
               invokeGetGlobalWithNullCheck(mv);
      -        mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
      +        mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
       
               endInitMethod(mv);
           }
      @@ -652,10 +656,10 @@ final class JavaAdapterBytecodeGenerator {
               // Load the creatingGlobal object
               if(classOverride) {
                   // If class handle is defined, load the static defining global
      -            mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
      +            mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
               } else {
                   mv.visitVarInsn(ALOAD, 0);
      -            mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
      +            mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
               }
               // stack: [creatingGlobal, handle]
               final Label setupGlobal = new Label();
      @@ -674,7 +678,7 @@ final class JavaAdapterBytecodeGenerator {
               // stack: [creatingGlobal, creatingGlobal, handle]
       
               // Emit code for switching to the creating global
      -        // ScriptObject currentGlobal = Context.getGlobal();
      +        // Global currentGlobal = Context.getGlobal();
               invokeGetGlobal(mv);
               mv.dup();
       
      @@ -744,7 +748,7 @@ final class JavaAdapterBytecodeGenerator {
               final Label methodEnd = new Label();
               mv.visitLabel(methodEnd);
       
      -        mv.visitLocalVariable("currentGlobal", SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar);
      +        mv.visitLocalVariable("currentGlobal", GLOBAL_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar);
               mv.visitLocalVariable("globalsDiffer", Type.INT_TYPE.getDescriptor(), null, setupGlobal, methodEnd, globalsDifferVar);
       
               if(throwableDeclared) {
      diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
      index 5e0b890a6d2..475ab08c369 100644
      --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
      +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
      @@ -48,7 +48,6 @@ import java.util.Map;
       import java.util.concurrent.ConcurrentHashMap;
       import jdk.internal.dynalink.beans.StaticClass;
       import jdk.internal.dynalink.support.LinkRequestImpl;
      -import jdk.nashorn.internal.objects.NativeJava;
       import jdk.nashorn.internal.runtime.Context;
       import jdk.nashorn.internal.runtime.ECMAException;
       import jdk.nashorn.internal.runtime.ScriptFunction;
      @@ -68,8 +67,8 @@ import jdk.nashorn.internal.runtime.ScriptObject;
        * generate the adapter class itself; see its documentation for details about the generated class.
        * 

      * You normally don't use this class directly, but rather either create adapters from script using - * {@link NativeJava#extend(Object, Object...)}, using the {@code new} operator on abstract classes and interfaces (see - * {@link NativeJava#type(Object, Object)}), or implicitly when passing script functions to Java methods expecting SAM + * {@link jdk.nashorn.internal.objects.NativeJava#extend(Object, Object...)}, using the {@code new} operator on abstract classes and interfaces (see + * {@link jdk.nashorn.internal.objects.NativeJava#type(Object, Object)}), or implicitly when passing script functions to Java methods expecting SAM * types. *

      */ @@ -337,6 +336,7 @@ public final class JavaAdapterFactory { private static ProtectionDomain createMinimalPermissionDomain() { // Generated classes need to have at least the permission to access Nashorn runtime and runtime.linker packages. final Permissions permissions = new Permissions(); + permissions.add(new RuntimePermission("accessClassInPackage.jdk.nashorn.internal.objects")); permissions.add(new RuntimePermission("accessClassInPackage.jdk.nashorn.internal.runtime")); permissions.add(new RuntimePermission("accessClassInPackage.jdk.nashorn.internal.runtime.linker")); return new ProtectionDomain(new CodeSource(null, (CodeSigner[])null), permissions); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java index 0b720be2740..ca3e10c48d4 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java @@ -29,6 +29,11 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.ref.WeakReference; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.nashorn.internal.codegen.ObjectClassGenerator; +import jdk.nashorn.internal.objects.Global; +import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; @@ -40,6 +45,7 @@ public final class NashornGuards { private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class); private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class); private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class); + private static final MethodHandle SAME_OBJECT = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class); private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class); // don't create me! @@ -74,6 +80,55 @@ public final class NashornGuards { return MH.insertArguments(IS_MAP, 1, map); } + /** + * Determine whether the given callsite needs a guard. + * @param property the property, or null + * @param desc the callsite descriptor + * @return true if a guard should be used for this callsite + */ + static boolean needsGuard(final Property property, final CallSiteDescriptor desc) { + return property == null || property.isConfigurable() + || property.isBound() || !ObjectClassGenerator.OBJECT_FIELDS_ONLY + || !NashornCallSiteDescriptor.isFastScope(desc) || property.canChangeType(); + } + + /** + * Get the guard for a property access. This returns an identity guard for non-configurable global properties + * and a map guard for everything else. + * + * @param sobj the first object in the prototype chain + * @param property the property + * @param desc the callsite descriptor + * @return method handle for guard + */ + public static MethodHandle getGuard(final ScriptObject sobj, final Property property, final CallSiteDescriptor desc) { + if (!needsGuard(property, desc)) { + return null; + } + if (NashornCallSiteDescriptor.isScope(desc)) { + if (property != null && property.isBound()) { + // This is a declared top level variables in main script or eval, use identity guard. + return getIdentityGuard(sobj); + } + if (!(sobj instanceof Global) && (property == null || property.isConfigurable())) { + // Undeclared variables in nested evals need stronger guards + return combineGuards(getIdentityGuard(sobj), getMapGuard(sobj.getMap())); + } + } + return getMapGuard(sobj.getMap()); + } + + + /** + * Get a guard that checks referential identity of the current object. + * + * @param sobj the self object + * @return true if same self object instance + */ + public static MethodHandle getIdentityGuard(final ScriptObject sobj) { + return MH.insertArguments(SAME_OBJECT, 1, new WeakReference<>(sobj)); + } + /** * Get a guard that checks if in item is an instance of either of two classes. * @@ -111,6 +166,11 @@ public final class NashornGuards { return self instanceof ScriptObject && ((ScriptObject)self).getMap() == map; } + @SuppressWarnings("unused") + private static boolean sameObject(final Object self, final WeakReference ref) { + return self == ref.get(); + } + @SuppressWarnings("unused") private static boolean isInstanceOf2(final Object self, final Class class1, final Class class2) { return class1.isInstance(self) || class2.isInstance(self); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java index 5cc1cd2c632..22135bc15bc 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java @@ -37,9 +37,9 @@ import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.TypeUtilities; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.Context; -import jdk.nashorn.internal.runtime.GlobalObject; /** * Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other @@ -62,7 +62,7 @@ final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, Gu final LinkRequest request = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context final Object self = request.getReceiver(); - final GlobalObject global = (GlobalObject) Context.getGlobal(); + final Global global = Context.getGlobal(); final NashornCallSiteDescriptor desc = (NashornCallSiteDescriptor) request.getCallSiteDescriptor(); return Bootstrap.asType(global.primitiveLookup(request, self), linkerServices, desc); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java index c9b5eaa3fa9..7665be7fcb3 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java @@ -35,6 +35,7 @@ import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.support.CallSiteDescriptorFactory; import jdk.internal.dynalink.support.Guards; import jdk.nashorn.internal.lookup.Lookup; +import jdk.nashorn.internal.runtime.FindProperty; import jdk.nashorn.internal.runtime.ScriptObject; /** @@ -61,8 +62,9 @@ public final class PrimitiveLookup { * type {@code receiverClass}. */ public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Class receiverClass, - final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) { - return lookupPrimitive(request, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter); + final ScriptObject wrappedReceiver, final MethodHandle wrapFilter, + final MethodHandle protoFilter) { + return lookupPrimitive(request, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter, protoFilter); } /** @@ -79,7 +81,8 @@ public final class PrimitiveLookup { * type (that is implied by both {@code guard} and {@code wrappedReceiver}). */ public static GuardedInvocation lookupPrimitive(final LinkRequest request, final MethodHandle guard, - final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) { + final ScriptObject wrappedReceiver, final MethodHandle wrapFilter, + final MethodHandle protoFilter) { final CallSiteDescriptor desc = request.getCallSiteDescriptor(); final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0); if ("setProp".equals(operator) || "setElem".equals(operator)) { @@ -93,9 +96,23 @@ public final class PrimitiveLookup { if(desc.getNameTokenCount() > 2) { final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); - if(wrappedReceiver.findProperty(name, true) == null) { + final FindProperty find = wrappedReceiver.findProperty(name, true); + if(find == null) { // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it. return null; + } else if (find.isInherited() && !find.getProperty().hasGetterFunction(find.getOwner())) { + // If property is found in the prototype object bind the method handle directly to + // the proto filter instead of going through wrapper instantiation below. + final ScriptObject proto = wrappedReceiver.getProto(); + final GuardedInvocation link = proto.lookup(desc, request); + + if (link != null) { + final MethodHandle invocation = link.getInvocation(); + final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class)); + final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter); + final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter); + return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard)); + } } } final GuardedInvocation link = wrappedReceiver.lookup(desc, request); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties index e1c4d1f1f8a..47248fce715 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -79,6 +79,7 @@ type.error.not.a.function={0} is not a function type.error.not.a.constructor={0} is not a constructor function type.error.not.a.file={0} is not a File type.error.not.a.bytebuffer={0} is not a java.nio.ByteBuffer +type.error.not.an.arraybuffer.in.dataview=First arg to DataView constructor must be an ArrayBuffer # operations not permitted on undefined type.error.cant.call.undefined=Cannot call undefined @@ -137,6 +138,9 @@ type.error.no.method.matches.args=Can not invoke method {0} with the passed argu type.error.method.not.constructor=Java method {0} can't be used as a constructor. type.error.env.not.object=$ENV must be an Object. type.error.unsupported.java.to.type=Unsupported Java.to target type {0}. + +range.error.dataview.constructor.offset=Wrong offset or length in DataView constructor +range.error.dataview.offset=Offset is outside the bounds of the DataView range.error.inappropriate.array.length=inappropriate array length: {0} range.error.inappropriate.array.buffer.length=inappropriate array buffer length: {0} range.error.invalid.fraction.digits=fractionDigits argument to {0} must be in [0, 20] diff --git a/nashorn/src/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk/nashorn/tools/Shell.java index ad19484ceb8..ad833d8171b 100644 --- a/nashorn/src/jdk/nashorn/tools/Shell.java +++ b/nashorn/src/jdk/nashorn/tools/Shell.java @@ -42,6 +42,7 @@ import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.debug.ASTWriter; import jdk.nashorn.internal.ir.debug.PrintVisitor; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.parser.Parser; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; @@ -148,7 +149,7 @@ public class Shell { return COMMANDLINE_ERROR; } - final ScriptObject global = context.createGlobal(); + final Global global = context.createGlobal(); final ScriptEnvironment env = context.getEnv(); final List files = env.getFiles(); if (files.isEmpty()) { @@ -231,8 +232,8 @@ public class Shell { * @return error code * @throws IOException when any script file read results in I/O error */ - private static int compileScripts(final Context context, final ScriptObject global, final List files) throws IOException { - final ScriptObject oldGlobal = Context.getGlobal(); + private static int compileScripts(final Context context, final Global global, final List files) throws IOException { + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); final ScriptEnvironment env = context.getEnv(); try { @@ -281,8 +282,8 @@ public class Shell { * @return error code * @throws IOException when any script file read results in I/O error */ - private int runScripts(final Context context, final ScriptObject global, final List files) throws IOException { - final ScriptObject oldGlobal = Context.getGlobal(); + private int runScripts(final Context context, final Global global, final List files) throws IOException { + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { if (globalChanged) { @@ -339,8 +340,8 @@ public class Shell { * @return error code * @throws IOException when any script file read results in I/O error */ - private static int runFXScripts(final Context context, final ScriptObject global, final List files) throws IOException { - final ScriptObject oldGlobal = Context.getGlobal(); + private static int runFXScripts(final Context context, final Global global, final List files) throws IOException { + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { if (globalChanged) { @@ -389,11 +390,11 @@ public class Shell { * @return return code */ @SuppressWarnings("resource") - private static int readEvalPrint(final Context context, final ScriptObject global) { + private static int readEvalPrint(final Context context, final Global global) { final String prompt = bundle.getString("shell.prompt"); final BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); final PrintWriter err = context.getErr(); - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); final ScriptEnvironment env = context.getEnv(); diff --git a/langtools/test/tools/javac/ArrayCloneCodeGen.java b/nashorn/test/script/basic/JDK-8034055.js similarity index 65% rename from langtools/test/tools/javac/ArrayCloneCodeGen.java rename to nashorn/test/script/basic/JDK-8034055.js index ae496ef706a..0a21d9f915a 100644 --- a/langtools/test/tools/javac/ArrayCloneCodeGen.java +++ b/nashorn/test/script/basic/JDK-8034055.js @@ -1,43 +1,55 @@ /* - * Copyright (c) 1999, 2001, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. - * + * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). - * + * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * + * * Please 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 4267335 - * @summary Verify that code generated for Array.clone() with -target 1.2 passes verifier. - * @author maddox +/** + * JDK-8034055: delete on global object not properly guarded * - * @run compile -source 1.3 -target 1.2 ArrayCloneCodeGen.java - * @run main/othervm -Xverify:all ArrayCloneCodeGen + * @test + * @run */ -public class ArrayCloneCodeGen { - public static void main(String[] args) {} +var global = this; +var x; - private String[] args = null; - - public String[] getArgs() { - return (String []) (args.clone()); +function test(defineGlobals) { + if (defineGlobals) { + global.x = 1; + global.y = 2; + } + try { + print(x); + print(y); + } catch (e) { + print(e); + } finally { + print(delete global.x); + print(delete global.y); } } + +// Repeatedly set and delete global variables +test(true); +test(false); +test(true); +test(false); diff --git a/nashorn/test/script/basic/JDK-8034055.js.EXPECTED b/nashorn/test/script/basic/JDK-8034055.js.EXPECTED new file mode 100644 index 00000000000..c947f4aeb23 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8034055.js.EXPECTED @@ -0,0 +1,16 @@ +1 +2 +false +true +1 +ReferenceError: "y" is not defined +false +true +1 +2 +false +true +1 +ReferenceError: "y" is not defined +false +true diff --git a/nashorn/test/script/basic/dataview_endian.js b/nashorn/test/script/basic/dataview_endian.js new file mode 100644 index 00000000000..f7607c0ee05 --- /dev/null +++ b/nashorn/test/script/basic/dataview_endian.js @@ -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. + */ + +/** + * JDK-8015958: DataView constructor is not defined + * + * @test + * @run + */ + +// set/get endianess checks + +var buffer = new ArrayBuffer(4); +var dv = new DataView(buffer); + +// write (default) big endian, read big/little endian +dv.setUint16(0, 0xABCD); +Assert.assertEquals(dv.getUint16(0), 0xABCD); +Assert.assertEquals(dv.getUint16(0, false), 0xABCD); +Assert.assertEquals(dv.getUint16(0, true), 0xCDAB); + +// write little endian, read big/little endian +dv.setUint16(0, 0xABCD, true); +Assert.assertEquals(dv.getUint16(0), 0xCDAB); +Assert.assertEquals(dv.getUint16(0, false), 0xCDAB); +Assert.assertEquals(dv.getUint16(0, true), 0xABCD); + +// write explicit big endian, read big/little endian +dv.setUint16(0, 0xABCD, false); +Assert.assertEquals(dv.getUint16(0), 0xABCD); +Assert.assertEquals(dv.getUint16(0, false), 0xABCD); +Assert.assertEquals(dv.getUint16(0, true), 0xCDAB); + +// write (default) big endian, read big/little endian +dv.setUint32(0, 0xABCDEF89); +Assert.assertEquals(dv.getUint32(0), 0xABCDEF89); +Assert.assertEquals(dv.getUint32(0, false), 0xABCDEF89); +Assert.assertEquals(dv.getUint32(0, true), 0x89EFCDAB); + +// write little endian, read big/little endian +dv.setUint32(0, 0xABCDEF89, true); +Assert.assertEquals(dv.getUint32(0), 0x89EFCDAB); +Assert.assertEquals(dv.getUint32(0, false), 0x89EFCDAB); +Assert.assertEquals(dv.getUint32(0, true), 0xABCDEF89); + +// write explicit big endian, read big/little endian +dv.setUint32(0, 0xABCDEF89, false); +Assert.assertEquals(dv.getUint32(0), 0xABCDEF89); +Assert.assertEquals(dv.getUint32(0, false), 0xABCDEF89); +Assert.assertEquals(dv.getUint32(0, true), 0x89EFCDAB); diff --git a/nashorn/test/script/basic/dataview_getset.js b/nashorn/test/script/basic/dataview_getset.js new file mode 100644 index 00000000000..8c7a994c1d0 --- /dev/null +++ b/nashorn/test/script/basic/dataview_getset.js @@ -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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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-8015958: DataView constructor is not defined + * + * @test + * @run + */ + +// checking get/set of values of various types +// Also basic endianess check. + +var Float = Java.type("java.lang.Float"); +var Double = Java.type("java.lang.Double"); + +var DOUBLE_MIN = Double.MIN_VALUE; +var DOUBLE_MIN_NORMAL = Double.MIN_NORMAL; +var FLOAT_MIN = Float.MIN_VALUE; +var FLOAT_MIN_NORMAL = Float.MIN_NORMAL; + +var buffer = new ArrayBuffer(12); +var dv = new DataView(buffer); + +dv.setInt8(1, 123); +Assert.assertEquals(dv.getInt8(1), 123); +dv.setInt8(1, 123, true); +Assert.assertEquals(dv.getInt8(1, true), 123); + +dv.setUint8(1, 255); +Assert.assertEquals(dv.getUint8(1), 255); +dv.setUint8(1, 255, true); +Assert.assertEquals(dv.getUint8(1, true), 255); + +dv.setInt16(1, 1234); +Assert.assertEquals(dv.getInt16(1), 1234); +dv.setInt16(1, 1234, true); +Assert.assertEquals(dv.getInt16(1, true), 1234); + +dv.setUint16(1, 65535); +Assert.assertEquals(dv.getUint16(1), 65535); +dv.setUint16(1, 65535, true); +Assert.assertEquals(dv.getUint16(1, true), 65535); + +dv.setInt32(1, 1234); +Assert.assertEquals(dv.getInt32(1), 1234); +dv.setInt32(1, 1234, true); +Assert.assertEquals(dv.getInt32(1, true), 1234); + +dv.setUint32(1, 4294967295); +Assert.assertEquals(dv.getUint32(1), 4294967295); +dv.setUint32(1, 4294967295, true); +Assert.assertEquals(dv.getUint32(1, true), 4294967295); + +dv.setFloat64(1, Math.PI); +Assert.assertEquals(dv.getFloat64(1), Math.PI, DOUBLE_MIN); +dv.setFloat64(1, Math.PI, true); +Assert.assertEquals(dv.getFloat64(1, true), Math.PI, DOUBLE_MIN); + +dv.setFloat64(1, DOUBLE_MIN_NORMAL); +Assert.assertEquals(dv.getFloat64(1), DOUBLE_MIN_NORMAL, DOUBLE_MIN); +dv.setFloat64(1, DOUBLE_MIN_NORMAL, true); +Assert.assertEquals(dv.getFloat64(1, true), DOUBLE_MIN_NORMAL, DOUBLE_MIN); + +dv.setFloat32(1, 1.414); +Assert["assertEquals(float, float, float)"](dv.getFloat32(1), 1.414, FLOAT_MIN); +dv.setFloat32(1, 1.414, true); +Assert["assertEquals(float, float, float)"](dv.getFloat32(1, true), 1.414, FLOAT_MIN); + +dv.setFloat32(1, FLOAT_MIN_NORMAL); +Assert["assertEquals(float, float, float)"](dv.getFloat32(1), FLOAT_MIN_NORMAL, FLOAT_MIN); +dv.setFloat32(1, FLOAT_MIN_NORMAL, true); +Assert["assertEquals(float, float, float)"](dv.getFloat32(1, true), FLOAT_MIN_NORMAL, FLOAT_MIN); diff --git a/nashorn/test/script/basic/dataview_new.js b/nashorn/test/script/basic/dataview_new.js new file mode 100644 index 00000000000..78f8183d52a --- /dev/null +++ b/nashorn/test/script/basic/dataview_new.js @@ -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. + */ + +/** + * JDK-8015958: DataView constructor is not defined + * + * @test + * @run + */ + +// basic DataView constructor checks. + +// check ArrayBufferView property values of DataView instance +function check(dv, buf, offset, length) { + if (dv.buffer !== buf) { + fail("DataView.buffer is wrong"); + } + + if (dv.byteOffset != offset) { + fail("DataView.byteOffset = " + dv.byteOffset + ", expected " + offset); + } + + if (dv.byteLength != length) { + fail("DataView.byteLength = " + dv.byteLength + ", expected " + length); + } +} + +var buffer = new ArrayBuffer(12); +check(new DataView(buffer), buffer, 0, 12); +check(new DataView(buffer, 2), buffer, 2, 10); +check(new DataView(buffer, 4, 8), buffer, 4, 8); + +// make sure expected error is thrown +function checkError(callback, ErrorType) { + try { + callback(); + fail("Should have thrown " + ErrorType.name); + } catch (e) { + if (! (e instanceof ErrorType)) { + fail("Expected " + ErrorType.name + " got " + e); + } + } +} + +// non ArrayBuffer as first arg +checkError(function() { new DataView(344) }, TypeError); + +// illegal offset/length values +checkError(function() { new DataView(buffer, -1) }, RangeError); +checkError(function() { new DataView(buffer, 15) }, RangeError); +checkError(function() { new DataView(buffer, 1, 32) }, RangeError); diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java index a18055bb602..dc27d826402 100644 --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java @@ -245,4 +245,320 @@ public class ScopeTest { sb.put("x", "newX"); assertTrue(e.eval("x", ctx).equals("newX")); } + + /** + * Test multi-threaded access to defined global variables for shared script classes with multiple globals. + */ + @Test + public static void multiThreadedVarTest() throws ScriptException, InterruptedException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = e.createBindings(); + final ScriptContext origContext = e.getContext(); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + final String sharedScript = "foo"; + + assertEquals(e.eval("var foo = 'original context';", origContext), null); + assertEquals(e.eval("var foo = 'new context';", newCtxt), null); + + final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + assertEquals(e.eval("var foo = 'newer context';", newCtxt), null); + final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); + + t3.start(); + t4.start(); + t3.join(); + t4.join(); + + assertEquals(e.eval(sharedScript), "original context"); + assertEquals(e.eval(sharedScript, newCtxt), "newer context"); + } + + /** + * Test multi-threaded access to undefined global variables for shared script classes with multiple globals. + */ + @Test + public static void multiThreadedGlobalTest() throws ScriptException, InterruptedException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = e.createBindings(); + final ScriptContext origContext = e.getContext(); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + + assertEquals(e.eval("foo = 'original context';", origContext), "original context"); + assertEquals(e.eval("foo = 'new context';", newCtxt), "new context"); + final String sharedScript = "foo"; + + final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + Object obj3 = e.eval("delete foo; foo = 'newer context';", newCtxt); + assertEquals(obj3, "newer context"); + final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); + + t3.start(); + t4.start(); + t3.join(); + t4.join(); + + Assert.assertEquals(e.eval(sharedScript), "original context"); + Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context"); + } + + /** + * Test multi-threaded access using the postfix ++ operator for shared script classes with multiple globals. + */ + @Test + public static void multiThreadedIncTest() throws ScriptException, InterruptedException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = e.createBindings(); + final ScriptContext origContext = e.getContext(); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + + assertEquals(e.eval("var x = 0;", origContext), null); + assertEquals(e.eval("var x = 2;", newCtxt), null); + final String sharedScript = "x++;"; + + final Thread t1 = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int i = 0; i < 1000; i++) { + assertEquals(e.eval(sharedScript, origContext), (double)i); + } + } catch (ScriptException se) { + fail(se.toString()); + } + } + }); + final Thread t2 = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int i = 2; i < 1000; i++) { + assertEquals(e.eval(sharedScript, newCtxt), (double)i); + } + } catch (ScriptException se) { + fail(se.toString()); + } + } + }); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + } + + /** + * Test multi-threaded access to primitive prototype properties for shared script classes with multiple globals. + */ + @Test + public static void multiThreadedPrimitiveTest() throws ScriptException, InterruptedException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = e.createBindings(); + final ScriptContext origContext = e.getContext(); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + + Object obj1 = e.eval("String.prototype.foo = 'original context';", origContext); + Object obj2 = e.eval("String.prototype.foo = 'new context';", newCtxt); + assertEquals(obj1, "original context"); + assertEquals(obj2, "new context"); + final String sharedScript = "''.foo"; + + final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt); + assertEquals(obj3, "newer context"); + final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); + + t3.start(); + t4.start(); + t3.join(); + t4.join(); + + Assert.assertEquals(e.eval(sharedScript), "original context"); + Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context"); + } + + /** + * Test multi-threaded scope function invocation for shared script classes with multiple globals. + */ + @Test + public static void multiThreadedFunctionTest() throws ScriptException, InterruptedException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = e.createBindings(); + final ScriptContext origContext = e.getContext(); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + + e.eval(new URLReader(ScopeTest.class.getResource("resources/func.js")), origContext); + assertEquals(origContext.getAttribute("scopeVar"), 1); + assertEquals(e.eval("scopeTest()"), 1); + + e.eval(new URLReader(ScopeTest.class.getResource("resources/func.js")), newCtxt); + assertEquals(newCtxt.getAttribute("scopeVar"), 1); + assertEquals(e.eval("scopeTest();", newCtxt), 1); + + assertEquals(e.eval("scopeVar = 3;", newCtxt), 3); + assertEquals(newCtxt.getAttribute("scopeVar"), 3); + + + final Thread t1 = new Thread(new ScriptRunner(e, origContext, "scopeTest()", 1, 1000)); + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, "scopeTest()", 3, 1000)); + + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + } + + /** + * Test multi-threaded access to global getters and setters for shared script classes with multiple globals. + */ + @Test + public static void getterSetterTest() throws ScriptException, InterruptedException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = e.createBindings(); + final ScriptContext origContext = e.getContext(); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + final String sharedScript = "accessor1"; + + e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), origContext); + assertEquals(e.eval("accessor1 = 1;"), 1); + assertEquals(e.eval(sharedScript), 1); + + e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), newCtxt); + assertEquals(e.eval("accessor1 = 2;", newCtxt), 2); + assertEquals(e.eval(sharedScript, newCtxt), 2); + + + final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, 1, 1000)); + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, 2, 1000)); + + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + assertEquals(e.eval(sharedScript), 1); + assertEquals(e.eval(sharedScript, newCtxt), 2); + assertEquals(e.eval("v"), 1); + assertEquals(e.eval("v", newCtxt), 2); + } + + /** + * Test multi-threaded access to global getters and setters for shared script classes with multiple globals. + */ + @Test + public static void getterSetter2Test() throws ScriptException, InterruptedException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = e.createBindings(); + final ScriptContext origContext = e.getContext(); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + final String sharedScript = "accessor2"; + + e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), origContext); + assertEquals(e.eval("accessor2 = 1;"), 1); + assertEquals(e.eval(sharedScript), 1); + + e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), newCtxt); + assertEquals(e.eval("accessor2 = 2;", newCtxt), 2); + assertEquals(e.eval(sharedScript, newCtxt), 2); + + + final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, 1, 1000)); + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, 2, 1000)); + + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + assertEquals(e.eval(sharedScript), 1); + assertEquals(e.eval(sharedScript, newCtxt), 2); + assertEquals(e.eval("x"), 1); + assertEquals(e.eval("x", newCtxt), 2); + } + + /** + * Test "slow" scopes involving {@code with} and {@code eval} statements for shared script classes with multiple globals. + */ + @Test + public static void testSlowScope() throws ScriptException, InterruptedException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + + for (int i = 0; i < 100; i++) { + final Bindings b = e.createBindings(); + final ScriptContext ctxt = new SimpleScriptContext(); + ctxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + + e.eval(new URLReader(ScopeTest.class.getResource("resources/witheval.js")), ctxt); + assertEquals(e.eval("a", ctxt), 1); + assertEquals(b.get("a"), 1); + assertEquals(e.eval("b", ctxt), 3); + assertEquals(b.get("b"), 3); + assertEquals(e.eval("c", ctxt), 10); + assertEquals(b.get("c"), 10); + } + } + + private static class ScriptRunner implements Runnable { + + final ScriptEngine engine; + final ScriptContext context; + final String source; + final Object expected; + final int iterations; + + ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) { + this.engine = engine; + this.context = context; + this.source = source; + this.expected = expected; + this.iterations = iterations; + } + + @Override + public void run() { + try { + for (int i = 0; i < iterations; i++) { + assertEquals(engine.eval(source, context), expected); + } + } catch (ScriptException se) { + throw new RuntimeException(se); + } + } + } + } diff --git a/langtools/test/tools/javac/NoNoClassDefFoundErrorError.java b/nashorn/test/src/jdk/nashorn/api/scripting/resources/func.js similarity index 59% rename from langtools/test/tools/javac/NoNoClassDefFoundErrorError.java rename to nashorn/test/src/jdk/nashorn/api/scripting/resources/func.js index 1ad32d142a2..477bd1a64be 100644 --- a/langtools/test/tools/javac/NoNoClassDefFoundErrorError.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/resources/func.js @@ -1,10 +1,12 @@ /* - * Copyright (c) 2001, 2004, 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 * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -21,16 +23,20 @@ * questions. */ -/* - * @test - * @bug 4313429 - * @summary Compiling .class on CLDC crashed the compiler. - * - * @compile/fail -source 1.4 -target 1.4 -XDfailcomplete=java.lang.NoClassDefFoundError NoNoClassDefFoundErrorError.java - */ +// This script is loaded from jdk.nashorn.api.scripting.ScopeTest to test script class sharing and reuse. -class NoNoClassDefFoundErrorError { - public static void main() { - Class self = NoNoClassDefFoundErrorError.class; +var scopeVar = 1; +var global = this; +undefGlobal = this; + +function scopeTest() { + if (this !== global) { + throw new Error("this !== global"); } + if (this !== undefGlobal) { + throw new Error("this !== undefinedGlobal") + } + return scopeVar; } + +scopeTest(); diff --git a/langtools/test/tools/javac/generics/BridgeRestype.java b/nashorn/test/src/jdk/nashorn/api/scripting/resources/gettersetter.js similarity index 60% rename from langtools/test/tools/javac/generics/BridgeRestype.java rename to nashorn/test/src/jdk/nashorn/api/scripting/resources/gettersetter.js index 2107efa4260..51e24727466 100644 --- a/langtools/test/tools/javac/generics/BridgeRestype.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/resources/gettersetter.js @@ -1,10 +1,12 @@ /* - * Copyright (c) 2003, 2004, 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 * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -21,22 +23,16 @@ * questions. */ -/* - * @test - * @bug 4902704 - * @summary javac generates inappropriate bridge methods in -source 1.4 - * @author gafter - * - * @compile -source 1.4 -target 1.4 BridgeRestype.java - * @run main BridgeRestype - */ +// This script is loaded from jdk.nashorn.api.scripting.ScopeTest to test script class sharing and reuse. -import java.util.*; +var v; -public class BridgeRestype extends Vector { - public static void main(String[] args) { - BridgeRestype t = new BridgeRestype(); - for (int i=0; i { - public void foo(T t) { } - } - static class B extends A { - public void foo(String t) { } +function outer(p, e) { + eval(e); + with(p) { + function inner() { + a = 1; + c = 10; + if (a !== 1) { + throw new Error("a !== 1"); + } + if (b !== 3) { + throw new Error("b !== 3"); + } + if (c !== 10) { + throw new Error("c !== 10"); + } + } + inner(); } } + +outer({}, "b = 3;"); + +if (a !== 1) { + throw new Error("a !== 1"); +} +if (b !== 3) { + throw new Error("b !== 3"); +} +if (c !== 10) { + throw new Error("c !== 10"); +} diff --git a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java index 00d79acbda9..ac438101e67 100644 --- a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java @@ -28,6 +28,7 @@ package jdk.nashorn.internal.codegen; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.ScriptFunction; @@ -58,7 +59,7 @@ public class CompilerTest { } private Context context; - private ScriptObject global; + private Global global; @BeforeClass public void setupTest() { @@ -146,7 +147,7 @@ public class CompilerTest { log("Begin compiling " + file.getAbsolutePath()); } - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { diff --git a/nashorn/test/src/jdk/nashorn/internal/performance/PerformanceWrapper.java b/nashorn/test/src/jdk/nashorn/internal/performance/PerformanceWrapper.java index 999f6fa4529..ce969210053 100644 --- a/nashorn/test/src/jdk/nashorn/internal/performance/PerformanceWrapper.java +++ b/nashorn/test/src/jdk/nashorn/internal/performance/PerformanceWrapper.java @@ -31,9 +31,9 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ScriptFunction; -import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; /** @@ -89,7 +89,7 @@ public class PerformanceWrapper extends jdk.nashorn.tools.Shell { @Override protected Object apply(final ScriptFunction target, final Object self) { if (_runsPerIteration == 0 && _numberOfIterations == 0) { - final ScriptObject global = jdk.nashorn.internal.runtime.Context.getGlobal(); + final Global global = jdk.nashorn.internal.runtime.Context.getGlobal(); final ScriptFunction _target = target; final Object _self = self; diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java index 1b21c23f404..1ec416951a3 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java @@ -29,6 +29,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.util.Map; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.options.Options; import org.testng.annotations.Test; @@ -45,7 +46,7 @@ public class ContextTest { final Options options = new Options(""); final ErrorManager errors = new ErrorManager(); final Context cx = new Context(options, errors, Thread.currentThread().getContextClassLoader()); - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); Context.setGlobal(cx.createGlobal()); try { String code = "22 + 10"; @@ -65,7 +66,7 @@ public class ContextTest { final ErrorManager errors = new ErrorManager(); final Context cx = new Context(options, errors, Thread.currentThread().getContextClassLoader()); final boolean strict = cx.getEnv()._strict; - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); Context.setGlobal(cx.createGlobal()); try { diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java new file mode 100644 index 00000000000..aefa828b470 --- /dev/null +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java @@ -0,0 +1,133 @@ +/* + * 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.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import static org.testng.Assert.fail; +import org.testng.annotations.Test; + +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; +import javax.script.SimpleScriptContext; +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; + +/** + * @test + * @bug 8037378 + * @summary Sanity tests for no persistence caching + * @run testng/othervm jdk.nashorn.internal.runtime.NoPersistenceCachingTest + */ +public class NoPersistenceCachingTest { + + private ScriptEngine engine; + private ScriptContext context1, context2, context3; + private ByteArrayOutputStream stderr; + private PrintStream prevStderr; + private final String script = "print('Hello')"; + + public void setupTest() { + stderr = new ByteArrayOutputStream(); + prevStderr = System.err; + System.setErr(new PrintStream(stderr)); + NashornScriptEngineFactory nashornFactory = null; + ScriptEngineManager sm = new ScriptEngineManager(); + for (ScriptEngineFactory fac : sm.getEngineFactories()) { + if (fac instanceof NashornScriptEngineFactory) { + nashornFactory = (NashornScriptEngineFactory) fac; + break; + } + } + if (nashornFactory == null) { + fail("Cannot find nashorn factory!"); + } + String[] options = new String[]{"--log=compiler:finest"}; + engine = nashornFactory.getScriptEngine(options); + } + + 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); + 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); + break; + } + } catch (final Exception se) { + se.printStackTrace(); + fail(se.getMessage()); + } + Pattern deoptimizing = Pattern.compile(expectedOutputPattern); + Matcher matcher = deoptimizing.matcher(stderr.toString()); + int matches = 0; + while (matcher.find()) { + matches++; + } + if (matches != expectedPatternOccurrence) { + fail("Number of cache hit is not correct, expected: " + + expectedPatternOccurrence + " and found: " + matches + "\n" + + stderr); + } + setErrTest(); + } + + private static String getCodeCachePattern() { + return ("\\[compiler\\]\\sCode\\scache\\shit\\sfor\\s\\savoiding\\srecompile."); + } + + @Test + public void twoContextTest() { + runTest(2, getCodeCachePattern(), 1); + + } + + @Test + public void threeContextTest() { + runTest(3, getCodeCachePattern(), 2); + } +} diff --git a/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java b/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java index ac2dc17293c..83d057f327f 100644 --- a/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java +++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java @@ -34,10 +34,10 @@ import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import jdk.nashorn.api.scripting.NashornException; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.ScriptFunction; -import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; @@ -110,12 +110,12 @@ public final class SharedContextEvaluator implements ScriptEvaluator { @Override public int run(final OutputStream out, final OutputStream err, final String[] args) throws IOException { - final ScriptObject oldGlobal = Context.getGlobal(); + final Global oldGlobal = Context.getGlobal(); try { ctxOut.setDelegatee(out); ctxErr.setDelegatee(err); final ErrorManager errors = context.getErrorManager(); - final ScriptObject global = context.createGlobal(); + final Global global = context.createGlobal(); Context.setGlobal(global); // For each file on the command line.