diff --git a/.hgtags b/.hgtags index aaf78d35e9c..f496bfd1d5d 100644 --- a/.hgtags +++ b/.hgtags @@ -285,3 +285,9 @@ b409bc51bc23cfd51f2bd04ea919ec83535af9d0 jdk9-b37 82f4cb44b2d7af2352f48568a64b7b6a5ae960cd jdk9-b40 9fffb959eb4197ff806e4ac12244761815b4deee jdk9-b41 3107be2ba9c6e208a0b86bc7100a141abbc5b5fb jdk9-b42 +6494b13f88a867026ee316b444d9a4fa589dd6bd jdk9-b43 +abbfccd659b91a7bb815d5e36fed635dcdd40f31 jdk9-b44 +bfc24ae2b900187585079bb11e66e459d1e525fe jdk9-b45 +722378bc599e38d9a1dd484de30f10dfd7b21438 jdk9-b46 +8327024a99559982b848e9c2191da9c0bf8838fd jdk9-b47 +b2f9702efbe95527ea3a991474fda23987ff1c5c jdk9-b48 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 9cbf0f90d4e..26c2321b403 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -285,3 +285,9 @@ d42c0a90afc3c66ca87543076ec9aafd4b4680de jdk9-b38 cf136458ee747e151a27aa9ea0c1492ea55ef3e7 jdk9-b40 67395f7ca2db3b52e3a62a84888487de5cb9210a jdk9-b41 f7c11da0b0481d49cc7a65a453336c108191e821 jdk9-b42 +02ee8c65622e8bd97496d584e22fc7dcf0edc4ae jdk9-b43 +8994f5d87b3bb5e8d317d4e8ccb326da1a73684a jdk9-b44 +3dd628fde2086218d548841022ee8436b6b88185 jdk9-b45 +12f1e276447bcc81516e85367d53e4f08897049d jdk9-b46 +b6cca3e6175a69f39e5799b7349ddb0176630291 jdk9-b47 +0064e246d83f6f9fc245c19b6d05041ecaf4b6d4 jdk9-b48 diff --git a/Makefile b/Makefile index 1eff79b2194..0814d3867c6 100644 --- a/Makefile +++ b/Makefile @@ -54,8 +54,11 @@ ifneq ($(findstring qp,$(MAKEFLAGS)),) # Duplication of global targets, needed before ParseConfAndSpec in case we have # no configurations. help: - # If CONF is not set, look for all available configurations - CONF?= + # If both CONF and SPEC are unset, look for all available configurations by + # setting CONF to the empty string. + ifeq ($(SPEC), ) + CONF?= + endif endif # ... and then we can include our helper functions diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index 62d83574289..800c52b844b 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -987,3 +987,26 @@ AC_DEFUN_ONCE([BASIC_TEST_USABILITY_ISSUES], IS_RECONFIGURE=no fi ]) + +# Check for support for specific options in bash +AC_DEFUN_ONCE([BASIC_CHECK_BASH_OPTIONS], +[ + # Test if bash supports pipefail. + AC_MSG_CHECKING([if bash supports pipefail]) + if ${BASH} -c 'set -o pipefail'; then + BASH_ARGS="$BASH_ARGS -o pipefail" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + AC_MSG_CHECKING([if bash supports errexit (-e)]) + if ${BASH} -e -c 'true'; then + BASH_ARGS="$BASH_ARGS -e" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + AC_SUBST(BASH_ARGS) +]) diff --git a/common/autoconf/bootcycle-spec.gmk.in b/common/autoconf/bootcycle-spec.gmk.in index a547f34c951..6e68c3a0b34 100644 --- a/common/autoconf/bootcycle-spec.gmk.in +++ b/common/autoconf/bootcycle-spec.gmk.in @@ -46,8 +46,12 @@ endif BOOT_JDK := $(JDK_IMAGE_DIR) # The bootcycle build has a different output directory -BUILD_OUTPUT:=@BUILD_OUTPUT@/bootcycle-build -SJAVAC_SERVER_DIR:=$(subst @BUILD_OUTPUT@,$(BUILD_OUTPUT),$(SJAVAC_SERVER_DIR)) +OLD_BUILD_OUTPUT:=@BUILD_OUTPUT@ +BUILD_OUTPUT:=$(OLD_BUILD_OUTPUT)/bootcycle-build +# The HOTSPOT_DIST dir is not defined relative to BUILD_OUTPUT in spec.gmk. Must not +# use space in this patsubst to avoid leading space in HOTSPOT_DIST. +HOTSPOT_DIST:=$(patsubst $(OLD_BUILD_OUTPUT)%,$(BUILD_OUTPUT)%,$(HOTSPOT_DIST)) +SJAVAC_SERVER_DIR:=$(patsubst $(OLD_BUILD_OUTPUT)%, $(BUILD_OUTPUT)%, $(SJAVAC_SERVER_DIR)) JAVA_CMD:=$(BOOT_JDK)/bin/java JAVAC_CMD:=$(BOOT_JDK)/bin/javac diff --git a/common/autoconf/configure b/common/autoconf/configure index b49e03e7fad..b6a38a307e3 100644 --- a/common/autoconf/configure +++ b/common/autoconf/configure @@ -36,6 +36,13 @@ else shift fi +if test "x$BASH" = x; then + echo "Error: This script must be run using bash." 1>&2 + exit 1 +fi +# Force autoconf to use bash +export CONFIG_SHELL=$BASH + conf_script_dir="$TOPDIR/common/autoconf" if [ "$CUSTOM_CONFIG_DIR" = "" ]; then diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index 146556f479e..902ba475684 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -113,6 +113,7 @@ HELP_SETUP_DEPENDENCY_HELP # Setup tools that requires more complex handling, or that is not needed by the configure script. BASIC_SETUP_COMPLEX_TOOLS +BASIC_CHECK_BASH_OPTIONS # Check if pkg-config is available. PKG_PROG_PKG_CONFIG diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 0b1567ce0ce..11b5d337733 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -853,6 +853,7 @@ OS_VERSION_MICRO OS_VERSION_MINOR OS_VERSION_MAJOR PKG_CONFIG +BASH_ARGS CODESIGN XATTR DSYMUTIL @@ -3522,6 +3523,9 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. +# Check for support for specific options in bash + + # # Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -4329,7 +4333,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=1418036274 +DATE_WHEN_GENERATED=1421247827 ############################################################################### # @@ -13965,7 +13969,8 @@ $as_echo "$COMPILE_TYPE" >&6; } # ZERO_ARCHDEF is used to enable architecture-specific code case "${OPENJDK_TARGET_CPU}" in - ppc*) ZERO_ARCHDEF=PPC ;; + ppc) ZERO_ARCHDEF=PPC32 ;; + ppc64) ZERO_ARCHDEF=PPC64 ;; s390*) ZERO_ARCHDEF=S390 ;; sparc*) ZERO_ARCHDEF=SPARC ;; x86_64*) ZERO_ARCHDEF=AMD64 ;; @@ -19608,6 +19613,32 @@ $as_echo "yes" >&6; } fi + # Test if bash supports pipefail. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if bash supports pipefail" >&5 +$as_echo_n "checking if bash supports pipefail... " >&6; } + if ${BASH} -c 'set -o pipefail'; then + BASH_ARGS="$BASH_ARGS -o pipefail" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if bash supports errexit (-e)" >&5 +$as_echo_n "checking if bash supports errexit (-e)... " >&6; } + if ${BASH} -e -c 'true'; then + BASH_ARGS="$BASH_ARGS -e" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + + + # Check if pkg-config is available. diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index 27db8d047eb..6f26b855e95 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -367,7 +367,8 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS], # ZERO_ARCHDEF is used to enable architecture-specific code case "${OPENJDK_TARGET_CPU}" in - ppc*) ZERO_ARCHDEF=PPC ;; + ppc) ZERO_ARCHDEF=PPC32 ;; + ppc64) ZERO_ARCHDEF=PPC64 ;; s390*) ZERO_ARCHDEF=S390 ;; sparc*) ZERO_ARCHDEF=SPARC ;; x86_64*) ZERO_ARCHDEF=AMD64 ;; diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 60d70886925..d25b35b2070 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -78,6 +78,11 @@ endif OUTPUT_SYNC_SUPPORTED:=@OUTPUT_SYNC_SUPPORTED@ OUTPUT_SYNC:=@OUTPUT_SYNC@ +# Override the shell with bash +BASH:=@BASH@ +BASH_ARGS:=@BASH_ARGS@ +SHELL:=$(BASH) $(BASH_ARGS) + # The "human readable" name of this configuration CONF_NAME:=@CONF_NAME@ @@ -243,7 +248,7 @@ MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/makesupport HOTSPOT_OUTPUTDIR=$(BUILD_OUTPUT)/hotspot JDK_OUTPUTDIR=$(BUILD_OUTPUT)/jdk IMAGES_OUTPUTDIR=$(BUILD_OUTPUT)/images -TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/testmake +TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/test-make MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/make-support HOTSPOT_DIST=@HOTSPOT_DIST@ @@ -495,7 +500,6 @@ endif # Tools adhering to a minimal and common standard of posix compliance. AWK:=@AWK@ BASENAME:=@BASENAME@ -BASH:=@BASH@ CAT:=@CAT@ CCACHE:=@CCACHE@ # CD is going away, but remains to cater for legacy makefiles. @@ -690,10 +694,15 @@ OS_VERSION_MICRO:=@OS_VERSION_MICRO@ # Images directory definitions JDK_IMAGE_SUBDIR:=jdk JRE_IMAGE_SUBDIR:=jre + # Colon left out to be able to override output dir for bootcycle-images JDK_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(JDK_IMAGE_SUBDIR) JRE_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(JRE_IMAGE_SUBDIR) +# Test image, as above +TEST_IMAGE_SUBDIR:=test +TEST_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(TEST_IMAGE_SUBDIR) + # Macosx bundles directory definitions JDK_BUNDLE_SUBDIR=jdk-bundle/jdk$(JDK_VERSION).jdk/Contents JRE_BUNDLE_SUBDIR=jre-bundle/jre$(JDK_VERSION).jre/Contents diff --git a/common/autoconf/toolchain_windows.m4 b/common/autoconf/toolchain_windows.m4 index 231d2e837f2..e1ec6f3db5b 100644 --- a/common/autoconf/toolchain_windows.m4 +++ b/common/autoconf/toolchain_windows.m4 @@ -173,8 +173,8 @@ AC_DEFUN([TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV], # The trailing space for everyone except PATH is no typo, but is needed due # to trailing \ in the Windows paths. These will be stripped later. $ECHO "$WINPATH_BASH -c 'echo VS_PATH="'\"$PATH\" > set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE - $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE - $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE\;$include \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB\;$lib \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE $ECHO "$WINPATH_BASH -c 'echo VCINSTALLDIR="'\"$VCINSTALLDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE $ECHO "$WINPATH_BASH -c 'echo WindowsSdkDir="'\"$WindowsSdkDir \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE $ECHO "$WINPATH_BASH -c 'echo WINDOWSSDKDIR="'\"$WINDOWSSDKDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE diff --git a/common/bin/compare.sh b/common/bin/compare.sh index 418ca1d3517..1eae597a109 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -22,7 +22,7 @@ # questions. # -# This script is processed by configure before it's usable. It is run from +# This script is processed by configure before it's usable. It is run from # the root of the build directory. @@ -76,10 +76,13 @@ diff_text() { TMP=1 if [[ "$THIS_FILE" = *"META-INF/MANIFEST.MF" ]]; then + # Filter out date string, ant version and java version differences. TMP=$(LC_ALL=C $DIFF $OTHER_FILE $THIS_FILE | \ $GREP '^[<>]' | \ $SED -e '/[<>] Ant-Version: Apache Ant .*/d' \ - -e '/[<>] Created-By: .* (Oracle Corporation).*/d') + -e '/[<>] Created-By: .* (Oracle [Corpatin)]*/d' \ + -e '/[<>] [Corpatin]*)/d' \ + -e '/[<>].*[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}-b[0-9]\{2\}.*/d') fi if test "x$SUFFIX" = "xjava"; then TMP=$(LC_ALL=C $DIFF $OTHER_FILE $THIS_FILE | \ @@ -92,7 +95,7 @@ diff_text() { -e '/\/\/ java GenerateCharacter.*/d') fi # Ignore date strings in class files. - # On Macosx the system sources for generated java classes produce different output on + # On Macosx the system sources for generated java classes produce different output on # consequtive invocations seemingly randomly. # For example a method parameter randomly named "thePoint" or "aPoint". Ignore this. # Anonymous lambda classes get randomly assigned counters in their names. @@ -100,18 +103,18 @@ diff_text() { # To improve performance when large diffs are found, do a rough filtering of classes # elibeble for these exceptions if $GREP -R -e '[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}-b[0-9]\{2\}' \ - -e '[0-9]\{2\}/[0-9]\{2\}/[0-9]\{4\}' \ - -e thePoint -e aPoint -e setItemsPtr \ + -e '[0-9]\{2\}/[0-9]\{2\}/[0-9]\{4\}' \ + -e thePoint -e aPoint -e setItemsPtr \ -e 'lambda\$[a-zA-Z0-9]*\$[0-9]' ${THIS_FILE} > /dev/null; then $JAVAP -c -constants -l -p "${OTHER_FILE}" > ${OTHER_FILE}.javap $JAVAP -c -constants -l -p "${THIS_FILE}" > ${THIS_FILE}.javap TMP=$($DIFF ${OTHER_FILE}.javap ${THIS_FILE}.javap | \ $GREP '^[<>]' | \ $SED -e '/[<>].*[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}-b[0-9]\{2\}.*/d' \ - -e '/[0-9]\{2\}\/[0-9]\{2\}\/[0-9]\{4\}/d' \ - -e '/[<>].*Point Lcom\/apple\/jobjc\/foundation\/NSPoint;/d' \ - -e '/[<>].*public com\.apple\.jobjc\.Pointer].*public void setItemsPtr(com\.apple\.jobjc\.Pointer].*Point Lcom\/apple\/jobjc\/foundation\/NSPoint;/d' \ + -e '/[<>].*public com\.apple\.jobjc\.Pointer].*public void setItemsPtr(com\.apple\.jobjc\.Pointer].*lambda\$[a-zA-Z0-9]*\$[0-9]*/d') fi fi @@ -121,20 +124,19 @@ diff_text() { # Disable this exception since we aren't changing the properties cleaning method yet. # $CAT $OTHER_FILE | $SED -e 's/\([^\\]\):/\1\\:/g' -e 's/\([^\\]\)=/\1\\=/g' -e 's/#.*/#/g' \ # | $SED -f "$SRC_ROOT/common/makefiles/support/unicode2x.sed" \ -# | $SED -e '/^#/d' -e '/^$/d' \ +# | $SED -e '/^#/d' -e '/^$/d' \ # -e :a -e '/\\$/N; s/\\\n//; ta' \ -# -e 's/^[ \t]*//;s/[ \t]*$//' \ -# -e 's/\\=/=/' | LC_ALL=C $SORT > $OTHER_FILE.cleaned +# -e 's/^[ \t]*//;s/[ \t]*$//' \ +# -e 's/\\=/=/' | LC_ALL=C $SORT > $OTHER_FILE.cleaned # Filter out date string differences. TMP=$(LC_ALL=C $DIFF $OTHER_FILE.cleaned $THIS_FILE | \ $GREP '^[<>]' | \ $SED -e '/[<>].*[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}-b[0-9]\{2\}.*/d') fi - if test "x$SUFFIX" = "xMF"; then - # Filter out date string differences. + if test "x$SUFFIX" = "xhtml"; then TMP=$(LC_ALL=C $DIFF $OTHER_FILE $THIS_FILE | \ $GREP '^[<>]' | \ - $SED -e '/[<>].*[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}-b[0-9]\{2\}.*/d') + $SED -e '/[<>] /d' ) fi if test -n "$TMP"; then echo Files $OTHER_FILE and $THIS_FILE differ @@ -158,7 +160,7 @@ compare_dirs() { (cd $THIS_DIR && $FIND . -type d | $SORT > $WORK_DIR/dirs_this) $DIFF $WORK_DIR/dirs_other $WORK_DIR/dirs_this > $WORK_DIR/dirs_diff - + echo -n Directory structure... if [ -s $WORK_DIR/dirs_diff ]; then echo Differences found. @@ -192,7 +194,7 @@ compare_files() { (cd $OTHER_DIR && $FIND . ! -type d | $SORT > $WORK_DIR/files_other) (cd $THIS_DIR && $FIND . ! -type d | $SORT > $WORK_DIR/files_this) - + $DIFF $WORK_DIR/files_other $WORK_DIR/files_this > $WORK_DIR/files_diff echo -n File names... @@ -236,11 +238,11 @@ compare_permissions() { TP=`ls -l ${THIS_DIR}/$f | awk '{printf("%.10s\n", $1);}'` if [ "$OP" != "$TP" ] then - if [ -z "$found" ]; then echo ; found="yes"; fi - $PRINTF "\told: ${OP} new: ${TP}\t$f\n" + if [ -z "$found" ]; then echo ; found="yes"; fi + $PRINTF "\tother: ${OP} this: ${TP}\t$f\n" fi done - if [ -z "$found" ]; then + if [ -z "$found" ]; then echo "Identical!" else REGRESSIONS=true @@ -265,24 +267,22 @@ compare_file_types() { if [ ! -f ${THIS_DIR}/$f ]; then continue; fi OF=`cd ${OTHER_DIR} && $FILE -h $f | $SED 's/BuildID[^,]*//g'` TF=`cd ${THIS_DIR} && $FILE -h $f | $SED 's/BuildID[^,]*//g'` - if [ "$f" = "./src.zip" ] || [[ "$f" = *"/Home/src.zip" ]] || [[ "$f" = *"/lib/JObjC.jar" ]] - then - if [ "`echo $OF | $GREP -ic zip`" -gt 0 -a "`echo $TF | $GREP -ic zip`" -gt 0 ] - then - # the way we produces zip-files make it so that directories are stored in old file - # but not in new (only files with full-path) - # this makes file-5.09 report them as different - continue; - fi - fi - if [ "$OF" != "$TF" ] then - if [ -z "$found" ]; then echo ; found="yes"; fi - $PRINTF "\tother: ${OF}\n\tthis : ${TF}\n" + if [ "`echo $OF | $GREP -c 'Zip archive data'`" -gt 0 ] \ + && [ "`echo $TF | $GREP -c 'Zip archive data'`" -gt 0 ] + then + # the way we produce zip-files make it so that directories are stored in + # old file but not in new (only files with full-path) this makes file + # report them as different + continue + else + if [ -z "$found" ]; then echo ; found="yes"; fi + $PRINTF "\tother: ${OF}\n\tthis : ${TF}\n" + fi fi done - if [ -z "$found" ]; then + if [ -z "$found" ]; then echo "Identical!" else REGRESSIONS=true @@ -296,12 +296,13 @@ compare_general_files() { THIS_DIR=$1 OTHER_DIR=$2 WORK_DIR=$3 - + GENERAL_FILES=$(cd $THIS_DIR && $FIND . -type f ! -name "*.so" ! -name "*.jar" ! -name "*.zip" \ ! -name "*.debuginfo" ! -name "*.dylib" ! -name "jexec" ! -name "*.jimage" \ - ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" \ + ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" ! -name "*.cpl" \ ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \ ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" \ + ! -name "*.obj" ! -name "*.o" ! -name "JavaControlPanelHelper" ! -name "JavaUpdater" \ | $GREP -v "./bin/" | $SORT | $FILTER) echo General files... @@ -377,7 +378,7 @@ compare_zip_file() { THIS_SUFFIX="${THIS_ZIP##*.}" OTHER_SUFFIX="${OTHER_ZIP##*.}" if [ "$THIS_SUFFIX" != "$OTHER_SUFFIX" ]; then - echo The files do not have the same suffix type! + echo "The files do not have the same suffix type! ($THIS_SUFFIX != $OTHER_SUFFIX)" return 2 fi @@ -389,7 +390,7 @@ compare_zip_file() { fi # Not quite identical, the might still contain the same data. # Unpack the jar/zip files in temp dirs - + THIS_UNZIPDIR=$WORK_DIR/$ZIP_FILE.this OTHER_UNZIPDIR=$WORK_DIR/$ZIP_FILE.other $RM -rf $THIS_UNZIPDIR $OTHER_UNZIPDIR @@ -464,9 +465,9 @@ compare_zip_file() { $RM -f $WORK_DIR/$ZIP_FILE.diffs for file in $DIFFING_FILES; do - if [[ "$ACCEPTED_JARZIP_CONTENTS $EXCEPTIONS" != *"$file"* ]]; then + if [[ "$ACCEPTED_JARZIP_CONTENTS $EXCEPTIONS" != *"$file"* ]]; then diff_text $OTHER_UNZIPDIR/$file $THIS_UNZIPDIR/$file >> $WORK_DIR/$ZIP_FILE.diffs - fi + fi done if [ -s "$WORK_DIR/$ZIP_FILE.diffs" ]; then @@ -573,6 +574,10 @@ compare_bin_file() { $MKDIR -p $FILE_WORK_DIR + # Make soft links to original files from work dir to facilitate debugging + $LN -f -s $THIS_FILE $WORK_FILE_BASE.this + $LN -f -s $OTHER_FILE $WORK_FILE_BASE.other + ORIG_THIS_FILE="$THIS_FILE" ORIG_OTHER_FILE="$OTHER_FILE" @@ -589,50 +594,51 @@ compare_bin_file() { fi if [ "$OPENJDK_TARGET_OS" = "windows" ]; then - unset _NT_SYMBOL_PATH - # On windows we need to unzip the debug symbols, if present - OTHER_FILE_BASE=${OTHER_FILE/.dll/} - OTHER_FILE_BASE=${OTHER_FILE_BASE/.exe/} - DIZ_NAME=$(basename $OTHER_FILE_BASE).diz + unset _NT_SYMBOL_PATH + # On windows we need to unzip the debug symbols, if present + OTHER_FILE_BASE=${OTHER_FILE/.dll/} + OTHER_FILE_BASE=${OTHER_FILE_BASE/.exe/} + OTHER_FILE_BASE=${OTHER_FILE_BASE/.cpl/} + DIZ_NAME=$(basename $OTHER_FILE_BASE).diz # java.exe and java.dll diz files will have the same name. Have to - # make sure java.exe gets the right one. This is only needed for - # OTHER since in the new build, all pdb files are left around. - if [ "$NAME" = "java.exe" ] && [ -f "$OTHER/tmp/java/java/obj64/java.diz" ]; then - OTHER_DIZ_FILE="$OTHER/tmp/java/java/obj64/java.diz" - elif [ -f "${OTHER_FILE_BASE}.diz" ]; then - OTHER_DIZ_FILE=${OTHER_FILE_BASE}.diz - else + # make sure java.exe gets the right one. This is only needed for + # OTHER since in the new build, all pdb files are left around. + if [ "$NAME" = "java.exe" ] && [ -f "$OTHER/tmp/java/java/obj64/java.diz" ]; then + OTHER_DIZ_FILE="$OTHER/tmp/java/java/obj64/java.diz" + elif [ -f "${OTHER_FILE_BASE}.diz" ]; then + OTHER_DIZ_FILE=${OTHER_FILE_BASE}.diz + else # Some files, jli.dll, appears twice in the image but only one of - # thme has a diz file next to it. - OTHER_DIZ_FILE="$($FIND $OTHER_DIR -name $DIZ_NAME | $SED 1q)" - if [ ! -f "$OTHER_DIZ_FILE" ]; then - # As a last resort, look for diz file in the whole build output - # dir. - OTHER_DIZ_FILE="$($FIND $OTHER -name $DIZ_NAME | $SED 1q)" - fi - fi - if [ -n "$OTHER_DIZ_FILE" ]; then - $MKDIR -p $FILE_WORK_DIR/other - (cd $FILE_WORK_DIR/other ; $UNARCHIVE -o $OTHER_DIZ_FILE) - export _NT_SYMBOL_PATH="$FILE_WORK_DIR/other" - fi - THIS_FILE_BASE=${THIS_FILE/.dll/} - THIS_FILE_BASE=${THIS_FILE_BASE/.exe/} - if [ -f "${THIS_FILE/.dll/}.diz" ]; then - THIS_DIZ_FILE=${THIS_FILE/.dll/}.diz - else - THIS_DIZ_FILE="$($FIND $THIS_DIR -name $DIZ_NAME | $SED 1q)" - if [ ! -f "$THIS_DIZ_FILE" ]; then - # As a last resort, look for diz file in the whole build output - # dir. - THIS_DIZ_FILE="$($FIND $THIS -name $DIZ_NAME | $SED 1q)" - fi - fi - if [ -n "$THIS_DIZ_FILE" ]; then - $MKDIR -p $FILE_WORK_DIR/this - (cd $FILE_WORK_DIR/this ; $UNARCHIVE -o $THIS_DIZ_FILE) - export _NT_SYMBOL_PATH="$_NT_SYMBOL_PATH;$FILE_WORK_DIR/this" - fi + # thme has a diz file next to it. + OTHER_DIZ_FILE="$($FIND $OTHER_DIR -name $DIZ_NAME | $SED 1q)" + if [ ! -f "$OTHER_DIZ_FILE" ]; then + # As a last resort, look for diz file in the whole build output + # dir. + OTHER_DIZ_FILE="$($FIND $OTHER -name $DIZ_NAME | $SED 1q)" + fi + fi + if [ -n "$OTHER_DIZ_FILE" ]; then + $MKDIR -p $FILE_WORK_DIR/other + (cd $FILE_WORK_DIR/other ; $UNARCHIVE -o $OTHER_DIZ_FILE) + export _NT_SYMBOL_PATH="$FILE_WORK_DIR/other" + fi + THIS_FILE_BASE=${THIS_FILE/.dll/} + THIS_FILE_BASE=${THIS_FILE_BASE/.exe/} + if [ -f "${THIS_FILE/.dll/}.diz" ]; then + THIS_DIZ_FILE=${THIS_FILE/.dll/}.diz + else + THIS_DIZ_FILE="$($FIND $THIS_DIR -name $DIZ_NAME | $SED 1q)" + if [ ! -f "$THIS_DIZ_FILE" ]; then + # As a last resort, look for diz file in the whole build output + # dir. + THIS_DIZ_FILE="$($FIND $THIS -name $DIZ_NAME | $SED 1q)" + fi + fi + if [ -n "$THIS_DIZ_FILE" ]; then + $MKDIR -p $FILE_WORK_DIR/this + (cd $FILE_WORK_DIR/this ; $UNARCHIVE -o $THIS_DIZ_FILE) + export _NT_SYMBOL_PATH="$_NT_SYMBOL_PATH;$FILE_WORK_DIR/this" + fi fi if [ -z "$SKIP_BIN_DIFF" ]; then @@ -670,19 +676,19 @@ compare_bin_file() { DIFF_SIZE_REL=$($EXPR $THIS_SIZE \* 100 / $OTHER_SIZE) SIZE_MSG=$($PRINTF "%3d%% %4d" $DIFF_SIZE_REL $DIFF_SIZE_NUM) if [[ "$ACCEPTED_SMALL_SIZE_DIFF" = *"$BIN_FILE"* ]] && [ "$DIFF_SIZE_REL" -gt 98 ] \ - && [ "$DIFF_SIZE_REL" -lt 102 ]; then + && [ "$DIFF_SIZE_REL" -lt 102 ]; then SIZE_MSG="($SIZE_MSG)" DIFF_SIZE= elif [ "$OPENJDK_TARGET_OS" = "windows" ] \ - && [[ "$ACCEPTED_SMALL_SIZE_DIFF" = *"$BIN_FILE"* ]] \ - && [ "$DIFF_SIZE_NUM" = 512 ]; then - # On windows, size of binaries increase in 512 increments. + && [[ "$ACCEPTED_SMALL_SIZE_DIFF" = *"$BIN_FILE"* ]] \ + && [ "$DIFF_SIZE_NUM" = 512 ]; then + # On windows, size of binaries increase in 512 increments. SIZE_MSG="($SIZE_MSG)" DIFF_SIZE= elif [ "$OPENJDK_TARGET_OS" = "windows" ] \ - && [[ "$ACCEPTED_SMALL_SIZE_DIFF" = *"$BIN_FILE"* ]] \ - && [ "$DIFF_SIZE_NUM" = -512 ]; then - # On windows, size of binaries increase in 512 increments. + && [[ "$ACCEPTED_SMALL_SIZE_DIFF" = *"$BIN_FILE"* ]] \ + && [ "$DIFF_SIZE_NUM" = -512 ]; then + # On windows, size of binaries increase in 512 increments. SIZE_MSG="($SIZE_MSG)" DIFF_SIZE= else @@ -717,18 +723,18 @@ compare_bin_file() { if [ "$OPENJDK_TARGET_OS" = "windows" ]; then # The output from dumpbin on windows differs depending on if the debug symbol # files are still around at the location the binary is pointing too. Need - # to filter out that extra information. - $DUMPBIN -exports $OTHER_FILE | $GREP -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other - $DUMPBIN -exports $THIS_FILE | $GREP -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this + # to filter out that extra information. + $DUMPBIN -exports $OTHER_FILE | $GREP -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other + $DUMPBIN -exports $THIS_FILE | $GREP -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then # Some symbols get seemingly random 15 character prefixes. Filter them out. $NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other - $NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this + $NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this else - $NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other - $NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this + $NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other + $NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this fi - + LC_ALL=C $DIFF $WORK_FILE_BASE.symbols.other $WORK_FILE_BASE.symbols.this > $WORK_FILE_BASE.symbols.diff if [ -s $WORK_FILE_BASE.symbols.diff ]; then SYM_MSG=" diff " @@ -741,7 +747,7 @@ compare_bin_file() { SYM_MSG=" $SYM_MSG " fi else - SYM_MSG="($SYM_MSG)" + SYM_MSG="($SYM_MSG)" DIFF_SYM= fi else @@ -754,48 +760,48 @@ compare_bin_file() { # Check dependencies if [ -n "$LDD_CMD" ]; then - (cd $FILE_WORK_DIR && $CP $OTHER_FILE . && $LDD_CMD $NAME 2>/dev/null | $AWK '{ print $1;}' | $SORT | $TEE $WORK_FILE_BASE.deps.other | $UNIQ > $WORK_FILE_BASE.deps.other.uniq) - (cd $FILE_WORK_DIR && $CP $THIS_FILE . && $LDD_CMD $NAME 2 $WORK_FILE_BASE.deps.this.uniq) - (cd $FILE_WORK_DIR && $RM -f $NAME) - - LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other $WORK_FILE_BASE.deps.this > $WORK_FILE_BASE.deps.diff - LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other.uniq $WORK_FILE_BASE.deps.this.uniq > $WORK_FILE_BASE.deps.diff.uniq - - if [ -s $WORK_FILE_BASE.deps.diff ]; then + (cd $FILE_WORK_DIR && $CP $OTHER_FILE . && $LDD_CMD $NAME 2>/dev/null | $AWK '{ print $1;}' | $SORT | $TEE $WORK_FILE_BASE.deps.other | $UNIQ > $WORK_FILE_BASE.deps.other.uniq) + (cd $FILE_WORK_DIR && $CP $THIS_FILE . && $LDD_CMD $NAME 2 $WORK_FILE_BASE.deps.this.uniq) + (cd $FILE_WORK_DIR && $RM -f $NAME) + + LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other $WORK_FILE_BASE.deps.this > $WORK_FILE_BASE.deps.diff + LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other.uniq $WORK_FILE_BASE.deps.this.uniq > $WORK_FILE_BASE.deps.diff.uniq + + if [ -s $WORK_FILE_BASE.deps.diff ]; then if [ -s $WORK_FILE_BASE.deps.diff.uniq ]; then - DEP_MSG=" diff " + DEP_MSG=" diff " else - DEP_MSG=" redun " + DEP_MSG=" redun " fi if [[ "$ACCEPTED_DEP_DIFF" != *"$BIN_FILE"* ]]; then - DIFF_DEP=true - if [[ "$KNOWN_DEP_DIFF" != *"$BIN_FILE"* ]]; then + DIFF_DEP=true + if [[ "$KNOWN_DEP_DIFF" != *"$BIN_FILE"* ]]; then DEP_MSG="*$DEP_MSG*" REGRESSIONS=true - else + else DEP_MSG=" $DEP_MSG " - fi + fi else - DEP_MSG="($DEP_MSG)" - DIFF_DEP= + DEP_MSG="($DEP_MSG)" + DIFF_DEP= fi - else - DEP_MSG=" " - DIFF_DEP= + else + DEP_MSG=" " + DIFF_DEP= if [[ "$KNOWN_DEP_DIFF $ACCEPTED_DEP_DIFF" = *"$BIN_FILE"* ]]; then DEP_MSG=" ! " fi - fi + fi else - DEP_MSG=" - " + DEP_MSG=" - " fi - + # Compare fulldump output if [ -n "$FULLDUMP_CMD" ] && [ -z "$SKIP_FULLDUMP_DIFF" ]; then $FULLDUMP_CMD $OTHER_FILE > $WORK_FILE_BASE.fulldump.other 2>&1 $FULLDUMP_CMD $THIS_FILE > $WORK_FILE_BASE.fulldump.this 2>&1 LC_ALL=C $DIFF $WORK_FILE_BASE.fulldump.other $WORK_FILE_BASE.fulldump.this > $WORK_FILE_BASE.fulldump.diff - + if [ -s $WORK_FILE_BASE.fulldump.diff ]; then ELF_DIFF_SIZE=$(ls -n $WORK_FILE_BASE.fulldump.diff | awk '{print $5}') ELF_MSG=$($PRINTF "%8d" $ELF_DIFF_SIZE) @@ -822,14 +828,17 @@ compare_bin_file() { # Compare disassemble output if [ -n "$DIS_CMD" ] && [ -z "$SKIP_DIS_DIFF" ]; then - if [ -z "$DIS_DIFF_FILTER" ]; then - DIS_DIFF_FILTER="$CAT" - fi - $DIS_CMD $OTHER_FILE | $GREP -v $NAME | $DIS_DIFF_FILTER > $WORK_FILE_BASE.dis.other 2>&1 - $DIS_CMD $THIS_FILE | $GREP -v $NAME | $DIS_DIFF_FILTER > $WORK_FILE_BASE.dis.this 2>&1 - + # By default we filter out differences that include references to symbols. + # To get a raw diff with the complete disassembly, set + # DIS_DIFF_FILTER="$CAT" + if [ -z "$DIS_DIFF_FILTER" ]; then + DIS_DIFF_FILTER="$GREP -v ' # .* <.*>$'" + fi + $DIS_CMD $OTHER_FILE | $GREP -v $NAME | eval "$DIS_DIFF_FILTER" > $WORK_FILE_BASE.dis.other 2>&1 + $DIS_CMD $THIS_FILE | $GREP -v $NAME | eval "$DIS_DIFF_FILTER" > $WORK_FILE_BASE.dis.this 2>&1 + LC_ALL=C $DIFF $WORK_FILE_BASE.dis.other $WORK_FILE_BASE.dis.this > $WORK_FILE_BASE.dis.diff - + if [ -s $WORK_FILE_BASE.dis.diff ]; then DIS_DIFF_SIZE=$(ls -n $WORK_FILE_BASE.dis.diff | awk '{print $5}') DIS_MSG=$($PRINTF "%8d" $DIS_DIFF_SIZE) @@ -907,7 +916,9 @@ compare_all_libs() { OTHER_DIR=$2 WORK_DIR=$3 - LIBS=$(cd $THIS_DIR && $FIND . -type f \( -name 'lib*.so' -o -name '*.dylib' -o -name '*.dll' -o -name 'JavaControlPanel' \) | $SORT | $FILTER) + LIBS=$(cd $THIS_DIR && $FIND . -type f \( -name 'lib*.so' -o -name '*.dylib' \ + -o -name '*.dll' -o -name '*.obj' -o -name '*.o' \ + -o -name '*.cpl' \) | $SORT | $FILTER) if [ -n "$LIBS" ]; then echo Libraries... @@ -967,7 +978,7 @@ COMPARE_ROOT=/tmp/cimages.$USER $MKDIR -p $COMPARE_ROOT if [ "$OPENJDK_TARGET_OS" = "windows" ]; then if [ "$(uname -o)" = "Cygwin" ]; then - COMPARE_ROOT=$(cygpath -msa $COMPARE_ROOT) + COMPARE_ROOT=$(cygpath -msa $COMPARE_ROOT) fi fi @@ -1091,7 +1102,7 @@ while [ -n "$1" ]; do CMP_JARS=true CMP_LIBS=true CMP_EXECS=true - + if [ -z "$FILTER" ]; then FILTER="$GREP" fi @@ -1177,8 +1188,8 @@ if [ "$SKIP_DEFAULT" != "true" ]; then OTHER_J2RE="$OTHER/images/jre" echo "Selecting jdk images for compare" else - echo "No common images found." - exit 1 + echo "No common images found." + exit 1 fi if [ -d "$THIS/images/jdk-bundle" ] && [ -d "$OTHER/images/jdk-bundle" ]; then @@ -1189,6 +1200,17 @@ if [ "$SKIP_DEFAULT" != "true" ]; then echo "Also comparing macosx bundles" fi + if [ -d "$THIS/deploy" ] && [ -d "$OTHER/deploy" ]; then + THIS_DEPLOY_BUNDLE_DIR="$THIS/deploy/dist/installer/bundles" + OTHER_DEPLOY_BUNDLE_DIR="$OTHER/deploy/bundles" + echo "Also comparing deploy/bundles" + if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then + THIS_DEPLOY_APPLET_PLUGIN_DIR="$THIS/deploy/JavaAppletPlugin.plugin" + OTHER_DEPLOY_APPLET_PLUGIN_DIR="$OTHER/deploy/JavaAppletPlugin.plugin" + echo "Also comparing JavaAppletPlugin" + fi + fi + if [ -d "$OTHER/images" ]; then OTHER_SEC_DIR="$OTHER/images" else @@ -1212,7 +1234,7 @@ if [ "$SKIP_DEFAULT" != "true" ]; then if [ -d "$THIS/docs" ] && [ -d "$OTHER/docs" ]; then THIS_DOCS="$THIS/docs" OTHER_DOCS="$OTHER/docs" - echo "Also comparing docs" + echo "Also comparing docs" else echo "WARNING! Docs haven't been built and won't be compared." fi @@ -1227,7 +1249,7 @@ if [ "$CMP_NAMES" = "true" ]; then compare_dirs $THIS_J2SDK $OTHER_J2SDK $COMPARE_ROOT/j2sdk echo -n "J2RE " compare_dirs $THIS_J2RE $OTHER_J2RE $COMPARE_ROOT/j2re - + echo -n "J2SDK " compare_files $THIS_J2SDK $OTHER_J2SDK $COMPARE_ROOT/j2sdk echo -n "J2RE " @@ -1238,7 +1260,7 @@ if [ "$CMP_NAMES" = "true" ]; then compare_dirs $THIS_J2SDK_BUNDLE $OTHER_J2SDK_BUNDLE $COMPARE_ROOT/jdk-bundle echo -n "J2RE Bundle " compare_dirs $THIS_J2RE_BUNDLE $OTHER_J2RE_BUNDLE $COMPARE_ROOT/jre-bundle - + echo -n "J2SDK Bundle " compare_files $THIS_J2SDK_BUNDLE $OTHER_J2SDK_BUNDLE $COMPARE_ROOT/jdk-bundle echo -n "J2RE Bundle " @@ -1254,6 +1276,12 @@ if [ "$CMP_NAMES" = "true" ]; then compare_dirs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir compare_files $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir fi + if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then + echo -n "JavaAppletPlugin " + compare_dirs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin + echo -n "JavaAppletPlugin " + compare_files $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin + fi fi if [ "$CMP_PERMS" = "true" ]; then @@ -1266,6 +1294,10 @@ if [ "$CMP_PERMS" = "true" ]; then if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then compare_permissions $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir fi + if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then + echo -n "JavaAppletPlugin " + compare_permissions $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin + fi fi if [ "$CMP_TYPES" = "true" ]; then @@ -1284,6 +1316,10 @@ if [ "$CMP_TYPES" = "true" ]; then if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then compare_file_types $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir fi + if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then + echo -n "JavaAppletPlugin " + compare_file_types $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin + fi fi if [ "$CMP_GENERAL" = "true" ]; then @@ -1306,6 +1342,10 @@ if [ "$CMP_GENERAL" = "true" ]; then if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then compare_general_files $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir fi + if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then + echo -n "JavaAppletPlugin " + compare_general_files $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin + fi fi if [ "$CMP_ZIPS" = "true" ]; then @@ -1333,6 +1373,12 @@ if [ "$CMP_ZIPS" = "true" ]; then if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then compare_all_zip_files $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir fi + if [ -n "$THIS_DEPLOY_BUNDLE_DIR" ] && [ -n "$OTHER_DEPLOY_BUNDLE_DIR" ]; then + compare_all_zip_files $THIS_DEPLOY_BUNDLE_DIR $OTHER_DEPLOY_BUNDLE_DIR $COMPARE_ROOT/deploy-bundle + fi + if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then + compare_all_zip_files $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin + fi fi if [ "$CMP_JARS" = "true" ]; then @@ -1342,6 +1388,9 @@ if [ "$CMP_JARS" = "true" ]; then if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then compare_all_jar_files $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir fi + if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then + compare_all_jar_files $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin + fi fi if [ "$CMP_LIBS" = "true" ]; then @@ -1356,15 +1405,27 @@ if [ "$CMP_LIBS" = "true" ]; then if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then compare_all_libs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir fi + if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then + echo -n "JavaAppletPlugin " + compare_all_libs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin + fi fi if [ "$CMP_EXECS" = "true" ]; then if [ -n "$THIS_J2SDK" ] && [ -n "$OTHER_J2SDK" ]; then compare_all_execs $THIS_J2SDK $OTHER_J2SDK $COMPARE_ROOT/j2sdk + if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then + echo -n "J2RE " + compare_all_execs $THIS_J2RE $OTHER_J2RE $COMPARE_ROOT/j2re + fi fi if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then compare_all_execs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir fi + if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then + echo -n "JavaAppletPlugin " + compare_all_execs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin + fi fi echo diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh index 5bf586bc13c..244881ae77c 100644 --- a/common/bin/hgforest.sh +++ b/common/bin/hgforest.sh @@ -106,12 +106,15 @@ if [ ${vflag} = "true" ] ; then echo "# Mercurial command: ${command}" > ${status_output} fi - -# capture command options and arguments (if any) -command_args="${@:-}" +# At this point all command options and args are in "$@". +# Always use "$@" (within double quotes) to avoid breaking +# args with spaces into separate args. if [ ${vflag} = "true" ] ; then - echo "# Mercurial command arguments: ${command_args}" > ${status_output} + echo "# Mercurial command argument count: $#" > ${status_output} + for cmdarg in "$@" ; do + echo "# Mercurial command argument: ${cmdarg}" > ${status_output} + done fi # Clean out the temporary directory that stores the pid files. @@ -205,13 +208,14 @@ if [ "${command}" = "clone" -o "${command}" = "fclone" -o "${command}" = "tclone pull_default_tail=`echo ${pull_default} | sed -e 's@^.*://[^/]*/\(.*\)@\1@'` - if [ -n "${command_args}" ] ; then + if [ $# -gt 0 ] ; then # if there is an "extra sources" path then reparent "extra" repos to that path if [ "x${pull_default}" = "x${pull_default_tail}" ] ; then echo "ERROR: Need initial clone from non-local source" > ${status_output} exit 1 fi - pull_extra="${command_args}/${pull_default_tail}" + # assume that "extra sources" path is the first arg + pull_extra="${1}/${pull_default_tail}" # determine which extra subrepos need to be cloned. for i in ${subrepos_extra} ; do @@ -356,8 +360,8 @@ else (PYTHONUNBUFFERED=true hg${global_opts} clone ${clone_newrepo} ${i}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & else # run the command. - echo "cd ${i} && hg${global_opts} ${command} ${command_args}" > ${status_output} - cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} ${command_args}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & + echo "cd ${i} && hg${global_opts} ${command} ${@}" > ${status_output} + cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} "${@}"; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & fi echo $! > ${tmp}/${repopidfile}.pid diff --git a/common/bin/unshuffle_list.txt b/common/bin/unshuffle_list.txt index cd0749c7aa8..0219bd7b005 100644 --- a/common/bin/unshuffle_list.txt +++ b/common/bin/unshuffle_list.txt @@ -26,10 +26,8 @@ corba/src/java.corba/share/classes/com/sun/org/omg : corba/src/share/classes/com corba/src/java.corba/share/classes/com/sun/tools/corba/se/idl : corba/src/share/classes/com/sun/tools/corba/se/idl corba/src/java.corba/share/classes/javax/activity : corba/src/share/classes/javax/activity corba/src/java.corba/share/classes/javax/rmi : corba/src/share/classes/javax/rmi -corba/src/java.corba/share/classes/javax/transaction : corba/src/share/classes/javax/transaction corba/src/java.corba/share/classes/org/omg : corba/src/share/classes/org/omg corba/src/java.corba/share/classes/sun/corba : corba/src/share/classes/sun/corba -corba/src/java.sql/share/classes/javax/transaction/xa : corba/src/share/classes/javax/transaction/xa corba/src/jdk.rmic/share/classes/sun/rmi/rmic/iiop : corba/src/share/classes/sun/rmi/rmic/iiop jaxp/src/java.xml/share/classes/com/sun/java_cup/internal/runtime : jaxp/src/com/sun/java_cup/internal/runtime jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal : jaxp/src/com/sun/org/apache/bcel/internal @@ -66,8 +64,8 @@ jaxws/src/java.xml.bind/share/classes/com/sun/xml/internal/fastinfoset : jaxws/s jaxws/src/java.xml.bind/share/classes/com/sun/xml/internal/org : jaxws/src/share/jaxws_classes/com/sun/xml/internal/org jaxws/src/java.xml.bind/share/classes/com/sun/xml/internal/txw2 : jaxws/src/share/jaxws_classes/com/sun/xml/internal/txw2 jaxws/src/java.xml.bind/share/classes/javax/xml/bind : jaxws/src/share/jaxws_classes/javax/xml/bind -jaxws/src/java.xml.soap/share/classes/com/sun/xml/internal/messaging : jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging -jaxws/src/java.xml.soap/share/classes/javax/xml/soap : jaxws/src/share/jaxws_classes/javax/xml/soap +jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging : jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging +jaxws/src/java.xml.ws/share/classes/javax/xml/soap : jaxws/src/share/jaxws_classes/javax/xml/soap jaxws/src/java.xml.ws/share/classes/com/oracle/webservices/internal : jaxws/src/share/jaxws_classes/com/oracle/webservices/internal jaxws/src/java.xml.ws/share/classes/com/oracle/xmlns/internal : jaxws/src/share/jaxws_classes/com/oracle/xmlns/internal jaxws/src/java.xml.ws/share/classes/com/sun/org/glassfish : jaxws/src/share/jaxws_classes/com/sun/org/glassfish @@ -1245,6 +1243,8 @@ jdk/src/java.sql.rowset/share/classes/com/sun/rowset : jdk/src/share/classes/com jdk/src/java.sql.rowset/share/classes/javax/sql/rowset : jdk/src/share/classes/javax/sql/rowset jdk/src/java.sql/share/classes/java/sql : jdk/src/share/classes/java/sql jdk/src/java.sql/share/classes/javax/sql : jdk/src/share/classes/javax/sql +jdk/src/java.sql/share/classes/javax/transaction/xa : corba/src/share/classes/javax/transaction/xa +jdk/src/java.transaction/share/classes/javax/transaction : corba/src/share/classes/javax/transaction jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security : jdk/src/share/classes/com/sun/org/apache/xml/internal/security jdk/src/java.xml.crypto/share/classes/javax/xml/crypto : jdk/src/share/classes/javax/xml/crypto jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal : jdk/src/share/classes/org/jcp/xml/dsig/internal diff --git a/corba/.hgtags b/corba/.hgtags index 26c65ed70d5..5fa0c422fef 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -285,3 +285,9 @@ ffd90c81d4ef9d94d880fc852e2fc482ecd9b374 jdk9-b36 e27c725d6c9d155667b35255f442d4ceb8c3c084 jdk9-b40 1908b886ba1eda46fa725cf1160fe5d30fd1a7e5 jdk9-b41 078bb11af876fe528d4b516f33ad4dd9bb60549e jdk9-b42 +9645e35616b60c5c07b4fdf11a132afc8081dfa8 jdk9-b43 +1f57bd728c9e6865ccb9d43ccd80a1c11230a32f jdk9-b44 +9e3f2bed80c0e5a84a256ce41f1d10c5ade48466 jdk9-b45 +326f2068b4a4c05e2fa27d6acf93eba7b54b090d jdk9-b46 +ee8447ca632e1d39180b4767c749db101bff7314 jdk9-b47 +a13c49c5f2899b702652a460ed7aa73123e671e6 jdk9-b48 diff --git a/corba/src/java.sql/share/classes/javax/transaction/xa/XAResource.java b/corba/src/java.sql/share/classes/javax/transaction/xa/XAResource.java deleted file mode 100644 index ffb7226a446..00000000000 --- a/corba/src/java.sql/share/classes/javax/transaction/xa/XAResource.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 javax.transaction.xa; - -/**

The XAResource interface is a Java mapping of the industry standard - * XA interface based on the X/Open CAE Specification (Distributed - * Transaction Processing: The XA Specification). - * - *

The XA interface defines the contract between a Resource Manager - * and a Transaction Manager in a distributed transaction processing - * (DTP) environment. A JDBC driver or a JMS provider implements - * this interface to support the association between a global transaction - * and a database or message service connection. - * - *

The XAResource interface can be supported by any transactional - * resource that is intended to be used by application programs in an - * environment where transactions are controlled by an external - * transaction manager. An example of such a resource is a database - * management system. An application may access data through multiple - * database connections. Each database connection is enlisted with - * the transaction manager as a transactional resource. The transaction - * manager obtains an XAResource for each connection participating - * in a global transaction. The transaction manager uses the - * start method - * to associate the global transaction with the resource, and it uses the - * end method to disassociate the transaction from - * the resource. The resource - * manager is responsible for associating the global transaction to all - * work performed on its data between the start and end method invocations. - * - *

At transaction commit time, the resource managers are informed by - * the transaction manager to prepare, commit, or rollback a transaction - * according to the two-phase commit protocol.

- * - */ - -public interface XAResource -{ - /** Commits the global transaction specified by xid. - * - * @param xid A global transaction identifier - * - * @param onePhase If true, the resource manager should use a one-phase - * commit protocol to commit the work done on behalf of xid. - * - * @exception XAException An error has occurred. Possible XAExceptions - * are XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX, XAER_RMERR, - * XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO. - * - *

If the resource manager did not commit the transaction and the - * paramether onePhase is set to true, the resource manager may throw - * one of the XA_RB* exceptions. Upon return, the resource manager has - * rolled back the branch's work and has released all held resources. - */ - - void commit(Xid xid, boolean onePhase) throws XAException; - - - /** Ends the work performed on behalf of a transaction branch. - * The resource manager disassociates the XA resource from the - * transaction branch specified and lets the transaction - * complete. - * - *

If TMSUSPEND is specified in the flags, the transaction branch - * is temporarily suspended in an incomplete state. The transaction - * context is in a suspended state and must be resumed via the - * start method with TMRESUME specified.

- * - *

If TMFAIL is specified, the portion of work has failed. - * The resource manager may mark the transaction as rollback-only

- * - *

If TMSUCCESS is specified, the portion of work has completed - * successfully.

- * - * @param xid A global transaction identifier that is the same as - * the identifier used previously in the start method. - * - * @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND. - * - * @exception XAException An error has occurred. Possible XAException - * values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA, XAER_INVAL, - * XAER_PROTO, or XA_RB*. - */ - - void end(Xid xid, int flags) throws XAException; - - - /** Tells the resource manager to forget about a heuristically - * completed transaction branch. - * - * @param xid A global transaction identifier. - * - * @exception XAException An error has occurred. Possible exception - * values are XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or - * XAER_PROTO. - */ - - void forget(Xid xid) throws XAException; - - /** Obtains the current transaction timeout value set for this - * XAResource instance. If XAResource.setTransactionTimeout - * was not used prior to invoking this method, the return value - * is the default timeout set for the resource manager; otherwise, - * the value used in the previous setTransactionTimeout - * call is returned. - * - * @return the transaction timeout value in seconds. - * - * @exception XAException An error has occurred. Possible exception - * values are XAER_RMERR and XAER_RMFAIL. - */ - int getTransactionTimeout() throws XAException; - - /** This method is called to determine if the resource manager - * instance represented by the target object is the same as the - * resouce manager instance represented by the parameter xares. - * - * @param xares An XAResource object whose resource manager instance - * is to be compared with the resource manager instance of the - * target object. - * - * @return true if it's the same RM instance; otherwise - * false. - * - * @exception XAException An error has occurred. Possible exception - * values are XAER_RMERR and XAER_RMFAIL. - * - */ - boolean isSameRM(XAResource xares) throws XAException; - - /** Ask the resource manager to prepare for a transaction commit - * of the transaction specified in xid. - * - * @param xid A global transaction identifier. - * - * @exception XAException An error has occurred. Possible exception - * values are: XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, - * or XAER_PROTO. - * - * @return A value indicating the resource manager's vote on the - * outcome of the transaction. The possible values are: XA_RDONLY - * or XA_OK. If the resource manager wants to roll back the - * transaction, it should do so by raising an appropriate XAException - * in the prepare method. - */ - - int prepare(Xid xid) throws XAException; - - - /** Obtains a list of prepared transaction branches from a resource - * manager. The transaction manager calls this method during recovery - * to obtain the list of transaction branches that are currently in - * prepared or heuristically completed states. - * - * @param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. TMNOFLAGS - * must be used when no other flags are set in the parameter. - * - * @exception XAException An error has occurred. Possible values are - * XAER_RMERR, XAER_RMFAIL, XAER_INVAL, and XAER_PROTO. - * - * @return The resource manager returns zero or more XIDs of the - * transaction branches that are currently in a prepared or - * heuristically completed state. If an error occurs during the - * operation, the resource manager should throw the appropriate - * XAException. - * - */ - - Xid[] recover(int flag) throws XAException; - - - /** Informs the resource manager to roll back work done on behalf - * of a transaction branch. - * - * @param xid A global transaction identifier. - * - * @exception XAException An error has occurred. - */ - - void rollback(Xid xid) throws XAException; - - - /**

Sets the current transaction timeout value for this XAResource - * instance. Once set, this timeout value is effective until - * setTransactionTimeout is invoked again with a different - * value. To reset the timeout value to the default value used by the resource - * manager, set the value to zero. - * - * If the timeout operation is performed successfully, the method returns - * true; otherwise false. If a resource manager does not - * support explicitly setting the transaction timeout value, this method - * returns false. - * - * @param seconds The transaction timeout value in seconds. - * - * @return true if the transaction timeout value is set successfully; - * otherwise false. - * - * @exception XAException An error has occurred. Possible exception values - * are XAER_RMERR, XAER_RMFAIL, or XAER_INVAL. - */ - boolean setTransactionTimeout(int seconds) throws XAException; - - - /** Starts work on behalf of a transaction branch specified in - * xid. - * - * If TMJOIN is specified, the start applies to joining a transaction - * previously seen by the resource manager. If TMRESUME is specified, - * the start applies to resuming a suspended transaction specified in the - * parameter xid. - * - * If neither TMJOIN nor TMRESUME is specified and the transaction - * specified by xid has previously been seen by the resource - * manager, the resource manager throws the XAException exception with - * XAER_DUPID error code. - * - * @param xid A global transaction identifier to be associated - * with the resource. - * - * @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME. - * - * @exception XAException An error has occurred. Possible exceptions - * are XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_DUPID, XAER_OUTSIDE, - * XAER_NOTA, XAER_INVAL, or XAER_PROTO. - * - */ - void start(Xid xid, int flags) throws XAException; - - - /** - * Ends a recovery scan. - */ - public final static int TMENDRSCAN = 0x00800000; - - /** - * Disassociates the caller and marks the transaction branch - * rollback-only. - */ - public final static int TMFAIL = 0x20000000; - - /** - * Caller is joining existing transaction branch. - */ - public final static int TMJOIN = 0x00200000; - - /** - * Use TMNOFLAGS to indicate no flags value is selected. - */ - public final static int TMNOFLAGS = 0x00000000; - - /** - * Caller is using one-phase optimization. - */ - public final static int TMONEPHASE = 0x40000000; - - /** - * Caller is resuming association with a suspended - * transaction branch. - */ - public final static int TMRESUME = 0x08000000; - - /** - * Starts a recovery scan. - */ - public final static int TMSTARTRSCAN = 0x01000000; - - - /** - * Disassociates caller from a transaction branch. - */ - public final static int TMSUCCESS = 0x04000000; - - - /** - * Caller is suspending (not ending) its association with - * a transaction branch. - */ - public final static int TMSUSPEND = 0x02000000; - - /** - * The transaction branch has been read-only and has been committed. - */ - public final static int XA_RDONLY = 0x00000003; - - /** - * The transaction work has been prepared normally. - */ - public final static int XA_OK = 0; - -} diff --git a/hotspot/.hgtags b/hotspot/.hgtags index ae7d006d45b..a0e96eab962 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -445,3 +445,9 @@ c363a8b87e477ee45d6d3cb2a36cb365141bc596 jdk9-b38 6b09b3193d731e3288e2a240c504a20d0a06c766 jdk9-b40 1d29b13e8a515a7ea3b882f140576d5d675bc11f jdk9-b41 38cb4fbd47e3472bd1b5ebac83bda96fe4869c4f jdk9-b42 +65a9747147b8090037541040ba67156ec914db6a jdk9-b43 +43a44b56dca61a4d766a20f0528fdd8b5ceff873 jdk9-b44 +5dc8184af1e2bb30b0103113d1f1a58a21a80c37 jdk9-b45 +a184ee1d717297bd35b7c3e35393e137921a3ed2 jdk9-b46 +3b241fb72b8925b75941d612db762a6d5da66d02 jdk9-b47 +cc775a4a24c7f5d9e624b4205e9fbd48a17331f6 jdk9-b48 diff --git a/hotspot/agent/make/Makefile b/hotspot/agent/make/Makefile index 5efd67e649c..8462ef68086 100644 --- a/hotspot/agent/make/Makefile +++ b/hotspot/agent/make/Makefile @@ -58,15 +58,19 @@ sun.jvm.hotspot.debugger.cdbg.basic.x86 \ sun.jvm.hotspot.debugger.dummy \ sun.jvm.hotspot.debugger.linux \ sun.jvm.hotspot.debugger.linux.amd64 \ +sun.jvm.hotspot.debugger.linux.ppc64 \ sun.jvm.hotspot.debugger.linux.x86 \ sun.jvm.hotspot.debugger.posix \ sun.jvm.hotspot.debugger.posix.elf \ +sun.jvm.hotspot.debugger.ppc64 \ sun.jvm.hotspot.debugger.proc \ sun.jvm.hotspot.debugger.proc.amd64 \ +sun.jvm.hotspot.debugger.proc.ppc64 \ sun.jvm.hotspot.debugger.proc.sparc \ sun.jvm.hotspot.debugger.proc.x86 \ sun.jvm.hotspot.debugger.remote \ sun.jvm.hotspot.debugger.remote.amd64 \ +sun.jvm.hotspot.debugger.remote.ppc64 \ sun.jvm.hotspot.debugger.remote.sparc \ sun.jvm.hotspot.debugger.remote.x86 \ sun.jvm.hotspot.debugger.sparc \ @@ -93,9 +97,11 @@ sun.jvm.hotspot.runtime.bsd_amd64 \ sun.jvm.hotspot.runtime.bsd_x86 \ sun.jvm.hotspot.runtime.linux \ sun.jvm.hotspot.runtime.linux_amd64 \ +sun.jvm.hotspot.runtime.linux_ppc64 \ sun.jvm.hotspot.runtime.linux_sparc \ sun.jvm.hotspot.runtime.linux_x86 \ sun.jvm.hotspot.runtime.posix \ +sun.jvm.hotspot.runtime.ppc64 \ sun.jvm.hotspot.runtime.solaris_amd64 \ sun.jvm.hotspot.runtime.solaris_sparc \ sun.jvm.hotspot.runtime.solaris_x86 \ @@ -142,15 +148,19 @@ sun/jvm/hotspot/debugger/cdbg/basic/amd64/*.java \ sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \ sun/jvm/hotspot/debugger/dummy/*.java \ sun/jvm/hotspot/debugger/linux/*.java \ +sun/jvm/hotspot/debugger/linux/ppc64/*.java \ sun/jvm/hotspot/debugger/linux/x86/*.java \ sun/jvm/hotspot/debugger/posix/*.java \ sun/jvm/hotspot/debugger/posix/elf/*.java \ +sun/jvm/hotspot/debugger/ppc64/*.java \ sun/jvm/hotspot/debugger/proc/*.java \ sun/jvm/hotspot/debugger/proc/amd64/*.java \ +sun/jvm/hotspot/debugger/proc/ppc64/*.java \ sun/jvm/hotspot/debugger/proc/sparc/*.java \ sun/jvm/hotspot/debugger/proc/x86/*.java \ sun/jvm/hotspot/debugger/remote/*.java \ sun/jvm/hotspot/debugger/remote/amd64/*.java \ +sun/jvm/hotspot/debugger/remote/ppc64/*.java \ sun/jvm/hotspot/debugger/remote/sparc/*.java \ sun/jvm/hotspot/debugger/remote/x86/*.java \ sun/jvm/hotspot/debugger/sparc/*.java \ @@ -174,9 +184,11 @@ sun/jvm/hotspot/runtime/bsd_amd64/*.java \ sun/jvm/hotspot/runtime/bsd_x86/*.java \ sun/jvm/hotspot/runtime/linux/*.java \ sun/jvm/hotspot/runtime/linux_amd64/*.java \ +sun/jvm/hotspot/runtime/linux_ppc64/*.java \ sun/jvm/hotspot/runtime/linux_sparc/*.java \ sun/jvm/hotspot/runtime/linux_x86/*.java \ sun/jvm/hotspot/runtime/posix/*.java \ +sun/jvm/hotspot/runtime/ppc64/*.java \ sun/jvm/hotspot/runtime/solaris_amd64/*.java \ sun/jvm/hotspot/runtime/solaris_sparc/*.java \ sun/jvm/hotspot/runtime/solaris_x86/*.java \ diff --git a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c index 5df5f1f1359..e9feeb8ebb8 100644 --- a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c +++ b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c @@ -49,6 +49,10 @@ #include "sun_jvm_hotspot_debugger_sparc_SPARCThreadContext.h" #endif +#ifdef ppc64 +#include "sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext.h" +#endif + static jfieldID p_ps_prochandle_ID = 0; static jfieldID threadList_ID = 0; static jfieldID loadObjectList_ID = 0; @@ -341,7 +345,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo return (err == PS_OK)? array : 0; } -#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) +#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0 (JNIEnv *env, jobject this_obj, jint lwp_id) { @@ -366,6 +370,10 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo #if defined(sparc) || defined(sparcv9) #define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG #endif +#ifdef ppc64 +#define NPRGREG sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_NPRGREG +#endif + array = (*env)->NewLongArray(env, NPRGREG); CHECK_EXCEPTION_(0); @@ -458,6 +466,45 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo regs[REG_INDEX(R_O7)] = gregs.u_regs[14]; #endif /* sparc */ +#ifdef ppc64 +#define REG_INDEX(reg) sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_##reg + + regs[REG_INDEX(LR)] = gregs.link; + regs[REG_INDEX(NIP)] = gregs.nip; + regs[REG_INDEX(R0)] = gregs.gpr[0]; + regs[REG_INDEX(R1)] = gregs.gpr[1]; + regs[REG_INDEX(R2)] = gregs.gpr[2]; + regs[REG_INDEX(R3)] = gregs.gpr[3]; + regs[REG_INDEX(R4)] = gregs.gpr[4]; + regs[REG_INDEX(R5)] = gregs.gpr[5]; + regs[REG_INDEX(R6)] = gregs.gpr[6]; + regs[REG_INDEX(R7)] = gregs.gpr[7]; + regs[REG_INDEX(R8)] = gregs.gpr[8]; + regs[REG_INDEX(R9)] = gregs.gpr[9]; + regs[REG_INDEX(R10)] = gregs.gpr[10]; + regs[REG_INDEX(R11)] = gregs.gpr[11]; + regs[REG_INDEX(R12)] = gregs.gpr[12]; + regs[REG_INDEX(R13)] = gregs.gpr[13]; + regs[REG_INDEX(R14)] = gregs.gpr[14]; + regs[REG_INDEX(R15)] = gregs.gpr[15]; + regs[REG_INDEX(R16)] = gregs.gpr[16]; + regs[REG_INDEX(R17)] = gregs.gpr[17]; + regs[REG_INDEX(R18)] = gregs.gpr[18]; + regs[REG_INDEX(R19)] = gregs.gpr[19]; + regs[REG_INDEX(R20)] = gregs.gpr[20]; + regs[REG_INDEX(R21)] = gregs.gpr[21]; + regs[REG_INDEX(R22)] = gregs.gpr[22]; + regs[REG_INDEX(R23)] = gregs.gpr[23]; + regs[REG_INDEX(R24)] = gregs.gpr[24]; + regs[REG_INDEX(R25)] = gregs.gpr[25]; + regs[REG_INDEX(R26)] = gregs.gpr[26]; + regs[REG_INDEX(R27)] = gregs.gpr[27]; + regs[REG_INDEX(R28)] = gregs.gpr[28]; + regs[REG_INDEX(R29)] = gregs.gpr[29]; + regs[REG_INDEX(R30)] = gregs.gpr[30]; + regs[REG_INDEX(R31)] = gregs.gpr[31]; + +#endif (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT); return array; diff --git a/hotspot/agent/src/os/linux/ps_proc.c b/hotspot/agent/src/os/linux/ps_proc.c index a3c18c9e0de..7d9d2611c3b 100644 --- a/hotspot/agent/src/os/linux/ps_proc.c +++ b/hotspot/agent/src/os/linux/ps_proc.c @@ -27,9 +27,11 @@ #include #include #include +#include #include #include #include +#include #include "libproc_impl.h" #if defined(x86_64) && !defined(amd64) @@ -138,6 +140,15 @@ static bool process_get_lwp_regs(struct ps_prochandle* ph, pid_t pid, struct use return false; } return true; +#elif defined(PTRACE_GETREGSET) + struct iovec iov; + iov.iov_base = user; + iov.iov_len = sizeof(*user); + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, (void*) &iov) < 0) { + print_debug("ptrace(PTRACE_GETREGSET, ...) failed for lwp %d\n", pid); + return false; + } + return true; #else print_debug("ptrace(PTRACE_GETREGS, ...) not supported\n"); return false; diff --git a/hotspot/agent/src/os/linux/symtab.c b/hotspot/agent/src/os/linux/symtab.c index 077532a06f3..61c98747854 100644 --- a/hotspot/agent/src/os/linux/symtab.c +++ b/hotspot/agent/src/os/linux/symtab.c @@ -325,6 +325,12 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t // Reading of elf header struct elf_section *scn_cache = NULL; +#if defined(ppc64) && !defined(ABI_ELFv2) + // Only big endian ppc64 (i.e. ABI_ELFv1) has 'official procedure descriptors' in ELF files + // see: http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html + struct elf_section *opd_sect = NULL; + ELF_SHDR *opd = NULL; +#endif int cnt = 0; ELF_SHDR* shbuf = NULL; ELF_SHDR* cursct = NULL; @@ -368,6 +374,14 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t cursct++; } +#if defined(ppc64) && !defined(ABI_ELFv2) + opd_sect = find_section_by_name(".opd", fd, &ehdr, scn_cache); + if (opd_sect != NULL && opd_sect->c_data != NULL && opd_sect->c_shdr != NULL) { + // plausibility check + opd = opd_sect->c_shdr; + } +#endif + for (cnt = 1; cnt < ehdr.e_shnum; cnt++) { ELF_SHDR *shdr = scn_cache[cnt].c_shdr; @@ -412,6 +426,7 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t // copy symbols info our symtab and enter them info the hash table for (j = 0; j < n; j++, syms++) { ENTRY item, *ret; + uintptr_t sym_value; char *sym_name = symtab->strs + syms->st_name; // skip non-object and non-function symbols @@ -422,9 +437,19 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue; symtab->symbols[j].name = sym_name; - symtab->symbols[j].offset = syms->st_value - baseaddr; symtab->symbols[j].size = syms->st_size; + sym_value = syms->st_value; +#if defined(ppc64) && !defined(ABI_ELFv2) + // see hotspot/src/share/vm/utilities/elfFuncDescTable.hpp for a detailed description + // of why we have to go this extra way via the '.opd' section on big endian ppc64 + if (opd != NULL && *sym_name != '.' && + (opd->sh_addr <= sym_value && sym_value <= opd->sh_addr + opd->sh_size)) { + sym_value = ((ELF_ADDR*)opd_sect->c_data)[(sym_value - opd->sh_addr) / sizeof(ELF_ADDR*)]; + } +#endif + + symtab->symbols[j].offset = sym_value - baseaddr; item.key = sym_name; item.data = (void *)&(symtab->symbols[j]); @@ -433,9 +458,17 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t } } +#if defined(ppc64) && !defined(ABI_ELFv2) + // On Linux/PPC64 the debuginfo files contain an empty function descriptor + // section (i.e. '.opd' section) which makes the resolution of symbols + // with the above algorithm impossible (we would need the have both, the + // .opd section from the library and the symbol table from the debuginfo + // file which doesn't match with the current workflow.) + goto quit; +#endif + // Look for a separate debuginfo file. if (try_debuginfo) { - // We prefer a debug symtab to an object's own symtab, so look in // the debuginfo file. We stash a copy of the old symtab in case // there is no debuginfo. diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java index 070ac8d42d6..6cc16695d99 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java @@ -34,6 +34,6 @@ public class MachineDescriptionPPC64 extends MachineDescriptionTwosComplement im } public boolean isBigEndian() { - return true; + return "big".equals(System.getProperty("sun.cpu.endian")); } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java index 91d47c60e3f..9a02dadc17b 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java @@ -26,14 +26,17 @@ package sun.jvm.hotspot.debugger.linux; import java.io.*; import java.util.*; + import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.x86.*; import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.sparc.*; +import sun.jvm.hotspot.debugger.ppc64.*; import sun.jvm.hotspot.debugger.linux.x86.*; import sun.jvm.hotspot.debugger.linux.amd64.*; import sun.jvm.hotspot.debugger.linux.sparc.*; +import sun.jvm.hotspot.debugger.linux.ppc64.*; import sun.jvm.hotspot.utilities.*; class LinuxCDebugger implements CDebugger { @@ -96,7 +99,14 @@ class LinuxCDebugger implements CDebugger { Address pc = context.getRegisterAsAddress(SPARCThreadContext.R_O7); if (pc == null) return null; return new LinuxSPARCCFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize()); - } else { + } else if (cpu.equals("ppc64")) { + PPC64ThreadContext context = (PPC64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP); + if (sp == null) return null; + Address pc = context.getRegisterAsAddress(PPC64ThreadContext.PC); + if (pc == null) return null; + return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize()); + } else { // Runtime exception thrown by LinuxThreadContextFactory if unknown cpu ThreadContext context = (ThreadContext) thread.getContext(); return context.getTopFrame(dbg); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java index 44c2265d7a0..2225558000b 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java @@ -29,6 +29,7 @@ import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.linux.amd64.*; import sun.jvm.hotspot.debugger.linux.ia64.*; import sun.jvm.hotspot.debugger.linux.x86.*; +import sun.jvm.hotspot.debugger.linux.ppc64.*; import sun.jvm.hotspot.debugger.linux.sparc.*; class LinuxThreadContextFactory { @@ -42,6 +43,8 @@ class LinuxThreadContextFactory { return new LinuxIA64ThreadContext(dbg); } else if (cpu.equals("sparc")) { return new LinuxSPARCThreadContext(dbg); + } else if (cpu.equals("ppc64")) { + return new LinuxPPC64ThreadContext(dbg); } else { try { Class tcc = Class.forName("sun.jvm.hotspot.debugger.linux." + diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java new file mode 100644 index 00000000000..9c10400c2b7 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.debugger.linux.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.ppc64.*; +import sun.jvm.hotspot.debugger.linux.*; +import sun.jvm.hotspot.debugger.cdbg.*; +import sun.jvm.hotspot.debugger.cdbg.basic.*; + +final public class LinuxPPC64CFrame extends BasicCFrame { + // package/class internals only + + public LinuxPPC64CFrame(LinuxDebugger dbg, Address sp, Address pc, int address_size) { + super(dbg.getCDebugger()); + this.sp = sp; + this.pc = pc; + this.dbg = dbg; + this.address_size = address_size; + } + + // override base class impl to avoid ELF parsing + public ClosestSymbol closestSymbolToPC() { + // try native lookup in debugger. + return dbg.lookup(dbg.getAddressValue(pc())); + } + + public Address pc() { + return pc; + } + + public Address localVariableBase() { + return sp; + } + + public CFrame sender(ThreadProxy thread) { + if (sp == null) { + return null; + } + + Address nextSP = sp.getAddressAt(0); + if (nextSP == null) { + return null; + } + Address nextPC = sp.getAddressAt(2 * address_size); + if (nextPC == null) { + return null; + } + return new LinuxPPC64CFrame(dbg, nextSP, nextPC, address_size); + } + + public static int PPC64_STACK_BIAS = 0; + private static int address_size; + private Address pc; + private Address sp; + private LinuxDebugger dbg; +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64ThreadContext.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64ThreadContext.java new file mode 100644 index 00000000000..4a033c26aa4 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64ThreadContext.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.debugger.linux.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.ppc64.*; +import sun.jvm.hotspot.debugger.linux.*; + +public class LinuxPPC64ThreadContext extends PPC64ThreadContext { + private LinuxDebugger debugger; + + public LinuxPPC64ThreadContext(LinuxDebugger debugger) { + super(); + this.debugger = debugger; + } + + public void setRegisterAsAddress(int index, Address value) { + setRegister(index, debugger.getAddressValue(value)); + } + + public Address getRegisterAsAddress(int index) { + return debugger.newAddress(getRegister(index)); + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ppc64/PPC64ThreadContext.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ppc64/PPC64ThreadContext.java new file mode 100644 index 00000000000..1b6dce83376 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ppc64/PPC64ThreadContext.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.debugger.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.cdbg.*; + +/** Specifies the thread context on ppc64 platforms; only a sub-portion + * of the context is guaranteed to be present on all operating + * systems. */ + +public abstract class PPC64ThreadContext implements ThreadContext { + + // NOTE: The indices for the various registers must be maintained as + // listed across various operating systems. However, only a small + // subset of the registers' values are guaranteed to be present (and + // must be present for the SA's stack walking to work). + + public static final int R31 = 0; + public static final int R30 = 1; + public static final int R29 = 2; + public static final int R28 = 3; + public static final int R27 = 4; + public static final int R26 = 5; + public static final int R25 = 6; + public static final int R24 = 7; + public static final int R23 = 8; + public static final int R22 = 9; + public static final int R21 = 10; + public static final int R20 = 11; + public static final int R19 = 12; + public static final int R18 = 13; + public static final int R17 = 14; + public static final int R16 = 15; + public static final int R15 = 16; + public static final int R14 = 17; + public static final int R13 = 18; + public static final int R12 = 19; + public static final int R11 = 20; + public static final int R10 = 21; + public static final int R9 = 22; + public static final int R8 = 23; + public static final int R7 = 24; + public static final int R6 = 25; + public static final int R5 = 26; + public static final int R4 = 27; + public static final int R3 = 28; + public static final int R2 = 29; + public static final int R1 = 30; + public static final int R0 = 31; + public static final int NIP = 32; + public static final int LR = 33; + + public static final int NPRGREG = 34; + + private static final String[] regNames = { + "r31", "r30", "r29", "r28", "r27", "r26", "r25", "r24", + "r23", "r22", "r21", "r20", "r19", "r18", "r17", "r16", + "r15", "r14", "r13", "r12", "r11", "r10", "r9", "r8", + "r7", "r6", "r5", "r4", "r3", "r2", "r1", "r0", + "nip", "link" + }; + + public static final int PC = NIP; + public static final int SP = R1; + + private long[] data; + + public PPC64ThreadContext() { + data = new long[NPRGREG]; + } + + public int getNumRegisters() { + return NPRGREG; + } + + public String getRegisterName(int index) { + return regNames[index]; + } + + public void setRegister(int index, long value) { + data[index] = value; + } + + public long getRegister(int index) { + return data[index]; + } + + public CFrame getTopFrame(Debugger dbg) { + return null; + } + + /** This can't be implemented in this class since we would have to + * tie the implementation to, for example, the debugging system */ + public abstract void setRegisterAsAddress(int index, Address value); + + /** This can't be implemented in this class since we would have to + * tie the implementation to, for example, the debugging system */ + public abstract Address getRegisterAsAddress(int index); + +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java index 298dbfda634..67086fb9ac4 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, 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 @@ -32,7 +32,9 @@ import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.proc.amd64.*; import sun.jvm.hotspot.debugger.proc.sparc.*; +import sun.jvm.hotspot.debugger.proc.ppc64.*; import sun.jvm.hotspot.debugger.proc.x86.*; +import sun.jvm.hotspot.debugger.ppc64.*; import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.sparc.*; import sun.jvm.hotspot.debugger.x86.*; @@ -86,6 +88,10 @@ public class ProcDebuggerLocal extends DebuggerBase implements ProcDebugger { threadFactory = new ProcAMD64ThreadFactory(this); pcRegIndex = AMD64ThreadContext.RIP; fpRegIndex = AMD64ThreadContext.RBP; + } else if (cpu.equals("ppc64")) { + threadFactory = new ProcPPC64ThreadFactory(this); + pcRegIndex = PPC64ThreadContext.PC; + fpRegIndex = PPC64ThreadContext.SP; } else { try { Class tfc = Class.forName("sun.jvm.hotspot.debugger.proc." + diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64Thread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64Thread.java new file mode 100644 index 00000000000..f51841766ff --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64Thread.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.debugger.proc.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.ppc64.*; +import sun.jvm.hotspot.debugger.proc.*; +import sun.jvm.hotspot.utilities.*; + +public class ProcPPC64Thread implements ThreadProxy { + private ProcDebugger debugger; + private int id; + + public ProcPPC64Thread(ProcDebugger debugger, Address addr) { + this.debugger = debugger; + + // FIXME: the size here should be configurable. However, making it + // so would produce a dependency on the "types" package from the + // debugger package, which is not desired. + this.id = (int) addr.getCIntegerAt(0, 4, true); + } + + public ProcPPC64Thread(ProcDebugger debugger, long id) { + this.debugger = debugger; + this.id = (int) id; + } + + public ThreadContext getContext() throws IllegalThreadStateException { + ProcPPC64ThreadContext context = new ProcPPC64ThreadContext(debugger); + long[] regs = debugger.getThreadIntegerRegisterSet(id); + if (Assert.ASSERTS_ENABLED) { + Assert.that(regs.length <= PPC64ThreadContext.NPRGREG, "size of register set is greater than " + PPC64ThreadContext.NPRGREG); + } + for (int i = 0; i < regs.length; i++) { + context.setRegister(i, regs[i]); + } + return context; + } + + public boolean canSetContext() throws DebuggerException { + return false; + } + + public void setContext(ThreadContext context) + throws IllegalThreadStateException, DebuggerException { + throw new DebuggerException("Unimplemented"); + } + + public String toString() { + return "t@" + id; + } + + public boolean equals(Object obj) { + if ((obj == null) || !(obj instanceof ProcPPC64Thread)) { + return false; + } + + return (((ProcPPC64Thread) obj).id == id); + } + + public int hashCode() { + return id; + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadContext.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadContext.java new file mode 100644 index 00000000000..d65c4defcb9 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadContext.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.debugger.proc.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.ppc64.*; +import sun.jvm.hotspot.debugger.proc.*; + +public class ProcPPC64ThreadContext extends PPC64ThreadContext { + private ProcDebugger debugger; + + public ProcPPC64ThreadContext(ProcDebugger debugger) { + super(); + this.debugger = debugger; + } + + public void setRegisterAsAddress(int index, Address value) { + setRegister(index, debugger.getAddressValue(value)); + } + + public Address getRegisterAsAddress(int index) { + return debugger.newAddress(getRegister(index)); + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadFactory.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadFactory.java new file mode 100644 index 00000000000..115b0fd3074 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.debugger.proc.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.proc.*; + +public class ProcPPC64ThreadFactory implements ProcThreadFactory { + private ProcDebugger debugger; + + public ProcPPC64ThreadFactory(ProcDebugger debugger) { + this.debugger = debugger; + } + + public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) { + return new ProcPPC64Thread(debugger, threadIdentifierAddr); + } + + public ThreadProxy createThreadWrapper(long id) { + return new ProcPPC64Thread(debugger, id); + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java index ffa61b548e7..b6253f6d63d 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java @@ -33,6 +33,7 @@ import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.remote.sparc.*; import sun.jvm.hotspot.debugger.remote.x86.*; import sun.jvm.hotspot.debugger.remote.amd64.*; +import sun.jvm.hotspot.debugger.remote.ppc64.*; /** An implementation of Debugger which wraps a RemoteDebugger, providing remote debugging via RMI. @@ -70,6 +71,11 @@ public class RemoteDebuggerClient extends DebuggerBase implements JVMDebugger { cachePageSize = 4096; cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize); unalignedAccessesOkay = true; + } else if (cpu.equals("ppc64")) { + threadFactory = new RemotePPC64ThreadFactory(this); + cachePageSize = 4096; + cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize); + unalignedAccessesOkay = true; } else { try { Class tf = Class.forName("sun.jvm.hotspot.debugger.remote." + diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64Thread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64Thread.java new file mode 100644 index 00000000000..299ddfe4512 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64Thread.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.debugger.remote.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.ppc64.*; +import sun.jvm.hotspot.debugger.remote.*; +import sun.jvm.hotspot.utilities.*; + +public class RemotePPC64Thread extends RemoteThread { + public RemotePPC64Thread(RemoteDebuggerClient debugger, Address addr) { + super(debugger, addr); + } + + public RemotePPC64Thread(RemoteDebuggerClient debugger, long id) { + super(debugger, id); + } + + public ThreadContext getContext() throws IllegalThreadStateException { + RemotePPC64ThreadContext context = new RemotePPC64ThreadContext(debugger); + long[] regs = (addr != null)? debugger.getThreadIntegerRegisterSet(addr) : + debugger.getThreadIntegerRegisterSet(id); + if (Assert.ASSERTS_ENABLED) { + Assert.that(regs.length == PPC64ThreadContext.NPRGREG, "size of register set must match"); + } + for (int i = 0; i < regs.length; i++) { + context.setRegister(i, regs[i]); + } + return context; + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadContext.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadContext.java new file mode 100644 index 00000000000..c716e249c4f --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadContext.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.debugger.remote.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.ppc64.*; +import sun.jvm.hotspot.debugger.remote.*; + +public class RemotePPC64ThreadContext extends PPC64ThreadContext { + private RemoteDebuggerClient debugger; + + public RemotePPC64ThreadContext(RemoteDebuggerClient debugger) { + super(); + this.debugger = debugger; + } + + /** This can't be implemented in this class since we would have to + tie the implementation to, for example, the debugging system */ + public void setRegisterAsAddress(int index, Address value) { + setRegister(index, debugger.getAddressValue(value)); + } + + /** This can't be implemented in this class since we would have to + tie the implementation to, for example, the debugging system */ + public Address getRegisterAsAddress(int index) { + return debugger.newAddress(getRegister(index)); + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadFactory.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadFactory.java new file mode 100644 index 00000000000..a45cebecdb2 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.debugger.remote.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.remote.*; + +public class RemotePPC64ThreadFactory implements RemoteThreadFactory { + private RemoteDebuggerClient debugger; + + public RemotePPC64ThreadFactory(RemoteDebuggerClient debugger) { + this.debugger = debugger; + } + + public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) { + return new RemotePPC64Thread(debugger, threadIdentifierAddr); + } + + public ThreadProxy createThreadWrapper(long id) { + return new RemotePPC64Thread(debugger, id); + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java index 3b6a53c5302..0714e80d9f9 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java @@ -25,6 +25,7 @@ package sun.jvm.hotspot.runtime; import java.util.*; + import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.runtime.solaris_sparc.SolarisSPARCJavaThreadPDAccess; @@ -34,6 +35,7 @@ import sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess; import sun.jvm.hotspot.runtime.win32_x86.Win32X86JavaThreadPDAccess; import sun.jvm.hotspot.runtime.linux_x86.LinuxX86JavaThreadPDAccess; import sun.jvm.hotspot.runtime.linux_amd64.LinuxAMD64JavaThreadPDAccess; +import sun.jvm.hotspot.runtime.linux_ppc64.LinuxPPC64JavaThreadPDAccess; import sun.jvm.hotspot.runtime.linux_sparc.LinuxSPARCJavaThreadPDAccess; import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess; import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess; @@ -87,6 +89,8 @@ public class Threads { access = new LinuxAMD64JavaThreadPDAccess(); } else if (cpu.equals("sparc")) { access = new LinuxSPARCJavaThreadPDAccess(); + } else if (cpu.equals("ppc64")) { + access = new LinuxPPC64JavaThreadPDAccess(); } else { try { access = (JavaThreadPDAccess) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java index ea1ec197c6e..2506d417371 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java @@ -78,7 +78,7 @@ public class VFrame { } if (f.isRuntimeFrame()) { - // This is a conversion frame. Skip this frame and try again. + // This is a conversion frame or a Stub routine. Skip this frame and try again. RegisterMap tempMap = regMap.copy(); Frame s = f.sender(tempMap); return newVFrame(s, tempMap, thread, unsafe, false); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_ppc64/LinuxPPC64JavaThreadPDAccess.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_ppc64/LinuxPPC64JavaThreadPDAccess.java new file mode 100644 index 00000000000..26f132af0b6 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_ppc64/LinuxPPC64JavaThreadPDAccess.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.runtime.linux_ppc64; + +import java.io.*; +import java.util.*; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.ppc64.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.ppc64.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; + +public class LinuxPPC64JavaThreadPDAccess implements JavaThreadPDAccess { + private static AddressField osThreadField; + + // Field from OSThread + private static CIntegerField osThreadThreadIDField; + + // This is currently unneeded but is being kept in case we change + // the currentFrameGuess algorithm + private static final long GUESS_SCAN_RANGE = 128 * 1024; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("JavaThread"); + osThreadField = type.getAddressField("_osthread"); + + Type osThreadType = db.lookupType("OSThread"); + osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id"); + } + + public Address getLastJavaFP(Address addr) { + return null; + } + + public Address getLastJavaPC(Address addr) { + return null; + } + + public Address getBaseOfStackPointer(Address addr) { + return null; + } + + public Frame getLastFramePD(JavaThread thread, Address addr) { + Address fp = thread.getLastJavaFP(); + if (fp == null) { + return null; // no information + } + return new PPC64Frame(thread.getLastJavaSP(), fp); + } + + public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) { + return new PPC64RegisterMap(thread, updateMap); + } + + public Frame getCurrentFrameGuess(JavaThread thread, Address addr) { + ThreadProxy t = getThreadProxy(addr); + PPC64ThreadContext context = (PPC64ThreadContext) t.getContext(); + PPC64CurrentFrameGuess guesser = new PPC64CurrentFrameGuess(context, thread); + if (!guesser.run(GUESS_SCAN_RANGE)) { + return null; + } + if (guesser.getPC() == null) { + return new PPC64Frame(guesser.getSP(), guesser.getFP()); + } else { + return new PPC64Frame(guesser.getSP(), guesser.getFP(), guesser.getPC()); + } + } + + public void printThreadIDOn(Address addr, PrintStream tty) { + tty.print(getThreadProxy(addr)); + } + + public void printInfoOn(Address threadAddr, PrintStream tty) { + tty.print("Thread id: "); + printThreadIDOn(threadAddr, tty); + // tty.println("\nPostJavaState: " + getPostJavaState(threadAddr)); + } + + public Address getLastSP(Address addr) { + ThreadProxy t = getThreadProxy(addr); + PPC64ThreadContext context = (PPC64ThreadContext) t.getContext(); + return context.getRegisterAsAddress(PPC64ThreadContext.SP); + } + + public Address getLastFP(Address addr) { + return getLastSP(addr).getAddressAt(0); + } + + public ThreadProxy getThreadProxy(Address addr) { + // Addr is the address of the JavaThread. + // Fetch the OSThread (for now and for simplicity, not making a + // separate "OSThread" class in this package) + Address osThreadAddr = osThreadField.getValue(addr); + // Get the address of the _thread_id from the OSThread + Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset()); + + JVMDebugger debugger = VM.getVM().getDebugger(); + return debugger.getThreadForIdentifierAddress(threadIdAddr); + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64CurrentFrameGuess.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64CurrentFrameGuess.java new file mode 100644 index 00000000000..a399af0e92a --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64CurrentFrameGuess.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.runtime.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.ppc64.*; +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.interpreter.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.ppc64.*; + +/**

Should be able to be used on all ppc64 platforms we support + (Linux/ppc64) to implement JavaThread's "currentFrameGuess()" + functionality. Input is a PPC64ThreadContext; output is SP, FP, + and PC for an PPC64Frame. Instantiation of the PPC64Frame is left + to the caller, since we may need to subclass PPC64Frame to support + signal handler frames on Unix platforms.

+ */ + +public class PPC64CurrentFrameGuess { + private PPC64ThreadContext context; + private JavaThread thread; + private Address spFound; + private Address fpFound; + private Address pcFound; + + private static final boolean DEBUG; + static { + DEBUG = System.getProperty("sun.jvm.hotspot.runtime.ppc64.PPC64Frame.DEBUG") != null; + } + + public PPC64CurrentFrameGuess(PPC64ThreadContext context, + JavaThread thread) { + this.context = context; + this.thread = thread; + } + + /** Returns false if not able to find a frame within a reasonable range. */ + public boolean run(long regionInBytesToSearch) { + Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP); + Address pc = context.getRegisterAsAddress(PPC64ThreadContext.PC); + if (sp == null) { + // Bail out if no last java frame either + if (thread.getLastJavaSP() != null) { + Address javaSP = thread.getLastJavaSP(); + Address javaFP = javaSP.getAddressAt(0); + setValues(javaSP, javaFP, null); + return true; + } + return false; + } + /* There is no frame pointer per se for the ppc64 architecture. To mirror + * the behavior of the VM frame manager, we set fp to be the caller's (i.e., "sender's") + * stack pointer, which is the back chain value contained in our sp. + */ + Address fp = sp.getAddressAt(0); + setValues(null, null, null); // Assume we're not going to find anything + + VM vm = VM.getVM(); + if (vm.isJavaPCDbg(pc)) { + if (vm.isClientCompiler()) { + // Topmost frame is a Java frame. + if (DEBUG) { + System.out.println("CurrentFrameGuess: choosing compiler frame: sp = " + + sp + ", fp = " + fp + ", pc = " + pc); + } + setValues(sp, fp, pc); + return true; + } else { + if (vm.getInterpreter().contains(pc)) { + if (DEBUG) { + System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " + + sp + ", fp = " + fp + ", pc = " + pc); + } + setValues(sp, fp, pc); + return true; + } + + // This algorithm takes the current PC as a given and tries to + // find the correct corresponding SP by walking up the stack + // and repeatedly performing stackwalks (very inefficient). + for (long offset = 0; + offset < regionInBytesToSearch; + offset += vm.getAddressSize()) { + try { + Address curSP = sp.addOffsetTo(offset); + fp = curSP.getAddressAt(0); + Frame frame = new PPC64Frame(curSP, fp, pc); + RegisterMap map = thread.newRegisterMap(false); + while (frame != null) { + if (frame.isEntryFrame() && frame.entryFrameIsFirst()) { + // We were able to traverse all the way to the + // bottommost Java frame. + // This sp looks good. Keep it. + if (DEBUG) { + System.out.println("CurrentFrameGuess: Choosing sp = " + curSP + ", pc = " + pc); + } + setValues(curSP, fp, pc); + return true; + } + frame = frame.sender(map); + } + } catch (Exception e) { + if (DEBUG) { + System.out.println("CurrentFrameGuess: Exception " + e + " at offset " + offset); + } + // Bad SP. Try another. + } + } + + // Were not able to find a plausible SP to go with this PC. + // Bail out. + return false; + + } + } else { + // If the current program counter was not known to us as a Java + // PC, we currently assume that we are in the run-time system + // and attempt to look to thread-local storage for saved java SP. + // Note that if this is null (because we were, in fact, + // in Java code, i.e., vtable stubs or similar, and the SA + // didn't have enough insight into the target VM to understand + // that) then we are going to lose the entire stack trace for + // the thread, which is sub-optimal. FIXME. + + if (thread.getLastJavaSP() == null) { + if (DEBUG) { + System.out.println("CurrentFrameGuess: last java sp is null"); + } + return false; // No known Java frames on stack + } + + Address javaSP = thread.getLastJavaSP(); + Address javaFP = javaSP.getAddressAt(0); + Address javaPC = thread.getLastJavaPC(); + if (DEBUG) { + System.out.println("CurrentFrameGuess: choosing last Java frame: sp = " + + javaSP + ", fp = " + javaFP + ", pc = " + javaPC); + } + setValues(javaSP, javaFP, javaPC); + return true; + } + } + + public Address getSP() { return spFound; } + public Address getFP() { return fpFound; } + /** May be null if getting values from thread-local storage; take + care to call the correct PPC64Frame constructor to recover this if + necessary */ + public Address getPC() { return pcFound; } + + private void setValues(Address sp, Address fp, Address pc) { + spFound = sp; + fpFound = fp; + pcFound = pc; + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java new file mode 100644 index 00000000000..c996b6dc0de --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.runtime.ppc64; + +import java.util.*; +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.compiler.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.oops.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; + +/** Specialization of and implementation of abstract methods of the + Frame class for the ppc64 family of CPUs. */ + +public class PPC64Frame extends Frame { + private static final boolean DEBUG; + static { + DEBUG = System.getProperty("sun.jvm.hotspot.runtime.ppc64.PPC64Frame.DEBUG") != null; + } + + // All frames + private static final int SENDER_SP_OFFSET = 0; + + // Interpreter frames + private static final int INTERPRETER_FRAME_MIRROR_OFFSET = -3; // for native calls only + private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -4; + private static final int INTERPRETER_FRAME_LAST_SP_OFFSET = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1; + private static final int INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_LAST_SP_OFFSET -1; + private static final int INTERPRETER_FRAME_ESP_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1; + private static final int INTERPRETER_FRAME_BCX_OFFSET = INTERPRETER_FRAME_ESP_OFFSET - 1; + private static final int INTERPRETER_FRAME_CACHE_OFFSET =INTERPRETER_FRAME_BCX_OFFSET - 1; + private static final int INTERPRETER_FRAME_MONITORS_OFFSET = INTERPRETER_FRAME_CACHE_OFFSET - 1; + private static final int INTERPRETER_FRAME_LOCALS_OFFSET = INTERPRETER_FRAME_MONITORS_OFFSET - 1; + private static final int INTERPRETER_FRAME_METHOD_OFFSET = INTERPRETER_FRAME_LOCALS_OFFSET - 1; + private static final int INTERPRETER_FRAME_INITIAL_SP_OFFSET = INTERPRETER_FRAME_BCX_OFFSET - 1; // FIXME: probably wrong, but unused anyway + private static final int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET; + private static final int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET; + + // Entry frames + private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET; + + // Native frames + private static int NATIVE_FRAME_INITIAL_PARAM_OFFSET; + + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + int abi_minframe_size = db.lookupIntConstant("frame::abi_minframe_size").intValue(); + int entry_frame_locals_size = db.lookupIntConstant("frame::entry_frame_locals_size").intValue(); + int wordLength = (int) VM.getVM().getAddressSize(); + NATIVE_FRAME_INITIAL_PARAM_OFFSET = -abi_minframe_size/wordLength; + ENTRY_FRAME_CALL_WRAPPER_OFFSET = -entry_frame_locals_size/wordLength; + } + + + // an additional field beyond sp and pc: + Address raw_fp; // frame pointer + private Address raw_unextendedSP; + + private PPC64Frame() { + } + + private void adjustForDeopt() { + if ( pc != null) { + // Look for a deopt pc and if it is deopted convert to original pc + CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); + if (cb != null && cb.isJavaMethod()) { + NMethod nm = (NMethod) cb; + if (pc.equals(nm.deoptHandlerBegin())) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); + } + // adjust pc if frame is deoptimized. + pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); + deoptimized = true; + } + } + } + } + + public PPC64Frame(Address raw_sp, Address raw_fp, Address pc) { + this.raw_sp = raw_sp; + this.raw_unextendedSP = raw_sp; + if (raw_fp == null) { + this.raw_fp = raw_sp.getAddressAt(0); + } else { + this.raw_fp = raw_fp; + } + if (pc == null) { + this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize()); + } else { + this.pc = pc; + } + adjustUnextendedSP(); + + // Frame must be fully constructed before this call + adjustForDeopt(); + + if (DEBUG) { + System.out.println("PPC64Frame(sp, fp, pc): " + this); + dumpStack(); + } + } + + public PPC64Frame(Address raw_sp, Address raw_fp) { + this.raw_sp = raw_sp; + this.raw_unextendedSP = raw_sp; + if (raw_fp == null) { + this.raw_fp = raw_sp.getAddressAt(0); + } else { + this.raw_fp = raw_fp; + } + this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize()); + adjustUnextendedSP(); + + // Frame must be fully constructed before this call + adjustForDeopt(); + + if (DEBUG) { + System.out.println("PPC64Frame(sp, fp): " + this); + dumpStack(); + } + } + + public PPC64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) { + this.raw_sp = raw_sp; + this.raw_unextendedSP = raw_unextendedSp; + if (raw_fp == null) { + this.raw_fp = raw_sp.getAddressAt(0); + } else { + this.raw_fp = raw_fp; + } + if (pc == null) { + this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize()); + } else { + this.pc = pc; + } + adjustUnextendedSP(); + + // Frame must be fully constructed before this call + adjustForDeopt(); + + if (DEBUG) { + System.out.println("PPC64Frame(sp, unextendedSP, fp, pc): " + this); + dumpStack(); + } + + } + + public Object clone() { + PPC64Frame frame = new PPC64Frame(); + frame.raw_sp = raw_sp; + frame.raw_unextendedSP = raw_unextendedSP; + frame.raw_fp = raw_fp; + frame.pc = pc; + frame.deoptimized = deoptimized; + return frame; + } + + public boolean equals(Object arg) { + if (arg == null) { + return false; + } + + if (!(arg instanceof PPC64Frame)) { + return false; + } + + PPC64Frame other = (PPC64Frame) arg; + + return (AddressOps.equal(getSP(), other.getSP()) && + AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) && + AddressOps.equal(getFP(), other.getFP()) && + AddressOps.equal(getPC(), other.getPC())); + } + + public int hashCode() { + if (raw_sp == null) { + return 0; + } + + return raw_sp.hashCode(); + } + + public String toString() { + return "sp: " + (getSP() == null ? "null" : getSP().toString()) + + ", unextendedSP: " + (getUnextendedSP() == null ? "null" : getUnextendedSP().toString()) + + ", fp: " + (getFP() == null ? "null" : getFP().toString()) + + ", pc: " + (pc == null ? "null" : pc.toString()); + } + + // accessors for the instance variables + public Address getFP() { return raw_fp; } + public Address getSP() { return raw_sp; } + public Address getID() { return raw_sp; } + + // FIXME: not implemented yet (should be done for Solaris/PPC64) + public boolean isSignalHandlerFrameDbg() { return false; } + public int getSignalNumberDbg() { return 0; } + public String getSignalNameDbg() { return null; } + + public boolean isInterpretedFrameValid() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(isInterpretedFrame(), "Not an interpreted frame"); + } + + // These are reasonable sanity checks + if (getFP() == null || getFP().andWithMask(0x3) != null) { + return false; + } + + if (getSP() == null || getSP().andWithMask(0x3) != null) { + return false; + } + + // These are hacks to keep us out of trouble. + // The problem with these is that they mask other problems + if (getFP().lessThanOrEqual(getSP())) { + // this attempts to deal with unsigned comparison above + return false; + } + + if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) { + // stack frames shouldn't be large. + return false; + } + + return true; + } + + // FIXME: not applicable in current system + // void patch_pc(Thread* thread, address pc); + + public Frame sender(RegisterMap regMap, CodeBlob cb) { + PPC64RegisterMap map = (PPC64RegisterMap) regMap; + + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + + // Default is we done have to follow them. The sender_for_xxx will + // update it accordingly + map.setIncludeArgumentOops(false); + + if (isEntryFrame()) return senderForEntryFrame(map); + if (isInterpretedFrame()) return senderForInterpreterFrame(map); + + if(cb == null) { + cb = VM.getVM().getCodeCache().findBlob(getPC()); + } else { + if (Assert.ASSERTS_ENABLED) { + Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same"); + } + } + + if (cb != null) { + return senderForCompiledFrame(map, cb); + } + + // Must be native-compiled frame, i.e. the marshaling code for native + // methods that exists in the core system. + return new PPC64Frame(getSenderSP(), getLink(), getSenderPC()); + } + + private Frame senderForEntryFrame(PPC64RegisterMap map) { + if (DEBUG) { + System.out.println("senderForEntryFrame"); + } + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + // Java frame called from C; skip all C frames and return top C + // frame of that chunk as the sender + PPC64JavaCallWrapper jcw = (PPC64JavaCallWrapper) getEntryFrameCallWrapper(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero"); + Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack"); + } + PPC64Frame fr; + if (jcw.getLastJavaPC() != null) { + fr = new PPC64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC()); + } else { + fr = new PPC64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP()); + } + map.clear(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(map.getIncludeArgumentOops(), "should be set by clear"); + } + return fr; + } + + //------------------------------------------------------------------------------ + // frame::adjust_unextended_sp + private void adjustUnextendedSP() { + raw_unextendedSP = getFP(); + } + private Frame senderForInterpreterFrame(PPC64RegisterMap map) { + if (DEBUG) { + System.out.println("senderForInterpreterFrame"); + } + Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0); + Address sp = getSenderSP(); + + return new PPC64Frame(sp, unextendedSP, getLink(), getSenderPC()); + } + + + private Frame senderForCompiledFrame(PPC64RegisterMap map, CodeBlob cb) { + if (DEBUG) { + System.out.println("senderForCompiledFrame"); + } + + // + // NOTE: some of this code is (unfortunately) duplicated in PPC64CurrentFrameGuess + // + + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + + // frame owned by optimizing compiler + if (Assert.ASSERTS_ENABLED) { + Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size"); + } + Address senderSP = getSenderSP(); + + Address senderPC = getSenderPC(); + + if (map.getUpdateMap()) { + // Tell GC to use argument oopmaps for some runtime stubs that need it. + // For C1, the runtime stub might not have oop maps, so set this flag + // outside of update_register_map. + map.setIncludeArgumentOops(cb.callerMustGCArguments()); + + if (cb.getOopMaps() != null) { + OopMapSet.updateRegisterMap(this, cb, map, true); + } + } + + return new PPC64Frame(senderSP, getLink(), senderPC); + } + + protected boolean hasSenderPD() { + // FIXME + return true; + } + + public long frameSize() { + return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize()); + } + + public Address getLink() { + return getSenderSP().getAddressAt(0); + } + + public Address getUnextendedSP() { return raw_unextendedSP; } + + // Return address: + public Address getSenderPC() { return getSenderSP().getAddressAt(2 * VM.getVM().getAddressSize()); } + + // return address of param, zero origin index. + // MPJ note: Appears to be unused. + public Address getNativeParamAddr(int idx) { + return null; + // return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx); + } + + public Address getSenderSP() { return getFP(); } + public Address addressOfInterpreterFrameLocals() { + return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET); + } + + private Address addressOfInterpreterFrameBCX() { + return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET); + } + + public int getInterpreterFrameBCI() { + // FIXME: this is not atomic with respect to GC and is unsuitable + // for use in a non-debugging, or reflective, system. Need to + // figure out how to express this. + Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0); + Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0); + Method method = (Method)Metadata.instantiateWrapperFor(methodHandle); + return bcpToBci(bcp, method); + } + + public Address addressOfInterpreterFrameMDX() { + return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET); + } + + // FIXME + //inline int frame::interpreter_frame_monitor_size() { + // return BasicObjectLock::size(); + //} + + // expression stack + // (the max_stack arguments are used by the GC; see class FrameClosure) + + public Address addressOfInterpreterFrameExpressionStack() { + Address monitorEnd = interpreterFrameMonitorEnd().address(); + return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize()); + } + + public int getInterpreterFrameExpressionStackDirection() { return -1; } + + // top of expression stack + public Address addressOfInterpreterFrameTOS() { + return getSP(); + } + + /** Expression stack from top down */ + public Address addressOfInterpreterFrameTOSAt(int slot) { + return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize()); + } + + public Address getInterpreterFrameSenderSP() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(isInterpretedFrame(), "interpreted frame expected"); + } + return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0); + } + + // Monitors + public BasicObjectLock interpreterFrameMonitorBegin() { + return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET)); + } + + public BasicObjectLock interpreterFrameMonitorEnd() { + Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0); + if (Assert.ASSERTS_ENABLED) { + // make sure the pointer points inside the frame + Assert.that(AddressOps.gt(getFP(), result), "result must < than frame pointer"); + Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer"); + } + return new BasicObjectLock(result); + } + + public int interpreterFrameMonitorSize() { + return BasicObjectLock.size(); + } + + // Method + public Address addressOfInterpreterFrameMethod() { + return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET); + } + + // Constant pool cache + public Address addressOfInterpreterFrameCPCache() { + return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET); + } + + // Entry frames + public JavaCallWrapper getEntryFrameCallWrapper() { + return new PPC64JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0)); + } + + protected Address addressOfSavedOopResult() { + // offset is 2 for compiler2 and 3 for compiler1 + return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) * + VM.getVM().getAddressSize()); + } + + protected Address addressOfSavedReceiver() { + return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize()); + } + + private void dumpStack() { + if (getFP() != null) { + for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize()); + AddressOps.lte(addr, getFP().addOffsetTo(5 * VM.getVM().getAddressSize())); + addr = addr.addOffsetTo(VM.getVM().getAddressSize())) { + System.out.println(addr + ": " + addr.getAddressAt(0)); + } + } else { + for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize()); + AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize())); + addr = addr.addOffsetTo(VM.getVM().getAddressSize())) { + System.out.println(addr + ": " + addr.getAddressAt(0)); + } + } + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64JavaCallWrapper.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64JavaCallWrapper.java new file mode 100644 index 00000000000..427d39b2eed --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64JavaCallWrapper.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.runtime.ppc64; + +import java.util.*; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.runtime.*; + +public class PPC64JavaCallWrapper extends JavaCallWrapper { + + public PPC64JavaCallWrapper(Address addr) { + super(addr); + } + + public Address getLastJavaFP() { + return null; + } + +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64RegisterMap.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64RegisterMap.java new file mode 100644 index 00000000000..ca06fc413e2 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64RegisterMap.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 20014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.runtime.ppc64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; + +public class PPC64RegisterMap extends RegisterMap { + + /** This is the only public constructor */ + public PPC64RegisterMap(JavaThread thread, boolean updateMap) { + super(thread, updateMap); + } + + protected PPC64RegisterMap(RegisterMap map) { + super(map); + } + + public Object clone() { + PPC64RegisterMap retval = new PPC64RegisterMap(this); + return retval; + } + + // no PD state to clear or copy: + protected void clearPD() {} + protected void initializePD() {} + protected void initializeFromPD(RegisterMap map) {} + protected Address getLocationPD(VMReg reg) { return null; } +} diff --git a/hotspot/make/aix/Makefile b/hotspot/make/aix/Makefile index e0150749678..bbb92c9d75d 100644 --- a/hotspot/make/aix/Makefile +++ b/hotspot/make/aix/Makefile @@ -246,8 +246,7 @@ endif XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \ diff --git a/hotspot/make/aix/makefiles/mapfile-vers-debug b/hotspot/make/aix/makefiles/mapfile-vers-debug index 348c128e434..1b3409a6de0 100644 --- a/hotspot/make/aix/makefiles/mapfile-vers-debug +++ b/hotspot/make/aix/makefiles/mapfile-vers-debug @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,7 @@ SUNWprivate_1.1 { JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameters; JVM_GetMethodTypeAnnotations; + JVM_GetNanoTimeAdjustment; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetStackAccessControlContext; diff --git a/hotspot/make/aix/makefiles/mapfile-vers-product b/hotspot/make/aix/makefiles/mapfile-vers-product index 25bd5bfff7c..966060f7de6 100644 --- a/hotspot/make/aix/makefiles/mapfile-vers-product +++ b/hotspot/make/aix/makefiles/mapfile-vers-product @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -130,6 +130,7 @@ SUNWprivate_1.1 { JVM_GetMethodIxNameUTF; JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameters; + JVM_GetNanoTimeAdjustment; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetStackAccessControlContext; diff --git a/hotspot/make/aix/makefiles/ppc64.make b/hotspot/make/aix/makefiles/ppc64.make index 079d0764769..2636a4b9742 100644 --- a/hotspot/make/aix/makefiles/ppc64.make +++ b/hotspot/make/aix/makefiles/ppc64.make @@ -46,7 +46,9 @@ CFLAGS += -qsuppress=1540-0198 # - 1540-1090 (I) The destructor of "..." might not be called. # - 1500-010: (W) WARNING in ...: Infinite loop. Program may not stop. # There are several infinite loops in the vm, suppress. -CFLAGS += -qsuppress=1540-1090 -qsuppress=1500-010 +# - 1540-1639 (I) The behavior of long type bit fields has changed ... +# ... long type bit fields now default to long, not int. +CFLAGS += -qsuppress=1540-1090 -qsuppress=1500-010 -qsuppress=1540-1639 # Suppress # - 540-1088 (W) The exception specification is being ignored. diff --git a/hotspot/make/aix/makefiles/xlc.make b/hotspot/make/aix/makefiles/xlc.make index f281a08ea4f..17a71b60124 100644 --- a/hotspot/make/aix/makefiles/xlc.make +++ b/hotspot/make/aix/makefiles/xlc.make @@ -74,6 +74,12 @@ CFLAGS += -D_REENTRANT # no xlc counterpart for -fcheck-new # CFLAGS += -fcheck-new +# We need to define this on the command line if we want to use the the +# predefined format specifiers from "inttypes.h". Otherwise system headrs +# can indirectly include inttypes.h before we define __STDC_FORMAT_MACROS +# in globalDefinitions.hpp +CFLAGS += -D__STDC_FORMAT_MACROS + ARCHFLAG = -q64 CFLAGS += $(ARCHFLAG) @@ -124,7 +130,7 @@ STATIC_STDCXX = -Wl,-lC_r # MAPFLAG = -Xlinker --version-script=FILENAME # Build shared library -SHARED_FLAG = -q64 -b64 -bexpall -G -bnoentry -qmkshrobj -brtl -bnolibpath +SHARED_FLAG = -q64 -b64 -bexpall -G -bnoentry -qmkshrobj -brtl -bnolibpath -bernotok #------------------------------------------------------------------------ # Debug flags diff --git a/hotspot/make/bsd/Makefile b/hotspot/make/bsd/Makefile index 3f0cfc36344..4d45841475e 100644 --- a/hotspot/make/bsd/Makefile +++ b/hotspot/make/bsd/Makefile @@ -240,8 +240,7 @@ endif XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \ diff --git a/hotspot/make/bsd/makefiles/dtrace.make b/hotspot/make/bsd/makefiles/dtrace.make index dbb41163e39..80eb4d9a873 100644 --- a/hotspot/make/bsd/makefiles/dtrace.make +++ b/hotspot/make/bsd/makefiles/dtrace.make @@ -179,23 +179,23 @@ $(GENOFFS): $(DTRACE_SRCDIR)/$(GENOFFS)Main.c lib$(GENOFFS).dylib # $@.tmp is created first to avoid an empty $(JVMOFFS).h if an error occurs. $(JVMOFFS).h: $(GENOFFS) $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -header > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1 ; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS)Index.h: $(GENOFFS) $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -index > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1 ; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS).cpp: $(GENOFFS) $(JVMOFFS).h $(JVMOFFS)Index.h $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -table > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS.o): $(JVMOFFS).h $(JVMOFFS).cpp diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug index ba3e771364c..8779ec5ff1d 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug +++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -130,6 +130,7 @@ _JVM_GetMethodIxSignatureUTF _JVM_GetMethodParameters _JVM_GetMethodTypeAnnotations + _JVM_GetNanoTimeAdjustment _JVM_GetPrimitiveArrayElement _JVM_GetProtectionDomain _JVM_GetStackAccessControlContext diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product index ba3e771364c..8779ec5ff1d 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product +++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -130,6 +130,7 @@ _JVM_GetMethodIxSignatureUTF _JVM_GetMethodParameters _JVM_GetMethodTypeAnnotations + _JVM_GetNanoTimeAdjustment _JVM_GetPrimitiveArrayElement _JVM_GetProtectionDomain _JVM_GetStackAccessControlContext diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-debug b/hotspot/make/bsd/makefiles/mapfile-vers-debug index fc05d864ad6..7a5c5430436 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-debug +++ b/hotspot/make/bsd/makefiles/mapfile-vers-debug @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,7 @@ SUNWprivate_1.1 { JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameters; JVM_GetMethodTypeAnnotations; + JVM_GetNanoTimeAdjustment; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetStackAccessControlContext; diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-product b/hotspot/make/bsd/makefiles/mapfile-vers-product index fc05d864ad6..7a5c5430436 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-product +++ b/hotspot/make/bsd/makefiles/mapfile-vers-product @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,7 @@ SUNWprivate_1.1 { JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameters; JVM_GetMethodTypeAnnotations; + JVM_GetNanoTimeAdjustment; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetStackAccessControlContext; diff --git a/hotspot/make/bsd/makefiles/universal.gmk b/hotspot/make/bsd/makefiles/universal.gmk index 12a34d70157..40868adf849 100644 --- a/hotspot/make/bsd/makefiles/universal.gmk +++ b/hotspot/make/bsd/makefiles/universal.gmk @@ -59,7 +59,7 @@ universalize: $(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST) # Package built libraries in a universal binary $(UNIVERSAL_LIPO_LIST): - BUILT_LIPO_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`"; \ + BUILT_LIPO_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_LIPO_FILES}" ]; then \ $(MKDIR) -p $(shell dirname $@); \ lipo -create -output $@ $${BUILT_LIPO_FILES}; \ @@ -70,7 +70,7 @@ $(UNIVERSAL_LIPO_LIST): # - copies directories; including empty dirs # - copies files, symlinks, other non-directory files $(UNIVERSAL_COPY_LIST): - BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) -prune 2>/dev/null`"; \ + BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) -prune 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_COPY_FILES}" ]; then \ for i in $${BUILT_COPY_FILES}; do \ $(MKDIR) -p $(shell dirname $@); \ diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index c3ed19f09f1..33ed65db9b8 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -246,8 +246,7 @@ endif XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \ diff --git a/hotspot/make/linux/makefiles/build_vm_def.sh b/hotspot/make/linux/makefiles/build_vm_def.sh deleted file mode 100644 index ea81ff6c22f..00000000000 --- a/hotspot/make/linux/makefiles/build_vm_def.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -# If we're cross compiling use that path for nm -if [ "$CROSS_COMPILE_ARCH" != "" ]; then -NM=$ALT_COMPILER_PATH/nm -else -NM=nm -fi - -$NM --defined-only $* \ - | awk '{ - if ($3 ~ /^_ZTV/ || $3 ~ /^gHotSpotVM/) print "\t" $3 ";" - if ($3 ~ /^UseSharedSpaces$/) print "\t" $3 ";" - if ($3 ~ /^_ZN9Arguments17SharedArchivePathE$/) print "\t" $3 ";" - }' \ - | sort -u diff --git a/hotspot/make/linux/makefiles/mapfile-vers-debug b/hotspot/make/linux/makefiles/mapfile-vers-debug index fc05d864ad6..7a5c5430436 100644 --- a/hotspot/make/linux/makefiles/mapfile-vers-debug +++ b/hotspot/make/linux/makefiles/mapfile-vers-debug @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,7 @@ SUNWprivate_1.1 { JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameters; JVM_GetMethodTypeAnnotations; + JVM_GetNanoTimeAdjustment; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetStackAccessControlContext; diff --git a/hotspot/make/linux/makefiles/mapfile-vers-product b/hotspot/make/linux/makefiles/mapfile-vers-product index fc05d864ad6..7a5c5430436 100644 --- a/hotspot/make/linux/makefiles/mapfile-vers-product +++ b/hotspot/make/linux/makefiles/mapfile-vers-product @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,7 @@ SUNWprivate_1.1 { JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameters; JVM_GetMethodTypeAnnotations; + JVM_GetNanoTimeAdjustment; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetStackAccessControlContext; diff --git a/hotspot/make/linux/makefiles/sa.make b/hotspot/make/linux/makefiles/sa.make index 178c5555425..4c41e63df55 100644 --- a/hotspot/make/linux/makefiles/sa.make +++ b/hotspot/make/linux/makefiles/sa.make @@ -109,6 +109,7 @@ $(GENERATED)/sa-jdi.jar:: $(AGENT_FILES) $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.x86.X86ThreadContext $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.sparc.SPARCThreadContext + $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.ppc64.PPC64ThreadContext $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.asm.Disassembler clean: diff --git a/hotspot/make/linux/makefiles/vm.make b/hotspot/make/linux/makefiles/vm.make index a138a163f20..d0c31ca125c 100644 --- a/hotspot/make/linux/makefiles/vm.make +++ b/hotspot/make/linux/makefiles/vm.make @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -239,8 +239,14 @@ mapfile_reorder : mapfile $(REORDERFILE) rm -f $@ cat $^ > $@ +VMDEF_PAT = ^_ZTV +VMDEF_PAT := ^gHotSpotVM|$(VMDEF_PAT) +VMDEF_PAT := ^UseSharedSpaces$$|$(VMDEF_PAT) +VMDEF_PAT := ^_ZN9Arguments17SharedArchivePathE$$|$(VMDEF_PAT) + vm.def: $(Res_Files) $(Obj_Files) - sh $(GAMMADIR)/make/linux/makefiles/build_vm_def.sh *.o > $@ + $(QUIETLY) $(NM) --defined-only $(Obj_Files) | sort -k3 -u | \ + awk '$$3 ~ /$(VMDEF_PAT)/ { print "\t" $$3 ";" }' > $@ mapfile_ext: rm -f $@ @@ -334,10 +340,8 @@ $(LIBJVM): $(LIBJVM.o) $(LIBJVM_MAPFILE) $(LD_SCRIPT) rm -f $@.1; ln -s $@ $@.1; \ if [ \"$(CROSS_COMPILE_ARCH)\" = \"\" ] ; then \ if [ -x /usr/sbin/selinuxenabled ] ; then \ - /usr/sbin/selinuxenabled; \ - if [ $$? = 0 ] ; then \ - /usr/bin/chcon -t textrel_shlib_t $@; \ - if [ $$? != 0 ]; then \ + if /usr/sbin/selinuxenabled; then \ + if ! /usr/bin/chcon -t textrel_shlib_t $@; then \ echo "ERROR: Cannot chcon $@"; \ fi \ fi \ diff --git a/hotspot/make/sa.files b/hotspot/make/sa.files index faad4dd109f..dfe1e53a209 100644 --- a/hotspot/make/sa.files +++ b/hotspot/make/sa.files @@ -39,6 +39,7 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/c1/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/ci/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/classfile/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/code/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/compiler/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/*.java \ @@ -49,24 +50,31 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/dummy/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ia64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/posix/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/posix/elf/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/win32/coff/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/amd64/*.java \ @@ -90,12 +98,16 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_amd64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_sparc/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/posix/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_amd64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/x86/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_x86/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/jcore/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/soql/*.java \ diff --git a/hotspot/make/solaris/Makefile b/hotspot/make/solaris/Makefile index 869db69646d..f8fb06c8725 100644 --- a/hotspot/make/solaris/Makefile +++ b/hotspot/make/solaris/Makefile @@ -190,8 +190,7 @@ endif XSLT_CHECK = $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \ diff --git a/hotspot/make/solaris/makefiles/dtrace.make b/hotspot/make/solaris/makefiles/dtrace.make index be6e71dba9e..1b76dc74d6a 100644 --- a/hotspot/make/solaris/makefiles/dtrace.make +++ b/hotspot/make/solaris/makefiles/dtrace.make @@ -171,11 +171,11 @@ $(GENOFFS): $(DTRACE_SRCDIR)/$(GENOFFS)Main.c lib$(GENOFFS).so ./lib$(GENOFFS).so CONDITIONALLY_UPDATE_JVMOFFS_TARGET = \ - cmp -s $@ $@.tmp; \ - case $$? in \ - 0) rm -f $@.tmp;; \ - *) rm -f $@ && mv $@.tmp $@ && echo Updated $@;; \ - esac + if cmp -s $@ $@.tmp; then \ + rm -f $@.tmp; \ + else \ + rm -f $@ && mv $@.tmp $@ && echo Updated $@; \ + fi # $@.tmp is created first to avoid an empty $(JVMOFFS).h if an error occurs. $(JVMOFFS).h: $(GENOFFS) diff --git a/hotspot/make/solaris/makefiles/mapfile-vers b/hotspot/make/solaris/makefiles/mapfile-vers index 082b9f0e052..02cf70f3958 100644 --- a/hotspot/make/solaris/makefiles/mapfile-vers +++ b/hotspot/make/solaris/makefiles/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,7 @@ SUNWprivate_1.1 { JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameters; JVM_GetMethodTypeAnnotations; + JVM_GetNanoTimeAdjustment; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetStackAccessControlContext; diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp index 7d9aecb310f..f1087dbc02c 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -284,19 +284,20 @@ class Assembler : public AbstractAssembler { MTCTR_OPCODE = (MTSPR_OPCODE | 9 << SPR_0_4_SHIFT), MFCTR_OPCODE = (MFSPR_OPCODE | 9 << SPR_0_4_SHIFT), - MTTFHAR_OPCODE = (MTSPR_OPCODE | 128 << SPR_0_4_SHIFT), - MFTFHAR_OPCODE = (MFSPR_OPCODE | 128 << SPR_0_4_SHIFT), - MTTFIAR_OPCODE = (MTSPR_OPCODE | 129 << SPR_0_4_SHIFT), - MFTFIAR_OPCODE = (MFSPR_OPCODE | 129 << SPR_0_4_SHIFT), - MTTEXASR_OPCODE = (MTSPR_OPCODE | 130 << SPR_0_4_SHIFT), - MFTEXASR_OPCODE = (MFSPR_OPCODE | 130 << SPR_0_4_SHIFT), - MTTEXASRU_OPCODE = (MTSPR_OPCODE | 131 << SPR_0_4_SHIFT), - MFTEXASRU_OPCODE = (MFSPR_OPCODE | 131 << SPR_0_4_SHIFT), + // Attention: Higher and lower half are inserted in reversed order. + MTTFHAR_OPCODE = (MTSPR_OPCODE | 4 << SPR_5_9_SHIFT | 0 << SPR_0_4_SHIFT), + MFTFHAR_OPCODE = (MFSPR_OPCODE | 4 << SPR_5_9_SHIFT | 0 << SPR_0_4_SHIFT), + MTTFIAR_OPCODE = (MTSPR_OPCODE | 4 << SPR_5_9_SHIFT | 1 << SPR_0_4_SHIFT), + MFTFIAR_OPCODE = (MFSPR_OPCODE | 4 << SPR_5_9_SHIFT | 1 << SPR_0_4_SHIFT), + MTTEXASR_OPCODE = (MTSPR_OPCODE | 4 << SPR_5_9_SHIFT | 2 << SPR_0_4_SHIFT), + MFTEXASR_OPCODE = (MFSPR_OPCODE | 4 << SPR_5_9_SHIFT | 2 << SPR_0_4_SHIFT), + MTTEXASRU_OPCODE = (MTSPR_OPCODE | 4 << SPR_5_9_SHIFT | 3 << SPR_0_4_SHIFT), + MFTEXASRU_OPCODE = (MFSPR_OPCODE | 4 << SPR_5_9_SHIFT | 3 << SPR_0_4_SHIFT), - MTVRSAVE_OPCODE = (MTSPR_OPCODE | 256 << SPR_0_4_SHIFT), - MFVRSAVE_OPCODE = (MFSPR_OPCODE | 256 << SPR_0_4_SHIFT), + MTVRSAVE_OPCODE = (MTSPR_OPCODE | 8 << SPR_5_9_SHIFT | 0 << SPR_0_4_SHIFT), + MFVRSAVE_OPCODE = (MFSPR_OPCODE | 8 << SPR_5_9_SHIFT | 0 << SPR_0_4_SHIFT), - MFTB_OPCODE = (MFSPR_OPCODE | 268 << SPR_0_4_SHIFT), + MFTB_OPCODE = (MFSPR_OPCODE | 8 << SPR_5_9_SHIFT | 12 << SPR_0_4_SHIFT), MTCRF_OPCODE = (31u << OPCODE_SHIFT | 144u << 1), MFCR_OPCODE = (31u << OPCODE_SHIFT | 19u << 1), @@ -1494,6 +1495,26 @@ class Assembler : public AbstractAssembler { inline void mftexasr(Register d); inline void mftexasru(Register d); + // TEXASR bit description + enum transaction_failure_reason { + // Upper half (TEXASRU): + tm_failure_persistent = 7, // The failure is likely to recur on each execution. + tm_disallowed = 8, // The instruction is not permitted. + tm_nesting_of = 9, // The maximum transaction level was exceeded. + tm_footprint_of = 10, // The tracking limit for transactional storage accesses was exceeded. + tm_self_induced_cf = 11, // A self-induced conflict occurred in Suspended state. + tm_non_trans_cf = 12, // A conflict occurred with a non-transactional access by another processor. + tm_trans_cf = 13, // A conflict occurred with another transaction. + tm_translation_cf = 14, // A conflict occurred with a TLB invalidation. + tm_inst_fetch_cf = 16, // An instruction fetch was performed from a block that was previously written transactionally. + tm_tabort = 31, // Termination was caused by the execution of an abort instruction. + // Lower half: + tm_suspended = 32, // Failure was recorded in Suspended state. + tm_failure_summary = 36, // Failure has been detected and recorded. + tm_tfiar_exact = 37, // Value in the TFIAR is exact. + tm_rot = 38, // Rollback-only transaction. + }; + // PPC 1, section 2.4.1 Branch Instructions inline void b( address a, relocInfo::relocType rt = relocInfo::none); inline void b( Label& L); @@ -1581,6 +1602,7 @@ class Assembler : public AbstractAssembler { inline void bnectrl(ConditionRegister crx, relocInfo::relocType rt = relocInfo::none); // condition register logic instructions + // NOTE: There's a preferred form: d and s2 should point into the same condition register. inline void crand( int d, int s1, int s2); inline void crnand(int d, int s1, int s2); inline void cror( int d, int s1, int s2); @@ -1590,6 +1612,19 @@ class Assembler : public AbstractAssembler { inline void crandc(int d, int s1, int s2); inline void crorc( int d, int s1, int s2); + // More convenient version. + int condition_register_bit(ConditionRegister cr, Condition c) { + return 4 * (int)(intptr_t)cr + c; + } + void crand( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc); + void crnand(ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc); + void cror( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc); + void crxor( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc); + void crnor( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc); + void creqv( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc); + void crandc(ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc); + void crorc( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc); + // icache and dcache related instructions inline void icbi( Register s1, Register s2); //inline void dcba(Register s1, Register s2); // Instruction for embedded processor only. @@ -1673,6 +1708,10 @@ class Assembler : public AbstractAssembler { inline void smt_prio_low(); inline void smt_prio_medium_low(); inline void smt_prio_medium(); + // >= Power7 + inline void smt_yield(); + inline void smt_mdoio(); + inline void smt_mdoom(); // trap instructions inline void twi_0(Register a); // for load with acquire semantics use load+twi_0+isync (trap can't occur) @@ -1958,6 +1997,7 @@ class Assembler : public AbstractAssembler { inline void tbeginrot_(); // R=1 Rollback-Only Transaction inline void tend_(); // A=0 inline void tendall_(); // A=1 + inline void tabort_(); inline void tabort_(Register a); inline void tabortwc_(int t, Register a, Register b); inline void tabortwci_(int t, Register a, int si); @@ -1967,6 +2007,10 @@ class Assembler : public AbstractAssembler { inline void tresume_(); // tsr with L=1 inline void tcheck(int f); + static bool is_tbegin(int x) { + return TBEGIN_OPCODE == (x & (0x3f << OPCODE_SHIFT | 0x3ff << 1)); + } + // The following encoders use r0 as second operand. These instructions // read r0 as '0'. inline void lwzx( Register d, Register s2); diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp index b4a7370994d..5493f124371 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -453,6 +453,48 @@ inline void Assembler::creqv( int d, int s1, int s2) { emit_int32(CREQV_OPCODE inline void Assembler::crandc(int d, int s1, int s2) { emit_int32(CRANDC_OPCODE | bt(d) | ba(s1) | bb(s2)); } inline void Assembler::crorc( int d, int s1, int s2) { emit_int32(CRORC_OPCODE | bt(d) | ba(s1) | bb(s2)); } +// More convenient version. +inline void Assembler::crand( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) { + int dst_bit = condition_register_bit(crdst, cdst), + src_bit = condition_register_bit(crsrc, csrc); + crand(dst_bit, src_bit, dst_bit); +} +inline void Assembler::crnand(ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) { + int dst_bit = condition_register_bit(crdst, cdst), + src_bit = condition_register_bit(crsrc, csrc); + crnand(dst_bit, src_bit, dst_bit); +} +inline void Assembler::cror( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) { + int dst_bit = condition_register_bit(crdst, cdst), + src_bit = condition_register_bit(crsrc, csrc); + cror(dst_bit, src_bit, dst_bit); +} +inline void Assembler::crxor( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) { + int dst_bit = condition_register_bit(crdst, cdst), + src_bit = condition_register_bit(crsrc, csrc); + crxor(dst_bit, src_bit, dst_bit); +} +inline void Assembler::crnor( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) { + int dst_bit = condition_register_bit(crdst, cdst), + src_bit = condition_register_bit(crsrc, csrc); + crnor(dst_bit, src_bit, dst_bit); +} +inline void Assembler::creqv( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) { + int dst_bit = condition_register_bit(crdst, cdst), + src_bit = condition_register_bit(crsrc, csrc); + creqv(dst_bit, src_bit, dst_bit); +} +inline void Assembler::crandc(ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) { + int dst_bit = condition_register_bit(crdst, cdst), + src_bit = condition_register_bit(crsrc, csrc); + crandc(dst_bit, src_bit, dst_bit); +} +inline void Assembler::crorc( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) { + int dst_bit = condition_register_bit(crdst, cdst), + src_bit = condition_register_bit(crsrc, csrc); + crorc(dst_bit, src_bit, dst_bit); +} + // Conditional move (>= Power7) inline void Assembler::isel(Register d, ConditionRegister cr, Condition cc, bool inv, Register a, Register b) { if (b == noreg) { @@ -516,6 +558,10 @@ inline void Assembler::smt_prio_medium_low() { Assembler::or_unchecked(R6, R6, inline void Assembler::smt_prio_medium() { Assembler::or_unchecked(R2, R2, R2); } inline void Assembler::smt_prio_medium_high() { Assembler::or_unchecked(R5, R5, R5); } inline void Assembler::smt_prio_high() { Assembler::or_unchecked(R3, R3, R3); } +// >= Power7 +inline void Assembler::smt_yield() { Assembler::or_unchecked(R27, R27, R27); } +inline void Assembler::smt_mdoio() { Assembler::or_unchecked(R29, R29, R29); } +inline void Assembler::smt_mdoom() { Assembler::or_unchecked(R30, R30, R30); } inline void Assembler::twi_0(Register a) { twi_unchecked(0, a, 0);} @@ -778,7 +824,8 @@ inline void Assembler::tbegin_() { emit_int32( TB inline void Assembler::tbeginrot_() { emit_int32( TBEGIN_OPCODE | /*R=1*/ 1u << (31-10) | rc(1)); } inline void Assembler::tend_() { emit_int32( TEND_OPCODE | rc(1)); } inline void Assembler::tendall_() { emit_int32( TEND_OPCODE | /*A=1*/ 1u << (31-6) | rc(1)); } -inline void Assembler::tabort_(Register a) { emit_int32( TABORT_OPCODE | ra(a) | rc(1)); } +inline void Assembler::tabort_() { emit_int32( TABORT_OPCODE | rc(1)); } +inline void Assembler::tabort_(Register a) { assert(a != R0, "r0 not allowed"); emit_int32( TABORT_OPCODE | ra(a) | rc(1)); } inline void Assembler::tabortwc_(int t, Register a, Register b) { emit_int32( TABORTWC_OPCODE | to(t) | ra(a) | rb(b) | rc(1)); } inline void Assembler::tabortwci_(int t, Register a, int si) { emit_int32( TABORTWCI_OPCODE | to(t) | ra(a) | sh1620(si) | rc(1)); } inline void Assembler::tabortdc_(int t, Register a, Register b) { emit_int32( TABORTDC_OPCODE | to(t) | ra(a) | rb(b) | rc(1)); } 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 dec0d9732a8..9cb22c11433 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, 2014 SAP AG. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1712,7 +1712,7 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, Register mdo_addr andi_(R0, klass, TypeEntries::type_unknown); // Already unknown. Nothing to do anymore. //bne(CCR0, do_nothing); - crorc(/*CCR0 eq*/2, /*CCR1 eq*/4+2, /*CCR0 eq*/2); // cr0 eq = cr1 eq or cr0 ne + crorc(CCR0, Assembler::equal, CCR1, Assembler::equal); // cr0 eq = cr1 eq or cr0 ne beq(CCR0, do_nothing); clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask)); @@ -1826,9 +1826,9 @@ void InterpreterMacroAssembler::profile_return_type(Register ret, Register tmp1, lbz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method); cmpwi(CCR0, tmp1, Bytecodes::_invokedynamic); cmpwi(CCR1, tmp1, Bytecodes::_invokehandle); - cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + cror(CCR0, Assembler::equal, CCR1, Assembler::equal); cmpwi(CCR1, tmp2, vmIntrinsics::_compiledLambdaForm); - cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + cror(CCR0, Assembler::equal, CCR1, Assembler::equal); bne(CCR0, profile_continue); } diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 5c118981415..46216782c97 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -567,16 +567,21 @@ class MacroAssembler: public Assembler { inline void load_with_trap_null_check(Register d, int si16, Register s1); // 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); + // Specify tmp to save one cycle. + inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg, + Register tmp = noreg); + // Store heap oop and decompress. Decompressed oop may not be null. + // Specify tmp register if d should not be changed. inline void store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, - /*specify if d must stay uncompressed*/ Register tmp = noreg); + 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. + // src == d allowed. inline Register encode_heap_oop_not_null(Register d, Register src = noreg); - inline void decode_heap_oop_not_null(Register d); + inline Register decode_heap_oop_not_null(Register d, Register src = noreg); // Null allowed. inline void decode_heap_oop(Register d); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp index 84485d4f6af..f5d19dff066 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp @@ -311,11 +311,14 @@ inline void MacroAssembler::load_with_trap_null_check(Register d, int si16, Regi ld(d, si16, s1); } -inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1) { +inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) { if (UseCompressedOops) { - lwz(d, offs, s1); + // In disjoint mode decoding can save a cycle if src != dst. + Register narrowOop = (tmp != noreg && Universe::narrow_oop_base_disjoint()) ? tmp : d; + lwz(narrowOop, offs, s1); // Attention: no null check here! - decode_heap_oop_not_null(d); + Register res = decode_heap_oop_not_null(d, narrowOop); + assert(res == d, "caller will not consume loaded value"); } else { ld(d, offs, s1); } @@ -340,26 +343,36 @@ inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, R } 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) { + Register current = (src != noreg) ? src : d; // Oop to be compressed is in d if no src provided. + if (Universe::narrow_oop_base_overlaps()) { sub(d, current, R30); current = d; } if (Universe::narrow_oop_shift() != 0) { - srdi(d, current, LogMinObjAlignmentInBytes); + rldicl(d, current, 64-Universe::narrow_oop_shift(), 32); // Clears the upper bits. current = d; } return current; // Encoded oop is in this register. } -inline void MacroAssembler::decode_heap_oop_not_null(Register d) { +inline Register MacroAssembler::decode_heap_oop_not_null(Register d, Register src) { + if (Universe::narrow_oop_base_disjoint() && src != noreg && src != d && + Universe::narrow_oop_shift() != 0) { + mr(d, R30); + rldimi(d, src, Universe::narrow_oop_shift(), 32-Universe::narrow_oop_shift()); + return d; + } + + Register current = (src != noreg) ? src : d; // Compressed oop is in d if no src provided. if (Universe::narrow_oop_shift() != 0) { - assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - sldi(d, d, LogMinObjAlignmentInBytes); + sldi(d, current, Universe::narrow_oop_shift()); + current = d; } if (Universe::narrow_oop_base() != NULL) { - add(d, d, R30); + add(d, current, R30); + current = d; } + return current; // Decoded oop is in this register. } inline void MacroAssembler::decode_heap_oop(Register d) { @@ -368,13 +381,7 @@ inline void MacroAssembler::decode_heap_oop(Register d) { cmpwi(CCR0, d, 0); beq(CCR0, isNull); } - if (Universe::narrow_oop_shift() != 0) { - assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - sldi(d, d, LogMinObjAlignmentInBytes); - } - if (Universe::narrow_oop_base() != NULL) { - add(d, d, R30); - } + decode_heap_oop_not_null(d); bind(isNull); } diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp index 89c0344a5fe..88e0dec0709 100644 --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp @@ -172,15 +172,15 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, // Load the invoker, as MH -> MH.form -> LF.vmentry __ verify_oop(recv); - __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), recv); + __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), recv, temp2); __ verify_oop(method_temp); - __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp); + __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp, temp2); __ verify_oop(method_temp); - // the following assumes that a Method* is normally compressed in the vmtarget field: + // The following assumes that a Method* is normally compressed in the vmtarget field: __ ld(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()), method_temp); if (VerifyMethodHandles && !for_compiler_entry) { - // make sure recv is already on stack + // Make sure recv is already on stack. __ ld(temp2, in_bytes(Method::const_offset()), method_temp); __ load_sized_value(temp2, in_bytes(ConstMethod::size_of_parameters_offset()), temp2, sizeof(u2), /*is_signed*/ false); @@ -259,8 +259,9 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* } if (TraceMethodHandles) { - if (tmp_mh != noreg) + if (tmp_mh != noreg) { __ mr(R23_method_handle, tmp_mh); // make stub happy + } trace_method_handle_interpreter_entry(_masm, iid); } @@ -332,7 +333,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) { Label L_ok; Register temp2_defc = temp2; - __ load_heap_oop_not_null(temp2_defc, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg); + __ load_heap_oop_not_null(temp2_defc, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg, temp3); load_klass_from_Class(_masm, temp2_defc, temp3, temp4); __ verify_klass_ptr(temp2_defc); __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, temp4, L_ok); @@ -407,7 +408,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, } Register temp2_intf = temp2; - __ load_heap_oop_not_null(temp2_intf, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg); + __ load_heap_oop_not_null(temp2_intf, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg, temp3); load_klass_from_Class(_masm, temp2_intf, temp3, temp4); __ verify_klass_ptr(temp2_intf); @@ -464,7 +465,7 @@ void trace_method_handle_stub(const char* adaptername, strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH const char* mh_reg_name = has_mh ? "R23_method_handle" : "G23"; tty->print_cr("MH %s %s="INTPTR_FORMAT " sp=" INTPTR_FORMAT, - adaptername, mh_reg_name, (intptr_t) mh, (intptr_t) entry_sp); + adaptername, mh_reg_name, (intptr_t) mh, entry_sp); if (Verbose) { tty->print_cr("Registers:"); @@ -535,23 +536,22 @@ void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adapt BLOCK_COMMENT("trace_method_handle {"); - int nbytes_save = 10 * 8; // 10 volatile gprs - __ save_LR_CR(R0); - __ mr(R0, R1_SP); // saved_sp - assert(Assembler::is_simm(-nbytes_save, 16), "Overwriting 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. + const Register tmp = R11; // Will be preserved. + const int nbytes_save = 11*8; // volatile gprs except R0 + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ save_LR_CR(tmp); // save in old frame - __ load_const(R3_ARG1, (address)adaptername); + __ mr(R5_ARG3, R1_SP); // saved_sp + __ push_frame_reg_args(nbytes_save, tmp); + + __ load_const_optimized(R3_ARG1, (address)adaptername, tmp); __ mr(R4_ARG2, R23_method_handle); - __ mr(R5_ARG3, R0); // saved_sp __ mr(R6_ARG4, R1_SP); __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub)); - __ restore_volatile_gprs(R1_SP, 112); // Except R0. __ pop_frame(); - __ restore_LR_CR(R0); + __ restore_LR_CR(tmp); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 BLOCK_COMMENT("} trace_method_handle"); } diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index 51a9762e983..a9d576c5014 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -1,6 +1,6 @@ // -// Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. -// Copyright 2012, 2014 SAP AG. All rights reserved. +// Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +// Copyright 2012, 2015 SAP AG. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -2698,7 +2698,7 @@ encode %{ const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else if (constant_reloc == relocInfo::metadata_type) { - AddressLiteral a = __ allocate_metadata_address((Metadata *)val); + AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else { @@ -2727,7 +2727,7 @@ encode %{ const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else if (constant_reloc == relocInfo::metadata_type) { - AddressLiteral a = __ allocate_metadata_address((Metadata *)val); + AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else { // non-oop pointers, e.g. card mark base, heap top @@ -6029,6 +6029,20 @@ instruct clearMs32b(iRegNdst dst, iRegNsrc src) %{ ins_pipe(pipe_class_default); %} +// Optimize DecodeN for disjoint base. +// Load base of compressed oops into a register +instruct loadBase(iRegLdst dst) %{ + effect(DEF dst); + + format %{ "MR $dst, r30_heapbase" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_or); + __ mr($dst$$Register, R30); + %} + ins_pipe(pipe_class_default); +%} + // Loading ConN must be postalloc expanded so that edges between // the nodes are safe. They may not interfere with a safepoint. // GL TODO: This needs three instructions: better put this into the constant pool. @@ -6724,13 +6738,12 @@ instruct cond_set_0_oop(iRegNdst dst, flagsReg crx, iRegPsrc src1) %{ ins_pipe(pipe_class_default); %} -// base != 0 -// 32G aligned narrow oop base. -instruct encodeP_32GAligned(iRegNdst dst, iRegPsrc src) %{ +// Disjoint narrow oop base. +instruct encodeP_Disjoint(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodeP src)); - predicate(false /* TODO: PPC port Universe::narrow_oop_base_disjoint()*/); + predicate(Universe::narrow_oop_base_disjoint()); - format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with 32G aligned base" %} + format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with disjoint base" %} size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_rldicl); @@ -6745,7 +6758,7 @@ instruct encodeP_Ex(iRegNdst dst, flagsReg crx, iRegPsrc src) %{ effect(TEMP crx); predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull && Universe::narrow_oop_shift() != 0 && - true /* TODO: PPC port Universe::narrow_oop_base_overlaps()*/); + Universe::narrow_oop_base_overlaps()); format %{ "EncodeP $dst, $crx, $src \t// postalloc expanded" %} postalloc_expand( postalloc_expand_encode_oop(dst, src, crx)); @@ -6756,7 +6769,7 @@ instruct encodeP_not_null_Ex(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodeP src)); predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull && Universe::narrow_oop_shift() != 0 && - true /* TODO: PPC port Universe::narrow_oop_base_overlaps()*/); + Universe::narrow_oop_base_overlaps()); format %{ "EncodeP $dst, $src\t// $src != Null, postalloc expanded" %} postalloc_expand( postalloc_expand_encode_oop_not_null(dst, src) ); @@ -6876,6 +6889,7 @@ instruct decodeN_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && Universe::narrow_oop_shift() != 0 && Universe::narrow_oop_base() != 0); + ins_cost(4 * DEFAULT_COST); // Should be more expensive than decodeN_Disjoint_isel_Ex. effect(TEMP crx); format %{ "DecodeN $dst, $src \t// Kills $crx, postalloc expanded" %} @@ -6897,6 +6911,106 @@ instruct decodeN_nullBase(iRegPdst dst, iRegNsrc src) %{ ins_pipe(pipe_class_default); %} +// Optimize DecodeN for disjoint base. +// Shift narrow oop and or it into register that already contains the heap base. +// Base == dst must hold, and is assured by construction in postaloc_expand. +instruct decodeN_mergeDisjoint(iRegPdst dst, iRegNsrc src, iRegLsrc base) %{ + match(Set dst (DecodeN src)); + effect(TEMP base); + predicate(false); + + format %{ "RLDIMI $dst, $src, shift, 32-shift \t// DecodeN (disjoint base)" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_rldimi); + __ rldimi($dst$$Register, $src$$Register, Universe::narrow_oop_shift(), 32-Universe::narrow_oop_shift()); + %} + ins_pipe(pipe_class_default); +%} + +// Optimize DecodeN for disjoint base. +// This node requires only one cycle on the critical path. +// We must postalloc_expand as we can not express use_def effects where +// the used register is L and the def'ed register P. +instruct decodeN_Disjoint_notNull_Ex(iRegPdst dst, iRegNsrc src) %{ + match(Set dst (DecodeN src)); + effect(TEMP_DEF dst); + predicate((n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull || + n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && + Universe::narrow_oop_base_disjoint()); + ins_cost(DEFAULT_COST); + + format %{ "MOV $dst, R30 \t\n" + "RLDIMI $dst, $src, shift, 32-shift \t// decode with disjoint base" %} + postalloc_expand %{ + loadBaseNode *n1 = new loadBaseNode(); + n1->add_req(NULL); + n1->_opnds[0] = op_dst; + + decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); + n2->add_req(n_region, n_src, n1); + n2->_opnds[0] = op_dst; + n2->_opnds[1] = op_src; + n2->_opnds[2] = op_dst; + n2->_bottom_type = _bottom_type; + + ra_->set_pair(n1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + + nodes->push(n1); + nodes->push(n2); + %} +%} + +instruct decodeN_Disjoint_isel_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ + match(Set dst (DecodeN src)); + effect(TEMP_DEF dst, TEMP crx); + predicate((n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && + n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && + Universe::narrow_oop_base_disjoint() && VM_Version::has_isel()); + ins_cost(3 * DEFAULT_COST); + + format %{ "DecodeN $dst, $src \t// decode with disjoint base using isel" %} + postalloc_expand %{ + loadBaseNode *n1 = new loadBaseNode(); + n1->add_req(NULL); + n1->_opnds[0] = op_dst; + + cmpN_reg_imm0Node *n_compare = new cmpN_reg_imm0Node(); + n_compare->add_req(n_region, n_src); + n_compare->_opnds[0] = op_crx; + n_compare->_opnds[1] = op_src; + n_compare->_opnds[2] = new immN_0Oper(TypeNarrowOop::NULL_PTR); + + decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); + n2->add_req(n_region, n_src, n1); + n2->_opnds[0] = op_dst; + n2->_opnds[1] = op_src; + n2->_opnds[2] = op_dst; + n2->_bottom_type = _bottom_type; + + cond_set_0_ptrNode *n_cond_set = new cond_set_0_ptrNode(); + n_cond_set->add_req(n_region, n_compare, n2); + n_cond_set->_opnds[0] = op_dst; + n_cond_set->_opnds[1] = op_crx; + n_cond_set->_opnds[2] = op_dst; + n_cond_set->_bottom_type = _bottom_type; + + assert(ra_->is_oop(this) == true, "A decodeN node must produce an oop!"); + ra_->set_oop(n_cond_set, true); + + ra_->set_pair(n1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); + ra_->set_pair(n2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_cond_set->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + + nodes->push(n1); + nodes->push(n_compare); + nodes->push(n2); + nodes->push(n_cond_set); + %} +%} + // src != 0, shift != 0, base != 0 instruct decodeN_notNull_addBase_Ex(iRegPdst dst, iRegNsrc src) %{ match(Set dst (DecodeN src)); @@ -6904,6 +7018,7 @@ instruct decodeN_notNull_addBase_Ex(iRegPdst dst, iRegNsrc src) %{ n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && Universe::narrow_oop_shift() != 0 && Universe::narrow_oop_base() != 0); + ins_cost(2 * DEFAULT_COST); format %{ "DecodeN $dst, $src \t// $src != NULL, postalloc expanded" %} postalloc_expand( postalloc_expand_decode_oop_not_null(dst, src)); @@ -6973,13 +7088,12 @@ instruct encodePKlass_sub_base(iRegPdst dst, iRegLsrc base, iRegPdst src) %{ ins_pipe(pipe_class_default); %} -// base != 0 -// 32G aligned narrow oop base. -instruct encodePKlass_32GAligned(iRegNdst dst, iRegPsrc src) %{ +// Disjoint narrow oop base. +instruct encodePKlass_Disjoint(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodePKlass src)); predicate(false /* TODO: PPC port Universe::narrow_klass_base_disjoint()*/); - format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with 32G aligned base" %} + format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with disjoint base" %} size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_rldicl); @@ -7486,7 +7600,7 @@ instruct storeLConditional_regP_regL_regL(flagsReg crx, indirect mem_ptr, iRegLs ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ cmpxchgd($crx$$CondRegister, R0, $oldVal$$Register, $newVal$$Register, $mem_ptr$$Register, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + MacroAssembler::MemBarAcq, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, NULL, true); %} ins_pipe(pipe_class_default); @@ -10476,7 +10590,7 @@ instruct cmpN_reg_reg(flagsReg crx, iRegNsrc src1, iRegNsrc src2) %{ match(Set crx (CmpN src1 src2)); size(4); - ins_cost(DEFAULT_COST); + ins_cost(2); format %{ "CMPLW $crx, $src1, $src2 \t// compressed ptr" %} ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_cmpl); @@ -10488,7 +10602,7 @@ instruct cmpN_reg_reg(flagsReg crx, iRegNsrc src1, iRegNsrc src2) %{ instruct cmpN_reg_imm0(flagsReg crx, iRegNsrc src1, immN_0 src2) %{ match(Set crx (CmpN src1 src2)); // Make this more expensive than zeroCheckN_iReg_imm0. - ins_cost(DEFAULT_COST); + ins_cost(2); format %{ "CMPLWI $crx, $src1, $src2 \t// compressed ptr" %} size(4); @@ -10508,6 +10622,7 @@ instruct zeroCheckP_reg_imm0(cmpOp cmp, iRegP_N2P value, immP_0 zero, label labl _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne && _leaf->as_If()->_prob >= PROB_LIKELY_MAG(4) && Matcher::branches_to_uncommon_trap(_leaf)); + ins_cost(1); // Should not be cheaper than zeroCheckN. ins_is_TrapBasedCheckNode(true); @@ -10889,7 +11004,7 @@ instruct branchLoopEndSched(cmpOp cmp, flagsReg crx, label labl) %{ instruct partialSubtypeCheck(iRegPdst result, iRegP_N2P subklass, iRegP_N2P superklass, iRegPdst tmp_klass, iRegPdst tmp_arrayptr) %{ match(Set result (PartialSubtypeCheck subklass superklass)); - effect(TEMP result, TEMP tmp_klass, TEMP tmp_arrayptr); + effect(TEMP_DEF result, TEMP tmp_klass, TEMP tmp_arrayptr); ins_cost(DEFAULT_COST*10); format %{ "PartialSubtypeCheck $result = ($subklass instanceOf $superklass) tmp: $tmp_klass, $tmp_arrayptr" %} @@ -11000,7 +11115,7 @@ instruct string_indexOf_imm1_char(iRegIdst result, iRegPsrc haystack, iRegIsrc h predicate(SpecialStringIndexOf); // type check implicit by parameter type, See Matcher::match_rule_supported match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); - effect(TEMP result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1); ins_cost(150); format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" @@ -11037,7 +11152,7 @@ instruct string_indexOf_imm1(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0, flagsRegCR1 cr1) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); - effect(USE_KILL needle, /* TDEF needle, */ TEMP result, + effect(USE_KILL needle, /* TDEF needle, */ TEMP_DEF result, TEMP tmp1, TEMP tmp2); // Required for EA: check if it is still a type_array. predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && @@ -11084,7 +11199,7 @@ instruct string_indexOf_imm(iRegIdst result, iRegPsrc haystack, rscratch1RegI ha iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); - effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP result, + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6); // Required for EA: check if it is still a type_array. predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && @@ -11118,7 +11233,7 @@ instruct string_indexOf(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ - TEMP result, + TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6); predicate(SpecialStringIndexOf); // See Matcher::match_rule_supported. ins_cost(300); @@ -11142,7 +11257,7 @@ instruct string_equals_imm(iRegPsrc str1, iRegPsrc str2, uimmI15 cntImm, iRegIds iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0, flagsRegCR6 cr6, regCTR ctr) %{ match(Set result (StrEquals (Binary str1 str2) cntImm)); - effect(TEMP result, TEMP tmp1, TEMP tmp2, + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr6, KILL ctr); predicate(SpecialStringEquals); // See Matcher::match_rule_supported. ins_cost(250); @@ -11165,7 +11280,7 @@ instruct string_equals(iRegPsrc str1, iRegPsrc str2, iRegIsrc cnt, iRegIdst resu iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, iRegPdst tmp4, iRegPdst tmp5, flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(TEMP result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); predicate(SpecialStringEquals); // See Matcher::match_rule_supported. ins_cost(300); @@ -11188,7 +11303,7 @@ instruct string_equals(iRegPsrc str1, iRegPsrc str2, iRegIsrc cnt, iRegIdst resu instruct string_compare(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, iRegPdst tmp, flagsRegCR0 cr0, regCTR ctr) %{ match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(USE_KILL cnt1, USE_KILL cnt2, USE_KILL str1, USE_KILL str2, TEMP result, TEMP tmp, KILL cr0, KILL ctr); + effect(USE_KILL cnt1, USE_KILL cnt2, USE_KILL str1, USE_KILL str2, TEMP_DEF result, TEMP tmp, KILL cr0, KILL ctr); ins_cost(300); ins_alignment(8); // 'compute_padding()' gets called, up to this number-1 nops will get inserted. diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index 0f8c752cacc..43258ce2a9a 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, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1079,7 +1079,7 @@ class StubGenerator: public StubCodeGenerator { __ sldi(tmp2, R5_ARG3, log2_elem_size); // size in bytes __ cmpld(CCR0, R3_ARG1, R4_ARG2); // Use unsigned comparison! __ cmpld(CCR1, tmp1, tmp2); - __ crand(/*CCR0 lt*/0, /*CCR1 lt*/4+0, /*CCR0 lt*/0); + __ crand(CCR0, Assembler::less, CCR1, Assembler::less); __ blt(CCR0, l_overlap); // Src before dst and distance smaller than size. // need to copy forwards diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp index 2a58b36d420..432a96d8268 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp @@ -264,11 +264,11 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* __ cmpdi(CCR0, Rmdo, 0); __ beq(CCR0, no_mdo); - // Increment backedge counter in the MDO. - const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); - __ lwz(Rscratch2, mdo_bc_offs, Rmdo); + // Increment invocation counter in the MDO. + const int mdo_ic_offs = in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ lwz(Rscratch2, mdo_ic_offs, Rmdo); __ addi(Rscratch2, Rscratch2, increment); - __ stw(Rscratch2, mdo_bc_offs, Rmdo); + __ stw(Rscratch2, mdo_ic_offs, Rmdo); __ load_const_optimized(Rscratch1, mask, R0); __ and_(Rscratch1, Rscratch2, Rscratch1); __ bne(CCR0, done); @@ -276,12 +276,12 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* } // Increment counter in MethodCounters*. - const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + const int mo_ic_offs = in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); __ bind(no_mdo); __ get_method_counters(R19_method, R3_counters, done); - __ lwz(Rscratch2, mo_bc_offs, R3_counters); + __ lwz(Rscratch2, mo_ic_offs, R3_counters); __ addi(Rscratch2, Rscratch2, increment); - __ stw(Rscratch2, mo_bc_offs, R3_counters); + __ stw(Rscratch2, mo_ic_offs, R3_counters); __ load_const_optimized(Rscratch1, mask, R0); __ and_(Rscratch1, Rscratch2, Rscratch1); __ beq(CCR0, *overflow); diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp index 40cd339c2c0..69c1e0d1be1 100644 --- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013, 2014 SAP AG. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -335,11 +335,11 @@ void TemplateTable::ldc(bool wide) { __ 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); + __ cror(CCR0, Assembler::equal, CCR1, Assembler::equal); // 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? + __ crnor(CCR0, Assembler::equal, CCR1, Assembler::equal); // Neither resolved class nor unresolved case from above? __ beq(CCR0, notClass); __ li(R4, wide ? 1 : 0); @@ -2611,7 +2611,7 @@ void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, boo __ 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); + __ crnor(CCR0, Assembler::equal, CCR1, Assembler::equal); __ beq(CCR0, is_one_slot); __ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(2)); __ bind(is_one_slot); @@ -3563,7 +3563,7 @@ void TemplateTable::_new() { // 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? + __ crnand(CCR0, Assembler::equal, CCR1, Assembler::equal); // slow path bit set or not fully initialized? __ beq(CCR0, Lslow_case); // -------------------------------------------------------------------------- diff --git a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp index f3709eb8d05..1187443000d 100644 --- a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -483,15 +483,6 @@ void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { } -jbyte* G1PostBarrierStub::_byte_map_base = NULL; - -jbyte* G1PostBarrierStub::byte_map_base_slow() { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->is_a(BarrierSet::G1SATBCTLogging), - "Must be if we're using this."); - return ((G1SATBCardTableModRefBS*)bs)->byte_map_base; -} - void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index 51f237ba626..153bfbdda55 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -1374,6 +1374,7 @@ void InterpreterMacroAssembler::verify_method_data_pointer() { } void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, + Register method_counters, Register Rtmp, Label &profile_continue) { assert(ProfileInterpreter, "must be profiling interpreter"); @@ -1386,9 +1387,8 @@ void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocat br_notnull_short(ImethodDataPtr, Assembler::pn, done); // Test to see if we should create a method data oop - AddressLiteral profile_limit((address) &InvocationCounter::InterpreterProfileLimit); - sethi(profile_limit, Rtmp); - ld(Rtmp, profile_limit.low10(), Rtmp); + Address profile_limit(method_counters, MethodCounters::interpreter_profile_limit_offset()); + ld(profile_limit, Rtmp); cmp(invocation_count, Rtmp); // Use long branches because call_VM() code and following code generated by // test_backedge_count_for_osr() is large in debug VM. @@ -2375,6 +2375,7 @@ void InterpreterMacroAssembler::increment_backedge_counter( Register Rcounters, #ifndef CC_INTERP void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_count, + Register method_counters, Register branch_bcp, Register Rtmp ) { Label did_not_overflow; @@ -2382,8 +2383,8 @@ void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_c assert_different_registers(backedge_count, Rtmp, branch_bcp); assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr"); - AddressLiteral limit(&InvocationCounter::InterpreterBackwardBranchLimit); - load_contents(limit, Rtmp); + Address limit(method_counters, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset())); + ld(limit, Rtmp); cmp_and_br_short(backedge_count, Rtmp, Assembler::lessUnsigned, Assembler::pt, did_not_overflow); // When ProfileInterpreter is on, the backedge_count comes from the @@ -2500,17 +2501,13 @@ 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, + int increment, Address mask_addr, 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); - } + ld(mask_addr, scratch2); + andcc(scratch1, scratch2, G0); br(cond, false, Assembler::pn, *where); delayed()->st(scratch1, counter_addr); } diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp index 5ba547d2241..862611c4252 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp @@ -267,7 +267,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); void increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); #ifndef CC_INTERP - void test_backedge_count_for_osr( Register backedge_count, Register branch_bcp, Register Rtmp ); + void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register branch_bcp, Register Rtmp ); #endif /* CC_INTERP */ // Object locking @@ -280,7 +280,7 @@ class InterpreterMacroAssembler: public MacroAssembler { 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 Rtmp, Label &profile_continue); + void test_invocation_counter_for_mdp(Register invocation_count, Register method_counters, Register Rtmp, Label &profile_continue); void set_mdp_data_at(int constant, Register value); void increment_mdp_data_at(Address counter, Register bumped_count, @@ -291,7 +291,7 @@ class InterpreterMacroAssembler: public MacroAssembler { Register bumped_count, Register scratch2, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask_addr, Register scratch1, Register scratch2, Condition cond, Label *where); void set_mdp_flag_at(int flag_constant, Register scratch); diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp index 7e3804fd379..3518d0b6336 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp @@ -630,7 +630,12 @@ inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, Register s1, Registe inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset) { relocate(a.rspec(offset)); - ldf(w, a.base(), a.disp() + offset, d); + if (a.has_index()) { + assert(offset == 0, ""); + ldf(w, a.base(), a.index(), d); + } else { + ldf(w, a.base(), a.disp() + offset, d); + } } // returns if membar generates anything, obviously this code should mirror diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index dfc67d5df66..739cc9612bd 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -2996,7 +2996,7 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{ %} enc_class enc_String_Equals(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result) %{ - Label Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone; + Label Lchar, Lchar_loop, Ldone; MacroAssembler _masm(&cbuf); Register str1_reg = reg_to_register_object($str1$$reg); diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index 93f87807482..c3039d51337 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -282,12 +282,11 @@ address TemplateInterpreterGenerator::generate_continuation_for(TosState state) void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { // Note: In tiered we increment either counters in MethodCounters* or in // MDO depending if we're profiling or not. - const Register Rcounters = G3_scratch; + const Register G3_method_counters = G3_scratch; Label done; if (TieredCompilation) { const int increment = InvocationCounter::count_increment; - const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // If no method data exists, go to profile_continue. @@ -297,6 +296,7 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile Address mdo_invocation_counter(G4_scratch, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G4_scratch, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, G3_scratch, Lscratch, Assembler::zero, overflow); @@ -305,20 +305,21 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile // Increment counter in MethodCounters* __ bind(no_mdo); - Address invocation_counter(Rcounters, + Address invocation_counter(G3_method_counters, in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); - __ get_method_counters(Lmethod, Rcounters, done); + __ get_method_counters(Lmethod, G3_method_counters, done); + Address mask(G3_method_counters, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, G4_scratch, Lscratch, Assembler::zero, overflow); __ bind(done); - } else { + } else { // not TieredCompilation // Update standard invocation counters - __ get_method_counters(Lmethod, Rcounters, done); - __ increment_invocation_counter(Rcounters, O0, G4_scratch); + __ get_method_counters(Lmethod, G3_method_counters, done); + __ increment_invocation_counter(G3_method_counters, O0, G4_scratch); if (ProfileInterpreter) { - Address interpreter_invocation_counter(Rcounters, + Address interpreter_invocation_counter(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_counter_offset())); __ ld(interpreter_invocation_counter, G4_scratch); __ inc(G4_scratch); @@ -327,16 +328,16 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - AddressLiteral profile_limit((address)&InvocationCounter::InterpreterProfileLimit); - __ load_contents(profile_limit, G3_scratch); - __ cmp_and_br_short(O0, G3_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue); + Address profile_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_profile_limit_offset())); + __ ld(profile_limit, G1_scratch); + __ cmp_and_br_short(O0, G1_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(*profile_method); } - AddressLiteral invocation_limit((address)&InvocationCounter::InterpreterInvocationLimit); - __ load_contents(invocation_limit, G3_scratch); + Address invocation_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_limit_offset())); + __ ld(invocation_limit, G3_scratch); __ cmp(O0, G3_scratch); __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); // Far distance __ delayed()->nop(); diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index 9424b1be1f6..438d376b2c6 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -1599,13 +1599,12 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Bump bytecode pointer by displacement (take the branch) __ delayed()->add( O1_disp, Lbcp, Lbcp ); // add to bc addr - const Register Rcounters = G3_scratch; - __ get_method_counters(Lmethod, Rcounters, Lforward); + const Register G3_method_counters = G3_scratch; + __ get_method_counters(Lmethod, G3_method_counters, Lforward); if (TieredCompilation) { Label Lno_mdo, Loverflow; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // If no method data exists, go to profile_continue. __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch); @@ -1614,6 +1613,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment backedge counter in the MDO Address mdo_backedge_counter(G4_scratch, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G4_scratch, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, O0, Assembler::notZero, &Lforward); __ ba_short(Loverflow); @@ -1621,9 +1621,10 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // If there's no MDO, increment counter in MethodCounters* __ bind(Lno_mdo); - Address backedge_counter(Rcounters, + Address backedge_counter(G3_method_counters, in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G3_method_counters, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(backedge_counter, increment, mask, G4_scratch, O0, Assembler::notZero, &Lforward); __ bind(Loverflow); @@ -1663,18 +1664,19 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ jmp(O2, G0); __ delayed()->nop(); - } else { + } else { // not TieredCompilation // Update Backedge branch separately from invocations const Register G4_invoke_ctr = G4; - __ increment_backedge_counter(Rcounters, G4_invoke_ctr, G1_scratch); + __ increment_backedge_counter(G3_method_counters, G4_invoke_ctr, G1_scratch); if (ProfileInterpreter) { - __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_scratch, Lforward); + __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_method_counters, G1_scratch, Lforward); if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(O2_bumped_count, l_cur_bcp, G3_scratch); + + __ test_backedge_count_for_osr(O2_bumped_count, G3_method_counters, l_cur_bcp, G1_scratch); } } else { if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(G4_invoke_ctr, l_cur_bcp, G3_scratch); + __ test_backedge_count_for_osr(G4_invoke_ctr, G3_method_counters, l_cur_bcp, G1_scratch); } } } diff --git a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp index 718c82904f0..919c2a6df9c 100644 --- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -541,15 +541,6 @@ void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { } -jbyte* G1PostBarrierStub::_byte_map_base = NULL; - -jbyte* G1PostBarrierStub::byte_map_base_slow() { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->is_a(BarrierSet::G1SATBCTLogging), - "Must be if we're using this."); - return ((G1SATBCardTableModRefBS*)bs)->byte_map_base; -} - void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); assert(addr()->is_register(), "Precondition."); 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 181ee15251b..9aa4587f793 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -1360,7 +1360,7 @@ 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, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where) { if (!preloaded) { 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 e4d61364de4..2cd8e162fde 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp @@ -182,7 +182,7 @@ void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant); 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 23e3b973041..76335ca9fcc 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -1426,7 +1426,7 @@ 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, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where) { if (!preloaded) { 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 a1cd4466bb9..c4ed238bc20 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp @@ -191,7 +191,7 @@ void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index a6a5b43c07b..2cb6bd820d0 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3184,7 +3184,24 @@ void MacroAssembler::pow_or_exp(bool is_exp, int num_fpu_regs_in_use) { jmp(done); } else { // Stack: X Y - Label x_negative, y_odd; + Label x_negative, y_not_2; + + static double two = 2.0; + ExternalAddress two_addr((address)&two); + + // constant maybe too far on 64 bit + lea(tmp2, two_addr); + fld_d(Address(tmp2, 0)); // Stack: 2 X Y + fcmp(tmp, 2, true, false); // Stack: X Y + jcc(Assembler::parity, y_not_2); + jcc(Assembler::notEqual, y_not_2); + + fxch(); fpop(); // Stack: X + fmul(0); // Stack: X*X + + jmp(done); + + bind(y_not_2); fldz(); // Stack: 0 X Y fcmp(tmp, 1, true, false); // Stack: X Y @@ -6177,7 +6194,7 @@ void MacroAssembler::string_indexofC8(Register str1, Register str2, ShortBranchVerifier sbv(this); assert(UseSSE42Intrinsics, "SSE4.2 is required"); - // This method uses pcmpestri inxtruction with bound registers + // This method uses pcmpestri instruction with bound registers // inputs: // xmm - substring // rax - substring length (elements count) @@ -6338,7 +6355,7 @@ void MacroAssembler::string_indexof(Register str1, Register str2, // assert(int_cnt2 == -1 || (0 < int_cnt2 && int_cnt2 < 8), "should be != 0"); - // This method uses pcmpestri inxtruction with bound registers + // This method uses pcmpestri instruction with bound registers // inputs: // xmm - substring // rax - substring length (elements count) @@ -6627,7 +6644,6 @@ void MacroAssembler::string_compare(Register str1, Register str2, // start from first character again because it has aligned address. int stride2 = 16; int adr_stride = stride << scale; - int adr_stride2 = stride2 << scale; assert(result == rax && cnt2 == rdx && cnt1 == rcx, "pcmpestri"); // rax and rdx are used by pcmpestri as elements counters @@ -6726,7 +6742,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, // inputs: // vec1- substring // rax - negative string length (elements count) - // mem - scaned string + // mem - scanned string // rdx - string length (elements count) // pcmpmask - cmp mode: 11000 (string compare with negated result) // + 00 (unsigned bytes) or + 01 (unsigned shorts) diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index 93772f3df4c..69c8533d12e 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -346,7 +346,6 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile // depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -356,6 +355,7 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile // Increment counter in the MDO const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ jmp(done); } @@ -366,11 +366,12 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); + const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ bind(done); - } else { - const Address backedge_counter (rax, + } else { // not TieredCompilation + const Address backedge_counter(rax, MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); const Address invocation_counter(rax, @@ -400,16 +401,16 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(rax, *profile_method); } - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset()))); __ jcc(Assembler::aboveEqual, *overflow); __ bind(done); } diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index f3390c94ca9..6318a958517 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -299,7 +299,6 @@ void InterpreterGenerator::generate_counter_incr( // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -309,6 +308,7 @@ void InterpreterGenerator::generate_counter_incr( // Increment counter in the MDO const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ jmp(done); } @@ -318,10 +318,11 @@ void InterpreterGenerator::generate_counter_incr( MethodCounters::invocation_counter_offset() + InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); + const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ bind(done); - } else { + } else { // not TieredCompilation const Address backedge_counter(rax, MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); @@ -350,14 +351,16 @@ void InterpreterGenerator::generate_counter_incr( if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(rax, *profile_method); } - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset()))); __ jcc(Assembler::aboveEqual, *overflow); __ bind(done); } diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp index 2187056a384..d0bdc33905c 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -1621,7 +1621,6 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -1630,6 +1629,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment the MDO backedge counter const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); __ jmp(dispatch); @@ -1637,9 +1637,10 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ bind(no_mdo); // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); + const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); - } else { + } else { // not TieredCompilation // increment counter __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter @@ -1653,8 +1654,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (ProfileInterpreter) { // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, dispatch); // if no method data exists, go to profile method @@ -1662,8 +1662,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (UseOnStackReplacement) { // check for overflow against rbx, which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rbx, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::below, dispatch); // When ProfileInterpreter is on, the backedge_count comes from the @@ -1678,8 +1677,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { } else { if (UseOnStackReplacement) { // check for overflow against rax, which is the sum of the counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::aboveEqual, backedge_counter_overflow); } diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp index b1b1b00a615..82072f0c920 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -1642,7 +1642,6 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -1651,6 +1650,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment the MDO backedge counter const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); __ jmp(dispatch); @@ -1658,9 +1658,10 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ bind(no_mdo); // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); + const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); - } else { + } else { // not TieredCompilation // increment counter __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter @@ -1674,8 +1675,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (ProfileInterpreter) { // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, dispatch); // if no method data exists, go to profile method @@ -1683,8 +1683,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (UseOnStackReplacement) { // check for overflow against ebx which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rbx, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::below, dispatch); // When ProfileInterpreter is on, the backedge_count comes @@ -1702,8 +1701,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (UseOnStackReplacement) { // check for overflow against eax, which is the sum of the // counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::aboveEqual, backedge_counter_overflow); } diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index e3322ca0364..d77a26ffa66 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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. * @@ -1115,6 +1115,15 @@ jlong os::javaTimeMillis() { return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000); } +void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { + timeval time; + int status = gettimeofday(&time, NULL); + assert(status != -1, "aix error at gettimeofday()"); + seconds = jlong(time.tv_sec); + nanos = jlong(time.tv_usec) * 1000; +} + + // We need to manually declare mread_real_time, // because IBM didn't provide a prototype in time.h. // (they probably only ever tested in C, not C++) diff --git a/hotspot/src/os/aix/vm/perfMemory_aix.cpp b/hotspot/src/os/aix/vm/perfMemory_aix.cpp index b509cf94110..c9dd76b7881 100644 --- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp +++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp @@ -31,6 +31,7 @@ #include "os_aix.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/perfMemory.hpp" +#include "services/memTracker.hpp" #include "utilities/exceptions.hpp" // put OS-includes here @@ -196,12 +197,37 @@ static pid_t filename_to_pid(const char* filename) { return pid; } +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + return false; + } + return true; +} -// check if the given path is considered a secure directory for + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. -// static bool is_directory_secure(const char* path) { struct stat statbuf; int result = 0; @@ -211,38 +237,276 @@ static bool is_directory_secure(const char* path) { return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + +// (Taken over from Solaris to support the O_NOFOLLOW case on AIX.) +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { + return false; + } +} + +// Helper functions for open without O_NOFOLLOW which is not present on AIX 5.3/6.1. +// We use the jdk6 implementation here. +#ifndef O_NOFOLLOW +// The O_NOFOLLOW oflag doesn't exist before solaris 5.10, this is to simulate that behaviour +// was done in jdk 5/6 hotspot by Oracle this way +static int open_o_nofollow_impl(const char* path, int oflag, mode_t mode, bool use_mode) { + struct stat orig_st; + struct stat new_st; + bool create; + int error; + int fd; + + create = false; + + if (lstat(path, &orig_st) != 0) { + if (errno == ENOENT && (oflag & O_CREAT) != 0) { + // File doesn't exist, but_we want to create it, add O_EXCL flag + // to make sure no-one creates it (or a symlink) before us + // This works as we expect with symlinks, from posix man page: + // 'If O_EXCL and O_CREAT are set, and path names a symbolic + // link, open() shall fail and set errno to [EEXIST]'. + oflag |= O_EXCL; + create = true; + } else { + // File doesn't exist, and we are not creating it. + return OS_ERR; } + } else { + // Lstat success, check if existing file is a link. + if ((orig_st.st_mode & S_IFMT) == S_IFLNK) { + // File is a symlink. + errno = ELOOP; + return OS_ERR; + } + } + + if (use_mode == true) { + fd = open(path, oflag, mode); + } else { + fd = open(path, oflag); + } + + if (fd == OS_ERR) { + return fd; + } + + // Can't do inode checks on before/after if we created the file. + if (create == false) { + if (fstat(fd, &new_st) != 0) { + // Keep errno from fstat, in case close also fails. + error = errno; + ::close(fd); + errno = error; + return OS_ERR; + } + + if (orig_st.st_dev != new_st.st_dev || orig_st.st_ino != new_st.st_ino) { + // File was tampered with during race window. + ::close(fd); + errno = EEXIST; + if (PrintMiscellaneous && Verbose) { + warning("possible file tampering attempt detected when opening %s", path); + } + return OS_ERR; + } + } + + return fd; +} + +static int open_o_nofollow(const char* path, int oflag, mode_t mode) { + return open_o_nofollow_impl(path, oflag, mode, true); +} + +static int open_o_nofollow(const char* path, int oflag) { + return open_o_nofollow_impl(path, oflag, 0, false); +} +#endif + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case. +#ifdef O_NOFOLLOW + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); +#else + // workaround (jdk6 coding) + RESTARTABLE(::open_o_nofollow(dirname, O_RDONLY), result); +#endif + + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } + } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirp->dd_fd)) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirp->dd_fd; + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - -// return the user name for the given user id -// -// the caller is expected to free the allocated memory. +// Return the user name for the given user id. // +// The caller is expected to free the allocated memory. static char* get_user_name(uid_t uid) { struct passwd pwent; - // determine the max pwbuf size from sysconf, and hardcode + // Determine the max pwbuf size from sysconf, and hardcode // a default if this not available through sysconf. - // long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (bufsize == -1) bufsize = 1024; @@ -344,7 +608,8 @@ static char* get_user_name_slow(int vmid, TRAPS) { strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // Open the user directory. + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name); @@ -464,28 +729,7 @@ static void remove_file(const char* path) { } } - -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path); -} - - -// cleanup stale shared memory resources +// Cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in // the named user temporary directory. It scans the named directory @@ -493,33 +737,26 @@ static void remove_file(const char* dirname, const char* filename) { // process id is extracted from the file name and a test is run to // determine if the process is alive. If the process is not alive, // any stale file resources are removed. -// static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // Open the directory. + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup + // Directory doesn't exist or is insecure, so there is nothing to cleanup. return; } - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory - os::closedir(dirp); - return; - } - - // for each entry in the directory that matches the expected file + // For each entry in the directory that matches the expected file // name pattern, determine if the file resources are stale and if // so, remove the file resources. Note, instrumented HotSpot processes // for this user may start and/or terminate during this search and // remove or create new files in this directory. The behavior of this // loop under these conditions is dependent upon the implementation of // opendir/readdir. - // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -529,56 +766,55 @@ static void cleanup_sharedmem_resources(const char* dirname) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + // Attempt to remove all unexpected files, except "." and "..". + unlink(entry->d_name); } errno = 0; continue; } - // we now have a file name that converts to a valid integer + // We now have a file name that converts to a valid integer // that could represent a process id . if this process id // matches the current process id or the process is not running, // then remove the stale file resources. // - // process liveness is detected by sending signal number 0 to + // Process liveness is detected by sending signal number 0 to // the process id (see kill(2)). if kill determines that the // process does not exist, then the file resources are removed. // if kill determines that that we don't have permission to // signal the process, then the file resources are assumed to // be stale and are removed because the resources for such a // process should be in a different user specific directory. - // if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); - FREE_C_HEAP_ARRAY(char, dbuf); + + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } -// make the user specific temporary directory. Returns true if +// Make the user specific temporary directory. Returns true if // the directory exists and is secure upon return. Returns false // if the directory exists but is either a symlink, is otherwise // insecure, or if an error occurred. -// static bool make_user_tmp_dir(const char* dirname) { - // create the directory with 0755 permissions. note that the directory + // Create the directory with 0755 permissions. note that the directory // will be owned by euid::egid, which may not be the same as uid::gid. - // if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) { if (errno == EEXIST) { // The directory already exists and was probably created by another // JVM instance. However, this could also be the result of a // deliberate symlink. Verify that the existing directory is safe. - // if (!is_directory_secure(dirname)) { - // directory is not secure + // Directory is not secure. if (PrintMiscellaneous && Verbose) { warning("%s directory is insecure\n", dirname); } @@ -614,19 +850,63 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, return -1; } - int result; - - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); - } + int saved_cwd_fd; + // Open the directory and set the current working directory to it. + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. return -1; } + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case. +#ifdef O_NOFOLLOW + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); +#else + // workaround function (jdk6 code) + RESTARTABLE(::open_o_nofollow(filename, O_RDWR|O_CREAT, S_IREAD|S_IWRITE), result); +#endif + + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } + } + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + + return -1; + } + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + // save the file descriptor int fd = result; + // Check to see if the file is secure. + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // Truncate the file to get rid of any existing data. + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -648,7 +928,14 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { // open the file int result; + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case +#ifdef O_NOFOLLOW RESTARTABLE(::open(filename, oflags), result); +#else + RESTARTABLE(::open_o_nofollow(filename, oflags), result); +#endif + if (result == OS_ERR) { if (errno == ENOENT) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), @@ -662,8 +949,15 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); } } + int fd = result; - return result; + // Check to see if the file is secure. + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -695,13 +989,21 @@ static char* mmap_create_shared(size_t size) { char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // Get the short filename. + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name); FREE_C_HEAP_ARRAY(char, dirname); @@ -733,6 +1035,9 @@ static char* mmap_create_shared(size_t size) { // clear the shared memory region (void)::memset((void*) mapAddress, 0, size); + // It does not go through os api, the operation has to record from here. + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal); + return mapAddress; } @@ -807,7 +1112,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor char* mapAddress; int result; int fd; - size_t size; + size_t size = 0; const char* luser = NULL; int mmap_prot; @@ -819,12 +1124,18 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open. +#ifdef O_NOFOLLOW + file_flags = O_RDONLY | O_NOFOLLOW; +#else file_flags = O_RDONLY; +#endif } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode"); @@ -853,9 +1164,9 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor // store file, we don't follow them when attaching either. // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); + FREE_C_HEAP_ARRAY(char, dirname, mtInternal); if (luser != user) { - FREE_C_HEAP_ARRAY(char, luser); + FREE_C_HEAP_ARRAY(char, luser, mtInternal); } THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); @@ -901,6 +1212,9 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor "Could not map PerfMemory"); } + // It does not go through os api, the operation has to record from here. + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal); + *addr = mapAddress; *sizep = size; diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index cddb9449712..445ff225f8e 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -984,6 +984,14 @@ jlong os::javaTimeMillis() { return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000); } +void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { + timeval time; + int status = gettimeofday(&time, NULL); + assert(status != -1, "bsd error"); + seconds = jlong(time.tv_sec); + nanos = jlong(time.tv_usec) * 1000; +} + #ifndef __APPLE__ #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC (1) diff --git a/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp b/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp index 513494cf6bf..7f7468a5de3 100644 --- a/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp +++ b/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp @@ -197,7 +197,38 @@ static pid_t filename_to_pid(const char* filename) { } -// check if the given path is considered a secure directory for +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +// +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + // + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + // + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + // + return false; + } + return true; +} + + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. @@ -211,27 +242,185 @@ static bool is_directory_secure(const char* path) { return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + + +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +// +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +// +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { + return false; + } +} + + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +// +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirfd(dirp))) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirfd(dirp); + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +// +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +// +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - // return the user name for the given user id // // the caller is expected to free the allocated memory. @@ -317,9 +506,11 @@ static char* get_user_name_slow(int vmid, TRAPS) { const char* tmpdirname = os::get_temp_directory(); + // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { + // Cannot open the directory to get the user name, return. return NULL; } @@ -344,25 +535,14 @@ static char* get_user_name_slow(int vmid, TRAPS) { strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // open the user directory + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name); continue; } - // Since we don't create the backing store files in directories - // pointed to by symbolic links, we also don't follow them when - // looking for the files. We check for a symbolic link after the - // call to opendir in order to eliminate a small window where the - // symlink can be exploited. - // - if (!is_directory_secure(usrdir_name)) { - FREE_C_HEAP_ARRAY(char, usrdir_name); - os::closedir(subdirp); - continue; - } - struct dirent* udentry; char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal); errno = 0; @@ -465,26 +645,6 @@ static void remove_file(const char* path) { } -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path); -} - - // cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in @@ -496,17 +656,11 @@ static void remove_file(const char* dirname, const char* filename) { // static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup - return; - } - - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory - os::closedir(dirp); + // directory doesn't exist or is insecure, so there is nothing to cleanup return; } @@ -520,6 +674,7 @@ static void cleanup_sharedmem_resources(const char* dirname) { // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -530,7 +685,7 @@ static void cleanup_sharedmem_resources(const char* dirname) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; @@ -553,11 +708,14 @@ static void cleanup_sharedmem_resources(const char* dirname) { if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); + + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + FREE_C_HEAP_ARRAY(char, dbuf); } @@ -614,19 +772,54 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, return -1; } - int result; - - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); - } + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. return -1; } + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } + } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + + return -1; + } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + // save the file descriptor int fd = result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // truncate the file to get rid of any existing data + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -684,8 +877,15 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } + int fd = result; - return result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -717,13 +917,21 @@ static char* mmap_create_shared(size_t size) { char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // get the short filename + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name); FREE_C_HEAP_ARRAY(char, dirname); @@ -838,12 +1046,12 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; - file_flags = O_RDONLY; + file_flags = O_RDONLY | O_NOFOLLOW; } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode"); diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 4ad556ad388..323f8219ebe 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1322,6 +1322,15 @@ jlong os::javaTimeMillis() { return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000); } +void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { + timeval time; + int status = gettimeofday(&time, NULL); + assert(status != -1, "linux error"); + seconds = jlong(time.tv_sec); + nanos = jlong(time.tv_usec) * 1000; +} + + #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC (1) #endif diff --git a/hotspot/src/os/linux/vm/perfMemory_linux.cpp b/hotspot/src/os/linux/vm/perfMemory_linux.cpp index 4497cc997dc..a6fd68ed3db 100644 --- a/hotspot/src/os/linux/vm/perfMemory_linux.cpp +++ b/hotspot/src/os/linux/vm/perfMemory_linux.cpp @@ -197,7 +197,38 @@ static pid_t filename_to_pid(const char* filename) { } -// check if the given path is considered a secure directory for +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +// +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + // + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + // + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + // + return false; + } + return true; +} + + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. @@ -211,22 +242,180 @@ static bool is_directory_secure(const char* path) { return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + + +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +// +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +// +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { + return false; + } +} + + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +// +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirfd(dirp))) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirfd(dirp); + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +// +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +// +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } @@ -317,9 +506,11 @@ static char* get_user_name_slow(int vmid, TRAPS) { const char* tmpdirname = os::get_temp_directory(); + // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { + // Cannot open the directory to get the user name, return. return NULL; } @@ -344,7 +535,8 @@ static char* get_user_name_slow(int vmid, TRAPS) { strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // open the user directory + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name); @@ -465,26 +657,6 @@ static void remove_file(const char* path) { } -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path); -} - - // cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in @@ -496,17 +668,11 @@ static void remove_file(const char* dirname, const char* filename) { // static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // open the directory + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup - return; - } - - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory - os::closedir(dirp); + // directory doesn't exist or is insecure, so there is nothing to cleanup return; } @@ -520,6 +686,7 @@ static void cleanup_sharedmem_resources(const char* dirname) { // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -528,9 +695,8 @@ static void cleanup_sharedmem_resources(const char* dirname) { if (pid == 0) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; @@ -552,12 +718,14 @@ static void cleanup_sharedmem_resources(const char* dirname) { // if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); + + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + FREE_C_HEAP_ARRAY(char, dbuf); } @@ -614,19 +782,54 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, return -1; } - int result; - - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); - } + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. return -1; } + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } + } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + + return -1; + } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + // save the file descriptor int fd = result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // truncate the file to get rid of any existing data + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -684,8 +887,15 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } + int fd = result; - return result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -716,6 +926,13 @@ static char* mmap_create_shared(size_t size) { char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // get the short filename + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); @@ -723,7 +940,7 @@ static char* mmap_create_shared(size_t size) { assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name); FREE_C_HEAP_ARRAY(char, dirname); @@ -838,12 +1055,12 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; - file_flags = O_RDONLY; + file_flags = O_RDONLY | O_NOFOLLOW; } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode"); diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 8a280b0b5ae..47c0f8a9253 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1475,6 +1475,16 @@ jlong os::javaTimeMillis() { return jlong(t.tv_sec) * 1000 + jlong(t.tv_usec) / 1000; } +void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { + timeval t; + if (gettimeofday(&t, NULL) == -1) { + fatal(err_msg("os::javaTimeSystemUTC: gettimeofday (%s)", strerror(errno))); + } + seconds = jlong(t.tv_sec); + nanos = jlong(t.tv_usec) * 1000; +} + + jlong os::javaTimeNanos() { return (jlong)getTimeNanos(); } diff --git a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp index b6c3c26f049..3c941eaeef4 100644 --- a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp +++ b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp @@ -199,7 +199,38 @@ static pid_t filename_to_pid(const char* filename) { } -// check if the given path is considered a secure directory for +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +// +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + // + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + // + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + // + return false; + } + return true; +} + + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. @@ -213,27 +244,185 @@ static bool is_directory_secure(const char* path) { return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + + +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +// +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +// +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { + return false; + } +} + + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +// +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirp->dd_fd)) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirp->dd_fd; + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +// +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +// +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - // return the user name for the given user id // // the caller is expected to free the allocated memory. @@ -308,9 +497,11 @@ static char* get_user_name_slow(int vmid, TRAPS) { const char* tmpdirname = os::get_temp_directory(); + // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { + // Cannot open the directory to get the user name, return. return NULL; } @@ -335,7 +526,8 @@ static char* get_user_name_slow(int vmid, TRAPS) { strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // open the user directory + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name); @@ -504,26 +696,6 @@ static void remove_file(const char* path) { } -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path); -} - - // cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in @@ -535,17 +707,11 @@ static void remove_file(const char* dirname, const char* filename) { // static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // open the directory + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup - return; - } - - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory - os::closedir(dirp); + // directory doesn't exist or is insecure, so there is nothing to cleanup return; } @@ -559,6 +725,7 @@ static void cleanup_sharedmem_resources(const char* dirname) { // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -569,7 +736,7 @@ static void cleanup_sharedmem_resources(const char* dirname) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; @@ -592,11 +759,14 @@ static void cleanup_sharedmem_resources(const char* dirname) { if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); + + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + FREE_C_HEAP_ARRAY(char, dbuf); } @@ -653,19 +823,54 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, return -1; } - int result; - - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); - } + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. return -1; } + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } + } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + + return -1; + } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + // save the file descriptor int fd = result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // truncate the file to get rid of any existing data + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -701,8 +906,15 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } + int fd = result; - return result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -734,13 +946,21 @@ static char* mmap_create_shared(size_t size) { char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // get the short filename + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name); FREE_C_HEAP_ARRAY(char, dirname); @@ -856,12 +1076,12 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; - file_flags = O_RDONLY; + file_flags = O_RDONLY | O_NOFOLLOW; } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode"); diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index fb09815cf79..76f6384b7b9 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -428,9 +428,9 @@ static unsigned __stdcall java_start(Thread* thread) { } // Diagnostic code to investigate JDK-6573254 - int res = 50115; // non-java thread + int res = 30115; // non-java thread if (thread->is_Java_thread()) { - res = 40115; // java thread + res = 20115; // java thread } // Install a win32 structured exception handler around every thread created @@ -839,6 +839,12 @@ jlong windows_to_java_time(FILETIME wt) { return (a - offset()) / 10000; } +// Returns time ticks in (10th of micro seconds) +jlong windows_to_time_ticks(FILETIME wt) { + jlong a = jlong_from(wt.dwHighDateTime, wt.dwLowDateTime); + return (a - offset()); +} + FILETIME java_to_windows_time(jlong l) { jlong a = (l * 10000) + offset(); FILETIME result; @@ -874,6 +880,15 @@ jlong os::javaTimeMillis() { } } +void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { + FILETIME wt; + GetSystemTimeAsFileTime(&wt); + jlong ticks = windows_to_time_ticks(wt); // 10th of micros + jlong secs = jlong(ticks / 10000000); // 10000 * 1000 + seconds = secs; + nanos = jlong(ticks - (secs*10000000)) * 100; +} + jlong os::javaTimeNanos() { if (!win32::_has_performance_count) { return javaTimeMillis() * NANOSECS_PER_MILLISEC; // the best we can do. @@ -1693,7 +1708,7 @@ void os::win32::print_windows_version(outputStream* st) { } break; - case 6004: + case 10000: if (is_workstation) { st->print("10"); } else { @@ -3791,6 +3806,7 @@ int os::win32::exit_process_or_thread(Ept what, int exit_code) { static INIT_ONCE init_once_crit_sect = INIT_ONCE_STATIC_INIT; static CRITICAL_SECTION crit_sect; + static volatile jint process_exiting = 0; int i, j; DWORD res; HANDLE hproc, hthr; @@ -3798,10 +3814,10 @@ int os::win32::exit_process_or_thread(Ept what, int exit_code) { // The first thread that reached this point, initializes the critical section. if (!InitOnceExecuteOnce(&init_once_crit_sect, init_crit_sect_call, &crit_sect, NULL)) { warning("crit_sect initialization failed in %s: %d\n", __FILE__, __LINE__); - } else { + } else if (OrderAccess::load_acquire(&process_exiting) == 0) { EnterCriticalSection(&crit_sect); - if (what == EPT_THREAD) { + if (what == EPT_THREAD && OrderAccess::load_acquire(&process_exiting) == 0) { // Remove from the array those handles of the threads that have completed exiting. for (i = 0, j = 0; i < handle_count; ++i) { res = WaitForSingleObject(handles[i], 0 /* don't wait */); @@ -3856,7 +3872,7 @@ int os::win32::exit_process_or_thread(Ept what, int exit_code) { // The current exiting thread has stored its handle in the array, and now // should leave the critical section before calling _endthreadex(). - } else { // what != EPT_THREAD + } else if (what != EPT_THREAD) { if (handle_count > 0) { // Before ending the process, make sure all the threads that had called // _endthreadex() completed. @@ -3882,24 +3898,28 @@ int os::win32::exit_process_or_thread(Ept what, int exit_code) { handle_count = 0; } - // End the process, not leaving critical section. - // This makes sure no other thread executes exit-related code at the same - // time, thus a race is avoided. - if (what == EPT_PROCESS) { - ::exit(exit_code); - } else { - _exit(exit_code); - } + OrderAccess::release_store(&process_exiting, 1); } LeaveCriticalSection(&crit_sect); } + + if (what == EPT_THREAD) { + while (OrderAccess::load_acquire(&process_exiting) != 0) { + // Some other thread is about to call exit(), so we + // don't let the current thread proceed to _endthreadex() + SuspendThread(GetCurrentThread()); + // Avoid busy-wait loop, if SuspendThread() failed. + Sleep(EXIT_TIMEOUT); + } + } } // We are here if either // - there's no 'race at exit' bug on this OS release; // - initialization of the critical section failed (unlikely); - // - the current thread has stored its handle and left the critical section. + // - the current thread has stored its handle and left the critical section; + // - the process-exiting thread has raised the flag and left the critical section. if (what == EPT_THREAD) { _endthreadex((unsigned)exit_code); } else if (what == EPT_PROCESS) { diff --git a/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp b/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp index 60969caa962..4e7e702ad66 100644 --- a/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp +++ b/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2011 Red Hat, Inc. + * Copyright 2007, 2008, 2011, 2015, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,7 +237,13 @@ inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { // operation. Note that some platforms only support this with the // limitation that the only valid value to store is the immediate // constant 1. There is a test for this in JNI_CreateJavaVM(). - return __sync_lock_test_and_set (dest, exchange_value); + jint result = __sync_lock_test_and_set (dest, exchange_value); + // All atomic operations are expected to be full memory barriers + // (see atomic.hpp). However, __sync_lock_test_and_set is not + // a full memory barrier, but an acquire barrier. Hence, this added + // barrier. + __sync_synchronize(); + return result; #endif // M68K #endif // ARM } @@ -250,7 +256,9 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, #ifdef M68K return m68k_lock_test_and_set(dest, exchange_value); #else - return __sync_lock_test_and_set (dest, exchange_value); + intptr_t result = __sync_lock_test_and_set (dest, exchange_value); + __sync_synchronize(); + return result; #endif // M68K #endif // ARM } diff --git a/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp b/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp index d9df41034d4..266c950422b 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp +++ b/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2011 Red Hat, Inc. + * Copyright 2007, 2008, 2011, 2015, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -231,7 +231,13 @@ inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { // operation. Note that some platforms only support this with the // limitation that the only valid value to store is the immediate // constant 1. There is a test for this in JNI_CreateJavaVM(). - return __sync_lock_test_and_set (dest, exchange_value); + jint result = __sync_lock_test_and_set (dest, exchange_value); + // All atomic operations are expected to be full memory barriers + // (see atomic.hpp). However, __sync_lock_test_and_set is not + // a full memory barrier, but an acquire barrier. Hence, this added + // barrier. + __sync_synchronize(); + return result; #endif // M68K #endif // ARM } @@ -244,7 +250,9 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, #ifdef M68K return m68k_lock_test_and_set(dest, exchange_value); #else - return __sync_lock_test_and_set (dest, exchange_value); + intptr_t result = __sync_lock_test_and_set (dest, exchange_value); + __sync_synchronize(); + return result; #endif // M68K #endif // ARM } diff --git a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp index e3a4f4d5680..05a8c70506f 100644 --- a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp +++ b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -601,15 +601,6 @@ class G1PostBarrierStub: public CodeStub { LIR_Opr _addr; LIR_Opr _new_val; - static jbyte* _byte_map_base; - static jbyte* byte_map_base_slow(); - static jbyte* byte_map_base() { - if (_byte_map_base == NULL) { - _byte_map_base = byte_map_base_slow(); - } - return _byte_map_base; - } - public: // addr (the address of the object head) and new_val must be registers. G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { } diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 2beb72a60f1..8fe99af08ad 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -32,6 +32,7 @@ #include "ci/ciArrayKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObjArray.hpp" +#include "runtime/arguments.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/vm_version.hpp" @@ -3351,7 +3352,12 @@ void LIRGenerator::do_ProfileInvoke(ProfileInvoke* x) { if (!x->inlinee()->is_accessor()) { CodeEmitInfo* info = state_for(x, x->state(), true); // Notify the runtime very infrequently only to take care of counter overflows - increment_event_counter_impl(info, x->inlinee(), (1 << Tier23InlineeNotifyFreqLog) - 1, InvocationEntryBci, false, true); + int freq_log = Tier23InlineeNotifyFreqLog; + double scale; + if (_method->has_option_value("CompileThresholdScaling", scale)) { + freq_log = Arguments::scaled_freq_log(freq_log, scale); + } + increment_event_counter_impl(info, x->inlinee(), right_n_bits(freq_log), InvocationEntryBci, false, true); } } @@ -3366,7 +3372,11 @@ void LIRGenerator::increment_event_counter(CodeEmitInfo* info, int bci, bool bac ShouldNotReachHere(); } // Increment the appropriate invocation/backedge counter and notify the runtime. - increment_event_counter_impl(info, info->scope()->method(), (1 << freq_log) - 1, bci, backedge, true); + double scale; + if (_method->has_option_value("CompileThresholdScaling", scale)) { + freq_log = Arguments::scaled_freq_log(freq_log, scale); + } + increment_event_counter_impl(info, info->scope()->method(), right_n_bits(freq_log), bci, backedge, true); } void LIRGenerator::decrement_age(CodeEmitInfo* info) { diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp index ae9def38b26..4c0cd3d8083 100644 --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp @@ -89,8 +89,8 @@ class BCEscapeAnalyzer::StateInfo { public: ArgumentMap *_vars; ArgumentMap *_stack; - short _stack_height; - short _max_stack; + int _stack_height; + int _max_stack; bool _initialized; ArgumentMap empty_map; diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index d32df16bcbb..4769254e9b6 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -70,7 +70,8 @@ // Loaded method. ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) : ciMetadata(h_m()), - _holder(holder) + _holder(holder), + _has_injected_profile(false) { assert(h_m() != NULL, "no null method"); @@ -168,7 +169,8 @@ ciMethod::ciMethod(ciInstanceKlass* holder, _liveness( NULL), _can_be_statically_bound(false), _method_blocks( NULL), - _method_data( NULL) + _method_data( NULL), + _has_injected_profile( false) #if defined(COMPILER2) || defined(SHARK) , _flow( NULL), diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 5a46fc483c9..76662089bd8 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -79,6 +79,7 @@ class ciMethod : public ciMetadata { bool _is_c1_compilable; bool _is_c2_compilable; bool _can_be_statically_bound; + bool _has_injected_profile; // Lazy fields, filled in on demand address _code; @@ -286,6 +287,9 @@ class ciMethod : public ciMetadata { int instructions_size(); int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC + bool has_injected_profile() const { return _has_injected_profile; } + void set_injected_profile(bool x) { _has_injected_profile = x; } + // Stack walking support bool is_ignored_by_security_stack_walk() const; diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 96e48340847..44e152b8384 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -786,17 +786,12 @@ void ClassLoaderDataGraph::clean_metaspaces() { MetadataOnStackMark md_on_stack(has_redefined_a_class); if (has_redefined_a_class) { - // purge_previous_versions also cleans weak method links. Because - // one method's MDO can reference another method from another - // class loader, we need to first clean weak method links for all - // class loaders here. Below, we can then free redefined methods - // for all class loaders. for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { data->classes_do(InstanceKlass::purge_previous_versions); } } - // Need to purge the previous version before deallocating. + // Should purge the previous version before deallocating. free_deallocate_lists(); } @@ -834,8 +829,6 @@ void ClassLoaderDataGraph::post_class_unload_events(void) { void ClassLoaderDataGraph::free_deallocate_lists() { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { - // We need to keep this data until InstanceKlass::purge_previous_version has been - // called on all alive classes. See the comment in ClassLoaderDataGraph::clean_metaspaces. cld->free_deallocate_list(); } } diff --git a/hotspot/src/share/vm/classfile/compactHashtable.cpp b/hotspot/src/share/vm/classfile/compactHashtable.cpp new file mode 100644 index 00000000000..bd197554293 --- /dev/null +++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp @@ -0,0 +1,441 @@ +/* + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/javaClasses.hpp" +#include "memory/metaspaceShared.hpp" +#include "utilities/numberSeq.hpp" +#include + +///////////////////////////////////////////////////// +// +// The compact hash table writer implementations +// +CompactHashtableWriter::CompactHashtableWriter(const char* table_name, + int num_entries, + CompactHashtableStats* stats) { + assert(DumpSharedSpaces, "dump-time only"); + _table_name = table_name; + _num_entries = num_entries; + _num_buckets = number_of_buckets(_num_entries); + _buckets = NEW_C_HEAP_ARRAY(Entry*, _num_buckets, mtSymbol); + memset(_buckets, 0, sizeof(Entry*) * _num_buckets); + + /* bucket sizes table */ + _bucket_sizes = NEW_C_HEAP_ARRAY(juint, _num_buckets, mtSymbol); + memset(_bucket_sizes, 0, sizeof(juint) * _num_buckets); + + stats->hashentry_count = _num_entries; + // Compact buckets' entries will have only the 4-byte offset, but + // we don't know how many there will be at this point. So use a + // conservative estimate here. The size is adjusted later when we + // write out the buckets. + stats->hashentry_bytes = _num_entries * 8; + stats->bucket_count = _num_buckets; + stats->bucket_bytes = (_num_buckets + 1) * (sizeof(juint)); + _stats = stats; + + // See compactHashtable.hpp for table layout + _required_bytes = sizeof(juint) * 2; // _base_address, written as 2 juints + _required_bytes+= sizeof(juint) + // num_entries + sizeof(juint) + // num_buckets + stats->hashentry_bytes + + stats->bucket_bytes; +} + +CompactHashtableWriter::~CompactHashtableWriter() { + for (int index = 0; index < _num_buckets; index++) { + Entry* next = NULL; + for (Entry* tent = _buckets[index]; tent; tent = next) { + next = tent->next(); + delete tent; + } + } + + FREE_C_HEAP_ARRAY(juint, _bucket_sizes); + FREE_C_HEAP_ARRAY(Entry*, _buckets); +} + +// Calculate the number of buckets in the temporary hash table +int CompactHashtableWriter::number_of_buckets(int num_entries) { + const int buksize = (int)SharedSymbolTableBucketSize; + int num_buckets = (num_entries + buksize - 1) / buksize; + num_buckets = (num_buckets + 1) & (~0x01); + + return num_buckets; +} + +// Add a symbol entry to the temporary hash table +void CompactHashtableWriter::add(unsigned int hash, Entry* entry) { + int index = hash % _num_buckets; + entry->set_next(_buckets[index]); + _buckets[index] = entry; + _bucket_sizes[index] ++; +} + +// Write the compact table's bucket infos +juint* CompactHashtableWriter::dump_table(juint* p, juint** first_bucket, + NumberSeq* summary) { + int index; + juint* compact_table = p; + // Find the start of the buckets, skip the compact_bucket_infos table + // and the table end offset. + juint offset = _num_buckets + 1; + *first_bucket = compact_table + offset; + + for (index = 0; index < _num_buckets; index++) { + int bucket_size = _bucket_sizes[index]; + if (bucket_size == 1) { + // bucket with one entry is compacted and only has the symbol offset + compact_table[index] = BUCKET_INFO(offset, COMPACT_BUCKET_TYPE); + offset += bucket_size; // each entry contains symbol offset only + } else { + // regular bucket, each entry is a symbol (hash, offset) pair + compact_table[index] = BUCKET_INFO(offset, REGULAR_BUCKET_TYPE); + offset += bucket_size * 2; // each hash entry is 2 juints + } + if (offset & ~BUCKET_OFFSET_MASK) { + vm_exit_during_initialization("CompactHashtableWriter::dump_table: Overflow! " + "Too many symbols."); + } + summary->add(bucket_size); + } + // Mark the end of the table + compact_table[_num_buckets] = BUCKET_INFO(offset, TABLEEND_BUCKET_TYPE); + + return compact_table; +} + +// Write the compact table's entries +juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p, + NumberSeq* summary) { + uintx base_address = uintx(MetaspaceShared::shared_rs()->base()); + uintx max_delta = uintx(MetaspaceShared::shared_rs()->size()); + assert(max_delta <= 0x7fffffff, "range check"); + int num_compact_buckets = 0; + + assert(p != NULL, "sanity"); + for (int index = 0; index < _num_buckets; index++) { + juint count = 0; + int bucket_size = _bucket_sizes[index]; + int bucket_type = BUCKET_TYPE(compact_table[index]); + + if (bucket_size == 1) { + assert(bucket_type == COMPACT_BUCKET_TYPE, "Bad bucket type"); + num_compact_buckets ++; + } + for (Entry* tent = _buckets[index]; tent; + tent = tent->next()) { + if (bucket_type == REGULAR_BUCKET_TYPE) { + *p++ = juint(tent->hash()); // write symbol hash + } + uintx deltax = uintx(tent->value()) - base_address; + assert(deltax < max_delta, "range check"); + juint delta = juint(deltax); + *p++ = delta; // write symbol offset + count ++; + } + assert(count == _bucket_sizes[index], "sanity"); + } + + // Adjust the hashentry_bytes in CompactHashtableStats. Each compact + // bucket saves 4-byte. + _stats->hashentry_bytes -= num_compact_buckets * 4; + + return p; +} + +// Write the compact table +void CompactHashtableWriter::dump(char** top, char* end) { + NumberSeq summary; + char* old_top = *top; + juint* p = (juint*)(*top); + + uintx base_address = uintx(MetaspaceShared::shared_rs()->base()); + + *p++ = high(base_address); + *p++ = low (base_address); // base address + *p++ = _num_entries; // number of entries in the table + *p++ = _num_buckets; // number of buckets in the table + + juint* first_bucket = NULL; + juint* compact_table = dump_table(p, &first_bucket, &summary); + juint* bucket_end = dump_buckets(compact_table, first_bucket, &summary); + + assert(bucket_end <= (juint*)end, "cannot write past end"); + *top = (char*)bucket_end; + + if (PrintSharedSpaces) { + double avg_cost = 0.0; + if (_num_entries > 0) { + avg_cost = double(_required_bytes)/double(_num_entries); + } + tty->print_cr("Shared %s table stats -------- base: " PTR_FORMAT, _table_name, (intptr_t)base_address); + tty->print_cr("Number of entries : %9d", _num_entries); + tty->print_cr("Total bytes used : %9d", (int)((*top) - old_top)); + tty->print_cr("Average bytes per entry : %9.3f", avg_cost); + tty->print_cr("Average bucket size : %9.3f", summary.avg()); + tty->print_cr("Variance of bucket size : %9.3f", summary.variance()); + tty->print_cr("Std. dev. of bucket size: %9.3f", summary.sd()); + tty->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); + } +} + +///////////////////////////////////////////////////////////// +// +// The CompactHashtable implementation +// +template const char* CompactHashtable::init(const char* buffer) { + assert(!DumpSharedSpaces, "run-time only"); + juint*p = (juint*)buffer; + juint upper = *p++; + juint lower = *p++; + _base_address = uintx(jlong_from(upper, lower)); + _entry_count = *p++; + _bucket_count = *p++; + _buckets = p; + _table_end_offset = BUCKET_OFFSET(p[_bucket_count]); // located at the end of the bucket_info table + + juint *end = _buckets + _table_end_offset; + return (const char*)end; +} + +template void CompactHashtable::symbols_do(SymbolClosure *cl) { + assert(!DumpSharedSpaces, "run-time only"); + for (juint i = 0; i < _bucket_count; i ++) { + juint bucket_info = _buckets[i]; + juint bucket_offset = BUCKET_OFFSET(bucket_info); + int bucket_type = BUCKET_TYPE(bucket_info); + juint* bucket = _buckets + bucket_offset; + juint* bucket_end = _buckets; + + Symbol* sym; + if (bucket_type == COMPACT_BUCKET_TYPE) { + sym = (Symbol*)((void*)(_base_address + bucket[0])); + cl->do_symbol(&sym); + } else { + bucket_end += BUCKET_OFFSET(_buckets[i + 1]); + while (bucket < bucket_end) { + sym = (Symbol*)((void*)(_base_address + bucket[1])); + cl->do_symbol(&sym); + bucket += 2; + } + } + } +} + +// Explicitly instantiate these types +template class CompactHashtable; + +#ifndef O_BINARY // if defined (Win32) use binary files. +#define O_BINARY 0 // otherwise do nothing. +#endif + +//////////////////////////////////////////////////////// +// +// HashtableTextDump +// +HashtableTextDump::HashtableTextDump(const char* filename) : _fd(-1) { + struct stat st; + if (os::stat(filename, &st) != 0) { + quit("Unable to get hashtable dump file size", filename); + } + _size = st.st_size; + _fd = open(filename, O_RDONLY | O_BINARY, 0); + if (_fd < 0) { + quit("Unable to open hashtable dump file", filename); + } + _base = os::map_memory(_fd, filename, 0, NULL, _size, true, false); + if (_base == NULL) { + quit("Unable to map hashtable dump file", filename); + } + _p = _base; + _end = _base + st.st_size; + _filename = filename; +} + +HashtableTextDump::~HashtableTextDump() { + os::unmap_memory((char*)_base, _size); + if (_fd >= 0) { + close(_fd); + } +} + +void HashtableTextDump::quit(const char* err, const char* msg) { + vm_exit_during_initialization(err, msg); +} + +void HashtableTextDump::corrupted(const char *p) { + char info[60]; + sprintf(info, "corrupted at pos %d", (int)(p - _base)); + quit(info, _filename); +} + +bool HashtableTextDump::skip_newline() { + if (_p[0] == '\r' && _p[1] == '\n') { + _p += 2; + } else if (_p[0] == '\n') { + _p += 1; + } else { + corrupted(_p); + } + return true; +} + +int HashtableTextDump::skip(char must_be_char) { + corrupted_if(remain() < 1); + corrupted_if(*_p++ != must_be_char); + return 0; +} + +void HashtableTextDump::skip_past(char c) { + for (;;) { + corrupted_if(remain() < 1); + if (*_p++ == c) { + return; + } + } +} + +void HashtableTextDump::check_version(const char* ver) { + int len = (int)strlen(ver); + corrupted_if(remain() < len); + if (strncmp(_p, ver, len) != 0) { + quit("wrong version of hashtable dump file", _filename); + } + _p += len; + skip_newline(); +} + + +int HashtableTextDump::scan_prefix() { + // Expect /[0-9]+: / + int utf8_length = get_num(':'); + if (*_p != ' ') { + corrupted(_p); + } + _p++; + return utf8_length; +} + +int HashtableTextDump::scan_prefix2() { + // Expect /[0-9]+ (-|)[0-9]+: / + int utf8_length = get_num(' '); + if (*_p == '-') { + _p++; + } + (void)get_num(':'); + if (*_p != ' ') { + corrupted(_p); + } + _p++; + return utf8_length; +} + +jchar HashtableTextDump::unescape(const char* from, const char* end, int count) { + jchar value = 0; + + corrupted_if(from + count > end); + + for (int i=0; i 0 && from < end; n--) { + if (*from != '\\') { + *to++ = *from++; + } else { + corrupted_if(from + 2 > end); + char c = from[1]; + from += 2; + switch (c) { + case 'x': + { + jchar value = unescape(from, end, 2); + from += 2; + assert(value <= 0xff, "sanity"); + *to++ = (char)(value & 0xff); + } + break; + case 't': *to++ = '\t'; break; + case 'n': *to++ = '\n'; break; + case 'r': *to++ = '\r'; break; + case '\\': *to++ = '\\'; break; + default: + ShouldNotReachHere(); + } + } + } + corrupted_if(n > 0); // expected more chars but file has ended + _p = from; + skip_newline(); +} + +// NOTE: the content is NOT the same as +// UTF8::as_quoted_ascii(const char* utf8_str, int utf8_length, char* buf, int buflen). +// We want to escape \r\n\t so that output [1] is more readable; [2] can be more easily +// parsed by scripts; [3] quickly processed by HashtableTextDump::get_utf8() +void HashtableTextDump::put_utf8(outputStream* st, const char* utf8_string, int utf8_length) { + const char *c = utf8_string; + const char *end = c + utf8_length; + for (; c < end; c++) { + switch (*c) { + case '\t': st->print("\\t"); break; + case '\r': st->print("\\r"); break; + case '\n': st->print("\\n"); break; + case '\\': st->print("\\\\"); break; + default: + if (isprint(*c)) { + st->print("%c", *c); + } else { + st->print("\\x%02x", ((unsigned int)*c) & 0xff); + } + } + } +} diff --git a/hotspot/src/share/vm/classfile/compactHashtable.hpp b/hotspot/src/share/vm/classfile/compactHashtable.hpp new file mode 100644 index 00000000000..3e32fc07df9 --- /dev/null +++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp @@ -0,0 +1,408 @@ +/* + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP +#define SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP + +#include "classfile/stringTable.hpp" +#include "classfile/symbolTable.hpp" +#include "memory/allocation.inline.hpp" +#include "oops/symbol.hpp" +#include "services/diagnosticCommand.hpp" +#include "utilities/hashtable.hpp" + +class NumberSeq; + +// Stats for symbol tables in the CDS archive +class CompactHashtableStats VALUE_OBJ_CLASS_SPEC { +public: + int hashentry_count; + int hashentry_bytes; + int bucket_count; + int bucket_bytes; +}; + +///////////////////////////////////////////////////////////////////////// +// +// The compact hash table writer. Used at dump time for writing out +// the compact table to the shared archive. +// +// At dump time, the CompactHashtableWriter obtains all entries from the +// symbol table and adds them to a new temporary hash table. The hash +// table size (number of buckets) is calculated using +// '(num_entries + bucket_size - 1) / bucket_size'. The default bucket +// size is 4 and can be changed by -XX:SharedSymbolTableBucketSize option. +// 4 is chosen because it produces smaller sized bucket on average for +// faster lookup. It also has relatively small number of empty buckets and +// good distribution of the entries. +// +// We use a simple hash function (symbol_hash % num_bucket) for the table. +// The new table is compacted when written out. Please see comments +// above the CompactHashtable class for the table layout detail. The bucket +// offsets are written to the archive as part of the compact table. The +// bucket offset is encoded in the low 30-bit (0-29) and the bucket type +// (regular or compact) are encoded in bit[31, 30]. For buckets with more +// than one entry, both symbol hash and symbol offset are written to the +// table. For buckets with only one entry, only the symbol offset is written +// to the table and the buckets are tagged as compact in their type bits. +// Buckets without entry are skipped from the table. Their offsets are +// still written out for faster lookup. +// +class CompactHashtableWriter: public StackObj { +public: + class Entry: public CHeapObj { + Entry* _next; + unsigned int _hash; + void* _literal; + + public: + Entry(unsigned int hash, Symbol *symbol) : _next(NULL), _hash(hash), _literal(symbol) {} + + void *value() { + return _literal; + } + Symbol *symbol() { + return (Symbol*)_literal; + } + unsigned int hash() { + return _hash; + } + Entry *next() {return _next;} + void set_next(Entry *p) {_next = p;} + }; // class CompactHashtableWriter::Entry + +private: + static int number_of_buckets(int num_entries); + + const char* _table_name; + int _num_entries; + int _num_buckets; + juint* _bucket_sizes; + Entry** _buckets; + int _required_bytes; + CompactHashtableStats* _stats; + +public: + // This is called at dump-time only + CompactHashtableWriter(const char* table_name, int num_entries, CompactHashtableStats* stats); + ~CompactHashtableWriter(); + + int get_required_bytes() { + return _required_bytes; + } + + void add(unsigned int hash, Symbol* symbol) { + add(hash, new Entry(hash, symbol)); + } + +private: + void add(unsigned int hash, Entry* entry); + juint* dump_table(juint* p, juint** first_bucket, NumberSeq* summary); + juint* dump_buckets(juint* table, juint* p, NumberSeq* summary); + +public: + void dump(char** top, char* end); +}; + +#define REGULAR_BUCKET_TYPE 0 +#define COMPACT_BUCKET_TYPE 1 +#define TABLEEND_BUCKET_TYPE 3 +#define BUCKET_OFFSET_MASK 0x3FFFFFFF +#define BUCKET_OFFSET(info) ((info) & BUCKET_OFFSET_MASK) +#define BUCKET_TYPE_SHIFT 30 +#define BUCKET_TYPE(info) (((info) & ~BUCKET_OFFSET_MASK) >> BUCKET_TYPE_SHIFT) +#define BUCKET_INFO(offset, type) (((type) << BUCKET_TYPE_SHIFT) | ((offset) & BUCKET_OFFSET_MASK)) + +///////////////////////////////////////////////////////////////////////////// +// +// CompactHashtable is used to stored the CDS archive's symbol table. Used +// at runtime only to access the compact table from the archive. +// +// Because these tables are read-only (no entries can be added/deleted) at run-time +// and tend to have large number of entries, we try to minimize the footprint +// cost per entry. +// +// Layout of compact symbol table in the shared archive: +// +// uintx base_address; +// juint num_symbols; +// juint num_buckets; +// juint bucket_infos[num_buckets+1]; // bit[31,30]: type; bit[29-0]: offset +// juint table[] +// +// ----------------------------------- +// | base_address | num_symbols | +// |---------------------------------| +// | num_buckets | bucket_info0 | +// |---------------------------------| +// | bucket_info1 | bucket_info2 | +// | bucket_info3 ... | +// | .... | table_end_info | +// |---------------------------------| +// | entry0 | +// | entry1 | +// | entry2 | +// | | +// | ... | +// ----------------------------------- +// +// The size of the bucket_info table is 'num_buckets + 1'. Each entry of the +// bucket_info table is a 32-bit encoding of the bucket type and bucket offset, +// with the type in the left-most 2-bit and offset in the remaining 30-bit. +// The last entry is a special type. It contains the offset of the last +// bucket end. We use that information when traversing the compact table. +// +// There are two types of buckets, regular buckets and compact buckets. The +// compact buckets have '01' in their highest 2-bit, and regular buckets have +// '00' in their highest 2-bit. +// +// For normal buckets, each symbol's entry is 8 bytes in the table[]: +// juint hash; /* symbol hash */ +// juint offset; /* Symbol* sym = (Symbol*)(base_address + offset) */ +// +// For compact buckets, each entry has only the 4-byte 'offset' in the table[]. +// +// See CompactHashtable::lookup() for how the table is searched at runtime. +// See CompactHashtableWriter::dump() for how the table is written at CDS +// dump time. +// +template class CompactHashtable VALUE_OBJ_CLASS_SPEC { + uintx _base_address; + juint _entry_count; + juint _bucket_count; + juint _table_end_offset; + juint* _buckets; + + inline bool equals(T entry, const char* name, int len) { + if (entry->equals(name, len)) { + assert(entry->refcount() == -1, "must be shared"); + return true; + } else { + return false; + } + } + +public: + CompactHashtable() { + _entry_count = 0; + _bucket_count = 0; + _table_end_offset = 0; + _buckets = 0; + } + const char* init(const char *buffer); + + // Lookup an entry from the compact table + inline T lookup(const N* name, unsigned int hash, int len) { + if (_entry_count > 0) { + assert(!DumpSharedSpaces, "run-time only"); + int index = hash % _bucket_count; + juint bucket_info = _buckets[index]; + juint bucket_offset = BUCKET_OFFSET(bucket_info); + int bucket_type = BUCKET_TYPE(bucket_info); + juint* bucket = _buckets + bucket_offset; + juint* bucket_end = _buckets; + + if (bucket_type == COMPACT_BUCKET_TYPE) { + // the compact bucket has one entry with symbol offset only + T entry = (T)((void*)(_base_address + bucket[0])); + if (equals(entry, name, len)) { + return entry; + } + } else { + // This is a regular bucket, which has more than one + // entries. Each entry is a pair of symbol (hash, offset). + // Seek until the end of the bucket. + bucket_end += BUCKET_OFFSET(_buckets[index + 1]); + while (bucket < bucket_end) { + unsigned int h = (unsigned int)(bucket[0]); + if (h == hash) { + juint offset = bucket[1]; + T entry = (T)((void*)(_base_address + offset)); + if (equals(entry, name, len)) { + return entry; + } + } + bucket += 2; + } + } + } + return NULL; + } + + // iterate over symbols + void symbols_do(SymbolClosure *cl); +}; + +//////////////////////////////////////////////////////////////////////// +// +// Read/Write the contents of a hashtable textual dump (created by +// SymbolTable::dump). +// Because the dump file may be big (hundred of MB in extreme cases), +// we use mmap for fast access when reading it. +// +class HashtableTextDump VALUE_OBJ_CLASS_SPEC { + int _fd; + const char* _base; + const char* _p; + const char* _end; + const char* _filename; + size_t _size; +public: + HashtableTextDump(const char* filename); + ~HashtableTextDump(); + + void quit(const char* err, const char* msg); + + inline int remain() { + return (int)(_end - _p); + } + + void corrupted(const char *p); + + inline void corrupted_if(bool cond) { + if (cond) { + corrupted(_p); + } + } + + bool skip_newline(); + int skip(char must_be_char); + void skip_past(char c); + void check_version(const char* ver); + + inline int get_num(char delim) { + const char* p = _p; + const char* end = _end; + int num = 0; + + while (p < end) { + char c = *p ++; + if ('0' <= c && c <= '9') { + num = num * 10 + (c - '0'); + } else if (c == delim) { + _p = p; + return num; + } else { + corrupted(p-1); + } + } + corrupted(_end); + ShouldNotReachHere(); + return 0; + } + + int scan_prefix(); + int scan_prefix2(); + + jchar unescape(const char* from, const char* end, int count); + void get_utf8(char* utf8_buffer, int utf8_length); + static void put_utf8(outputStream* st, const char* utf8_string, int utf8_length); +}; + +/////////////////////////////////////////////////////////////////////// +// +// jcmd command support for symbol table and string table dumping: +// VM.symboltable -verbose: for dumping the symbol table +// VM.stringtable -verbose: for dumping the string table +// +class VM_DumpHashtable : public VM_Operation { +private: + outputStream* _out; + int _which; + bool _verbose; +public: + enum { + DumpSymbols = 1 << 0, + DumpStrings = 1 << 1, + DumpSysDict = 1 << 2 // not implemented yet + }; + VM_DumpHashtable(outputStream* out, int which, bool verbose) { + _out = out; + _which = which; + _verbose = verbose; + } + + virtual VMOp_Type type() const { return VMOp_DumpHashtable; } + + virtual void doit() { + switch (_which) { + case DumpSymbols: + SymbolTable::dump(_out, _verbose); + break; + case DumpStrings: + StringTable::dump(_out, _verbose); + break; + default: + ShouldNotReachHere(); + } + } +}; + +class SymboltableDCmd : public DCmdWithParser { +protected: + DCmdArgument _verbose; +public: + SymboltableDCmd(outputStream* output, bool heap); + static const char* name() { + return "VM.symboltable"; + } + static const char* description() { + return "Dump symbol table."; + } + static const char* impact() { + return "Medium: Depends on Java content."; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments(); + virtual void execute(DCmdSource source, TRAPS); +}; + +class StringtableDCmd : public DCmdWithParser { +protected: + DCmdArgument _verbose; +public: + StringtableDCmd(outputStream* output, bool heap); + static const char* name() { + return "VM.stringtable"; + } + static const char* description() { + return "Dump string table."; + } + static const char* impact() { + return "Medium: Depends on Java content."; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments(); + virtual void execute(DCmdSource source, TRAPS); +}; + +#endif // SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP diff --git a/hotspot/src/share/vm/classfile/stringTable.cpp b/hotspot/src/share/vm/classfile/stringTable.cpp index 334fe7cbd39..7d2a4f93ef3 100644 --- a/hotspot/src/share/vm/classfile/stringTable.cpp +++ b/hotspot/src/share/vm/classfile/stringTable.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/altHashing.hpp" +#include "classfile/compactHashtable.hpp" #include "classfile/javaClasses.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" @@ -379,8 +380,36 @@ void StringTable::verify() { } } -void StringTable::dump(outputStream* st) { - the_table()->dump_table(st, "StringTable"); +void StringTable::dump(outputStream* st, bool verbose) { + if (!verbose) { + the_table()->dump_table(st, "StringTable"); + } else { + Thread* THREAD = Thread::current(); + st->print_cr("VERSION: 1.1"); + for (int i = 0; i < the_table()->table_size(); ++i) { + HashtableEntry* p = the_table()->bucket(i); + for ( ; p != NULL; p = p->next()) { + oop s = p->literal(); + typeArrayOop value = java_lang_String::value(s); + int offset = java_lang_String::offset(s); + int length = java_lang_String::length(s); + + if (length <= 0) { + st->print("%d: ", length); + } else { + ResourceMark rm(THREAD); + jchar* chars = (jchar*)value->char_at_addr(offset); + int utf8_length = UNICODE::utf8_length(chars, length); + char* utf8_string = NEW_RESOURCE_ARRAY(char, utf8_length + 1); + UNICODE::convert_to_utf8(chars, length, utf8_string); + + st->print("%d: ", utf8_length); + HashtableTextDump::put_utf8(st, utf8_string, utf8_length); + } + st->cr(); + } + } + } } StringTable::VerifyRetTypes StringTable::compare_entries( @@ -558,3 +587,28 @@ void StringTable::rehash_table() { _needs_rehashing = false; _the_table = new_table; } + +// Utility for dumping strings +StringtableDCmd::StringtableDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _verbose("-verbose", "Dump the content of each string in the table", + "BOOLEAN", false, "false") { + _dcmdparser.add_dcmd_option(&_verbose); +} + +void StringtableDCmd::execute(DCmdSource source, TRAPS) { + VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpStrings, + _verbose.value()); + VMThread::execute(&dumper); +} + +int StringtableDCmd::num_arguments() { + ResourceMark rm; + StringtableDCmd* dcmd = new StringtableDCmd(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} diff --git a/hotspot/src/share/vm/classfile/stringTable.hpp b/hotspot/src/share/vm/classfile/stringTable.hpp index e8f42834d07..72f69e93381 100644 --- a/hotspot/src/share/vm/classfile/stringTable.hpp +++ b/hotspot/src/share/vm/classfile/stringTable.hpp @@ -118,7 +118,7 @@ public: // Debugging static void verify(); - static void dump(outputStream* st); + static void dump(outputStream* st, bool verbose=false); enum VerifyMesgModes { _verify_quietly = 0, diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index 8ffb17f8f71..3d08364be82 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/altHashing.hpp" +#include "classfile/compactHashtable.hpp" #include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" @@ -47,6 +48,9 @@ SymbolTable* SymbolTable::_the_table = NULL; // Static arena for symbols that are not deallocated Arena* SymbolTable::_arena = NULL; bool SymbolTable::_needs_rehashing = false; +bool SymbolTable::_lookup_shared_first = false; + +CompactHashtable SymbolTable::_shared_table; Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) { assert (len <= Symbol::max_length(), "should be checked by caller"); @@ -78,6 +82,10 @@ void SymbolTable::initialize_symbols(int arena_alloc_size) { // Call function for all symbols in the symbol table. void SymbolTable::symbols_do(SymbolClosure *cl) { + // all symbols from shared table + _shared_table.symbols_do(cl); + + // all symbols from the dynamic table const int n = the_table()->table_size(); for (int i = 0; i < n; i++) { for (HashtableEntry* p = the_table()->bucket(i); @@ -186,8 +194,8 @@ void SymbolTable::rehash_table() { // Lookup a symbol in a bucket. -Symbol* SymbolTable::lookup(int index, const char* name, - int len, unsigned int hash) { +Symbol* SymbolTable::lookup_dynamic(int index, const char* name, + int len, unsigned int hash) { int count = 0; for (HashtableEntry* e = bucket(index); e != NULL; e = e->next()) { count++; // count all entries in this bucket, not just ones with same hash @@ -207,6 +215,34 @@ Symbol* SymbolTable::lookup(int index, const char* name, return NULL; } +Symbol* SymbolTable::lookup_shared(const char* name, + int len, unsigned int hash) { + return _shared_table.lookup(name, hash, len); +} + +Symbol* SymbolTable::lookup(int index, const char* name, + int len, unsigned int hash) { + Symbol* sym; + if (_lookup_shared_first) { + sym = lookup_shared(name, len, hash); + if (sym != NULL) { + return sym; + } + _lookup_shared_first = false; + return lookup_dynamic(index, name, len, hash); + } else { + sym = lookup_dynamic(index, name, len, hash); + if (sym != NULL) { + return sym; + } + sym = lookup_shared(name, len, hash); + if (sym != NULL) { + _lookup_shared_first = true; + } + return sym; + } +} + // Pick hashing algorithm. unsigned int SymbolTable::hash_symbol(const char* s, int len) { return use_alternate_hashcode() ? @@ -483,10 +519,56 @@ void SymbolTable::verify() { } } -void SymbolTable::dump(outputStream* st) { - the_table()->dump_table(st, "SymbolTable"); +void SymbolTable::dump(outputStream* st, bool verbose) { + if (!verbose) { + the_table()->dump_table(st, "SymbolTable"); + } else { + st->print_cr("VERSION: 1.0"); + for (int i = 0; i < the_table()->table_size(); ++i) { + HashtableEntry* p = the_table()->bucket(i); + for ( ; p != NULL; p = p->next()) { + Symbol* s = (Symbol*)(p->literal()); + const char* utf8_string = (const char*)s->bytes(); + int utf8_length = s->utf8_length(); + st->print("%d %d: ", utf8_length, s->refcount()); + HashtableTextDump::put_utf8(st, utf8_string, utf8_length); + st->cr(); + } + } + } } +bool SymbolTable::copy_compact_table(char** top, char*end) { +#if INCLUDE_CDS + CompactHashtableWriter ch_table("symbol", the_table()->number_of_entries(), + &MetaspaceShared::stats()->symbol); + if (*top + ch_table.get_required_bytes() > end) { + // not enough space left + return false; + } + + for (int i = 0; i < the_table()->table_size(); ++i) { + HashtableEntry* p = the_table()->bucket(i); + for ( ; p != NULL; p = p->next()) { + Symbol* s = (Symbol*)(p->literal()); + unsigned int fixed_hash = hash_symbol((char*)s->bytes(), s->utf8_length()); + assert(fixed_hash == p->hash(), "must not rehash during dumping"); + ch_table.add(fixed_hash, s); + } + } + + char* old_top = *top; + ch_table.dump(top, end); + + *top = (char*)align_pointer_up(*top, sizeof(void*)); +#endif + return true; +} + +const char* SymbolTable::init_shared_table(const char* buffer) { + const char* end = _shared_table.init(buffer); + return (const char*)align_pointer_up(end, sizeof(void*)); +} //--------------------------------------------------------------------------- // Non-product code @@ -574,3 +656,29 @@ void SymbolTable::print() { } } #endif // PRODUCT + + +// Utility for dumping symbols +SymboltableDCmd::SymboltableDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _verbose("-verbose", "Dump the content of each symbol in the table", + "BOOLEAN", false, "false") { + _dcmdparser.add_dcmd_option(&_verbose); +} + +void SymboltableDCmd::execute(DCmdSource source, TRAPS) { + VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpSymbols, + _verbose.value()); + VMThread::execute(&dumper); +} + +int SymboltableDCmd::num_arguments() { + ResourceMark rm; + SymboltableDCmd* dcmd = new SymboltableDCmd(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} diff --git a/hotspot/src/share/vm/classfile/symbolTable.hpp b/hotspot/src/share/vm/classfile/symbolTable.hpp index 81f3c085a00..4095e6e7615 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.hpp +++ b/hotspot/src/share/vm/classfile/symbolTable.hpp @@ -73,6 +73,8 @@ class TempNewSymbol : public StackObj { operator Symbol*() { return _temp; } }; +template class CompactHashtable; + class SymbolTable : public RehashableHashtable { friend class VMStructs; friend class ClassFileParser; @@ -83,11 +85,15 @@ private: // Set if one bucket is out of balance due to hash algorithm deficiency static bool _needs_rehashing; + static bool _lookup_shared_first; // For statistics static int _symbols_removed; static int _symbols_counted; + // shared symbol table. + static CompactHashtable _shared_table; + Symbol* allocate_symbol(const u1* name, int len, bool c_heap, TRAPS); // Assumes no characters larger than 0x7F // Adding elements @@ -106,6 +112,8 @@ private: add(loader_data, cp, names_count, name, lengths, cp_indices, hashValues, THREAD); } + static Symbol* lookup_shared(const char* name, int len, unsigned int hash); + Symbol* lookup_dynamic(int index, const char* name, int len, unsigned int hash); Symbol* lookup(int index, const char* name, int len, unsigned int hash); SymbolTable() @@ -144,20 +152,6 @@ public: initialize_symbols(symbol_alloc_arena_size); } - static void create_table(HashtableBucket* t, int length, - int number_of_entries) { - assert(_the_table == NULL, "One symbol table allowed."); - - // If CDS archive used a different symbol table size, use that size instead - // which is better than giving an error. - SymbolTableSize = length/bucket_size(); - - _the_table = new SymbolTable(t, number_of_entries); - // if CDS give symbol table a default arena size since most symbols - // are already allocated in the shared misc section. - initialize_symbols(); - } - static unsigned int hash_symbol(const char* s, int len); static Symbol* lookup(const char* name, int len, TRAPS); @@ -230,18 +224,12 @@ public: // Debugging static void verify(); - static void dump(outputStream* st); + static void dump(outputStream* st, bool verbose=false); + static void read(const char* filename, TRAPS); // Sharing - static void copy_buckets(char** top, char*end) { - the_table()->Hashtable::copy_buckets(top, end); - } - static void copy_table(char** top, char*end) { - the_table()->Hashtable::copy_table(top, end); - } - static void reverse(void* boundary = NULL) { - the_table()->Hashtable::reverse(boundary); - } + static bool copy_compact_table(char** top, char* end); + static const char* init_shared_table(const char* buffer); // Rehash the symbol table if it gets out of balance static void rehash_table(); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 9940f8e34e1..ca1b6b477cd 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" +#include "code/codeCache.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/interpreter.hpp" @@ -1627,7 +1628,7 @@ void SystemDictionary::add_to_hierarchy(instanceKlassHandle k, TRAPS) { // Note: must be done *after* linking k into the hierarchy (was bug 12/9/97) // Also, first reinitialize vtable because it may have gotten out of synch // while the new class wasn't connected to the class hierarchy. - Universe::flush_dependents_on(k); + CodeCache::flush_dependents_on(k); } // ---------------------------------------------------------------------------- @@ -1904,11 +1905,12 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { InstanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER); InstanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass)); - initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK); + initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Cleaner_klass), scan, CHECK); InstanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT); InstanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK); InstanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL); InstanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM); + InstanceKlass::cast(WK_KLASS(Cleaner_klass))->set_reference_type(REF_CLEANER); // JSR 292 classes WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index fd371bfb45d..a558e6479cd 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -128,6 +128,7 @@ class Ticks; do_klass(WeakReference_klass, java_lang_ref_WeakReference, Pre ) \ do_klass(FinalReference_klass, java_lang_ref_FinalReference, Pre ) \ do_klass(PhantomReference_klass, java_lang_ref_PhantomReference, Pre ) \ + do_klass(Cleaner_klass, sun_misc_Cleaner, Pre ) \ do_klass(Finalizer_klass, java_lang_ref_Finalizer, Pre ) \ \ do_klass(Thread_klass, java_lang_Thread, Pre ) \ diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp index d5094ae55be..aaf33d55079 100644 --- a/hotspot/src/share/vm/classfile/verifier.cpp +++ b/hotspot/src/share/vm/classfile/verifier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1546,23 +1546,28 @@ void ClassVerifier::verify_method(methodHandle m, TRAPS) { no_control_flow = true; break; case Bytecodes::_getstatic : case Bytecodes::_putstatic : + // pass TRUE, operand can be an array type for getstatic/putstatic. + verify_field_instructions( + &bcs, ¤t_frame, cp, true, CHECK_VERIFY(this)); + no_control_flow = false; break; case Bytecodes::_getfield : case Bytecodes::_putfield : + // pass FALSE, operand can't be an array type for getfield/putfield. verify_field_instructions( - &bcs, ¤t_frame, cp, CHECK_VERIFY(this)); + &bcs, ¤t_frame, cp, false, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_invokevirtual : case Bytecodes::_invokespecial : case Bytecodes::_invokestatic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_invokeinterface : case Bytecodes::_invokedynamic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_new : { @@ -1945,7 +1950,7 @@ bool ClassVerifier::is_protected_access(instanceKlassHandle this_class, InstanceKlass* target_instance = InstanceKlass::cast(target_class); fieldDescriptor fd; if (is_method) { - Method* m = target_instance->uncached_lookup_method(field_name, field_sig, Klass::normal); + Method* m = target_instance->uncached_lookup_method(field_name, field_sig, Klass::find_overpass); if (m != NULL && m->is_protected()) { if (!this_class->is_same_class_package(m->method_holder())) { return true; @@ -2107,6 +2112,7 @@ bool ClassVerifier::name_in_supers( void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, StackMapFrame* current_frame, constantPoolHandle cp, + bool allow_arrays, TRAPS) { u2 index = bcs->get_index_u2(); verify_cp_type(bcs->bci(), index, cp, @@ -2126,8 +2132,8 @@ void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, // Get referenced class type VerificationType ref_class_type = cp_ref_index_to_type( index, cp, CHECK_VERIFY(this)); - if (!ref_class_type.is_object()) { - /* Unreachable? Class file parser verifies Fieldref contents */ + if (!ref_class_type.is_object() && + (!allow_arrays || !ref_class_type.is_array())) { verify_error(ErrorContext::bad_type(bcs->bci(), TypeOrigin::cp(index, ref_class_type)), "Expecting reference to class in class %s at constant pool index %d", @@ -2406,8 +2412,9 @@ bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) { void ClassVerifier::verify_invoke_init( RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type, - StackMapFrame* current_frame, u4 code_length, bool *this_uninit, - constantPoolHandle cp, TRAPS) { + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + bool *this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, + TRAPS) { u2 bci = bcs->bci(); VerificationType type = current_frame->pop_stack( VerificationType::reference_check(), CHECK_VERIFY(this)); @@ -2423,28 +2430,36 @@ void ClassVerifier::verify_invoke_init( return; } - // Check if this call is done from inside of a TRY block. If so, make - // sure that all catch clause paths end in a throw. Otherwise, this - // can result in returning an incomplete object. - ExceptionTable exhandlers(_method()); - int exlength = exhandlers.length(); - for(int i = 0; i < exlength; i++) { - u2 start_pc = exhandlers.start_pc(i); - u2 end_pc = exhandlers.end_pc(i); + // If this invokespecial call is done from inside of a TRY block then make + // sure that all catch clause paths end in a throw. Otherwise, this can + // result in returning an incomplete object. + if (in_try_block) { + ExceptionTable exhandlers(_method()); + int exlength = exhandlers.length(); + for(int i = 0; i < exlength; i++) { + u2 start_pc = exhandlers.start_pc(i); + u2 end_pc = exhandlers.end_pc(i); - if (bci >= start_pc && bci < end_pc) { - if (!ends_in_athrow(exhandlers.handler_pc(i))) { - verify_error(ErrorContext::bad_code(bci), - "Bad method call from after the start of a try block"); - return; - } else if (VerboseVerification) { - ResourceMark rm; - tty->print_cr( - "Survived call to ends_in_athrow(): %s", - current_class()->name()->as_C_string()); + if (bci >= start_pc && bci < end_pc) { + if (!ends_in_athrow(exhandlers.handler_pc(i))) { + verify_error(ErrorContext::bad_code(bci), + "Bad method call from after the start of a try block"); + return; + } else if (VerboseVerification) { + ResourceMark rm; + tty->print_cr( + "Survived call to ends_in_athrow(): %s", + current_class()->name()->as_C_string()); + } } } - } + + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + verify_exception_handler_targets(bci, true, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } // in_try_block current_frame->initialize_object(type, current_type()); *this_uninit = true; @@ -2477,12 +2492,11 @@ void ClassVerifier::verify_invoke_init( // of the current class. VerificationType objectref_type = new_class_type; if (name_in_supers(ref_class_type.name(), current_class())) { - Klass* ref_klass = load_class( - ref_class_type.name(), CHECK_VERIFY(this)); + Klass* ref_klass = load_class(ref_class_type.name(), CHECK); Method* m = InstanceKlass::cast(ref_klass)->uncached_lookup_method( vmSymbols::object_initializer_name(), cp->signature_ref_at(bcs->get_index_u2()), - Klass::normal); + Klass::find_overpass); // Do nothing if method is not found. Let resolution detect the error. if (m != NULL) { instanceKlassHandle mh(THREAD, m->method_holder()); @@ -2499,6 +2513,13 @@ void ClassVerifier::verify_invoke_init( } } } + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + if (in_try_block) { + verify_exception_handler_targets(bci, *this_uninit, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } current_frame->initialize_object(type, new_class_type); } else { verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()), @@ -2527,8 +2548,8 @@ bool ClassVerifier::is_same_or_direct_interface( void ClassVerifier::verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool *this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS) { + bool in_try_block, bool *this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS) { // Make sure the constant pool item is the right type u2 index = bcs->get_index_u2(); Bytecodes::Code opcode = bcs->raw_code(); @@ -2694,7 +2715,8 @@ void ClassVerifier::verify_invoke_instructions( opcode != Bytecodes::_invokedynamic) { if (method_name == vmSymbols::object_initializer_name()) { // method verify_invoke_init(bcs, index, ref_class_type, current_frame, - code_length, this_uninit, cp, CHECK_VERIFY(this)); + code_length, in_try_block, this_uninit, cp, stackmap_table, + CHECK_VERIFY(this)); } else { // other methods // Ensures that target class is assignable to method class. if (opcode == Bytecodes::_invokespecial) { diff --git a/hotspot/src/share/vm/classfile/verifier.hpp b/hotspot/src/share/vm/classfile/verifier.hpp index ed9a173b187..113e404e42e 100644 --- a/hotspot/src/share/vm/classfile/verifier.hpp +++ b/hotspot/src/share/vm/classfile/verifier.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -297,12 +297,13 @@ class ClassVerifier : public StackObj { void verify_field_instructions( RawBytecodeStream* bcs, StackMapFrame* current_frame, - constantPoolHandle cp, TRAPS); + constantPoolHandle cp, bool allow_arrays, TRAPS); void verify_invoke_init( RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type, - StackMapFrame* current_frame, u4 code_length, bool* this_uninit, - constantPoolHandle cp, TRAPS); + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + bool* this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, + TRAPS); // Used by ends_in_athrow() to push all handlers that contain bci onto // the handler_stack, if the handler is not already on the stack. @@ -316,8 +317,8 @@ class ClassVerifier : public StackObj { void verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool* this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS); + bool in_try_block, bool* this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS); VerificationType get_newarray_type(u2 index, u2 bci, TRAPS); void verify_anewarray(u2 bci, u2 index, constantPoolHandle cp, diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index d6a84b75af0..94150a96cea 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -79,6 +79,7 @@ template(java_lang_ref_WeakReference, "java/lang/ref/WeakReference") \ template(java_lang_ref_FinalReference, "java/lang/ref/FinalReference") \ template(java_lang_ref_PhantomReference, "java/lang/ref/PhantomReference") \ + template(sun_misc_Cleaner, "sun/misc/Cleaner") \ template(java_lang_ref_Finalizer, "java/lang/ref/Finalizer") \ template(java_lang_reflect_AccessibleObject, "java/lang/reflect/AccessibleObject") \ template(java_lang_reflect_Method, "java/lang/reflect/Method") \ @@ -242,7 +243,6 @@ template(returnType_name, "returnType") \ template(signature_name, "signature") \ template(slot_name, "slot") \ - template(selectAlternative_name, "selectAlternative") \ \ /* Support for annotations (JDK 1.5 and above) */ \ \ @@ -294,8 +294,7 @@ template(setTarget_signature, "(Ljava/lang/invoke/MethodHandle;)V") \ NOT_LP64( do_alias(intptr_signature, int_signature) ) \ LP64_ONLY( do_alias(intptr_signature, long_signature) ) \ - template(selectAlternative_signature, "(ZLjava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;") \ - \ + \ /* common method and field names */ \ template(object_initializer_name, "") \ template(class_initializer_name, "") \ @@ -867,6 +866,12 @@ do_name( fullFence_name, "fullFence") \ do_alias( fullFence_signature, void_method_signature) \ \ + /* Custom branch frequencies profiling support for JSR292 */ \ + do_class(java_lang_invoke_MethodHandleImpl, "java/lang/invoke/MethodHandleImpl") \ + do_intrinsic(_profileBoolean, java_lang_invoke_MethodHandleImpl, profileBoolean_name, profileBoolean_signature, F_S) \ + do_name( profileBoolean_name, "profileBoolean") \ + do_signature(profileBoolean_signature, "(Z[I)Z") \ + \ /* unsafe memory references (there are a lot of them...) */ \ do_signature(getObject_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \ do_signature(putObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;)V") \ diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index f81e2983172..1d43669209e 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -199,15 +199,10 @@ void CodeCache::initialize_heaps() { } guarantee(NonProfiledCodeHeapSize + ProfiledCodeHeapSize + NonNMethodCodeHeapSize <= ReservedCodeCacheSize, "Size check"); - // Align reserved sizes of CodeHeaps - size_t non_method_size = ReservedCodeSpace::allocation_align_size_up(NonNMethodCodeHeapSize); - size_t profiled_size = ReservedCodeSpace::allocation_align_size_up(ProfiledCodeHeapSize); - size_t non_profiled_size = ReservedCodeSpace::allocation_align_size_up(NonProfiledCodeHeapSize); - - // Compute initial sizes of CodeHeaps - size_t init_non_method_size = MIN2(InitialCodeCacheSize, non_method_size); - size_t init_profiled_size = MIN2(InitialCodeCacheSize, profiled_size); - size_t init_non_profiled_size = MIN2(InitialCodeCacheSize, non_profiled_size); + // Align CodeHeaps + size_t alignment = heap_alignment(); + size_t non_method_size = align_size_up(NonNMethodCodeHeapSize, alignment); + size_t profiled_size = align_size_down(ProfiledCodeHeapSize, alignment); // Reserve one continuous chunk of memory for CodeHeaps and split it into // parts for the individual heaps. The memory layout looks like this: @@ -216,25 +211,34 @@ void CodeCache::initialize_heaps() { // Profiled nmethods // Non-nmethods // ---------- low ------------ - ReservedCodeSpace rs = reserve_heap_memory(non_profiled_size + profiled_size + non_method_size); + ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize); ReservedSpace non_method_space = rs.first_part(non_method_size); ReservedSpace rest = rs.last_part(non_method_size); ReservedSpace profiled_space = rest.first_part(profiled_size); ReservedSpace non_profiled_space = rest.last_part(profiled_size); // Non-nmethods (stubs, adapters, ...) - add_heap(non_method_space, "CodeHeap 'non-nmethods'", init_non_method_size, CodeBlobType::NonNMethod); + add_heap(non_method_space, "CodeHeap 'non-nmethods'", CodeBlobType::NonNMethod); // Tier 2 and tier 3 (profiled) methods - add_heap(profiled_space, "CodeHeap 'profiled nmethods'", init_profiled_size, CodeBlobType::MethodProfiled); + add_heap(profiled_space, "CodeHeap 'profiled nmethods'", CodeBlobType::MethodProfiled); // Tier 1 and tier 4 (non-profiled) methods and native methods - add_heap(non_profiled_space, "CodeHeap 'non-profiled nmethods'", init_non_profiled_size, CodeBlobType::MethodNonProfiled); + add_heap(non_profiled_space, "CodeHeap 'non-profiled nmethods'", CodeBlobType::MethodNonProfiled); +} + +size_t CodeCache::heap_alignment() { + // If large page support is enabled, align code heaps according to large + // page size to make sure that code cache is covered by large pages. + const size_t page_size = os::can_execute_large_page_memory() ? + os::page_size_for_region_unaligned(ReservedCodeCacheSize, 8) : + os::vm_page_size(); + return MAX2(page_size, (size_t) os::vm_allocation_granularity()); } ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size) { // Determine alignment const size_t page_size = os::can_execute_large_page_memory() ? - MIN2(os::page_size_for_region(InitialCodeCacheSize, 8), - os::page_size_for_region(size, 8)) : + MIN2(os::page_size_for_region_aligned(InitialCodeCacheSize, 8), + os::page_size_for_region_aligned(size, 8)) : os::vm_page_size(); const size_t granularity = os::vm_allocation_granularity(); const size_t r_align = MAX2(page_size, granularity); @@ -284,7 +288,7 @@ const char* CodeCache::get_code_heap_flag_name(int code_blob_type) { return NULL; } -void CodeCache::add_heap(ReservedSpace rs, const char* name, size_t size_initial, int code_blob_type) { +void CodeCache::add_heap(ReservedSpace rs, const char* name, int code_blob_type) { // Check if heap is needed if (!heap_available(code_blob_type)) { return; @@ -295,8 +299,8 @@ void CodeCache::add_heap(ReservedSpace rs, const char* name, size_t size_initial _heaps->append(heap); // Reserve Space + size_t size_initial = MIN2(InitialCodeCacheSize, rs.size()); size_initial = round_to(size_initial, os::vm_page_size()); - if (!heap->reserve(rs, size_initial, CodeCacheSegmentSize)) { vm_exit_during_initialization("Could not reserve enough space for code cache"); } @@ -840,7 +844,7 @@ void CodeCache::initialize() { } else { // Use a single code heap ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize); - add_heap(rs, "CodeCache", InitialCodeCacheSize, CodeBlobType::All); + add_heap(rs, "CodeCache", CodeBlobType::All); } // Initialize ICache flush mechanism @@ -1005,6 +1009,117 @@ void CodeCache::make_marked_nmethods_not_entrant() { } } +// Flushes compiled methods dependent on dependee. +void CodeCache::flush_dependents_on(instanceKlassHandle dependee) { + assert_lock_strong(Compile_lock); + + if (number_of_nmethods_with_dependencies() == 0) return; + + // CodeCache can only be updated by a thread_in_VM and they will all be + // stopped during the safepoint so CodeCache will be safe to update without + // holding the CodeCache_lock. + + KlassDepChange changes(dependee); + + // Compute the dependent nmethods + if (mark_for_deoptimization(changes) > 0) { + // At least one nmethod has been marked for deoptimization + VM_Deoptimize op; + VMThread::execute(&op); + } +} + +// Flushes compiled methods dependent on a particular CallSite +// instance when its target is different than the given MethodHandle. +void CodeCache::flush_dependents_on(Handle call_site, Handle method_handle) { + assert_lock_strong(Compile_lock); + + if (number_of_nmethods_with_dependencies() == 0) return; + + // CodeCache can only be updated by a thread_in_VM and they will all be + // stopped during the safepoint so CodeCache will be safe to update without + // holding the CodeCache_lock. + + CallSiteDepChange changes(call_site(), method_handle()); + + // Compute the dependent nmethods that have a reference to a + // CallSite object. We use InstanceKlass::mark_dependent_nmethod + // directly instead of CodeCache::mark_for_deoptimization because we + // want dependents on the call site class only not all classes in + // the ContextStream. + int marked = 0; + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + InstanceKlass* call_site_klass = InstanceKlass::cast(call_site->klass()); + marked = call_site_klass->mark_dependent_nmethods(changes); + } + if (marked > 0) { + // At least one nmethod has been marked for deoptimization + VM_Deoptimize op; + VMThread::execute(&op); + } +} + +#ifdef HOTSWAP +// Flushes compiled methods dependent on dependee in the evolutionary sense +void CodeCache::flush_evol_dependents_on(instanceKlassHandle ev_k_h) { + // --- Compile_lock is not held. However we are at a safepoint. + assert_locked_or_safepoint(Compile_lock); + if (number_of_nmethods_with_dependencies() == 0) return; + + // CodeCache can only be updated by a thread_in_VM and they will all be + // stopped during the safepoint so CodeCache will be safe to update without + // holding the CodeCache_lock. + + // Compute the dependent nmethods + if (mark_for_evol_deoptimization(ev_k_h) > 0) { + // At least one nmethod has been marked for deoptimization + + // All this already happens inside a VM_Operation, so we'll do all the work here. + // Stuff copied from VM_Deoptimize and modified slightly. + + // We do not want any GCs to happen while we are in the middle of this VM operation + ResourceMark rm; + DeoptimizationMarker dm; + + // Deoptimize all activations depending on marked nmethods + Deoptimization::deoptimize_dependents(); + + // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies) + make_marked_nmethods_not_entrant(); + } +} +#endif // HOTSWAP + + +// Flushes compiled methods dependent on dependee +void CodeCache::flush_dependents_on_method(methodHandle m_h) { + // --- Compile_lock is not held. However we are at a safepoint. + assert_locked_or_safepoint(Compile_lock); + + // CodeCache can only be updated by a thread_in_VM and they will all be + // stopped dring the safepoint so CodeCache will be safe to update without + // holding the CodeCache_lock. + + // Compute the dependent nmethods + if (mark_for_deoptimization(m_h()) > 0) { + // At least one nmethod has been marked for deoptimization + + // All this already happens inside a VM_Operation, so we'll do all the work here. + // Stuff copied from VM_Deoptimize and modified slightly. + + // We do not want any GCs to happen while we are in the middle of this VM operation + ResourceMark rm; + DeoptimizationMarker dm; + + // Deoptimize all activations depending on marked nmethods + Deoptimization::deoptimize_dependents(); + + // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies) + make_marked_nmethods_not_entrant(); + } +} + void CodeCache::verify() { assert_locked_or_safepoint(CodeCache_lock); FOR_ALL_HEAPS(heap) { diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index 25c5288cdde..d682f90c5b2 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,12 +98,13 @@ class CodeCache : AllStatic { // CodeHeap management static void initialize_heaps(); // Initializes the CodeHeaps // Creates a new heap with the given name and size, containing CodeBlobs of the given type - static void add_heap(ReservedSpace rs, const char* name, size_t size_initial, int code_blob_type); + static void add_heap(ReservedSpace rs, const char* name, int code_blob_type); static CodeHeap* get_code_heap(const CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob static CodeHeap* get_code_heap(int code_blob_type); // Returns the CodeHeap for the given CodeBlobType // Returns the name of the VM option to set the size of the corresponding CodeHeap static const char* get_code_heap_flag_name(int code_blob_type); static bool heap_available(int code_blob_type); // Returns true if an own CodeHeap for the given CodeBlobType is available + static size_t heap_alignment(); // Returns the alignment of the CodeHeaps in bytes static ReservedCodeSpace reserve_heap_memory(size_t size); // Reserves one continuous chunk of memory for the CodeHeaps // Iteration @@ -209,16 +210,28 @@ class CodeCache : AllStatic { static void verify_icholder_relocations(); // Deoptimization + private: static int mark_for_deoptimization(DepChange& changes); #ifdef HOTSWAP static int mark_for_evol_deoptimization(instanceKlassHandle dependee); #endif // HOTSWAP + public: static void mark_all_nmethods_for_deoptimization(); static int mark_for_deoptimization(Method* dependee); static void make_marked_nmethods_zombies(); static void make_marked_nmethods_not_entrant(); + // Flushing and deoptimization + static void flush_dependents_on(instanceKlassHandle dependee); + static void flush_dependents_on(Handle call_site, Handle method_handle); +#ifdef HOTSWAP + // Flushing and deoptimization in case of evolution + static void flush_evol_dependents_on(instanceKlassHandle dependee); +#endif // HOTSWAP + // Support for fullspeed debugging + static void flush_dependents_on_method(methodHandle dependee); + // tells how many nmethods have dependencies static int number_of_nmethods_with_dependencies(); diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp index fbefd4a9b1e..eebbf78be6d 100644 --- a/hotspot/src/share/vm/code/dependencies.cpp +++ b/hotspot/src/share/vm/code/dependencies.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -560,7 +560,7 @@ void Dependencies::print_dependency(DepType dept, GrowableArray* ar put_star = !Dependencies::is_concrete_klass((Klass*)arg.metadata_value()); } else if (arg.is_method()) { what = "method "; - put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value()); + put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value(), NULL); } else if (arg.is_klass()) { what = "class "; } else { @@ -878,8 +878,8 @@ class ClassHierarchyWalker { // Static methods don't override non-static so punt return true; } - if ( !Dependencies::is_concrete_method(lm) - && !Dependencies::is_concrete_method(m) + if ( !Dependencies::is_concrete_method(lm, k) + && !Dependencies::is_concrete_method(m, ctxk) && lm->method_holder()->is_subtype_of(m->method_holder())) // Method m is overridden by lm, but both are non-concrete. return true; @@ -915,8 +915,17 @@ class ClassHierarchyWalker { } else if (!k->oop_is_instance()) { return false; // no methods to find in an array type } else { - Method* m = InstanceKlass::cast(k)->find_method(_name, _signature); - if (m == NULL || !Dependencies::is_concrete_method(m)) return false; + // Search class hierarchy first. + Method* m = InstanceKlass::cast(k)->find_instance_method(_name, _signature); + if (!Dependencies::is_concrete_method(m, k)) { + // Check interface defaults also, if any exist. + Array* default_methods = InstanceKlass::cast(k)->default_methods(); + if (default_methods == NULL) + return false; + m = InstanceKlass::cast(k)->find_method(default_methods, _name, _signature); + if (!Dependencies::is_concrete_method(m, NULL)) + return false; + } _found_methods[_num_participants] = m; // Note: If add_participant(k) is called, // the method m will already be memoized for it. @@ -1209,15 +1218,17 @@ bool Dependencies::is_concrete_klass(Klass* k) { return true; } -bool Dependencies::is_concrete_method(Method* m) { - // Statics are irrelevant to virtual call sites. - if (m->is_static()) return false; - - // We could also return false if m does not yet appear to be - // executed, if the VM version supports this distinction also. - // Default methods are considered "concrete" as well. - return !m->is_abstract() && - !m->is_overpass(); // error functions aren't concrete +bool Dependencies::is_concrete_method(Method* m, Klass * k) { + // NULL is not a concrete method, + // statics are irrelevant to virtual call sites, + // abstract methods are not concrete, + // overpass (error) methods are not concrete if k is abstract + // + // note "true" is conservative answer -- + // overpass clause is false if k == NULL, implies return true if + // answer depends on overpass clause. + return ! ( m == NULL || m -> is_static() || m -> is_abstract() || + m->is_overpass() && k != NULL && k -> is_abstract() ); } @@ -1242,16 +1253,6 @@ bool Dependencies::is_concrete_klass(ciInstanceKlass* k) { return true; } -bool Dependencies::is_concrete_method(ciMethod* m) { - // Statics are irrelevant to virtual call sites. - if (m->is_static()) return false; - - // We could also return false if m does not yet appear to be - // executed, if the VM version supports this distinction also. - return !m->is_abstract(); -} - - bool Dependencies::has_finalizable_subclass(ciInstanceKlass* k) { return k->has_finalizable_subclass(); } @@ -1469,7 +1470,7 @@ Method* Dependencies::find_unique_concrete_method(Klass* ctxk, Method* m) { Klass* wit = wf.find_witness_definer(ctxk); if (wit != NULL) return NULL; // Too many witnesses. Method* fm = wf.found_method(0); // Will be NULL if num_parts == 0. - if (Dependencies::is_concrete_method(m)) { + if (Dependencies::is_concrete_method(m, ctxk)) { if (fm == NULL) { // It turns out that m was always the only implementation. fm = m; @@ -1499,61 +1500,6 @@ Klass* Dependencies::check_exclusive_concrete_methods(Klass* ctxk, return wf.find_witness_definer(ctxk, changes); } -// Find the set of all non-abstract methods under ctxk that match m[0]. -// (The method m[0] must be defined or inherited in ctxk.) -// Include m itself in the set, unless it is abstract. -// Fill the given array m[0..(mlen-1)] with this set, and return the length. -// (The length may be zero if no concrete methods are found anywhere.) -// If there are too many concrete methods to fit in marray, return -1. -int Dependencies::find_exclusive_concrete_methods(Klass* ctxk, - int mlen, - Method* marray[]) { - Method* m0 = marray[0]; - ClassHierarchyWalker wf(m0); - assert(wf.check_method_context(ctxk, m0), "proper context"); - wf.record_witnesses(mlen); - bool participants_hide_witnesses = true; - Klass* wit = wf.find_witness_definer(ctxk); - if (wit != NULL) return -1; // Too many witnesses. - int num = wf.num_participants(); - assert(num <= mlen, "oob"); - // Keep track of whether m is also part of the result set. - int mfill = 0; - assert(marray[mfill] == m0, "sanity"); - if (Dependencies::is_concrete_method(m0)) - mfill++; // keep m0 as marray[0], the first result - for (int i = 0; i < num; i++) { - Method* fm = wf.found_method(i); - if (fm == m0) continue; // Already put this guy in the list. - if (mfill == mlen) { - return -1; // Oops. Too many methods after all! - } - marray[mfill++] = fm; - } -#ifndef PRODUCT - // Make sure the dependency mechanism will pass this discovery: - if (VerifyDependencies) { - // Turn off dependency tracing while actually testing deps. - FlagSetting fs(TraceDependencies, false); - switch (mfill) { - case 1: - guarantee(NULL == (void *)check_unique_concrete_method(ctxk, marray[0]), - "verify dep."); - break; - case 2: - guarantee(NULL == (void *) - check_exclusive_concrete_methods(ctxk, marray[0], marray[1]), - "verify dep."); - break; - default: - ShouldNotReachHere(); // mlen > 2 yet supported - } - } -#endif //PRODUCT - return mfill; -} - - Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes) { Klass* search_at = ctxk; if (changes != NULL) @@ -1561,7 +1507,6 @@ Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepCh return find_finalizable_subclass(search_at); } - Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) { assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity"); assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity"); diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp index ff4ff328f8d..dee40b9beda 100644 --- a/hotspot/src/share/vm/code/dependencies.hpp +++ b/hotspot/src/share/vm/code/dependencies.hpp @@ -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 @@ -288,7 +288,7 @@ class Dependencies: public ResourceObj { // In that case, there would be a middle ground between concrete // and abstract (as defined by the Java language and VM). static bool is_concrete_klass(Klass* k); // k is instantiable - static bool is_concrete_method(Method* m); // m is invocable + static bool is_concrete_method(Method* m, Klass* k); // m is invocable static Klass* find_finalizable_subclass(Klass* k); // These versions of the concreteness queries work through the CI. @@ -302,7 +302,6 @@ class Dependencies: public ResourceObj { // not go back into the VM to get their value; they must cache the // bit in the CI, either eagerly or lazily.) static bool is_concrete_klass(ciInstanceKlass* k); // k appears instantiable - static bool is_concrete_method(ciMethod* m); // m appears invocable static bool has_finalizable_subclass(ciInstanceKlass* k); // As a general rule, it is OK to compile under the assumption that @@ -349,7 +348,6 @@ class Dependencies: public ResourceObj { static Klass* find_unique_concrete_subtype(Klass* ctxk); static Method* find_unique_concrete_method(Klass* ctxk, Method* m); static int find_exclusive_concrete_subtypes(Klass* ctxk, int klen, Klass* k[]); - static int find_exclusive_concrete_methods(Klass* ctxk, int mlen, Method* m[]); // Create the encoding which will be stored in an nmethod. void encode_content_bytes(); diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 835b3dc831d..0e60a131ae8 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -2310,17 +2310,6 @@ void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map #endif // !SHARK } - -oop nmethod::embeddedOop_at(u_char* p) { - RelocIterator iter(this, p, p + 1); - while (iter.next()) - if (iter.type() == relocInfo::oop_type) { - return iter.oop_reloc()->oop_value(); - } - return NULL; -} - - inline bool includes(void* p, void* from, void* to) { return from <= p && p < to; } diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index c95679649fd..5d4173738d9 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -730,11 +730,6 @@ public: int compile_id() const { return _compile_id; } const char* compile_kind() const; - // For debugging - // CompiledIC* IC_at(char* p) const; - // PrimitiveIC* primitiveIC_at(char* p) const; - oop embeddedOop_at(address p); - // tells if any of this method's dependencies have been invalidated // (this is expensive!) static void check_all_dependencies(DepChange& changes); diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 2b22da1f705..71b3fc5b3bf 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -252,7 +252,7 @@ CompileTask* CompileTask::allocate() { } else { task = new CompileTask(); DEBUG_ONLY(_num_allocated_tasks++;) - assert (_num_allocated_tasks < 10000, "Leaking compilation tasks?"); + assert (WhiteBoxAPI || _num_allocated_tasks < 10000, "Leaking compilation tasks?"); task->set_next(NULL); task->set_is_free(true); } @@ -1470,7 +1470,9 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, // The method may be explicitly excluded by the user. bool quietly; - if (CompilerOracle::should_exclude(method, quietly)) { + double scale; + if (CompilerOracle::should_exclude(method, quietly) + || (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) { if (!quietly) { // This does not happen quietly... ResourceMark rm; diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp index b733305666b..8299da22f0f 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp @@ -105,7 +105,6 @@ class MethodMatcher : public CHeapObj { tty->print("."); print_symbol(method_name(), _method_mode); if (signature() != NULL) { - tty->print(" "); signature()->print_symbol_on(tty); } } @@ -467,43 +466,85 @@ static OracleCommand parse_command_name(const char * line, int* bytes_read) { return UnknownCommand; } - static void usage() { - tty->print_cr(" CompileCommand and the CompilerOracle allows simple control over"); - tty->print_cr(" what's allowed to be compiled. The standard supported directives"); - tty->print_cr(" are exclude and compileonly. The exclude directive stops a method"); - tty->print_cr(" from being compiled and compileonly excludes all methods except for"); - tty->print_cr(" the ones mentioned by compileonly directives. The basic form of"); - tty->print_cr(" all commands is a command name followed by the name of the method"); - tty->print_cr(" in one of two forms: the standard class file format as in"); - tty->print_cr(" class/name.methodName or the PrintCompilation format"); - tty->print_cr(" class.name::methodName. The method name can optionally be followed"); - tty->print_cr(" by a space then the signature of the method in the class file"); - tty->print_cr(" format. Otherwise the directive applies to all methods with the"); - tty->print_cr(" same name and class regardless of signature. Leading and trailing"); - tty->print_cr(" *'s in the class and/or method name allows a small amount of"); - tty->print_cr(" wildcarding. "); tty->cr(); - tty->print_cr(" Examples:"); + tty->print_cr("The CompileCommand option enables the user of the JVM to control specific"); + tty->print_cr("behavior of the dynamic compilers. Many commands require a pattern that defines"); + tty->print_cr("the set of methods the command shall be applied to. The CompileCommand"); + tty->print_cr("option provides the following commands:"); tty->cr(); - tty->print_cr(" exclude java/lang/StringBuffer.append"); - tty->print_cr(" compileonly java/lang/StringBuffer.toString ()Ljava/lang/String;"); - tty->print_cr(" exclude java/lang/String*.*"); - tty->print_cr(" exclude *.toString"); -} + tty->print_cr(" break, - debug breakpoint in compiler and in generated code"); + tty->print_cr(" print, - print assembly"); + tty->print_cr(" exclude, - don't compile or inline"); + tty->print_cr(" inline, - always inline"); + tty->print_cr(" dontinline, - don't inline"); + tty->print_cr(" compileonly, - compile only"); + tty->print_cr(" log, - log compilation"); + tty->print_cr(" option,,