This commit is contained in:
David Dehaven 2015-01-21 12:00:04 -08:00
commit c185d7e8d4
370 changed files with 15863 additions and 8635 deletions

View File

@ -288,3 +288,4 @@ b409bc51bc23cfd51f2bd04ea919ec83535af9d0 jdk9-b37
6494b13f88a867026ee316b444d9a4fa589dd6bd jdk9-b43
abbfccd659b91a7bb815d5e36fed635dcdd40f31 jdk9-b44
bfc24ae2b900187585079bb11e66e459d1e525fe jdk9-b45
722378bc599e38d9a1dd484de30f10dfd7b21438 jdk9-b46

View File

@ -288,3 +288,4 @@ f7c11da0b0481d49cc7a65a453336c108191e821 jdk9-b42
02ee8c65622e8bd97496d584e22fc7dcf0edc4ae jdk9-b43
8994f5d87b3bb5e8d317d4e8ccb326da1a73684a jdk9-b44
3dd628fde2086218d548841022ee8436b6b88185 jdk9-b45
12f1e276447bcc81516e85367d53e4f08897049d jdk9-b46

View File

@ -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

View File

@ -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<com\.apple\.jobjc\..*itemsPtr();/d' \
-e '/[<>].*public void setItemsPtr(com\.apple\.jobjc\.Pointer<com\.apple\.jobjc\..*);/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<com\.apple\.jobjc\..*itemsPtr();/d' \
-e '/[<>].*public void setItemsPtr(com\.apple\.jobjc\.Pointer<com\.apple\.jobjc\..*);/d' \
-e '/[<>].*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 '/[<>] <!-- Generated by javadoc .* on .* -->/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</dev/null | $AWK '{ print $1;}' | $SORT | $TEE $WORK_FILE_BASE.deps.this | $UNIQ > $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</dev/null | $AWK '{ print $1;}' | $SORT | $TEE $WORK_FILE_BASE.deps.this | $UNIQ > $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

View File

@ -288,3 +288,4 @@ e27c725d6c9d155667b35255f442d4ceb8c3c084 jdk9-b40
9645e35616b60c5c07b4fdf11a132afc8081dfa8 jdk9-b43
1f57bd728c9e6865ccb9d43ccd80a1c11230a32f jdk9-b44
9e3f2bed80c0e5a84a256ce41f1d10c5ade48466 jdk9-b45
326f2068b4a4c05e2fa27d6acf93eba7b54b090d jdk9-b46

View File

@ -448,3 +448,4 @@ c363a8b87e477ee45d6d3cb2a36cb365141bc596 jdk9-b38
65a9747147b8090037541040ba67156ec914db6a jdk9-b43
43a44b56dca61a4d766a20f0528fdd8b5ceff873 jdk9-b44
5dc8184af1e2bb30b0103113d1f1a58a21a80c37 jdk9-b45
a184ee1d717297bd35b7c3e35393e137921a3ed2 jdk9-b46

View File

@ -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 \

View File

@ -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;

View File

@ -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.

View File

@ -34,6 +34,6 @@ public class MachineDescriptionPPC64 extends MachineDescriptionTwosComplement im
}
public boolean isBigEndian() {
return true;
return "big".equals(System.getProperty("sun.cpu.endian"));
}
}

View File

@ -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);

View File

@ -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." +

View File

@ -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;
}

View File

@ -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));
}
}

View File

@ -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);
}

View File

@ -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." +

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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." +

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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.*;
/** <P> 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. </P>
*/
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;
}
}

View File

@ -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));
}
}
}
}

View File

@ -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;
}
}

View File

@ -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; }
}

View File

@ -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.

View File

@ -124,7 +124,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

View File

@ -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:

View File

@ -51,16 +51,20 @@ $(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/linux/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.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 \
@ -90,12 +94,14 @@ $(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/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 \

View File

@ -59,7 +59,7 @@ ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) :
_has_nonstatic_fields = ik->has_nonstatic_fields();
_has_default_methods = ik->has_default_methods();
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
_has_injected_fields = -1;
_implementor = NULL; // we will fill these lazily
Thread *thread = Thread::current();
@ -100,6 +100,7 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
_nonstatic_field_size = -1;
_has_nonstatic_fields = false;
_nonstatic_fields = NULL;
_has_injected_fields = -1;
_loader = loader;
_protection_domain = protection_domain;
_is_shared = false;
@ -500,6 +501,34 @@ ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray<ciField*>*
return fields;
}
void ciInstanceKlass::compute_injected_fields_helper() {
ASSERT_IN_VM;
InstanceKlass* k = get_instanceKlass();
for (InternalFieldStream fs(k); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) continue;
_has_injected_fields++;
break;
}
}
bool ciInstanceKlass::compute_injected_fields() {
assert(_has_injected_fields == -1, "shouldn't be initialized yet");
assert(is_loaded(), "must be loaded");
if (super() != NULL && super()->has_injected_fields()) {
_has_injected_fields = 1;
return true;
}
_has_injected_fields = 0;
GUARDED_VM_ENTRY({
compute_injected_fields_helper();
});
return _has_injected_fields > 0 ? true : false;
}
// ------------------------------------------------------------------
// ciInstanceKlass::find_method
//

View File

@ -64,6 +64,7 @@ private:
ciConstantPoolCache* _field_cache; // cached map index->field
GrowableArray<ciField*>* _nonstatic_fields;
int _has_injected_fields; // any non static injected fields? lazily initialized.
// The possible values of the _implementor fall into following three cases:
// NULL: no implementor.
@ -71,6 +72,9 @@ private:
// Itsef: more than one implementors.
ciInstanceKlass* _implementor;
bool compute_injected_fields();
void compute_injected_fields_helper();
protected:
ciInstanceKlass(KlassHandle h_k);
ciInstanceKlass(ciSymbol* name, jobject loader, jobject protection_domain);
@ -186,6 +190,14 @@ public:
else
return _nonstatic_fields->length();
}
bool has_injected_fields() {
if (_has_injected_fields == -1) {
return compute_injected_fields();
}
return _has_injected_fields > 0 ? true : false;
}
// nth nonstatic field (presented by ascending address)
ciField* nonstatic_field_at(int i) {
assert(_nonstatic_fields != NULL, "");

View File

@ -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();
}
}

View File

@ -0,0 +1,417 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "memory/metaspaceShared.hpp"
#include "utilities/numberSeq.hpp"
#include <sys/stat.h>
/////////////////////////////////////////////////////
//
// 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 <class T, class N> const char* CompactHashtable<T, N>::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;
}
// Explicitly instantiate these types
template class CompactHashtable<Symbol*, char>;
#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<count; i++) {
char c = *from++;
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
value = (value << 4) + c - '0';
break;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
value = (value << 4) + 10 + c - 'a';
break;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
value = (value << 4) + 10 + c - 'A';
break;
default:
ShouldNotReachHere();
}
}
return value;
}
void HashtableTextDump::get_utf8(char* utf8_buffer, int utf8_length) {
// cache in local vars
const char* from = _p;
const char* end = _end;
char* to = utf8_buffer;
int n = utf8_length;
for (; n > 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);
}
}
}
}

View File

@ -0,0 +1,405 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_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<mtSymbol> {
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 T, class N> 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;
}
};
////////////////////////////////////////////////////////////////////////
//
// 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<bool> _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<bool> _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

View File

@ -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<oop, mtSymbol>* 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;
}
}

View File

@ -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,

View File

@ -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<Symbol*, char> 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");
@ -186,8 +190,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<Symbol*, mtSymbol>* e = bucket(index); e != NULL; e = e->next()) {
count++; // count all entries in this bucket, not just ones with same hash
@ -207,6 +211,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 +515,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<Symbol*, mtSymbol>* 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<Symbol*, mtSymbol>* 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 +652,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;
}
}

View File

@ -73,6 +73,8 @@ class TempNewSymbol : public StackObj {
operator Symbol*() { return _temp; }
};
template <class T, class N> class CompactHashtable;
class SymbolTable : public RehashableHashtable<Symbol*, mtSymbol> {
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<Symbol*, char> _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<mtSymbol>* 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<Symbol*, mtSymbol>::copy_buckets(top, end);
}
static void copy_table(char** top, char*end) {
the_table()->Hashtable<Symbol*, mtSymbol>::copy_table(top, end);
}
static void reverse(void* boundary = NULL) {
the_table()->Hashtable<Symbol*, mtSymbol>::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();

View File

@ -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);
}
// ----------------------------------------------------------------------------

View File

@ -2477,8 +2477,7 @@ 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()),

View File

@ -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
@ -1005,6 +1005,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) {

View File

@ -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
@ -209,16 +209,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();

View File

@ -99,8 +99,8 @@ void G1DefaultAllocator::release_gc_alloc_regions(uint no_of_gc_workers, Evacuat
}
if (ResizePLAB) {
_g1h->_survivor_plab_stats.adjust_desired_plab_sz(no_of_gc_workers);
_g1h->_old_plab_stats.adjust_desired_plab_sz(no_of_gc_workers);
_g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz(no_of_gc_workers);
_g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz(no_of_gc_workers);
}
}

View File

@ -2068,7 +2068,7 @@ void G1CollectedHeap::stop() {
}
void G1CollectedHeap::clear_humongous_is_live_table() {
guarantee(G1ReclaimDeadHumongousObjectsAtYoungGC, "Should only be called if true");
guarantee(G1EagerReclaimHumongousObjects, "Should only be called if true");
_humongous_is_live.clear();
}
@ -3485,8 +3485,24 @@ class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure {
private:
size_t _total_humongous;
size_t _candidate_humongous;
DirtyCardQueue _dcq;
bool humongous_region_is_candidate(uint index) {
HeapRegion* region = G1CollectedHeap::heap()->region_at(index);
assert(region->is_starts_humongous(), "Must start a humongous object");
HeapRegionRemSet* const rset = region->rem_set();
bool const allow_stale_refs = G1EagerReclaimHumongousObjectsWithStaleRefs;
return !oop(region->bottom())->is_objArray() &&
((allow_stale_refs && rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries)) ||
(!allow_stale_refs && rset->is_empty()));
}
public:
RegisterHumongousWithInCSetFastTestClosure() : _total_humongous(0), _candidate_humongous(0) {
RegisterHumongousWithInCSetFastTestClosure()
: _total_humongous(0),
_candidate_humongous(0),
_dcq(&JavaThread::dirty_card_queue_set()) {
}
virtual bool doHeapRegion(HeapRegion* r) {
@ -3496,11 +3512,29 @@ class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
uint region_idx = r->hrm_index();
bool is_candidate = !g1h->humongous_region_is_always_live(region_idx);
// Is_candidate already filters out humongous regions with some remembered set.
// This will not lead to humongous object that we mistakenly keep alive because
// during young collection the remembered sets will only be added to.
bool is_candidate = humongous_region_is_candidate(region_idx);
// Is_candidate already filters out humongous object with large remembered sets.
// If we have a humongous object with a few remembered sets, we simply flush these
// remembered set entries into the DCQS. That will result in automatic
// re-evaluation of their remembered set entries during the following evacuation
// phase.
if (is_candidate) {
if (!r->rem_set()->is_empty()) {
guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries),
"Found a not-small remembered set here. This is inconsistent with previous assumptions.");
G1SATBCardTableLoggingModRefBS* bs = g1h->g1_barrier_set();
HeapRegionRemSetIterator hrrs(r->rem_set());
size_t card_index;
while (hrrs.has_next(card_index)) {
jbyte* card_ptr = (jbyte*)bs->byte_for_index(card_index);
if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
*card_ptr = CardTableModRefBS::dirty_card_val();
_dcq.enqueue(card_ptr);
}
}
r->rem_set()->clear_locked();
}
assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
g1h->register_humongous_region_with_in_cset_fast_test(region_idx);
_candidate_humongous++;
}
@ -3511,23 +3545,32 @@ class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure {
size_t total_humongous() const { return _total_humongous; }
size_t candidate_humongous() const { return _candidate_humongous; }
void flush_rem_set_entries() { _dcq.flush(); }
};
void G1CollectedHeap::register_humongous_regions_with_in_cset_fast_test() {
if (!G1ReclaimDeadHumongousObjectsAtYoungGC) {
g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0, 0);
if (!G1EagerReclaimHumongousObjects) {
g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0.0, 0, 0);
return;
}
double time = os::elapsed_counter();
RegisterHumongousWithInCSetFastTestClosure cl;
heap_region_iterate(&cl);
g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(cl.total_humongous(),
time = ((double)(os::elapsed_counter() - time) / os::elapsed_frequency()) * 1000.0;
g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(time,
cl.total_humongous(),
cl.candidate_humongous());
_has_humongous_reclaim_candidates = cl.candidate_humongous() > 0;
if (_has_humongous_reclaim_candidates || G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
if (_has_humongous_reclaim_candidates || G1TraceEagerReclaimHumongousObjects) {
clear_humongous_is_live_table();
}
// Finally flush all remembered set entries to re-check into the global DCQS.
cl.flush_rem_set_entries();
}
void
@ -6140,22 +6183,20 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure {
// are completely up-to-date wrt to references to the humongous object.
//
// Other implementation considerations:
// - never consider object arrays: while they are a valid target, they have not
// been observed to be used as temporary objects.
// - they would also pose considerable effort for cleaning up the the remembered
// sets.
// While this cleanup is not strictly necessary to be done (or done instantly),
// given that their occurrence is very low, this saves us this additional
// complexity.
// - never consider object arrays at this time because they would pose
// considerable effort for cleaning up the the remembered sets. This is
// required because stale remembered sets might reference locations that
// are currently allocated into.
uint region_idx = r->hrm_index();
if (g1h->humongous_is_live(region_idx) ||
g1h->humongous_region_is_always_live(region_idx)) {
if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
gclog_or_tty->print_cr("Live humongous %d region %d size "SIZE_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
r->is_humongous(),
if (G1TraceEagerReclaimHumongousObjects) {
gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
region_idx,
obj->size()*HeapWordSize,
r->bottom(),
r->region_num(),
r->rem_set()->occupied(),
r->rem_set()->strong_code_roots_list_length(),
next_bitmap->isMarked(r->bottom()),
@ -6171,12 +6212,11 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure {
err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.",
r->bottom()));
if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
gclog_or_tty->print_cr("Reclaim humongous region %d size "SIZE_FORMAT" start "PTR_FORMAT" region %d length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
r->is_humongous(),
if (G1TraceEagerReclaimHumongousObjects) {
gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
region_idx,
obj->size()*HeapWordSize,
r->bottom(),
region_idx,
r->region_num(),
r->rem_set()->occupied(),
r->rem_set()->strong_code_roots_list_length(),
@ -6213,8 +6253,8 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure {
void G1CollectedHeap::eagerly_reclaim_humongous_regions() {
assert_at_safepoint(true);
if (!G1ReclaimDeadHumongousObjectsAtYoungGC ||
(!_has_humongous_reclaim_candidates && !G1TraceReclaimDeadHumongousObjectsAtYoungGC)) {
if (!G1EagerReclaimHumongousObjects ||
(!_has_humongous_reclaim_candidates && !G1TraceEagerReclaimHumongousObjects)) {
g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms(0.0, 0);
return;
}

View File

@ -186,32 +186,14 @@ class G1CollectedHeap : public SharedHeap {
friend class SurvivorGCAllocRegion;
friend class OldGCAllocRegion;
friend class G1Allocator;
friend class G1DefaultAllocator;
friend class G1ResManAllocator;
// Closures used in implementation.
template <G1Barrier barrier, G1Mark do_mark_object>
friend class G1ParCopyClosure;
friend class G1IsAliveClosure;
friend class G1EvacuateFollowersClosure;
friend class G1ParScanThreadState;
friend class G1ParScanClosureSuper;
friend class G1ParEvacuateFollowersClosure;
friend class G1ParTask;
friend class G1ParGCAllocator;
friend class G1DefaultParGCAllocator;
friend class G1FreeGarbageRegionClosure;
friend class RefineCardTableEntryClosure;
friend class G1PrepareCompactClosure;
friend class RegionSorter;
friend class RegionResetter;
friend class CountRCClosure;
friend class EvacPopObjClosure;
friend class G1ParCleanupCTTask;
friend class G1FreeHumongousRegionClosure;
// Other related classes.
friend class G1MarkSweep;
friend class HeapRegionClaimer;
// Testing classes.
@ -659,6 +641,9 @@ public:
// Returns whether the given region (which must be a humongous (start) region)
// is to be considered conservatively live regardless of any other conditions.
bool humongous_region_is_always_live(uint index);
// Returns whether the given region (which must be a humongous (start) region)
// is considered a candidate for eager reclamation.
bool humongous_region_is_candidate(uint index);
// Register the given region to be part of the collection set.
inline void register_humongous_region_with_in_cset_fast_test(uint index);
// Register regions with humongous objects (actually on the start region) in

View File

@ -344,11 +344,14 @@ void G1GCPhaseTimes::print(double pause_time_sec) {
_last_redirty_logged_cards_time_ms.print(3, "Parallel Redirty");
_last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards");
}
if (G1ReclaimDeadHumongousObjectsAtYoungGC) {
print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
if (G1EagerReclaimHumongousObjects) {
print_stats(2, "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms);
if (G1Log::finest()) {
print_stats(3, "Humongous Total", _cur_fast_reclaim_humongous_total);
print_stats(3, "Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
}
print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
if (G1Log::finest()) {
print_stats(3, "Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed);
}
}

View File

@ -157,6 +157,7 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
double _recorded_non_young_free_cset_time_ms;
double _cur_fast_reclaim_humongous_time_ms;
double _cur_fast_reclaim_humongous_register_time_ms;
size_t _cur_fast_reclaim_humongous_total;
size_t _cur_fast_reclaim_humongous_candidates;
size_t _cur_fast_reclaim_humongous_reclaimed;
@ -283,7 +284,8 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
_recorded_non_young_free_cset_time_ms = time_ms;
}
void record_fast_reclaim_humongous_stats(size_t total, size_t candidates) {
void record_fast_reclaim_humongous_stats(double time_ms, size_t total, size_t candidates) {
_cur_fast_reclaim_humongous_register_time_ms = time_ms;
_cur_fast_reclaim_humongous_total = total;
_cur_fast_reclaim_humongous_candidates = candidates;
}

View File

@ -270,10 +270,14 @@
product(uintx, G1MixedGCCountTarget, 8, \
"The target number of mixed GCs after a marking cycle.") \
\
experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true, \
experimental(bool, G1EagerReclaimHumongousObjects, true, \
"Try to reclaim dead large objects at every young GC.") \
\
experimental(bool, G1TraceReclaimDeadHumongousObjectsAtYoungGC, false, \
experimental(bool, G1EagerReclaimHumongousObjectsWithStaleRefs, true, \
"Try to reclaim dead large objects that have a few stale " \
"references at every young GC.") \
\
experimental(bool, G1TraceEagerReclaimHumongousObjects, false, \
"Print some information about large object liveness " \
"at every young GC.") \
\

View File

@ -681,6 +681,18 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
clear_fcc();
}
bool OtherRegionsTable::occupancy_less_or_equal_than(size_t limit) const {
if (limit <= (size_t)G1RSetSparseRegionEntries) {
return occ_coarse() == 0 && _first_all_fine_prts == NULL && occ_sparse() <= limit;
} else {
// Current uses of this method may only use values less than G1RSetSparseRegionEntries
// for the limit. The solution, comparing against occupied() would be too slow
// at this time.
Unimplemented();
return false;
}
}
bool OtherRegionsTable::is_empty() const {
return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL;
}

View File

@ -183,6 +183,10 @@ public:
// Returns whether the remembered set contains the given reference.
bool contains_reference(OopOrNarrowOopStar from) const;
// Returns whether this remembered set (and all sub-sets) have an occupancy
// that is less or equal than the given occupancy.
bool occupancy_less_or_equal_than(size_t limit) const;
// Removes any entries shown by the given bitmaps to contain only dead
// objects. Not thread safe.
// Set bits in the bitmaps indicate that the given region or card is live.
@ -261,6 +265,10 @@ public:
return (strong_code_roots_list_length() == 0) && _other_regions.is_empty();
}
bool occupancy_less_or_equal_than(size_t occ) const {
return (strong_code_roots_list_length() == 0) && _other_regions.occupancy_less_or_equal_than(occ);
}
size_t occupied() {
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
return occupied_locked();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -422,7 +422,7 @@ VirtualSpaceNode::VirtualSpaceNode(size_t bytes) : _top(NULL), _next(NULL), _rs(
bool large_pages = false; // No large pages when dumping the CDS archive.
char* shared_base = (char*)align_ptr_up((char*)SharedBaseAddress, Metaspace::reserve_alignment());
_rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages, shared_base, 0);
_rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages, shared_base);
if (_rs.is_reserved()) {
assert(shared_base == 0 || _rs.base() == shared_base, "should match");
} else {
@ -3025,7 +3025,7 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a
ReservedSpace metaspace_rs = ReservedSpace(compressed_class_space_size(),
_reserve_alignment,
large_pages,
requested_addr, 0);
requested_addr);
if (!metaspace_rs.is_reserved()) {
#if INCLUDE_CDS
if (UseSharedSpaces) {
@ -3039,7 +3039,7 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a
can_use_cds_with_metaspace_addr(addr + increment, cds_base)) {
addr = addr + increment;
metaspace_rs = ReservedSpace(compressed_class_space_size(),
_reserve_alignment, large_pages, addr, 0);
_reserve_alignment, large_pages, addr);
}
}
#endif

View File

@ -48,6 +48,8 @@ int MetaspaceShared::_max_alignment = 0;
ReservedSpace* MetaspaceShared::_shared_rs = NULL;
MetaspaceSharedStats MetaspaceShared::_stats;
bool MetaspaceShared::_link_classes_made_progress;
bool MetaspaceShared::_check_classes_made_progress;
bool MetaspaceShared::_has_error_classes;
@ -259,7 +261,7 @@ public:
#define SHAREDSPACE_OBJ_TYPES_DO(f) \
METASPACE_OBJ_TYPES_DO(f) \
f(SymbolHashentry) \
f(SymbolBuckets) \
f(SymbolBucket) \
f(Other)
#define SHAREDSPACE_OBJ_TYPE_DECLARE(name) name ## Type,
@ -315,18 +317,16 @@ void DumpAllocClosure::dump_stats(int ro_all, int rw_all, int md_all, int mc_all
int other_bytes = md_all + mc_all;
// Calculate size of data that was not allocated by Metaspace::allocate()
int symbol_count = _counts[RO][MetaspaceObj::SymbolType];
int symhash_bytes = symbol_count * sizeof (HashtableEntry<Symbol*, mtSymbol>);
int symbuck_count = SymbolTable::the_table()->table_size();
int symbuck_bytes = symbuck_count * sizeof(HashtableBucket<mtSymbol>);
MetaspaceSharedStats *stats = MetaspaceShared::stats();
_counts[RW][SymbolHashentryType] = symbol_count;
_bytes [RW][SymbolHashentryType] = symhash_bytes;
other_bytes -= symhash_bytes;
// symbols
_counts[RW][SymbolHashentryType] = stats->symbol.hashentry_count;
_bytes [RW][SymbolHashentryType] = stats->symbol.hashentry_bytes;
other_bytes -= stats->symbol.hashentry_bytes;
_counts[RW][SymbolBucketsType] = symbuck_count;
_bytes [RW][SymbolBucketsType] = symbuck_bytes;
other_bytes -= symbuck_bytes;
_counts[RW][SymbolBucketType] = stats->symbol.bucket_count;
_bytes [RW][SymbolBucketType] = stats->symbol.bucket_bytes;
other_bytes -= stats->symbol.bucket_bytes;
// TODO: count things like dictionary, vtable, etc
_bytes[RW][OtherType] = other_bytes;
@ -424,6 +424,13 @@ public:
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
void doit(); // outline because gdb sucks
private:
void handle_misc_data_space_failure(bool success) {
if (!success) {
report_out_of_shared_space(SharedMiscData);
}
}
}; // class VM_PopulateDumpSharedSpace
@ -517,9 +524,8 @@ void VM_PopulateDumpSharedSpace::doit() {
// buckets first [read-write], then copy the linked lists of entries
// [read-only].
SymbolTable::reverse(md_top);
NOT_PRODUCT(SymbolTable::verify());
SymbolTable::copy_buckets(&md_top, md_end);
handle_misc_data_space_failure(SymbolTable::copy_compact_table(&md_top, md_end));
SystemDictionary::reverse();
SystemDictionary::copy_buckets(&md_top, md_end);
@ -528,7 +534,6 @@ void VM_PopulateDumpSharedSpace::doit() {
ClassLoader::copy_package_info_buckets(&md_top, md_end);
ClassLoader::verify();
SymbolTable::copy_table(&md_top, md_end);
SystemDictionary::copy_table(&md_top, md_end);
ClassLoader::verify();
ClassLoader::copy_package_info_table(&md_top, md_end);
@ -1000,17 +1005,12 @@ void MetaspaceShared::initialize_shared_spaces() {
buffer += sizeof(intptr_t);
buffer += vtable_size;
// Create the symbol table using the bucket array at this spot in the
// misc data space. Since the symbol table is often modified, this
// region (of mapped pages) will be copy-on-write.
// Create the shared symbol table using the bucket array at this spot in the
// misc data space. (Todo: move this to read-only space. Currently
// this is mapped copy-on-write but will never be written into).
int symbolTableLen = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
int number_of_entries = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
SymbolTable::create_table((HashtableBucket<mtSymbol>*)buffer, symbolTableLen,
number_of_entries);
buffer += symbolTableLen;
buffer = (char*)SymbolTable::init_shared_table(buffer);
SymbolTable::create_table();
// Create the shared dictionary using the bucket array at this spot in
// the misc data space. Since the shared dictionary table is never
@ -1019,7 +1019,7 @@ void MetaspaceShared::initialize_shared_spaces() {
int sharedDictionaryLen = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
number_of_entries = *(intptr_t*)buffer;
int number_of_entries = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
SystemDictionary::set_shared_dictionary((HashtableBucket<mtClass>*)buffer,
sharedDictionaryLen,
@ -1041,18 +1041,10 @@ void MetaspaceShared::initialize_shared_spaces() {
ClassLoader::verify();
// The following data in the shared misc data region are the linked
// list elements (HashtableEntry objects) for the symbol table, string
// table, and shared dictionary. The heap objects referred to by the
// symbol table, string table, and shared dictionary are permanent and
// unmovable. Since new entries added to the string and symbol tables
// are always added at the beginning of the linked lists, THESE LINKED
// LIST ELEMENTS ARE READ-ONLY.
// list elements (HashtableEntry objects) for the shared dictionary
// and package info table.
int len = *(intptr_t*)buffer; // skip over symbol table entries
buffer += sizeof(intptr_t);
buffer += len;
len = *(intptr_t*)buffer; // skip over shared dictionary entries
int len = *(intptr_t*)buffer; // skip over shared dictionary entries
buffer += sizeof(intptr_t);
buffer += len;

View File

@ -24,6 +24,7 @@
#ifndef SHARE_VM_MEMORY_METASPACE_SHARED_HPP
#define SHARE_VM_MEMORY_METASPACE_SHARED_HPP
#include "classfile/compactHashtable.hpp"
#include "memory/allocation.hpp"
#include "memory/memRegion.hpp"
#include "runtime/virtualspace.hpp"
@ -45,12 +46,21 @@
class FileMapInfo;
class MetaspaceSharedStats VALUE_OBJ_CLASS_SPEC {
public:
MetaspaceSharedStats() {
memset(this, 0, sizeof(*this));
}
CompactHashtableStats symbol;
};
// Class Data Sharing Support
class MetaspaceShared : AllStatic {
// CDS support
static ReservedSpace* _shared_rs;
static int _max_alignment;
static MetaspaceSharedStats _stats;
static bool _link_classes_made_progress;
static bool _check_classes_made_progress;
static bool _has_error_classes;
@ -123,6 +133,10 @@ class MetaspaceShared : AllStatic {
char** mc_top, char* mc_end);
static void serialize(SerializeClosure* sc);
static MetaspaceSharedStats* stats() {
return &_stats;
}
// JVM/TI RedefineClasses() support:
// Remap the shared readonly space to shared readwrite, private if
// sharing is enabled. Simply returns true if sharing is not enabled

View File

@ -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
@ -694,103 +694,6 @@ jint universe_init() {
// NarrowOopHeapBaseMin + heap_size < 32Gb
// HeapBased - Use compressed oops with heap base + encoding.
// 4Gb
static const uint64_t UnscaledOopHeapMax = (uint64_t(max_juint) + 1);
// 32Gb
// OopEncodingHeapMax == UnscaledOopHeapMax << LogMinObjAlignmentInBytes;
char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) {
assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be");
assert(is_size_aligned((size_t)UnscaledOopHeapMax, alignment), "Must be");
assert(is_size_aligned(heap_size, alignment), "Must be");
uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment);
size_t base = 0;
#ifdef _LP64
if (UseCompressedOops) {
assert(mode == UnscaledNarrowOop ||
mode == ZeroBasedNarrowOop ||
mode == HeapBasedNarrowOop, "mode is invalid");
const size_t total_size = heap_size + heap_base_min_address_aligned;
// Return specified base for the first request.
if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) {
base = heap_base_min_address_aligned;
// If the total size is small enough to allow UnscaledNarrowOop then
// just use UnscaledNarrowOop.
} else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop)) {
if ((total_size <= UnscaledOopHeapMax) && (mode == UnscaledNarrowOop) &&
(Universe::narrow_oop_shift() == 0)) {
// Use 32-bits oops without encoding and
// place heap's top on the 4Gb boundary
base = (UnscaledOopHeapMax - heap_size);
} else {
// Can't reserve with NarrowOopShift == 0
Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
if (mode == UnscaledNarrowOop ||
mode == ZeroBasedNarrowOop && total_size <= UnscaledOopHeapMax) {
// Use zero based compressed oops with encoding and
// place heap's top on the 32Gb boundary in case
// total_size > 4Gb or failed to reserve below 4Gb.
uint64_t heap_top = OopEncodingHeapMax;
// For small heaps, save some space for compressed class pointer
// space so it can be decoded with no base.
if (UseCompressedClassPointers && !UseSharedSpaces &&
OopEncodingHeapMax <= 32*G) {
uint64_t class_space = align_size_up(CompressedClassSpaceSize, alignment);
assert(is_size_aligned((size_t)OopEncodingHeapMax-class_space,
alignment), "difference must be aligned too");
uint64_t new_top = OopEncodingHeapMax-class_space;
if (total_size <= new_top) {
heap_top = new_top;
}
}
// Align base to the adjusted top of the heap
base = heap_top - heap_size;
}
}
} else {
// UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or
// HeapBasedNarrowOop encoding was requested. So, can't reserve below 32Gb.
Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
}
// Set narrow_oop_base and narrow_oop_use_implicit_null_checks
// used in ReservedHeapSpace() constructors.
// The final values will be set in initialize_heap() below.
if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax)) {
// Use zero based compressed oops
Universe::set_narrow_oop_base(NULL);
// Don't need guard page for implicit checks in indexed
// addressing mode with zero based Compressed Oops.
Universe::set_narrow_oop_use_implicit_null_checks(true);
} else {
// Set to a non-NULL value so the ReservedSpace ctor computes
// the correct no-access prefix.
// The final value will be set in initialize_heap() below.
Universe::set_narrow_oop_base((address)UnscaledOopHeapMax);
#if defined(_WIN64) || defined(AIX)
if (UseLargePages) {
// Cannot allocate guard pages for implicit checks in indexed
// addressing mode when large pages are specified on windows.
Universe::set_narrow_oop_use_implicit_null_checks(false);
}
#endif // _WIN64
}
}
#endif
assert(is_ptr_aligned((char*)base, alignment), "Must be");
return (char*)base; // also return NULL (don't care) for 32-bit VM
}
jint Universe::initialize_heap() {
if (UseParallelGC) {
@ -844,30 +747,13 @@ jint Universe::initialize_heap() {
// See needs_explicit_null_check.
// Only set the heap base for compressed oops because it indicates
// compressed oops for pstack code.
if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax)) {
// Can't reserve heap below 32Gb.
// keep the Universe::narrow_oop_base() set in Universe::reserve_heap()
if ((uint64_t)Universe::heap()->reserved_region().end() > UnscaledOopHeapMax) {
// Didn't reserve heap below 4Gb. Must shift.
Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
#ifdef AIX
// There is no protected page before the heap. This assures all oops
// are decoded so that NULL is preserved, so this page will not be accessed.
Universe::set_narrow_oop_use_implicit_null_checks(false);
#endif
} else {
}
if ((uint64_t)Universe::heap()->reserved_region().end() <= OopEncodingHeapMax) {
// Did reserve heap below 32Gb. Can use base == 0;
Universe::set_narrow_oop_base(0);
#ifdef _WIN64
if (!Universe::narrow_oop_use_implicit_null_checks()) {
// Don't need guard page for implicit checks in indexed addressing
// mode with zero based Compressed Oops.
Universe::set_narrow_oop_use_implicit_null_checks(true);
}
#endif // _WIN64
if((uint64_t)Universe::heap()->reserved_region().end() > UnscaledOopHeapMax) {
// Can't reserve heap below 4Gb.
Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
} else {
Universe::set_narrow_oop_shift(0);
}
}
Universe::set_narrow_ptrs_base(Universe::narrow_oop_base());
@ -875,6 +761,11 @@ jint Universe::initialize_heap() {
if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) {
Universe::print_compressed_oops_mode();
}
// Tell tests in which mode we run.
Arguments::PropertyList_add(new SystemProperty("java.vm.compressedOopsMode",
narrow_oop_mode_to_string(narrow_oop_mode()),
false));
}
// Universe::narrow_oop_base() is one page below the heap.
assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() -
@ -903,22 +794,27 @@ void Universe::print_compressed_oops_mode() {
tty->print(", Compressed Oops mode: %s", narrow_oop_mode_to_string(narrow_oop_mode()));
if (Universe::narrow_oop_base() != 0) {
tty->print(":" PTR_FORMAT, Universe::narrow_oop_base());
tty->print(": " PTR_FORMAT, Universe::narrow_oop_base());
}
if (Universe::narrow_oop_shift() != 0) {
tty->print(", Oop shift amount: %d", Universe::narrow_oop_shift());
}
if (!Universe::narrow_oop_use_implicit_null_checks()) {
tty->print(", no protected page in front of the heap");
}
tty->cr();
tty->cr();
}
// Reserve the Java heap, which is now the same for all GCs.
ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) {
assert(alignment <= Arguments::conservative_max_heap_alignment(),
err_msg("actual alignment "SIZE_FORMAT" must be within maximum heap alignment "SIZE_FORMAT,
alignment, Arguments::conservative_max_heap_alignment()));
size_t total_reserved = align_size_up(heap_size, alignment);
assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())),
"heap size is too big for compressed oops");
@ -928,46 +824,31 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) {
|| UseParallelGC
|| use_large_pages, "Wrong alignment to use large pages");
char* addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::UnscaledNarrowOop);
// Now create the space.
ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages);
ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr);
if (total_rs.is_reserved()) {
assert((total_reserved == total_rs.size()) && ((uintptr_t)total_rs.base() % alignment == 0),
"must be exactly of required size and alignment");
// We are good.
if (UseCompressedOops) {
if (addr != NULL && !total_rs.is_reserved()) {
// Failed to reserve at specified address - the requested memory
// region is taken already, for example, by 'java' launcher.
// Try again to reserver heap higher.
addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop);
ReservedHeapSpace total_rs0(total_reserved, alignment,
use_large_pages, addr);
if (addr != NULL && !total_rs0.is_reserved()) {
// Failed to reserve at specified address again - give up.
addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::HeapBasedNarrowOop);
assert(addr == NULL, "");
ReservedHeapSpace total_rs1(total_reserved, alignment,
use_large_pages, addr);
total_rs = total_rs1;
} else {
total_rs = total_rs0;
}
if (UseCompressedOops) {
// Universe::initialize_heap() will reset this to NULL if unscaled
// or zero-based narrow oops are actually used.
// Else heap start and base MUST differ, so that NULL can be encoded nonambigous.
Universe::set_narrow_oop_base((address)total_rs.compressed_oop_base());
}
}
if (!total_rs.is_reserved()) {
vm_exit_during_initialization(err_msg("Could not reserve enough space for " SIZE_FORMAT "KB object heap", total_reserved/K));
return total_rs;
}
if (UseCompressedOops) {
// Universe::initialize_heap() will reset this to NULL if unscaled
// or zero-based narrow oops are actually used.
address base = (address)(total_rs.base() - os::vm_page_size());
Universe::set_narrow_oop_base(base);
}
return total_rs;
vm_exit_during_initialization(
err_msg("Could not reserve enough space for " SIZE_FORMAT "KB object heap",
total_reserved/K));
// satisfy compiler
ShouldNotReachHere();
return ReservedHeapSpace(0, 0, false);
}
@ -985,6 +866,8 @@ const char* Universe::narrow_oop_mode_to_string(Universe::NARROW_OOP_MODE mode)
return "32-bit";
case ZeroBasedNarrowOop:
return "Zero based";
case DisjointBaseNarrowOop:
return "Non-zero disjoint base";
case HeapBasedNarrowOop:
return "Non-zero based";
}
@ -995,6 +878,10 @@ const char* Universe::narrow_oop_mode_to_string(Universe::NARROW_OOP_MODE mode)
Universe::NARROW_OOP_MODE Universe::narrow_oop_mode() {
if (narrow_oop_base_disjoint()) {
return DisjointBaseNarrowOop;
}
if (narrow_oop_base() != 0) {
return HeapBasedNarrowOop;
}
@ -1176,9 +1063,7 @@ bool universe_post_init() {
MemoryService::set_universe_heap(Universe::_collectedHeap);
#if INCLUDE_CDS
if (UseSharedSpaces) {
SharedClassUtil::initialize(CHECK_false);
}
SharedClassUtil::initialize(CHECK_false);
#endif
return true;
}
@ -1189,119 +1074,6 @@ void Universe::compute_base_vtable_size() {
}
// %%% The Universe::flush_foo methods belong in CodeCache.
// Flushes compiled methods dependent on dependee.
void Universe::flush_dependents_on(instanceKlassHandle dependee) {
assert_lock_strong(Compile_lock);
if (CodeCache::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 (CodeCache::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 Universe::flush_dependents_on(Handle call_site, Handle method_handle) {
assert_lock_strong(Compile_lock);
if (CodeCache::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 Universe::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 (CodeCache::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 (CodeCache::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)
CodeCache::make_marked_nmethods_not_entrant();
}
}
#endif // HOTSWAP
// Flushes compiled methods dependent on dependee
void Universe::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 (CodeCache::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)
CodeCache::make_marked_nmethods_not_entrant();
}
}
void Universe::print() {
print_on(gclog_or_tty);
}

View File

@ -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
@ -102,8 +102,8 @@ class Universe: AllStatic {
friend class MarkSweep;
friend class oopDesc;
friend class ClassLoader;
friend class Arguments;
friend class SystemDictionary;
friend class ReservedHeapSpace;
friend class VMStructs;
friend class VM_PopulateDumpSharedSpace;
friend class Metaspace;
@ -351,17 +351,40 @@ class Universe: AllStatic {
// NarrowOopHeapBaseMin + heap_size < 4Gb
// 1 - Use zero based compressed oops with encoding when
// NarrowOopHeapBaseMin + heap_size < 32Gb
// 2 - Use compressed oops with heap base + encoding.
// 2 - Use compressed oops with disjoint heap base if
// base is 32G-aligned and base > 0. This allows certain
// optimizations in encoding/decoding.
// Disjoint: Bits used in base are disjoint from bits used
// for oops ==> oop = (cOop << 3) | base. One can disjoint
// the bits of an oop into base and compressed oop.
// 3 - Use compressed oops with heap base + encoding.
enum NARROW_OOP_MODE {
UnscaledNarrowOop = 0,
ZeroBasedNarrowOop = 1,
HeapBasedNarrowOop = 2
DisjointBaseNarrowOop = 2,
HeapBasedNarrowOop = 3,
AnyNarrowOopMode = 4
};
static NARROW_OOP_MODE narrow_oop_mode();
static const char* narrow_oop_mode_to_string(NARROW_OOP_MODE mode);
static char* preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode);
static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode);
static address narrow_oop_base() { return _narrow_oop._base; }
static address narrow_oop_base() { return _narrow_oop._base; }
// Test whether bits of addr and possible offsets into the heap overlap.
static bool is_disjoint_heap_base_address(address addr) {
return (((uint64_t)(intptr_t)addr) &
(((uint64_t)UCONST64(0xFFFFffffFFFFffff)) >> (32-LogMinObjAlignmentInBytes))) == 0;
}
// Check for disjoint base compressed oops.
static bool narrow_oop_base_disjoint() {
return _narrow_oop._base != NULL && is_disjoint_heap_base_address(_narrow_oop._base);
}
// Check for real heapbased compressed oops.
// We must subtract the base as the bits overlap.
// If we negate above function, we also get unscaled and zerobased.
static bool narrow_oop_base_overlaps() {
return _narrow_oop._base != NULL && !is_disjoint_heap_base_address(_narrow_oop._base);
}
static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); }
static int narrow_oop_shift() { return _narrow_oop._shift; }
static bool narrow_oop_use_implicit_null_checks() { return _narrow_oop._use_implicit_null_checks; }
@ -461,16 +484,6 @@ class Universe: AllStatic {
static uintptr_t verify_mark_bits() PRODUCT_RETURN0;
static uintptr_t verify_mark_mask() PRODUCT_RETURN0;
// 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);
// Compiler support
static int base_vtable_size() { return _base_vtable_size; }
};

View File

@ -51,7 +51,7 @@ class FieldStreamBase : public StackObj {
int init_generic_signature_start_slot() {
int length = _fields->length();
int num_fields = 0;
int num_fields = _index;
int skipped_generic_signature_slots = 0;
FieldInfo* fi;
AccessFlags flags;

View File

@ -3543,11 +3543,12 @@ void InstanceKlass::purge_previous_versions(InstanceKlass* ik) {
("purge: %s(%s): prev method @%d in version @%d is alive",
method->name()->as_C_string(),
method->signature()->as_C_string(), j, version));
#ifdef ASSERT
if (method->method_data() != NULL) {
// Clean out any weak method links for running methods
// (also should include not EMCP methods)
method->method_data()->clean_weak_method_links();
// Verify MethodData for running methods don't refer to old methods.
method->method_data()->verify_clean_weak_method_links();
}
#endif // ASSERT
}
}
}
@ -3561,15 +3562,17 @@ void InstanceKlass::purge_previous_versions(InstanceKlass* ik) {
deleted_count));
}
// Clean MethodData of this class's methods so they don't refer to
#ifdef ASSERT
// Verify clean MethodData for this class's methods, e.g. they don't refer to
// old methods that are no longer running.
Array<Method*>* methods = ik->methods();
int num_methods = methods->length();
for (int index2 = 0; index2 < num_methods; ++index2) {
if (methods->at(index2)->method_data() != NULL) {
methods->at(index2)->method_data()->clean_weak_method_links();
for (int index = 0; index < num_methods; ++index) {
if (methods->at(index)->method_data() != NULL) {
methods->at(index)->method_data()->verify_clean_weak_method_links();
}
}
#endif // ASSERT
}
void InstanceKlass::mark_newly_obsolete_methods(Array<Method*>* old_methods,

View File

@ -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
@ -100,17 +100,21 @@ void klassVtable::compute_vtable_size_and_num_mirandas(
vtable_length = Universe::base_vtable_size();
}
if (super == NULL && !Universe::is_bootstrapping() &&
vtable_length != Universe::base_vtable_size()) {
// Someone is attempting to redefine java.lang.Object incorrectly. The
// only way this should happen is from
// SystemDictionary::resolve_from_stream(), which will detect this later
// and throw a security exception. So don't assert here to let
// the exception occur.
vtable_length = Universe::base_vtable_size();
if (super == NULL && vtable_length != Universe::base_vtable_size()) {
if (Universe::is_bootstrapping()) {
// Someone is attempting to override java.lang.Object incorrectly on the
// bootclasspath. The JVM cannot recover from this error including throwing
// an exception
vm_exit_during_initialization("Incompatible definition of java.lang.Object");
} else {
// Someone is attempting to redefine java.lang.Object incorrectly. The
// only way this should happen is from
// SystemDictionary::resolve_from_stream(), which will detect this later
// and throw a security exception. So don't assert here to let
// the exception occur.
vtable_length = Universe::base_vtable_size();
}
}
assert(super != NULL || vtable_length == Universe::base_vtable_size(),
"bad vtable size for class Object");
assert(vtable_length % vtableEntry::size() == 0, "bad vtable length");
assert(vtable_length >= Universe::base_vtable_size(), "vtable too small");

View File

@ -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
@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "code/debugInfoRec.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/bytecodeStream.hpp"
@ -1727,7 +1728,7 @@ void BreakpointInfo::set(Method* method) {
// Deoptimize all dependents on this method
HandleMark hm(thread);
methodHandle mh(thread, method);
Universe::flush_dependents_on_method(mh);
CodeCache::flush_dependents_on_method(mh);
}
}

View File

@ -1283,6 +1283,11 @@ ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_mi
DataLayout::compute_size_in_bytes(SpeculativeTrapData::static_cell_count()),
"code needs to be adjusted");
// Do not create one of these if method has been redefined.
if (m != NULL && m->is_old()) {
return NULL;
}
DataLayout* dp = extra_data_base();
DataLayout* end = args_data_limit();
@ -1554,9 +1559,7 @@ public:
class CleanExtraDataMethodClosure : public CleanExtraDataClosure {
public:
CleanExtraDataMethodClosure() {}
bool is_live(Method* m) {
return !m->is_old() || m->on_stack();
}
bool is_live(Method* m) { return !m->is_old(); }
};
@ -1658,3 +1661,16 @@ void MethodData::clean_weak_method_links() {
clean_extra_data(&cl);
verify_extra_data_clean(&cl);
}
#ifdef ASSERT
void MethodData::verify_clean_weak_method_links() {
for (ProfileData* data = first_data();
is_valid(data);
data = next_data(data)) {
data->verify_clean_weak_method_links();
}
CleanExtraDataMethodClosure cl;
verify_extra_data_clean(&cl);
}
#endif // ASSERT

View File

@ -254,6 +254,7 @@ public:
// Redefinition support
void clean_weak_method_links();
DEBUG_ONLY(void verify_clean_weak_method_links();)
};
@ -511,6 +512,7 @@ public:
// Redefinition support
virtual void clean_weak_method_links() {}
DEBUG_ONLY(virtual void verify_clean_weak_method_links() {})
// CI translation: ProfileData can represent both MethodDataOop data
// as well as CIMethodData data. This function is provided for translating
@ -1971,6 +1973,7 @@ public:
}
void set_method(Method* m) {
assert(!m->is_old(), "cannot add old methods");
set_intptr_at(speculative_trap_method, (intptr_t)m);
}
@ -2480,6 +2483,7 @@ public:
void clean_method_data(BoolObjectClosure* is_alive);
void clean_weak_method_links();
DEBUG_ONLY(void verify_clean_weak_method_links();)
Mutex* extra_data_lock() { return &_extra_data_lock; }
};

View File

@ -669,6 +669,13 @@
product_pd(bool, TrapBasedRangeChecks, \
"Generate code for range checks that uses a cmp and trap " \
"instruction raising SIGTRAP. Used on PPC64.") \
\
product(intx, ArrayCopyLoadStoreMaxElem, 8, \
"Maximum number of arraycopy elements inlined as a sequence of" \
"loads/stores") \
\
develop(bool, StressArrayCopyMacroNode, false, \
"Perform ArrayCopy load/store replacement during IGVN only")
C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG)

View File

@ -39,6 +39,9 @@ const char* C2Compiler::retry_no_subsuming_loads() {
const char* C2Compiler::retry_no_escape_analysis() {
return "retry without escape analysis";
}
const char* C2Compiler::retry_class_loading_during_parsing() {
return "retry class loading during parsing";
}
bool C2Compiler::init_c2_runtime() {
// Check assumptions used while running ADLC
@ -104,6 +107,10 @@ void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
// Check result and retry if appropriate.
if (C.failure_reason() != NULL) {
if (C.failure_reason_is(retry_class_loading_during_parsing())) {
env->report_failure(C.failure_reason());
continue; // retry
}
if (C.failure_reason_is(retry_no_subsuming_loads())) {
assert(subsume_loads, "must make progress");
subsume_loads = false;

View File

@ -47,6 +47,7 @@ public:
// sentinel value used to trigger backtracking in compile_method().
static const char* retry_no_subsuming_loads();
static const char* retry_no_escape_analysis();
static const char* retry_class_loading_during_parsing();
// Print compilation timers and statistics
void print_timers();

View File

@ -28,6 +28,7 @@
#include "opto/callGenerator.hpp"
#include "opto/callnode.hpp"
#include "opto/castnode.hpp"
#include "opto/convertnode.hpp"
#include "opto/escape.hpp"
#include "opto/locknode.hpp"
#include "opto/machnode.hpp"
@ -1818,7 +1819,10 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
}
ArrayCopyNode::ArrayCopyNode(Compile* C, bool alloc_tightly_coupled)
: CallNode(arraycopy_type(), NULL, TypeRawPtr::BOTTOM), _alloc_tightly_coupled(alloc_tightly_coupled), _kind(ArrayCopy) {
: CallNode(arraycopy_type(), NULL, TypeRawPtr::BOTTOM),
_alloc_tightly_coupled(alloc_tightly_coupled),
_kind(None),
_arguments_validated(false) {
init_class_id(Class_ArrayCopy);
init_flags(Flag_is_macro);
C->add_macro_node(this);
@ -1870,3 +1874,136 @@ void ArrayCopyNode::dump_spec(outputStream *st) const {
st->print(" (%s%s)", _kind_names[_kind], _alloc_tightly_coupled ? ", tightly coupled allocation" : "");
}
#endif
int ArrayCopyNode::get_count(PhaseGVN *phase) const {
Node* src = in(ArrayCopyNode::Src);
const Type* src_type = phase->type(src);
assert(is_clonebasic(), "unexpected arraycopy type");
if (src_type->isa_instptr()) {
const TypeInstPtr* inst_src = src_type->is_instptr();
ciInstanceKlass* ik = inst_src->klass()->as_instance_klass();
// ciInstanceKlass::nof_nonstatic_fields() doesn't take injected
// fields into account. They are rare anyway so easier to simply
// skip instances with injected fields.
if ((!inst_src->klass_is_exact() && (ik->is_interface() || ik->has_subklass())) || ik->has_injected_fields()) {
return -1;
}
int nb_fields = ik->nof_nonstatic_fields();
return nb_fields;
}
return -1;
}
Node* ArrayCopyNode::try_clone_instance(PhaseGVN *phase, bool can_reshape, int count) {
assert(is_clonebasic(), "unexpected arraycopy type");
Node* src = in(ArrayCopyNode::Src);
Node* dest = in(ArrayCopyNode::Dest);
Node* ctl = in(TypeFunc::Control);
Node* in_mem = in(TypeFunc::Memory);
const Type* src_type = phase->type(src);
const Type* dest_type = phase->type(dest);
assert(src->is_AddP(), "should be base + off");
assert(dest->is_AddP(), "should be base + off");
Node* base_src = src->in(AddPNode::Base);
Node* base_dest = dest->in(AddPNode::Base);
MergeMemNode* mem = MergeMemNode::make(in_mem);
const TypeInstPtr* inst_src = src_type->is_instptr();
if (!inst_src->klass_is_exact()) {
ciInstanceKlass* ik = inst_src->klass()->as_instance_klass();
assert(!ik->is_interface() && !ik->has_subklass(), "inconsistent klass hierarchy");
phase->C->dependencies()->assert_leaf_type(ik);
}
ciInstanceKlass* ik = inst_src->klass()->as_instance_klass();
assert(ik->nof_nonstatic_fields() <= ArrayCopyLoadStoreMaxElem, "too many fields");
for (int i = 0; i < count; i++) {
ciField* field = ik->nonstatic_field_at(i);
int fieldidx = phase->C->alias_type(field)->index();
const TypePtr* adr_type = phase->C->alias_type(field)->adr_type();
Node* off = phase->MakeConX(field->offset());
Node* next_src = phase->transform(new AddPNode(base_src,base_src,off));
Node* next_dest = phase->transform(new AddPNode(base_dest,base_dest,off));
BasicType bt = field->layout_type();
const Type *type;
if (bt == T_OBJECT) {
if (!field->type()->is_loaded()) {
type = TypeInstPtr::BOTTOM;
} else {
ciType* field_klass = field->type();
type = TypeOopPtr::make_from_klass(field_klass->as_klass());
}
} else {
type = Type::get_const_basic_type(bt);
}
Node* v = LoadNode::make(*phase, ctl, mem->memory_at(fieldidx), next_src, adr_type, type, bt, MemNode::unordered);
v = phase->transform(v);
Node* s = StoreNode::make(*phase, ctl, mem->memory_at(fieldidx), next_dest, adr_type, v, bt, MemNode::unordered);
s = phase->transform(s);
mem->set_memory_at(fieldidx, s);
}
if (!finish_transform(phase, can_reshape, ctl, mem)) {
return NULL;
}
return mem;
}
bool ArrayCopyNode::finish_transform(PhaseGVN *phase, bool can_reshape,
Node* ctl, Node *mem) {
if (can_reshape) {
PhaseIterGVN* igvn = phase->is_IterGVN();
assert(is_clonebasic(), "unexpected arraycopy type");
Node* out_mem = proj_out(TypeFunc::Memory);
if (out_mem->outcnt() != 1 || !out_mem->raw_out(0)->is_MergeMem() ||
out_mem->raw_out(0)->outcnt() != 1 || !out_mem->raw_out(0)->raw_out(0)->is_MemBar()) {
assert(!GraphKit::use_ReduceInitialCardMarks(), "can only happen with card marking");
return false;
}
igvn->replace_node(out_mem->raw_out(0), mem);
Node* out_ctl = proj_out(TypeFunc::Control);
igvn->replace_node(out_ctl, ctl);
}
return true;
}
Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (StressArrayCopyMacroNode && !can_reshape) return NULL;
// See if it's a small array copy and we can inline it as
// loads/stores
// Here we can only do:
// - clone for which we don't need to do card marking
if (!is_clonebasic()) {
return NULL;
}
if (in(TypeFunc::Control)->is_top() || in(TypeFunc::Memory)->is_top()) {
return NULL;
}
int count = get_count(phase);
if (count < 0 || count > ArrayCopyLoadStoreMaxElem) {
return NULL;
}
Node* mem = try_clone_instance(phase, can_reshape, count);
return mem;
}

View File

@ -1070,8 +1070,8 @@ private:
// What kind of arraycopy variant is this?
enum {
None, // not set yet
ArrayCopy, // System.arraycopy()
ArrayCopyNoTest, // System.arraycopy(), all arguments validated
CloneBasic, // A clone that can be copied by 64 bit chunks
CloneOop, // An oop array clone
CopyOf, // Arrays.copyOf()
@ -1095,6 +1095,8 @@ private:
// LibraryCallKit::tightly_coupled_allocation() is called.
bool _alloc_tightly_coupled;
bool _arguments_validated;
static const TypeFunc* arraycopy_type() {
const Type** fields = TypeTuple::fields(ParmLimit - TypeFunc::Parms);
fields[Src] = TypeInstPtr::BOTTOM;
@ -1118,6 +1120,13 @@ private:
ArrayCopyNode(Compile* C, bool alloc_tightly_coupled);
int get_count(PhaseGVN *phase) const;
static const TypePtr* get_address_type(PhaseGVN *phase, Node* n);
Node* try_clone_instance(PhaseGVN *phase, bool can_reshape, int count);
bool finish_transform(PhaseGVN *phase, bool can_reshape,
Node* ctl, Node *mem);
public:
enum {
@ -1143,23 +1152,23 @@ public:
void connect_outputs(GraphKit* kit);
bool is_arraycopy() const { return _kind == ArrayCopy; }
bool is_arraycopy_notest() const { return _kind == ArrayCopyNoTest; }
bool is_clonebasic() const { return _kind == CloneBasic; }
bool is_cloneoop() const { return _kind == CloneOop; }
bool is_copyof() const { return _kind == CopyOf; }
bool is_copyofrange() const { return _kind == CopyOfRange; }
bool is_arraycopy() const { assert(_kind != None, "should bet set"); return _kind == ArrayCopy; }
bool is_arraycopy_validated() const { assert(_kind != None, "should bet set"); return _kind == ArrayCopy && _arguments_validated; }
bool is_clonebasic() const { assert(_kind != None, "should bet set"); return _kind == CloneBasic; }
bool is_cloneoop() const { assert(_kind != None, "should bet set"); return _kind == CloneOop; }
bool is_copyof() const { assert(_kind != None, "should bet set"); return _kind == CopyOf; }
bool is_copyofrange() const { assert(_kind != None, "should bet set"); return _kind == CopyOfRange; }
void set_arraycopy() { _kind = ArrayCopy; }
void set_arraycopy_notest() { _kind = ArrayCopyNoTest; }
void set_clonebasic() { _kind = CloneBasic; }
void set_cloneoop() { _kind = CloneOop; }
void set_copyof() { _kind = CopyOf; }
void set_copyofrange() { _kind = CopyOfRange; }
void set_arraycopy(bool validated) { assert(_kind == None, "shouldn't bet set yet"); _kind = ArrayCopy; _arguments_validated = validated; }
void set_clonebasic() { assert(_kind == None, "shouldn't bet set yet"); _kind = CloneBasic; }
void set_cloneoop() { assert(_kind == None, "shouldn't bet set yet"); _kind = CloneOop; }
void set_copyof() { assert(_kind == None, "shouldn't bet set yet"); _kind = CopyOf; _arguments_validated = false; }
void set_copyofrange() { assert(_kind == None, "shouldn't bet set yet"); _kind = CopyOfRange; _arguments_validated = false; }
virtual int Opcode() const;
virtual uint size_of() const; // Size is bigger
virtual bool guaranteed_safepoint() { return false; }
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
bool is_alloc_tightly_coupled() const { return _alloc_tightly_coupled; }

View File

@ -774,7 +774,9 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
}
JVMState* jvms = build_start_state(start(), tf());
if ((jvms = cg->generate(jvms)) == NULL) {
record_method_not_compilable("method parse failed");
if (!failure_reason_is(C2Compiler::retry_class_loading_during_parsing())) {
record_method_not_compilable("method parse failed");
}
return;
}
GraphKit kit(jvms);

View File

@ -4475,8 +4475,11 @@ void LibraryCallKit::copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, b
ArrayCopyNode* ac = ArrayCopyNode::make(this, false, src, NULL, dest, NULL, countx, false);
ac->set_clonebasic();
Node* n = _gvn.transform(ac);
assert(n == ac, "cannot disappear");
set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type);
if (n == ac) {
set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type);
} else {
set_all_memory(n);
}
// If necessary, emit some card marks afterwards. (Non-arrays only.)
if (card_mark) {
@ -4541,6 +4544,26 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
Node* obj = null_check_receiver();
if (stopped()) return true;
const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
// If we are going to clone an instance, we need its exact type to
// know the number and types of fields to convert the clone to
// loads/stores. Maybe a speculative type can help us.
if (!obj_type->klass_is_exact() &&
obj_type->speculative_type() != NULL &&
obj_type->speculative_type()->is_instance_klass()) {
ciInstanceKlass* spec_ik = obj_type->speculative_type()->as_instance_klass();
if (spec_ik->nof_nonstatic_fields() <= ArrayCopyLoadStoreMaxElem &&
!spec_ik->has_injected_fields()) {
ciKlass* k = obj_type->klass();
if (!k->is_instance_klass() ||
k->as_instance_klass()->is_interface() ||
k->as_instance_klass()->has_subklass()) {
obj = maybe_cast_profiled_obj(obj, obj_type->speculative_type(), false);
}
}
}
Node* obj_klass = load_object_klass(obj);
const TypeKlassPtr* tklass = _gvn.type(obj_klass)->isa_klassptr();
const TypeOopPtr* toop = ((tklass != NULL)
@ -4743,7 +4766,7 @@ bool LibraryCallKit::inline_arraycopy() {
sfpt->set_memory(map()->memory());
}
bool notest = false;
bool validated = false;
const Type* src_type = _gvn.type(src);
const Type* dest_type = _gvn.type(dest);
@ -4847,7 +4870,7 @@ bool LibraryCallKit::inline_arraycopy() {
if (!too_many_traps(Deoptimization::Reason_intrinsic) && !src->is_top() && !dest->is_top()) {
// validate arguments: enables transformation the ArrayCopyNode
notest = true;
validated = true;
RegionNode* slow_region = new RegionNode(1);
record_for_igvn(slow_region);
@ -4922,13 +4945,15 @@ bool LibraryCallKit::inline_arraycopy() {
load_object_klass(src), load_object_klass(dest),
load_array_length(src), load_array_length(dest));
if (notest) {
ac->set_arraycopy_notest();
}
ac->set_arraycopy(validated);
Node* n = _gvn.transform(ac);
assert(n == ac, "cannot disappear");
ac->connect_outputs(this);
if (n == ac) {
ac->connect_outputs(this);
} else {
assert(validated, "shouldn't transform if all arguments not validated");
set_all_memory(n);
}
return true;
}

View File

@ -519,7 +519,8 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode*
// Test S[] against D[], not S against D, because (probably)
// the secondary supertype cache is less busy for S[] than S.
// This usually only matters when D is an interface.
Node* not_subtype_ctrl = ac->is_arraycopy_notest() ? top() : Phase::gen_subtype_check(src_klass, dest_klass, ctrl, mem, &_igvn);
Node* not_subtype_ctrl = ac->is_arraycopy_validated() ? top() :
Phase::gen_subtype_check(src_klass, dest_klass, ctrl, mem, &_igvn);
// Plug failing path into checked_oop_disjoint_arraycopy
if (not_subtype_ctrl != top()) {
Node* local_ctrl = not_subtype_ctrl;
@ -1109,7 +1110,7 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) {
assert(alloc != NULL, "expect alloc");
}
assert(ac->is_arraycopy() || ac->is_arraycopy_notest(), "should be an arraycopy");
assert(ac->is_arraycopy() || ac->is_arraycopy_validated(), "should be an arraycopy");
// Compile time checks. If any of these checks cannot be verified at compile time,
// we do not make a fast path for this call. Instead, we let the call remain as it
@ -1191,7 +1192,7 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) {
RegionNode* slow_region = new RegionNode(1);
transform_later(slow_region);
if (!ac->is_arraycopy_notest()) {
if (!ac->is_arraycopy_validated()) {
// (3) operands must not be null
// We currently perform our null checks with the null_check routine.
// This means that the null exceptions will be reported in the caller

View File

@ -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
@ -433,6 +433,13 @@ public:
// NullCheck oop_reg
//
inline static bool gen_narrow_oop_implicit_null_checks() {
// Advice matcher to perform null checks on the narrow oop side.
// Implicit checks are not possible on the uncompressed oop side anyway
// (at least not for read accesses).
// Performs significantly better (especially on Power 6).
if (!os::zero_page_read_protected()) {
return true;
}
return Universe::narrow_oop_use_implicit_null_checks() &&
(narrow_oop_use_complex_address() ||
Universe::narrow_oop_base() != NULL);

View File

@ -27,6 +27,7 @@
#include "interpreter/linkResolver.hpp"
#include "oops/method.hpp"
#include "opto/addnode.hpp"
#include "opto/c2compiler.hpp"
#include "opto/castnode.hpp"
#include "opto/idealGraphPrinter.hpp"
#include "opto/locknode.hpp"
@ -986,7 +987,18 @@ void Parse::do_exits() {
if (tf()->range()->cnt() > TypeFunc::Parms) {
const Type* ret_type = tf()->range()->field_at(TypeFunc::Parms);
Node* ret_phi = _gvn.transform( _exits.argument(0) );
assert(_exits.control()->is_top() || !_gvn.type(ret_phi)->empty(), "return value must be well defined");
if (!_exits.control()->is_top() && _gvn.type(ret_phi)->empty()) {
// In case of concurrent class loading, the type we set for the
// ret_phi in build_exits() may have been too optimistic and the
// ret_phi may be top now.
#ifdef ASSERT
{
MutexLockerEx ml(Compile_lock, Mutex::_no_safepoint_check_flag);
assert(ret_type->isa_ptr() && C->env()->system_dictionary_modification_counter_changed(), "return value must be well defined");
}
#endif
C->record_failure(C2Compiler::retry_class_loading_during_parsing());
}
_exits.push_node(ret_type->basic_type(), ret_phi);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -148,6 +148,10 @@ void VM_RedefineClasses::doit() {
_scratch_classes[i] = NULL;
}
// Clean out MethodData pointing to old Method*
MethodDataCleaner clean_weak_method_links;
ClassLoaderDataGraph::classes_do(&clean_weak_method_links);
// Disable any dependent concurrent compilations
SystemDictionary::notice_modification();
@ -155,8 +159,8 @@ void VM_RedefineClasses::doit() {
// See jvmtiExport.hpp for detailed explanation.
JvmtiExport::set_has_redefined_a_class();
// check_class() is optionally called for product bits, but is
// always called for non-product bits.
// check_class() is optionally called for product bits, but is
// always called for non-product bits.
#ifdef PRODUCT
if (RC_TRACE_ENABLED(0x00004000)) {
#endif
@ -3445,6 +3449,22 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
}
}
// Clean method data for this class
void VM_RedefineClasses::MethodDataCleaner::do_klass(Klass* k) {
if (k->oop_is_instance()) {
InstanceKlass *ik = InstanceKlass::cast(k);
// Clean MethodData of this class's methods so they don't refer to
// old methods that are no longer running.
Array<Method*>* methods = ik->methods();
int num_methods = methods->length();
for (int index = 0; index < num_methods; ++index) {
if (methods->at(index)->method_data() != NULL) {
methods->at(index)->method_data()->clean_weak_method_links();
}
}
}
}
void VM_RedefineClasses::update_jmethod_ids() {
for (int j = 0; j < _matching_methods_length; ++j) {
Method* old_method = _matching_old_methods[j];
@ -3746,7 +3766,7 @@ void VM_RedefineClasses::flush_dependent_code(instanceKlassHandle k_h, TRAPS) {
// All dependencies have been recorded from startup or this is a second or
// subsequent use of RedefineClasses
if (JvmtiExport::all_dependencies_are_recorded()) {
Universe::flush_evol_dependents_on(k_h);
CodeCache::flush_evol_dependents_on(k_h);
} else {
CodeCache::mark_all_nmethods_for_deoptimization();

View File

@ -511,6 +511,12 @@ class VM_RedefineClasses: public VM_Operation {
void do_klass(Klass* k);
};
// Clean MethodData out
class MethodDataCleaner : public KlassClosure {
public:
MethodDataCleaner() {}
void do_klass(Klass* k);
};
public:
VM_RedefineClasses(jint class_count,
const jvmtiClassDefinition *class_defs,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 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/stringTable.hpp"
#include "code/codeCache.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/oopMapCache.hpp"
@ -1245,7 +1246,7 @@ JVM_ENTRY(void, MHN_setCallSiteTargetNormal(JNIEnv* env, jobject igcls, jobject
{
// Walk all nmethods depending on this call site.
MutexLocker mu(Compile_lock, thread);
Universe::flush_dependents_on(call_site, target);
CodeCache::flush_dependents_on(call_site, target);
java_lang_invoke_CallSite::set_target(call_site(), target());
}
}
@ -1257,7 +1258,7 @@ JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobjec
{
// Walk all nmethods depending on this call site.
MutexLocker mu(Compile_lock, thread);
Universe::flush_dependents_on(call_site, target);
CodeCache::flush_dependents_on(call_site, target);
java_lang_invoke_CallSite::set_target_volatile(call_site(), target());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -176,11 +176,11 @@ WB_END
WB_ENTRY(void, WB_ReadFromNoaccessArea(JNIEnv* env, jobject o))
size_t granularity = os::vm_allocation_granularity();
ReservedHeapSpace rhs(100 * granularity, granularity, false, NULL);
ReservedHeapSpace rhs(100 * granularity, granularity, false);
VirtualSpace vs;
vs.initialize(rhs, 50 * granularity);
//Check if constraints are complied
// Check if constraints are complied
if (!( UseCompressedOops && rhs.base() != NULL &&
Universe::narrow_oop_base() != NULL &&
Universe::narrow_oop_use_implicit_null_checks() )) {
@ -203,7 +203,7 @@ WB_END
static jint wb_stress_virtual_space_resize(size_t reserved_space_size,
size_t magnitude, size_t iterations) {
size_t granularity = os::vm_allocation_granularity();
ReservedHeapSpace rhs(reserved_space_size * granularity, granularity, false, NULL);
ReservedHeapSpace rhs(reserved_space_size * granularity, granularity, false);
VirtualSpace vs;
if (!vs.initialize(rhs, 0)) {
tty->print_cr("Failed to initialize VirtualSpace. Can't proceed.");
@ -1123,6 +1123,16 @@ WB_ENTRY(void, WB_AssertMatchingSafepointCalls(JNIEnv* env, jobject o, jboolean
attemptedNoSafepointValue == JNI_TRUE);
WB_END
WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj))
oop obj_oop = JNIHandles::resolve(obj);
return (jboolean) obj_oop->mark()->has_monitor();
WB_END
WB_ENTRY(void, WB_ForceSafepoint(JNIEnv* env, jobject wb))
VM_ForceSafepoint force_safepoint_op;
VMThread::execute(&force_safepoint_op);
WB_END
//Some convenience methods to deal with objects from java
int WhiteBox::offset_for_field(const char* field_name, oop object,
Symbol* signature_symbol) {
@ -1321,6 +1331,8 @@ static JNINativeMethod methods[] = {
{CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize },
{CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize },
{CC"assertMatchingSafepointCalls", CC"(ZZ)V", (void*)&WB_AssertMatchingSafepointCalls },
{CC"isMonitorInflated", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated },
{CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint },
};
#undef CC

View File

@ -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
@ -1522,15 +1522,6 @@ void Arguments::set_use_compressed_oops() {
FLAG_SET_ERGO(bool, UseCompressedOops, true);
}
#endif
#ifdef _WIN64
if (UseLargePages && UseCompressedOops) {
// Cannot allocate guard pages for implicit checks in indexed addressing
// mode, when large pages are specified on windows.
// This flag could be switched ON if narrow oop base address is set to 0,
// see code in Universe::initialize_heap().
Universe::set_narrow_oop_use_implicit_null_checks(false);
}
#endif // _WIN64
} else {
if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) {
warning("Max heap size too large for Compressed Oops");
@ -2416,6 +2407,7 @@ bool Arguments::check_vm_args_consistency() {
#ifdef COMPILER1
status = status && verify_min_value(ValueMapInitialSize, 1, "ValueMapInitialSize");
#endif
status = status && verify_min_value(HeapSearchSteps, 1, "HeapSearchSteps");
if (PrintNMTStatistics) {
#if INCLUDE_NMT
@ -4102,6 +4094,10 @@ void Arguments::PropertyList_add(SystemProperty** plist, const char* k, char* v)
PropertyList_add(plist, new_p);
}
void Arguments::PropertyList_add(SystemProperty *element) {
PropertyList_add(&_system_properties, element);
}
// This add maintains unique property key in the list.
void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append) {
if (plist == NULL)

View File

@ -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
@ -572,6 +572,7 @@ class Arguments : AllStatic {
static void init_version_specific_system_properties();
// Property List manipulation
static void PropertyList_add(SystemProperty *element);
static void PropertyList_add(SystemProperty** plist, SystemProperty *element);
static void PropertyList_add(SystemProperty** plist, const char* k, char* v);
static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {

View File

@ -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
@ -531,6 +531,11 @@ class CommandLineFlags {
product_pd(uintx, HeapBaseMinAddress, \
"OS specific low limit for heap base address") \
\
product(uintx, HeapSearchSteps, 3 PPC64_ONLY(+17), \
"Heap allocation steps through preferred address regions to find" \
" where it can allocate the heap. Number of steps to take per " \
"region.") \
\
diagnostic(bool, PrintCompressedOopsMode, false, \
"Print compressed oops base address and encoding mode") \
\
@ -3779,6 +3784,9 @@ class CommandLineFlags {
NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \
"Address to allocate shared memory region for class data") \
\
product(uintx, SharedSymbolTableBucketSize, 4, \
"Average number of symbols per bucket in shared table") \
\
diagnostic(bool, IgnoreUnverifiableClassesDuringDump, false, \
"Do not quit -Xshare:dump even if we encounter unverifiable " \
"classes. Just exclude them from the shared dictionary.") \

View File

@ -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
@ -43,21 +43,19 @@ ReservedSpace::ReservedSpace(size_t size) {
// Don't force the alignment to be large page aligned,
// since that will waste memory.
size_t alignment = os::vm_allocation_granularity();
initialize(size, alignment, large_pages, NULL, 0, false);
initialize(size, alignment, large_pages, NULL, false);
}
ReservedSpace::ReservedSpace(size_t size, size_t alignment,
bool large,
char* requested_address,
const size_t noaccess_prefix) {
initialize(size+noaccess_prefix, alignment, large, requested_address,
noaccess_prefix, false);
char* requested_address) {
initialize(size, alignment, large, requested_address, false);
}
ReservedSpace::ReservedSpace(size_t size, size_t alignment,
bool large,
bool executable) {
initialize(size, alignment, large, NULL, 0, executable);
initialize(size, alignment, large, NULL, executable);
}
// Helper method.
@ -91,7 +89,6 @@ static bool failed_to_reserve_as_requested(char* base, char* requested_address,
void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
char* requested_address,
const size_t noaccess_prefix,
bool executable) {
const size_t granularity = os::vm_allocation_granularity();
assert((size & (granularity - 1)) == 0,
@ -103,10 +100,6 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
alignment = MAX2(alignment, (size_t)os::vm_page_size());
// Assert that if noaccess_prefix is used, it is the same as alignment.
assert(noaccess_prefix == 0 ||
noaccess_prefix == alignment, "noaccess prefix wrong");
_base = NULL;
_size = 0;
_special = false;
@ -122,11 +115,6 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
bool special = large && !os::can_commit_large_page_memory();
char* base = NULL;
if (requested_address != 0) {
requested_address -= noaccess_prefix; // adjust requested address
assert(requested_address != NULL, "huge noaccess prefix?");
}
if (special) {
base = os::reserve_memory_special(size, alignment, requested_address, executable);
@ -176,7 +164,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
if (base == NULL) return;
// Check alignment constraints
if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) {
if ((((size_t)base) & (alignment - 1)) != 0) {
// Base not aligned, retry
if (!os::release_memory(base, size)) fatal("os::release_memory failed");
// Make sure that size is aligned
@ -197,16 +185,6 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
_base = base;
_size = size;
_alignment = alignment;
_noaccess_prefix = noaccess_prefix;
// Assert that if noaccess_prefix is used, it is the same as alignment.
assert(noaccess_prefix == 0 ||
noaccess_prefix == _alignment, "noaccess prefix wrong");
assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base,
"area must be distinguishable from marks for mark-sweep");
assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size],
"area must be distinguishable from marks for mark-sweep");
}
@ -276,54 +254,336 @@ void ReservedSpace::release() {
_base = NULL;
_size = 0;
_noaccess_prefix = 0;
_alignment = 0;
_special = false;
_executable = false;
}
}
void ReservedSpace::protect_noaccess_prefix(const size_t size) {
assert( (_noaccess_prefix != 0) == (UseCompressedOops && _base != NULL &&
(Universe::narrow_oop_base() != NULL) &&
Universe::narrow_oop_use_implicit_null_checks()),
"noaccess_prefix should be used only with non zero based compressed oops");
static size_t noaccess_prefix_size(size_t alignment) {
return lcm(os::vm_page_size(), alignment);
}
// If there is no noaccess prefix, return.
if (_noaccess_prefix == 0) return;
void ReservedHeapSpace::establish_noaccess_prefix() {
assert(_alignment >= (size_t)os::vm_page_size(), "must be at least page size big");
_noaccess_prefix = noaccess_prefix_size(_alignment);
assert(_noaccess_prefix >= (size_t)os::vm_page_size(),
"must be at least page size big");
// Protect memory at the base of the allocated region.
// If special, the page was committed (only matters on windows)
if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE,
_special)) {
fatal("cannot protect protection page");
}
if (PrintCompressedOopsMode) {
tty->cr();
tty->print_cr("Protected page at the reserved heap base: " PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix);
if (base() && base() + _size > (char *)OopEncodingHeapMax) {
if (true
WIN64_ONLY(&& !UseLargePages)
AIX_ONLY(&& os::vm_page_size() != SIZE_64K)) {
// Protect memory at the base of the allocated region.
// If special, the page was committed (only matters on windows)
if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, _special)) {
fatal("cannot protect protection page");
}
if (PrintCompressedOopsMode) {
tty->cr();
tty->print_cr("Protected page at the reserved heap base: "
PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix);
}
assert(Universe::narrow_oop_use_implicit_null_checks() == true, "not initialized?");
} else {
Universe::set_narrow_oop_use_implicit_null_checks(false);
}
}
_base += _noaccess_prefix;
_size -= _noaccess_prefix;
assert((size == _size) && ((uintptr_t)_base % _alignment == 0),
"must be exactly of required size and alignment");
assert(((uintptr_t)_base % _alignment == 0), "must be exactly of required alignment");
}
ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment,
bool large, char* requested_address) :
ReservedSpace(size, alignment, large,
requested_address,
(UseCompressedOops && (Universe::narrow_oop_base() != NULL) &&
Universe::narrow_oop_use_implicit_null_checks()) ?
lcm(os::vm_page_size(), alignment) : 0) {
// Tries to allocate memory of size 'size' at address requested_address with alignment 'alignment'.
// Does not check whether the reserved memory actually is at requested_address, as the memory returned
// might still fulfill the wishes of the caller.
// Assures the memory is aligned to 'alignment'.
// NOTE: If ReservedHeapSpace already points to some reserved memory this is freed, first.
void ReservedHeapSpace::try_reserve_heap(size_t size,
size_t alignment,
bool large,
char* requested_address) {
if (_base != NULL) {
// We tried before, but we didn't like the address delivered.
release();
}
// If OS doesn't support demand paging for large page memory, we need
// to use reserve_memory_special() to reserve and pin the entire region.
bool special = large && !os::can_commit_large_page_memory();
char* base = NULL;
if (PrintCompressedOopsMode && Verbose) {
tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " PTR_FORMAT ".\n",
requested_address, (address)size);
}
if (special) {
base = os::reserve_memory_special(size, alignment, requested_address, false);
if (base != NULL) {
// Check alignment constraints.
assert((uintptr_t) base % alignment == 0,
err_msg("Large pages returned a non-aligned address, base: "
PTR_FORMAT " alignment: " PTR_FORMAT,
base, (void*)(uintptr_t)alignment));
_special = true;
}
}
if (base == NULL) {
// Failed; try to reserve regular memory below
if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes))) {
if (PrintCompressedOopsMode) {
tty->cr();
tty->print_cr("Reserve regular memory without large pages.");
}
}
// Optimistically assume that the OSes returns an aligned base pointer.
// When reserving a large address range, most OSes seem to align to at
// least 64K.
// If the memory was requested at a particular address, use
// os::attempt_reserve_memory_at() to avoid over mapping something
// important. If available space is not detected, return NULL.
if (requested_address != 0) {
base = os::attempt_reserve_memory_at(size, requested_address);
} else {
base = os::reserve_memory(size, NULL, alignment);
}
}
if (base == NULL) { return; }
// Done
_base = base;
_size = size;
_alignment = alignment;
// Check alignment constraints
if ((((size_t)base) & (alignment - 1)) != 0) {
// Base not aligned, retry.
release();
}
}
void ReservedHeapSpace::try_reserve_range(char *highest_start,
char *lowest_start,
size_t attach_point_alignment,
char *aligned_heap_base_min_address,
char *upper_bound,
size_t size,
size_t alignment,
bool large) {
const size_t attach_range = highest_start - lowest_start;
// Cap num_attempts at possible number.
// At least one is possible even for 0 sized attach range.
const uint64_t num_attempts_possible = (attach_range / attach_point_alignment) + 1;
const uint64_t num_attempts_to_try = MIN2((uint64_t)HeapSearchSteps, num_attempts_possible);
const size_t stepsize = (attach_range == 0) ? // Only one try.
(size_t) highest_start : align_size_up(attach_range / num_attempts_to_try, attach_point_alignment);
// Try attach points from top to bottom.
char* attach_point = highest_start;
while (attach_point >= lowest_start &&
attach_point <= highest_start && // Avoid wrap around.
((_base == NULL) ||
(_base < aligned_heap_base_min_address || _base + size > upper_bound))) {
try_reserve_heap(size, alignment, large, attach_point);
attach_point -= stepsize;
}
}
#define SIZE_64K ((uint64_t) UCONST64( 0x10000))
#define SIZE_256M ((uint64_t) UCONST64( 0x10000000))
#define SIZE_32G ((uint64_t) UCONST64( 0x800000000))
// Helper for heap allocation. Returns an array with addresses
// (OS-specific) which are suited for disjoint base mode. Array is
// NULL terminated.
static char** get_attach_addresses_for_disjoint_mode() {
static uint64_t addresses[] = {
2 * SIZE_32G,
3 * SIZE_32G,
4 * SIZE_32G,
8 * SIZE_32G,
10 * SIZE_32G,
1 * SIZE_64K * SIZE_32G,
2 * SIZE_64K * SIZE_32G,
3 * SIZE_64K * SIZE_32G,
4 * SIZE_64K * SIZE_32G,
16 * SIZE_64K * SIZE_32G,
32 * SIZE_64K * SIZE_32G,
34 * SIZE_64K * SIZE_32G,
0
};
// Sort out addresses smaller than HeapBaseMinAddress. This assumes
// the array is sorted.
uint i = 0;
while (addresses[i] != 0 &&
(addresses[i] < OopEncodingHeapMax || addresses[i] < HeapBaseMinAddress)) {
i++;
}
uint start = i;
// Avoid more steps than requested.
i = 0;
while (addresses[start+i] != 0) {
if (i == HeapSearchSteps) {
addresses[start+i] = 0;
break;
}
i++;
}
return (char**) &addresses[start];
}
void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t alignment, bool large) {
guarantee(size + noaccess_prefix_size(alignment) <= OopEncodingHeapMax,
"can not allocate compressed oop heap for this size");
guarantee(alignment == MAX2(alignment, (size_t)os::vm_page_size()), "alignment too small");
assert(HeapBaseMinAddress > 0, "sanity");
const size_t granularity = os::vm_allocation_granularity();
assert((size & (granularity - 1)) == 0,
"size not aligned to os::vm_allocation_granularity()");
assert((alignment & (granularity - 1)) == 0,
"alignment not aligned to os::vm_allocation_granularity()");
assert(alignment == 0 || is_power_of_2((intptr_t)alignment),
"not a power of 2");
// The necessary attach point alignment for generated wish addresses.
// This is needed to increase the chance of attaching for mmap and shmat.
const size_t os_attach_point_alignment =
AIX_ONLY(SIZE_256M) // Known shm boundary alignment.
NOT_AIX(os::vm_allocation_granularity());
const size_t attach_point_alignment = lcm(alignment, os_attach_point_alignment);
char *aligned_heap_base_min_address = (char *)align_ptr_up((void *)HeapBaseMinAddress, alignment);
size_t noaccess_prefix = ((aligned_heap_base_min_address + size) > (char*)OopEncodingHeapMax) ?
noaccess_prefix_size(alignment) : 0;
// Attempt to alloc at user-given address.
if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) {
try_reserve_heap(size + noaccess_prefix, alignment, large, aligned_heap_base_min_address);
if (_base != aligned_heap_base_min_address) { // Enforce this exact address.
release();
}
}
// Keep heap at HeapBaseMinAddress.
if (_base == NULL) {
// Try to allocate the heap at addresses that allow efficient oop compression.
// Different schemes are tried, in order of decreasing optimization potential.
//
// For this, try_reserve_heap() is called with the desired heap base addresses.
// A call into the os layer to allocate at a given address can return memory
// at a different address than requested. Still, this might be memory at a useful
// address. try_reserve_heap() always returns this allocated memory, as only here
// the criteria for a good heap are checked.
// Attempt to allocate so that we can run without base and scale (32-Bit unscaled compressed oops).
// Give it several tries from top of range to bottom.
if (aligned_heap_base_min_address + size <= (char *)UnscaledOopHeapMax) {
// Calc address range within we try to attach (range of possible start addresses).
char* const highest_start = (char *)align_ptr_down((char *)UnscaledOopHeapMax - size, attach_point_alignment);
char* const lowest_start = (char *)align_ptr_up ( aligned_heap_base_min_address , attach_point_alignment);
try_reserve_range(highest_start, lowest_start, attach_point_alignment,
aligned_heap_base_min_address, (char *)UnscaledOopHeapMax, size, alignment, large);
}
// zerobased: Attempt to allocate in the lower 32G.
// But leave room for the compressed class pointers, which is allocated above
// the heap.
char *zerobased_max = (char *)OopEncodingHeapMax;
// For small heaps, save some space for compressed class pointer
// space so it can be decoded with no base.
if (UseCompressedClassPointers && !UseSharedSpaces &&
OopEncodingHeapMax <= KlassEncodingMetaspaceMax) {
const size_t class_space = align_size_up(CompressedClassSpaceSize, alignment);
zerobased_max = (char *)OopEncodingHeapMax - class_space;
}
// Give it several tries from top of range to bottom.
if (aligned_heap_base_min_address + size <= zerobased_max && // Zerobased theoretical possible.
((_base == NULL) || // No previous try succeeded.
(_base + size > zerobased_max))) { // Unscaled delivered an arbitrary address.
// Calc address range within we try to attach (range of possible start addresses).
char *const highest_start = (char *)align_ptr_down(zerobased_max - size, attach_point_alignment);
// SS10 and SS12u1 cannot compile "(char *)UnscaledOopHeapMax - size" on solaris sparc 32-bit:
// "Cannot use int to initialize char*." Introduce aux variable.
char *unscaled_end = (char *)UnscaledOopHeapMax;
unscaled_end -= size;
char *lowest_start = (size < UnscaledOopHeapMax) ?
MAX2(unscaled_end, aligned_heap_base_min_address) : aligned_heap_base_min_address;
lowest_start = (char *)align_ptr_up(lowest_start, attach_point_alignment);
try_reserve_range(highest_start, lowest_start, attach_point_alignment,
aligned_heap_base_min_address, zerobased_max, size, alignment, large);
}
// Now we go for heaps with base != 0. We need a noaccess prefix to efficiently
// implement null checks.
noaccess_prefix = noaccess_prefix_size(alignment);
// Try to attach at addresses that are aligned to OopEncodingHeapMax. Disjointbase mode.
char** addresses = get_attach_addresses_for_disjoint_mode();
int i = 0;
while (addresses[i] && // End of array not yet reached.
((_base == NULL) || // No previous try succeeded.
(_base + size > (char *)OopEncodingHeapMax && // Not zerobased or unscaled address.
!Universe::is_disjoint_heap_base_address((address)_base)))) { // Not disjoint address.
char* const attach_point = addresses[i];
assert(attach_point >= aligned_heap_base_min_address, "Flag support broken");
try_reserve_heap(size + noaccess_prefix, alignment, large, attach_point);
i++;
}
// Last, desperate try without any placement.
if (_base == NULL) {
if (PrintCompressedOopsMode && Verbose) {
tty->print("Trying to allocate at address NULL heap of size " PTR_FORMAT ".\n", (address)size + noaccess_prefix);
}
initialize(size + noaccess_prefix, alignment, large, NULL, false);
}
}
}
ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large) : ReservedSpace() {
if (size == 0) {
return;
}
// Heap size should be aligned to alignment, too.
guarantee(is_size_aligned(size, alignment), "set by caller");
if (UseCompressedOops) {
initialize_compressed_heap(size, alignment, large);
if (_size > size) {
// We allocated heap with noaccess prefix.
// It can happen we get a zerobased/unscaled heap with noaccess prefix,
// if we had to try at arbitrary address.
establish_noaccess_prefix();
}
} else {
initialize(size, alignment, large, NULL, false);
}
assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base,
"area must be distinguishable from marks for mark-sweep");
assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size],
"area must be distinguishable from marks for mark-sweep");
if (base() > 0) {
MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap);
}
// Only reserved space for the java heap should have a noaccess_prefix
// if using compressed oops.
protect_noaccess_prefix(size);
}
// Reserve space for code segment. Same as Java heap only we mark this as
@ -791,8 +1051,7 @@ class TestReservedSpace : AllStatic {
ReservedSpace rs(size, // size
alignment, // alignment
UseLargePages, // large
NULL, // requested_address
0); // noacces_prefix
(char *)NULL); // requested_address
test_log(" rs.special() == %d", rs.special());

View File

@ -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
@ -31,33 +31,29 @@
class ReservedSpace VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
private:
protected:
char* _base;
size_t _size;
size_t _noaccess_prefix;
size_t _alignment;
bool _special;
private:
bool _executable;
// ReservedSpace
ReservedSpace(char* base, size_t size, size_t alignment, bool special,
bool executable);
protected:
void initialize(size_t size, size_t alignment, bool large,
char* requested_address,
const size_t noaccess_prefix,
bool executable);
protected:
// Create protection page at the beginning of the space.
void protect_noaccess_prefix(const size_t size);
public:
// Constructor
ReservedSpace();
ReservedSpace(size_t size);
ReservedSpace(size_t size, size_t alignment, bool large,
char* requested_address = NULL,
const size_t noaccess_prefix = 0);
char* requested_address = NULL);
ReservedSpace(size_t size, size_t alignment, bool large, bool executable);
// Accessors
@ -98,12 +94,23 @@ ReservedSpace ReservedSpace::last_part(size_t partition_size)
return last_part(partition_size, alignment());
}
// Class encapsulating behavior specific of memory space reserved for Java heap
// Class encapsulating behavior specific of memory space reserved for Java heap.
class ReservedHeapSpace : public ReservedSpace {
public:
// Constructor
ReservedHeapSpace(size_t size, size_t forced_base_alignment,
bool large, char* requested_address);
private:
void try_reserve_heap(size_t size, size_t alignment, bool large,
char *requested_address);
void try_reserve_range(char *highest_start, char *lowest_start,
size_t attach_point_alignment, char *aligned_HBMA,
char *upper_bound, size_t size, size_t alignment, bool large);
void initialize_compressed_heap(const size_t size, size_t alignment, bool large);
// Create protection page at the beginning of the space.
void establish_noaccess_prefix();
public:
// Constructor. Tries to find a heap that is good for compressed oops.
ReservedHeapSpace(size_t size, size_t forced_base_alignment, bool large);
// Returns the base to be used for compression, i.e. so that null can be
// encoded safely and implicit null checks can work.
char *compressed_oop_base() { return _base - _noaccess_prefix; }
};
// Class encapsulating behavior specific memory space for Code

View File

@ -2559,6 +2559,8 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
/**********************/ \
/* frame */ \
/**********************/ \
NOT_ZERO(PPC64_ONLY(declare_constant(frame::abi_minframe_size))) \
NOT_ZERO(PPC64_ONLY(declare_constant(frame::entry_frame_locals_size))) \
\
NOT_ZERO(X86_ONLY(declare_constant(frame::entry_frame_call_wrapper_offset))) \
declare_constant(frame::pc_return_offset) \

View File

@ -100,6 +100,7 @@
template(RotateGCLog) \
template(WhiteBoxOperation) \
template(ClassLoaderStatsOperation) \
template(DumpHashtable) \
template(MarkActiveNMethods) \
template(PrintCompileQueue) \
template(PrintCodeList) \

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderStats.hpp"
#include "classfile/compactHashtable.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
@ -56,6 +57,8 @@ void DCmdRegistrant::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SymboltableDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<StringtableDCmd>(full_export, true, false));
#endif // INCLUDE_SERVICES
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));

View File

@ -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
@ -124,9 +124,6 @@ extern int LogBitsPerHeapOop;
extern int BytesPerHeapOop;
extern int BitsPerHeapOop;
// Oop encoding heap max
extern uint64_t OopEncodingHeapMax;
const int BitsPerJavaInteger = 32;
const int BitsPerJavaLong = 64;
const int BitsPerSize_t = size_tSize * BitsPerByte;
@ -195,7 +192,6 @@ inline size_t heap_word_size(size_t byte_size) {
return (byte_size + (HeapWordSize-1)) >> LogHeapWordSize;
}
const size_t K = 1024;
const size_t M = K*K;
const size_t G = M*K;
@ -397,8 +393,17 @@ const int LogKlassAlignment = LogKlassAlignmentInBytes - LogHeapWordSize;
const int KlassAlignmentInBytes = 1 << LogKlassAlignmentInBytes;
const int KlassAlignment = KlassAlignmentInBytes / HeapWordSize;
// Klass encoding metaspace max size
const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlassAlignmentInBytes;
// Maximal size of heap where unscaled compression can be used. Also upper bound
// for heap placement: 4GB.
const uint64_t UnscaledOopHeapMax = (uint64_t(max_juint) + 1);
// Maximal size of heap where compressed oops can be used. Also upper bound for heap
// placement for zero based compression algorithm: UnscaledOopHeapMax << LogMinObjAlignmentInBytes.
extern uint64_t OopEncodingHeapMax;
// Maximal size of compressed class space. Above this limit compression is not possible.
// Also upper bound for placement of zero based class space. (Class space is further limited
// to be < 3G, see arguments.cpp.)
const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlassAlignmentInBytes;
// Machine dependent stuff

View File

@ -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.
* Copyright 2012, 2013 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -172,21 +172,21 @@ inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); }
#define offset_of(klass,field) (size_t)((intx)&(((klass*)16)->field) - 16)
// Some constant sizes used throughout the AIX port
#define SIZE_1K ((uint64_t) 0x400ULL)
#define SIZE_4K ((uint64_t) 0x1000ULL)
#define SIZE_64K ((uint64_t) 0x10000ULL)
#define SIZE_1M ((uint64_t) 0x100000ULL)
#define SIZE_4M ((uint64_t) 0x400000ULL)
#define SIZE_8M ((uint64_t) 0x800000ULL)
#define SIZE_16M ((uint64_t) 0x1000000ULL)
#define SIZE_256M ((uint64_t) 0x10000000ULL)
#define SIZE_1G ((uint64_t) 0x40000000ULL)
#define SIZE_2G ((uint64_t) 0x80000000ULL)
#define SIZE_4G ((uint64_t) 0x100000000ULL)
#define SIZE_16G ((uint64_t) 0x400000000ULL)
#define SIZE_32G ((uint64_t) 0x800000000ULL)
#define SIZE_64G ((uint64_t) 0x1000000000ULL)
#define SIZE_1T ((uint64_t) 0x10000000000ULL)
#define SIZE_1K ((uint64_t) UCONST64( 0x400))
#define SIZE_4K ((uint64_t) UCONST64( 0x1000))
#define SIZE_64K ((uint64_t) UCONST64( 0x10000))
#define SIZE_1M ((uint64_t) UCONST64( 0x100000))
#define SIZE_4M ((uint64_t) UCONST64( 0x400000))
#define SIZE_8M ((uint64_t) UCONST64( 0x800000))
#define SIZE_16M ((uint64_t) UCONST64( 0x1000000))
#define SIZE_256M ((uint64_t) UCONST64( 0x10000000))
#define SIZE_1G ((uint64_t) UCONST64( 0x40000000))
#define SIZE_2G ((uint64_t) UCONST64( 0x80000000))
#define SIZE_4G ((uint64_t) UCONST64( 0x100000000))
#define SIZE_16G ((uint64_t) UCONST64( 0x400000000))
#define SIZE_32G ((uint64_t) UCONST64( 0x800000000))
#define SIZE_64G ((uint64_t) UCONST64( 0x1000000000))
#define SIZE_1T ((uint64_t) UCONST64(0x10000000000))
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_XLC_HPP

View File

@ -145,6 +145,7 @@ needs_compact3 = \
gc/survivorAlignment \
runtime/InternalApi/ThreadCpuTimesDeadlock.java \
serviceability/threads/TestFalseDeadLock.java \
compiler/codecache/jmx
# Compact 2 adds full VM tests
compact2 = \
@ -413,6 +414,12 @@ hotspot_gc = \
gc/ \
-gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java
hotspot_gc_closed = \
sanity/ExecuteInternalVMTests.java
hotspot_gc_gcold = \
stress/gc/TestGCOld.java
hotspot_runtime = \
runtime/ \
-runtime/6888954/vmerrors.sh \
@ -444,6 +451,8 @@ hotspot_jprt = \
:hotspot_compiler_3 \
:hotspot_compiler_closed \
:hotspot_gc \
:hotspot_gc_closed \
:hotspot_gc_gcold \
:hotspot_runtime \
:hotspot_runtime_closed \
:hotspot_serviceability

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7173584
* @summary arraycopy as macro node
* @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayCopyMacro
*
*/
public class TestArrayCopyMacro {
static class A {
}
// In its own method so profiling reports both branches taken
static Object m2(Object o1, Object o2, int i) {
if (i == 4) {
return o1;
}
return o2;
}
static Object m1(A[] src, Object dest) {
int i = 1;
// won't be optimized out until after parsing
for (; i < 3; i *= 4) {
}
dest = m2(new A[10], dest, i);
// dest is new array here but C2 picks the "disjoint" stub
// only if stub to call is decided after parsing
System.arraycopy(src, 0, dest, 0, 10);
return dest;
}
public static void main(String[] args) {
A[] array_src = new A[10];
for (int i = 0; i < array_src.length; i++) {
array_src[i] = new A();
}
for (int i = 0; i < 20000; i++) {
m2(null, null, 0);
}
for (int i = 0; i < 20000; i++) {
Object[] array_dest = (Object[])m1(array_src, null);
for (int j = 0; j < array_src.length; j++) {
if (array_dest[j] != array_src[j]) {
throw new RuntimeException("copy failed at index " + j + " src = " + array_src[j] + " dest = " + array_dest[j]);
}
}
}
}
}

View File

@ -25,13 +25,13 @@
* @test
* @bug 8055910
* @summary Arrays.copyOf doesn't perform subtype check
* @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayOfNoTypeCheck
* @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArraysCopyOfNoTypeCheck
*
*/
import java.util.Arrays;
public class TestArrayOfNoTypeCheck {
public class TestArraysCopyOfNoTypeCheck {
static class A {
}

View File

@ -0,0 +1,342 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6700100
* @summary small instance clone as loads/stores
* @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestInstanceCloneAsLoadsStores::m* TestInstanceCloneAsLoadsStores
* @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestInstanceCloneAsLoadsStores::m* -XX:+IgnoreUnrecognizedVMOptions -XX:+StressArrayCopyMacroNode TestInstanceCloneAsLoadsStores
*
*/
import java.lang.reflect.*;
import java.util.*;
public class TestInstanceCloneAsLoadsStores {
static class Base implements Cloneable {
void initialize(Class c, int i) {
for (Field f : c.getDeclaredFields()) {
setVal(f, i);
i++;
}
if (c != Base.class) {
initialize(c.getSuperclass(), i);
}
}
Base() {
initialize(getClass(), 0);
}
void setVal(Field f, int i) {
try {
if (f.getType() == int.class) {
f.setInt(this, i);
return;
} else if (f.getType() == short.class) {
f.setShort(this, (short)i);
return;
} else if (f.getType() == byte.class) {
f.setByte(this, (byte)i);
return;
} else if (f.getType() == long.class) {
f.setLong(this, i);
return;
}
} catch(IllegalAccessException iae) {
throw new RuntimeException("Getting fields failed");
}
throw new RuntimeException("unexpected field type");
}
int getVal(Field f) {
try {
if (f.getType() == int.class) {
return f.getInt(this);
} else if (f.getType() == short.class) {
return (int)f.getShort(this);
} else if (f.getType() == byte.class) {
return (int)f.getByte(this);
} else if (f.getType() == long.class) {
return (int)f.getLong(this);
}
} catch(IllegalAccessException iae) {
throw new RuntimeException("Setting fields failed");
}
throw new RuntimeException("unexpected field type");
}
boolean fields_equal(Class c, Base o) {
for (Field f : c.getDeclaredFields()) {
if (getVal(f) != o.getVal(f)) {
return false;
}
}
if (c != Base.class) {
return fields_equal(c.getSuperclass(), o);
}
return true;
}
public boolean equals(Object obj) {
return fields_equal(getClass(), (Base)obj);
}
String print_fields(Class c, String s) {
for (Field f : c.getDeclaredFields()) {
if (s != "") {
s += "\n";
}
s = s + f + " = " + getVal(f);
}
if (c != Base.class) {
return print_fields(c.getSuperclass(), s);
}
return s;
}
public String toString() {
return print_fields(getClass(), "");
}
int fields_sum(Class c, int s) {
for (Field f : c.getDeclaredFields()) {
s += getVal(f);
}
if (c != Base.class) {
return fields_sum(c.getSuperclass(), s);
}
return s;
}
public int sum() {
return fields_sum(getClass(), 0);
}
}
static class A extends Base {
int i1;
int i2;
int i3;
int i4;
int i5;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class B extends A {
int i6;
}
static final class D extends Base {
byte i1;
short i2;
long i3;
int i4;
int i5;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static final class E extends Base {
int i1;
int i2;
int i3;
int i4;
int i5;
int i6;
int i7;
int i8;
int i9;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static final class F extends Base {
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class G extends Base {
int i1;
int i2;
int i3;
public Object myclone() throws CloneNotSupportedException {
return clone();
}
}
static class H extends G {
int i4;
int i5;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class J extends Base {
int i1;
int i2;
int i3;
public Object myclone() throws CloneNotSupportedException {
return clone();
}
}
static class K extends J {
int i4;
int i5;
}
// Should be compiled as loads/stores
static Object m1(D src) throws CloneNotSupportedException {
return src.clone();
}
// Should be compiled as adds of src (dest allocation eliminated)
static int m2(D src) throws CloneNotSupportedException {
D dest = (D)src.clone();
return dest.i1 + dest.i2 + ((int)dest.i3) + dest.i4 + dest.i5;
}
// Should be compiled as arraycopy stub call (object too large)
static int m3(E src) throws CloneNotSupportedException {
E dest = (E)src.clone();
return dest.i1 + dest.i2 + dest.i3 + dest.i4 + dest.i5 +
dest.i6 + dest.i7 + dest.i8 + dest.i9;
}
// Need profiling on src's type to be able to know number of
// fields. Cannot clone as loads/stores if compile doesn't use it.
static Object m4(A src) throws CloneNotSupportedException {
return src.clone();
}
// Same as above but should optimize out dest allocation
static int m5(A src) throws CloneNotSupportedException {
A dest = (A)src.clone();
return dest.i1 + dest.i2 + dest.i3 + dest.i4 + dest.i5;
}
// Check that if we have no fields to clone we do fine
static Object m6(F src) throws CloneNotSupportedException {
return src.clone();
}
// With virtual call to clone: clone inlined from profling which
// gives us exact type of src so we can clone it with
// loads/stores.
static G m7(G src) throws CloneNotSupportedException {
return (G)src.myclone();
}
// Virtual call to clone but single target: exact type unknown,
// clone intrinsic uses profiling to determine exact type and
// clone with loads/stores.
static J m8(J src) throws CloneNotSupportedException {
return (J)src.myclone();
}
final HashMap<String,Method> tests = new HashMap<>();
{
for (Method m : this.getClass().getDeclaredMethods()) {
if (m.getName().matches("m[0-9]+")) {
assert(Modifier.isStatic(m.getModifiers())) : m;
tests.put(m.getName(), m);
}
}
}
boolean success = true;
void doTest(Base src, String name) throws Exception {
Method m = tests.get(name);
for (int i = 0; i < 20000; i++) {
boolean failure = false;
Base res = null;
int s = 0;
if (m.getReturnType().isPrimitive()) {
s = (int)m.invoke(null, src);
failure = (s != src.sum());
} else {
res = (Base)m.invoke(null, src);
failure = !res.equals(src);
}
if (failure) {
System.out.println("Test " + name + " failed");
System.out.println("source: ");
System.out.println(src);
System.out.println("result: ");
if (m.getReturnType().isPrimitive()) {
System.out.println(s);
} else {
System.out.println(res);
}
success = false;
break;
}
}
}
public static void main(String[] args) throws Exception {
TestInstanceCloneAsLoadsStores test = new TestInstanceCloneAsLoadsStores();
A a = new A();
B b = new B();
D d = new D();
E e = new E();
F f = new F();
G g = new G();
H h = new H();
J j = new J();
K k = new K();
test.doTest(d, "m1");
test.doTest(d, "m2");
test.doTest(e, "m3");
test.doTest(a, "m4");
test.doTest(a, "m5");
test.doTest(f, "m6");
test.doTest(g, "m7");
test.doTest(k, "m8");
if (!test.success) {
throw new RuntimeException("some tests failed");
}
}
}

View File

@ -26,7 +26,7 @@
##
## @test
## @bug 8011675
## @ignore 8031978
## @ignore 8029528
## @summary testing of ciReplay with using generated by SA replay.txt
## @author igor.ignatyev@oracle.com
## @run shell TestSA.sh
@ -69,7 +69,6 @@ fi
echo "dumpreplaydata -a > ${replay_data}" | \
${JAVA} ${TESTOPTS} \
-cp ${TESTJAVA}${FS}lib${FS}sa-jdi.jar \
sun.jvm.hotspot.CLHSDB ${JAVA} ${core_file}
if [ ! -s ${replay_data} ]

View File

@ -263,10 +263,10 @@ generate_replay() {
dir=`dirname $core_with_dir`
file=`basename $core_with_dir`
# add <core_path>/core.<pid> core
core_locations="'$core_with_dir' '$file'"
core_locations='$core_with_dir' '$file'
if [ -n "${core_with_pid}" ]
then
core_locations="$core_locations '$core_with_pid' '$dir${FS}$core_with_pid'"
core_locations=$core_locations '$core_with_pid' '$dir${FS}$core_with_pid'
fi
fi

View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.oracle.java.testlibrary.ExitCode;
import com.oracle.java.testlibrary.Platform;
import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
import common.CodeCacheOptions;
import sun.hotspot.code.BlobType;
/**
* @test
* @bug 8015774
* @summary Verify SegmentedCodeCache option's processing
* @library /testlibrary /../../test/lib
* @build TestSegmentedCodeCacheOption com.oracle.java.testlibrary.*
* @run main TestSegmentedCodeCacheOption
*/
public class TestSegmentedCodeCacheOption {
private static final String INT_MODE = "-Xint";
private static final String TIERED_COMPILATION = "TieredCompilation";
private static final String SEGMENTED_CODE_CACHE = "SegmentedCodeCache";
private static final String USE_SEGMENTED_CODE_CACHE
= CommandLineOptionTest.prepareBooleanFlag(SEGMENTED_CODE_CACHE,
true);
private static final long THRESHOLD_CC_SIZE_VALUE
= CodeCacheOptions.mB(240);
private static final long BELOW_THRESHOLD_CC_SIZE
= THRESHOLD_CC_SIZE_VALUE - CodeCacheOptions.mB(1);
private static final String[] UNEXPECTED_MESSAGES = new String[] {
".*" + SEGMENTED_CODE_CACHE + ".*"
};
private static enum TestCase {
JVM_STARTUP {
@Override
public void run() throws Throwable {
// There should be no errors when we're trying to enable SCC ...
String testCaseWarningMessage = "JVM output should not contain "
+ "any warnings related to " + SEGMENTED_CODE_CACHE;
String testCaseExitCodeMessage = "JVM should start without any "
+ "issues with " + USE_SEGMENTED_CODE_CACHE;
CommandLineOptionTest.verifySameJVMStartup(
/* expectedMessages */ null, UNEXPECTED_MESSAGES,
testCaseExitCodeMessage, testCaseWarningMessage,
ExitCode.OK, USE_SEGMENTED_CODE_CACHE);
// ... and when we're trying to enable it w/o TieredCompilation
testCaseExitCodeMessage = "Disabled tiered compilation should "
+ "not cause startup failure w/ "
+ USE_SEGMENTED_CODE_CACHE;
CommandLineOptionTest.verifySameJVMStartup(
/* expectedMessages */ null, UNEXPECTED_MESSAGES,
testCaseExitCodeMessage, testCaseWarningMessage,
ExitCode.OK, USE_SEGMENTED_CODE_CACHE,
CommandLineOptionTest.prepareBooleanFlag(
TIERED_COMPILATION, false));
// ... and even w/ Xint.
testCaseExitCodeMessage = "It should be possible to use "
+ USE_SEGMENTED_CODE_CACHE + " in interpreted mode "
+ "without any errors.";
CommandLineOptionTest.verifyJVMStartup(
/* expected messages */ null, UNEXPECTED_MESSAGES,
testCaseExitCodeMessage, testCaseWarningMessage,
ExitCode.OK, false, INT_MODE, USE_SEGMENTED_CODE_CACHE);
}
},
OPTION_VALUES_GENERIC {
@Override
public void run() throws Throwable {
// SCC is disabled w/o TieredCompilation by default
String errorMessage = SEGMENTED_CODE_CACHE
+ " should be disabled by default when tiered "
+ "compilation is disabled";
CommandLineOptionTest.verifyOptionValueForSameVM(
SEGMENTED_CODE_CACHE, "false", errorMessage,
CommandLineOptionTest.prepareBooleanFlag(
TIERED_COMPILATION, false));
// SCC is disabled by default when ReservedCodeCacheSize is too
// small
errorMessage = String.format("%s should be disabled bu default "
+ "when %s value is too small.", SEGMENTED_CODE_CACHE,
BlobType.All.sizeOptionName);
CommandLineOptionTest.verifyOptionValueForSameVM(
SEGMENTED_CODE_CACHE, "false", errorMessage,
CommandLineOptionTest.prepareNumericFlag(
BlobType.All.sizeOptionName,
BELOW_THRESHOLD_CC_SIZE));
// SCC could be explicitly enabled w/ Xint
errorMessage = String.format("It should be possible to "
+ "explicitly enable %s in interpreted mode.",
SEGMENTED_CODE_CACHE);
CommandLineOptionTest.verifyOptionValue(SEGMENTED_CODE_CACHE,
"true", errorMessage, false, INT_MODE,
USE_SEGMENTED_CODE_CACHE);
// SCC could be explicitly enabled w/o TieredCompilation and w/
// small ReservedCodeCacheSize value
errorMessage = String.format("It should be possible to "
+ "explicitly enable %s with small %s and "
+ "disabled tiered comp.", SEGMENTED_CODE_CACHE,
BlobType.All.sizeOptionName);
CommandLineOptionTest.verifyOptionValueForSameVM(
SEGMENTED_CODE_CACHE, "true", errorMessage,
CommandLineOptionTest.prepareBooleanFlag(
TIERED_COMPILATION, false),
CommandLineOptionTest.prepareNumericFlag(
BlobType.All.sizeOptionName,
BELOW_THRESHOLD_CC_SIZE),
USE_SEGMENTED_CODE_CACHE);
}
},
OPTION_VALUES_SERVER_SPECIFIC {
@Override
public boolean isApplicable() {
return Platform.isServer() && Platform.isTieredSupported();
}
@Override
public void run() throws Throwable {
// SCC is enabled by default when TieredCompilation is on and
// ReservedCodeCacheSize is large enough
String errorMessage = String.format("Large enough %s and "
+ "enabled tiered compilation should enable %s "
+ "by default.", BlobType.All.sizeOptionName,
SEGMENTED_CODE_CACHE);
CommandLineOptionTest.verifyOptionValueForSameVM(
SEGMENTED_CODE_CACHE, "true", errorMessage,
CommandLineOptionTest.prepareNumericFlag(
BlobType.All.sizeOptionName,
THRESHOLD_CC_SIZE_VALUE),
CommandLineOptionTest.prepareBooleanFlag(
TIERED_COMPILATION, true));
}
};
TestCase() {
}
public boolean isApplicable() {
return true;
}
public abstract void run() throws Throwable;
}
public static void main(String args[]) throws Throwable {
for (TestCase testCase : TestCase.values()) {
if (testCase.isApplicable()) {
System.out.println("Running test case: " + testCase.name());
testCase.run();
} else {
System.out.println("Test case skipped: " + testCase.name());
}
}
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package codeheapsize;
import com.oracle.java.testlibrary.ExitCode;
import com.oracle.java.testlibrary.Platform;
import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
import common.CodeCacheCLITestCase;
import common.CodeCacheOptions;
import sun.hotspot.code.BlobType;
/**
* Test case runner aimed to verify that NonNMethodCodeHeapSize smaller than
* CodeCacheMinimumUseSpace cause JVM startup failure.
*/
public class CodeCacheFreeSpaceRunner implements CodeCacheCLITestCase.Runner {
private static final String CC_MIN_USE_SPACE = "CodeCacheMinimumUseSpace";
private static final String TOO_SMALL_NMETHOD_CH_ERROR
= "Invalid NonNMethodCodeHeapSize.*";
private static final long MULTIPLIER = Platform.isDebugBuild() ? 3L : 1L;
@Override
public void run(CodeCacheCLITestCase.Description testCaseDescription,
CodeCacheOptions options) throws Throwable {
long ccMinUseSpace = ((options.nonNmethods - 1) / MULTIPLIER + 1);
String exitCodeErrorMessage = String.format("JVM startup should fail "
+ "if %s's value lower then %s.",
BlobType.NonNMethod.sizeOptionName, CC_MIN_USE_SPACE);
String vmOutputErrorMessage = String.format("JVM's output should "
+ "contain appropriate error message when %s lower "
+ "then %s.", BlobType.NonNMethod.sizeOptionName,
CC_MIN_USE_SPACE);
CommandLineOptionTest.verifySameJVMStartup(
new String[]{ TOO_SMALL_NMETHOD_CH_ERROR },
/* unexpected messages */ null,
exitCodeErrorMessage, vmOutputErrorMessage, ExitCode.FAIL,
testCaseDescription.getTestOptions(options,
CommandLineOptionTest.prepareNumericFlag(
CC_MIN_USE_SPACE, ccMinUseSpace + 1)));
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package codeheapsize;
import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
import common.CodeCacheCLITestCase;
import common.CodeCacheOptions;
import sun.hotspot.code.BlobType;
/**
* Test case runner aimed to verify that all four options related to code cache
* sizing have correct values.
*/
public class GenericCodeHeapSizeRunner implements CodeCacheCLITestCase.Runner {
@Override
public void run(CodeCacheCLITestCase.Description testCaseDescription,
CodeCacheOptions options) throws Throwable {
CodeCacheOptions expectedValues
= options.mapOptions(testCaseDescription.involvedCodeHeaps);
CommandLineOptionTest.verifyOptionValueForSameVM(
BlobType.All.sizeOptionName,
Long.toString(expectedValues.reserved),
String.format("%s should have value %d.",
BlobType.All.sizeOptionName, expectedValues.reserved),
testCaseDescription.getTestOptions(options));
CommandLineOptionTest.verifyOptionValueForSameVM(
BlobType.NonNMethod.sizeOptionName,
Long.toString(expectedValues.nonNmethods),
String.format("%s should have value %d.",
BlobType.NonNMethod.sizeOptionName,
expectedValues.nonNmethods),
testCaseDescription.getTestOptions(options));
CommandLineOptionTest.verifyOptionValueForSameVM(
BlobType.MethodNonProfiled.sizeOptionName,
Long.toString(expectedValues.nonProfiled),
String.format("%s should have value %d.",
BlobType.MethodNonProfiled.sizeOptionName,
expectedValues.nonProfiled),
testCaseDescription.getTestOptions(options));
CommandLineOptionTest.verifyOptionValueForSameVM(
BlobType.MethodProfiled.sizeOptionName,
Long.toString(expectedValues.profiled),
String.format("%s should have value %d.",
BlobType.MethodProfiled.sizeOptionName,
expectedValues.profiled),
testCaseDescription.getTestOptions(options));
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please 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 codeheapsize;
import common.CodeCacheCLITestCase;
import common.CodeCacheOptions;
import com.oracle.java.testlibrary.ExitCode;
import com.oracle.java.testlibrary.Utils;
import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
import sun.hotspot.code.BlobType;
import java.util.Random;
/**
* Test case runner aimed to verify option's consistency.
*/
public class JVMStartupRunner implements CodeCacheCLITestCase.Runner {
private static final String INCONSISTENT_CH_SIZES_ERROR
= "Invalid code heap sizes.*";
@Override
public void run(CodeCacheCLITestCase.Description testCaseDescription,
CodeCacheOptions options) throws Throwable {
// Everything should be fine when
// sum(all code heap sizes) == reserved CC size
CommandLineOptionTest.verifySameJVMStartup(/* expected messages */ null,
new String[]{ INCONSISTENT_CH_SIZES_ERROR },
"JVM startup should not fail with consistent code heap sizes",
"JVM output should not contain warning about inconsistent code "
+ "heap sizes", ExitCode.OK, options.prepareOptions());
verifySingleInconsistentValue(options);
verifyAllInconsistentValues(options);
}
/**
* Verifies that if at least one of three options will have value, such
* that sum of all three values will be inconsistent, then JVM startup will
* fail.
*/
private static void verifySingleInconsistentValue(CodeCacheOptions options)
throws Throwable {
verifyHeapSizesSum(options.reserved,
scaleCodeHeapSize(options.profiled), options.nonProfiled,
options.nonNmethods);
verifyHeapSizesSum(options.reserved, options.profiled,
scaleCodeHeapSize(options.nonProfiled), options.nonNmethods);
verifyHeapSizesSum(options.reserved, options.profiled,
options.nonProfiled, scaleCodeHeapSize(options.nonNmethods));
}
/**
* Verifies that if all three options will have values such that their sum
* is inconsistent with ReservedCodeCacheSize value, then JVM startup will
* fail.
*/
private static void verifyAllInconsistentValues(CodeCacheOptions options)
throws Throwable {
long profiled = options.profiled;
long nonProfiled = options.nonProfiled;
long nonNMethods = options.nonNmethods;
while (options.reserved == profiled + nonProfiled + nonNMethods) {
profiled = scaleCodeHeapSize(profiled);
nonProfiled = scaleCodeHeapSize(nonProfiled);
nonNMethods = scaleCodeHeapSize(nonNMethods);
}
verifyHeapSizesSum(options.reserved, profiled, nonProfiled,
nonNMethods);
}
private static void verifyHeapSizesSum(long reserved, long profiled,
long nonProfiled, long nonNmethods) throws Throwable {
// JVM startup expected to fail when
// sum(all code heap sizes) != reserved CC size
CommandLineOptionTest.verifySameJVMStartup(
new String[]{ INCONSISTENT_CH_SIZES_ERROR },
/* unexpected messages */ null,
"JVM startup should fail with inconsistent code heap size.",
"JVM output should contain appropriate error message of code "
+ "heap sizes are inconsistent",
ExitCode.FAIL,
CommandLineOptionTest.prepareBooleanFlag(
CodeCacheOptions.SEGMENTED_CODE_CACHE, true),
CommandLineOptionTest.prepareNumericFlag(
BlobType.All.sizeOptionName, reserved),
CommandLineOptionTest.prepareNumericFlag(
BlobType.MethodProfiled.sizeOptionName, profiled),
CommandLineOptionTest.prepareNumericFlag(
BlobType.MethodNonProfiled.sizeOptionName, nonProfiled),
CommandLineOptionTest.prepareNumericFlag(
BlobType.NonNMethod.sizeOptionName, nonNmethods));
}
/**
* Returns {@code unscaledSize} value scaled by a random factor from
* range (1, 2). If {@code unscaledSize} is not 0, then this
* method will return value that won't be equal to {@code unscaledSize}.
*
* @param unscaledSize The value to be scaled.
* @return {@code unscaledSize} value scaled by a factor from range (1, 2).
*/
private static long scaleCodeHeapSize(long unscaledSize) {
Random random = Utils.getRandomInstance();
long scaledSize = unscaledSize;
while (scaledSize == unscaledSize && unscaledSize != 0) {
float scale = 1.0f + random.nextFloat();
scaledSize = (long) Math.ceil(scale * unscaledSize);
}
return scaledSize;
}
}

Some files were not shown because too many files have changed in this diff Show More