Merge
This commit is contained in:
commit
ba7368fbd6
.hgtags
bin
make
Bundles.gmkCompileDemos.gmkInit.gmkInitSupport.gmkMacBundles.gmkRunTests.gmk
autoconf
common
hotspot/lib
lib
test
src/hotspot
.mx.jvmci
cpu
aarch64
arm
ppc
s390
sparc
x86
zero
os
aix
bsd
linux
windows
os_cpu
aix_ppc
linux_ppc
windows_x86
share
aot
asm
c1
classfile
altHashing.hppclassLoader.hppclassLoaderData.cppclassLoaderData.hppdictionary.hppjimage.hppklassFactory.cppmoduleEntry.cppmoduleEntry.hppverifier.cpp
code
gc
2
.hgtags
2
.hgtags
@ -450,3 +450,5 @@ e5357aa85dadacc6562175ff74714fecfb4470cf jdk-10+22
|
||||
22850b3a55240253841b9a425ad60a7fcdb22d47 jdk-10+23
|
||||
3b201865d5c1f244f555cad58da599c9261286d8 jdk-10+24
|
||||
8eb5e3ccee560c28ac9b1df2670adac2b3d36fad jdk-10+25
|
||||
1129253d3bc728a2963ba411ab9dd1adf358fb6b jdk-10+26
|
||||
b87d7b5d5dedc1185e5929470f945b7378cdb3ad jdk-10+27
|
||||
|
@ -39,7 +39,7 @@ setup_url() {
|
||||
jib_repository="jdk-virtual"
|
||||
jib_organization="jpg/infra/builddeps"
|
||||
jib_module="jib"
|
||||
jib_revision="2.0-SNAPSHOT"
|
||||
jib_revision="3.0-SNAPSHOT"
|
||||
jib_ext="jib.sh.gz"
|
||||
|
||||
closed_script="${mydir}/../../closed/make/conf/jib-install.conf"
|
||||
@ -146,4 +146,9 @@ elif [ ! -e "${install_data}" ] || [ "${data_string}" != "$(cat "${install_data}
|
||||
install_jib
|
||||
fi
|
||||
|
||||
# Provide a reasonable default for the --src-dir parameter if run out of tree
|
||||
if [ -z "${JIB_SRC_DIR}" ]; then
|
||||
export JIB_SRC_DIR="${mydir}/../"
|
||||
fi
|
||||
|
||||
${installed_jib_script} "$@"
|
||||
|
@ -70,9 +70,14 @@ define SetupBundleFileBody
|
||||
$$(call SetIfEmpty, $1_UNZIP_DEBUGINFO, false)
|
||||
|
||||
$(BUNDLES_OUTPUTDIR)/$$($1_BUNDLE_NAME): $$($1_FILES)
|
||||
# If any of the files contain a space in the file name, CacheFind
|
||||
# will have replaced it with ?. Tar does not accept that so need to
|
||||
# switch it back.
|
||||
$$(foreach d, $$($1_BASE_DIRS), \
|
||||
$$(eval $$(call ListPathsSafely, \
|
||||
$1_$$d_RELATIVE_FILES, $$($1_$$d_LIST_FILE))) \
|
||||
$$(CAT) $$($1_$$d_LIST_FILE) | $$(TR) '?' ' ' > $$($1_$$d_LIST_FILE).tmp \
|
||||
&& $(MV) $$($1_$$d_LIST_FILE).tmp $$($1_$$d_LIST_FILE) $$(NEWLINE) \
|
||||
)
|
||||
$$(call MakeDir, $$(@D))
|
||||
ifneq ($$($1_SPECIAL_INCLUDES), )
|
||||
|
@ -37,9 +37,13 @@ include SetupJavaCompilers.gmk
|
||||
include TextFileProcessing.gmk
|
||||
include ZipArchive.gmk
|
||||
|
||||
# Hook to include the corresponding custom file, if present.
|
||||
$(eval $(call IncludeCustomExtension, CompileDemos-pre.gmk))
|
||||
|
||||
# Prepare the find cache.
|
||||
$(eval $(call FillCacheFind, $(wildcard $(TOPDIR)/src/demo \
|
||||
$(TOPDIR)/src/*/demo)))
|
||||
DEMO_SRC_DIRS += $(TOPDIR)/src/demo
|
||||
|
||||
$(eval $(call FillCacheFind, $(wildcard $(DEMO_SRC_DIRS))))
|
||||
|
||||
# Append demo goals to this variable.
|
||||
TARGETS =
|
||||
@ -303,7 +307,7 @@ endif
|
||||
|
||||
################################################################################
|
||||
# Hook to include the corresponding custom file, if present.
|
||||
$(eval $(call IncludeCustomExtension, CompileDemos.gmk))
|
||||
$(eval $(call IncludeCustomExtension, CompileDemos-post.gmk))
|
||||
|
||||
all: $(TARGETS)
|
||||
images: $(IMAGES_TARGETS)
|
||||
|
@ -267,8 +267,9 @@ else # HAS_SPEC=true
|
||||
$(ECHO) "Re-running configure using default settings"
|
||||
endif
|
||||
( cd $(OUTPUTDIR) && PATH="$(ORIGINAL_PATH)" \
|
||||
CUSTOM_ROOT="$(CUSTOM_ROOT)" \
|
||||
CUSTOM_CONFIG_DIR="$(CUSTOM_CONFIG_DIR)" \
|
||||
$(BASH) $(CONFIGURE_CMD) $(CONFIGURE_COMMAND_LINE) )
|
||||
$(BASH) $(TOPDIR)/configure $(CONFIGURE_COMMAND_LINE) )
|
||||
|
||||
##############################################################################
|
||||
# The main target, for delegating into Main.gmk
|
||||
|
@ -70,10 +70,10 @@ ifeq ($(HAS_SPEC),)
|
||||
$(subst \ ,\#,$(MAKEOVERRIDES))))
|
||||
|
||||
# Setup information about available configurations, if any.
|
||||
ifeq ($(CUSTOM_BUILD_DIR), )
|
||||
build_dir=$(topdir)/build
|
||||
ifneq ($(CUSTOM_ROOT), )
|
||||
build_dir=$(CUSTOM_ROOT)/build
|
||||
else
|
||||
build_dir=$(CUSTOM_BUILD_DIR)
|
||||
build_dir=$(topdir)/build
|
||||
endif
|
||||
all_spec_files=$(wildcard $(build_dir)/*/spec.gmk)
|
||||
# Extract the configuration names from the path
|
||||
@ -227,7 +227,11 @@ ifeq ($(HAS_SPEC),)
|
||||
else
|
||||
# Use spec.gmk files in the build output directory
|
||||
ifeq ($$(all_spec_files),)
|
||||
$$(info Error: No configurations found for $$(topdir).)
|
||||
ifneq ($(CUSTOM_ROOT), )
|
||||
$$(info Error: No configurations found for $$(CUSTOM_ROOT).)
|
||||
else
|
||||
$$(info Error: No configurations found for $$(topdir).)
|
||||
endif
|
||||
$$(info Please run 'bash configure' to create a configuration.)
|
||||
$$(info )
|
||||
$$(error Cannot continue)
|
||||
|
@ -49,22 +49,17 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
BUNDLE_VENDOR := $(COMPANY_NAME)
|
||||
endif
|
||||
|
||||
JDK_FILE_LIST := $(shell $(FIND) $(JDK_IMAGE_DIR))
|
||||
JRE_FILE_LIST := $(shell $(FIND) $(JRE_IMAGE_DIR))
|
||||
$(eval $(call SetupCopyFiles, COPY_JDK_IMAGE, \
|
||||
SRC := $(JDK_IMAGE_DIR), \
|
||||
DEST := $(JDK_MACOSX_CONTENTS_DIR)/Home, \
|
||||
FILES := $(call CacheFind, $(JDK_IMAGE_DIR)), \
|
||||
))
|
||||
|
||||
JDK_TARGET_LIST := $(subst $(JDK_IMAGE_DIR)/,$(JDK_MACOSX_CONTENTS_DIR)/Home/,$(JDK_FILE_LIST))
|
||||
JRE_TARGET_LIST := $(subst $(JRE_IMAGE_DIR)/,$(JRE_MACOSX_CONTENTS_DIR)/Home/,$(JRE_FILE_LIST))
|
||||
|
||||
# Copy empty directories (jre/lib/applet).
|
||||
$(JDK_MACOSX_CONTENTS_DIR)/Home/%: $(JDK_IMAGE_DIR)/%
|
||||
$(call LogInfo, Copying $(patsubst $(OUTPUTDIR)/%,%,$@))
|
||||
$(MKDIR) -p $(@D)
|
||||
if [ -d "$<" ]; then $(MKDIR) -p $@; else $(CP) -f -R -P '$<' '$@'; fi
|
||||
|
||||
$(JRE_MACOSX_CONTENTS_DIR)/Home/%: $(JRE_IMAGE_DIR)/%
|
||||
$(call LogInfo, Copying $(patsubst $(OUTPUTDIR)/%,%,$@))
|
||||
$(MKDIR) -p $(@D)
|
||||
if [ -d "$<" ]; then $(MKDIR) -p $@; else $(CP) -f -R -P '$<' '$@'; fi
|
||||
$(eval $(call SetupCopyFiles, COPY_JRE_IMAGE, \
|
||||
SRC := $(JRE_IMAGE_DIR), \
|
||||
DEST := $(JRE_MACOSX_CONTENTS_DIR)/Home, \
|
||||
FILES := $(call CacheFind, $(JRE_IMAGE_DIR)), \
|
||||
))
|
||||
|
||||
$(JDK_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib:
|
||||
$(call LogInfo, Creating link $(patsubst $(OUTPUTDIR)/%,%,$@))
|
||||
@ -102,11 +97,11 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
@@VENDOR@@ => $(BUNDLE_VENDOR) , \
|
||||
))
|
||||
|
||||
jdk-bundle: $(JDK_TARGET_LIST) $(JDK_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib \
|
||||
jdk-bundle: $(COPY_JDK_IMAGE) $(JDK_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib \
|
||||
$(BUILD_JDK_PLIST)
|
||||
$(SETFILE) -a B $(dir $(JDK_MACOSX_CONTENTS_DIR))
|
||||
|
||||
jre-bundle: $(JRE_TARGET_LIST) $(JRE_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib \
|
||||
jre-bundle: $(COPY_JRE_IMAGE) $(JRE_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib \
|
||||
$(BUILD_JRE_PLIST)
|
||||
$(SETFILE) -a B $(dir $(JRE_MACOSX_CONTENTS_DIR))
|
||||
|
||||
|
@ -351,6 +351,9 @@ define SetupRunJtregTestBody
|
||||
|
||||
$1_JTREG_BASIC_OPTIONS += -automatic -keywords:\!ignore -ignore:quiet
|
||||
|
||||
# Make it possible to specify the JIB_DATA_DIR for tests using the
|
||||
# JIB Artifact resolver
|
||||
$1_JTREG_BASIC_OPTIONS += -e:JIB_DATA_DIR
|
||||
# Some tests needs to find a boot JDK using the JDK8_HOME variable.
|
||||
$1_JTREG_BASIC_OPTIONS += -e:JDK8_HOME=$$(BOOT_JDK)
|
||||
|
||||
|
@ -766,13 +766,10 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR],
|
||||
AC_ARG_WITH(conf-name, [AS_HELP_STRING([--with-conf-name],
|
||||
[use this as the name of the configuration @<:@generated from important configuration options@:>@])],
|
||||
[ CONF_NAME=${with_conf_name} ])
|
||||
AC_ARG_WITH(output-base-dir, [AS_HELP_STRING([--with-output-base-dir],
|
||||
[override the default output base directory @<:@./build@:>@])],
|
||||
[ OUTPUT_BASE=${with_output_base_dir} ], [ OUTPUT_BASE="$TOPDIR/build" ] )
|
||||
|
||||
# Test from where we are running configure, in or outside of src root.
|
||||
AC_MSG_CHECKING([where to store configuration])
|
||||
if test "x$CURDIR" = "x$TOPDIR" || test "x$CURDIR" = "x$TOPDIR/common" \
|
||||
if test "x$CURDIR" = "x$TOPDIR" || test "x$CURDIR" = "x$CUSTOM_ROOT" \
|
||||
|| test "x$CURDIR" = "x$TOPDIR/make/autoconf" \
|
||||
|| test "x$CURDIR" = "x$TOPDIR/make" ; then
|
||||
# We are running configure from the src root.
|
||||
@ -783,7 +780,12 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR],
|
||||
else
|
||||
AC_MSG_RESULT([in build directory with custom name])
|
||||
fi
|
||||
OUTPUTDIR="${OUTPUT_BASE}/${CONF_NAME}"
|
||||
|
||||
if test "x$CUSTOM_ROOT" != x; then
|
||||
OUTPUTDIR="${CUSTOM_ROOT}/build/${CONF_NAME}"
|
||||
else
|
||||
OUTPUTDIR="${TOPDIR}/build/${CONF_NAME}"
|
||||
fi
|
||||
$MKDIR -p "$OUTPUTDIR"
|
||||
if test ! -d "$OUTPUTDIR"; then
|
||||
AC_MSG_ERROR([Could not create build directory $OUTPUTDIR])
|
||||
|
@ -325,6 +325,27 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK],
|
||||
fi
|
||||
AC_MSG_CHECKING([if Boot JDK is 32 or 64 bits])
|
||||
AC_MSG_RESULT([$BOOT_JDK_BITS])
|
||||
|
||||
# Try to enable CDS
|
||||
AC_MSG_CHECKING([for local Boot JDK Class Data Sharing (CDS)])
|
||||
BOOT_JDK_CDS_ARCHIVE=$CONFIGURESUPPORT_OUTPUTDIR/classes.jsa
|
||||
ADD_JVM_ARG_IF_OK([-XX:+UnlockDiagnosticVMOptions -XX:-VerifySharedSpaces -XX:SharedArchiveFile=$BOOT_JDK_CDS_ARCHIVE],boot_jdk_cds_args,[$JAVA])
|
||||
|
||||
if test "x$boot_jdk_cds_args" != x; then
|
||||
# Try creating a CDS archive
|
||||
"$JAVA" $boot_jdk_cds_args -Xshare:dump > /dev/null 2>&1
|
||||
if test $? -eq 0; then
|
||||
BOOTJDK_USE_LOCAL_CDS=true
|
||||
AC_MSG_RESULT([yes, created])
|
||||
else
|
||||
# Generation failed, don't use CDS.
|
||||
BOOTJDK_USE_LOCAL_CDS=false
|
||||
AC_MSG_RESULT([no, creation failed])
|
||||
fi
|
||||
else
|
||||
BOOTJDK_USE_LOCAL_CDS=false
|
||||
AC_MSG_RESULT([no, -XX:SharedArchiveFile not supported])
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS],
|
||||
@ -346,6 +367,14 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS],
|
||||
# Force en-US environment
|
||||
ADD_JVM_ARG_IF_OK([-Duser.language=en -Duser.country=US],boot_jdk_jvmargs,[$JAVA])
|
||||
|
||||
if test "x$BOOTJDK_USE_LOCAL_CDS" = xtrue; then
|
||||
# Use our own CDS archive
|
||||
ADD_JVM_ARG_IF_OK([$boot_jdk_cds_args -Xshare:auto],boot_jdk_jvmargs,[$JAVA])
|
||||
else
|
||||
# Otherwise optimistically use the system-wide one, if one is present
|
||||
ADD_JVM_ARG_IF_OK([-Xshare:auto],boot_jdk_jvmargs,[$JAVA])
|
||||
fi
|
||||
|
||||
# Apply user provided options.
|
||||
ADD_JVM_ARG_IF_OK([$with_boot_jdk_jvmargs],boot_jdk_jvmargs,[$JAVA])
|
||||
|
||||
@ -355,7 +384,6 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS],
|
||||
JAVA_FLAGS=$boot_jdk_jvmargs
|
||||
AC_SUBST(JAVA_FLAGS)
|
||||
|
||||
|
||||
AC_MSG_CHECKING([flags for boot jdk java command for big workloads])
|
||||
|
||||
# Starting amount of heap memory.
|
||||
|
19
make/autoconf/configure
vendored
19
make/autoconf/configure
vendored
@ -23,19 +23,18 @@
|
||||
#
|
||||
|
||||
if test "x$1" != xCHECKME; then
|
||||
echo "WARNING: Calling the wrapper script directly is deprecated and unsupported."
|
||||
echo "Not all features of configure will be available."
|
||||
echo "ERROR: Calling this wrapper script directly is not supported."
|
||||
echo "Use the 'configure' script in the top-level directory instead."
|
||||
TOPDIR=$(cd $(dirname $0)/../.. > /dev/null && pwd)
|
||||
else
|
||||
# Now the next argument is the absolute top-level directory path.
|
||||
# The TOPDIR variable is passed on to configure.ac.
|
||||
TOPDIR="$2"
|
||||
# Remove these two arguments to get to the user supplied arguments
|
||||
shift
|
||||
shift
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The next argument is the absolute top-level directory path.
|
||||
# The TOPDIR variable is passed on to configure.ac.
|
||||
TOPDIR="$2"
|
||||
# Remove these two arguments to get to the user supplied arguments
|
||||
shift
|
||||
shift
|
||||
|
||||
if test "x$BASH" = x; then
|
||||
echo "Error: This script must be run using bash." 1>&2
|
||||
exit 1
|
||||
|
@ -1134,7 +1134,6 @@ with_toolchain_path
|
||||
with_extra_path
|
||||
with_sdk_name
|
||||
with_conf_name
|
||||
with_output_base_dir
|
||||
with_output_sync
|
||||
with_default_make_target
|
||||
enable_headless_only
|
||||
@ -2043,7 +2042,6 @@ Optional Packages:
|
||||
--with-sdk-name use the platform SDK of the given name. [macosx]
|
||||
--with-conf-name use this as the name of the configuration [generated
|
||||
from important configuration options]
|
||||
--with-output-base-dir override the default output base directory [./build]
|
||||
--with-output-sync set make output sync type if supported by make.
|
||||
[recurse]
|
||||
--with-default-make-target
|
||||
@ -5117,7 +5115,7 @@ VS_SDK_PLATFORM_NAME_2013=
|
||||
#CUSTOM_AUTOCONF_INCLUDE
|
||||
|
||||
# Do not change or remove the following line, it is needed for consistency checks:
|
||||
DATE_WHEN_GENERATED=1506397140
|
||||
DATE_WHEN_GENERATED=1508136203
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -17554,18 +17552,10 @@ if test "${with_conf_name+set}" = set; then :
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-output-base-dir was given.
|
||||
if test "${with_output_base_dir+set}" = set; then :
|
||||
withval=$with_output_base_dir; OUTPUT_BASE=${with_output_base_dir}
|
||||
else
|
||||
OUTPUT_BASE="$TOPDIR/build"
|
||||
fi
|
||||
|
||||
|
||||
# Test from where we are running configure, in or outside of src root.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking where to store configuration" >&5
|
||||
$as_echo_n "checking where to store configuration... " >&6; }
|
||||
if test "x$CURDIR" = "x$TOPDIR" || test "x$CURDIR" = "x$TOPDIR/common" \
|
||||
if test "x$CURDIR" = "x$TOPDIR" || test "x$CURDIR" = "x$CUSTOM_ROOT" \
|
||||
|| test "x$CURDIR" = "x$TOPDIR/make/autoconf" \
|
||||
|| test "x$CURDIR" = "x$TOPDIR/make" ; then
|
||||
# We are running configure from the src root.
|
||||
@ -17578,7 +17568,12 @@ $as_echo "in default location" >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: in build directory with custom name" >&5
|
||||
$as_echo "in build directory with custom name" >&6; }
|
||||
fi
|
||||
OUTPUTDIR="${OUTPUT_BASE}/${CONF_NAME}"
|
||||
|
||||
if test "x$CUSTOM_ROOT" != x; then
|
||||
OUTPUTDIR="${CUSTOM_ROOT}/build/${CONF_NAME}"
|
||||
else
|
||||
OUTPUTDIR="${TOPDIR}/build/${CONF_NAME}"
|
||||
fi
|
||||
$MKDIR -p "$OUTPUTDIR"
|
||||
if test ! -d "$OUTPUTDIR"; then
|
||||
as_fn_error $? "Could not create build directory $OUTPUTDIR" "$LINENO" 5
|
||||
@ -31483,6 +31478,45 @@ $as_echo_n "checking if Boot JDK is 32 or 64 bits... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOOT_JDK_BITS" >&5
|
||||
$as_echo "$BOOT_JDK_BITS" >&6; }
|
||||
|
||||
# Try to enable CDS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for local Boot JDK Class Data Sharing (CDS)" >&5
|
||||
$as_echo_n "checking for local Boot JDK Class Data Sharing (CDS)... " >&6; }
|
||||
BOOT_JDK_CDS_ARCHIVE=$CONFIGURESUPPORT_OUTPUTDIR/classes.jsa
|
||||
|
||||
$ECHO "Check if jvm arg is ok: -XX:+UnlockDiagnosticVMOptions -XX:-VerifySharedSpaces -XX:SharedArchiveFile=$BOOT_JDK_CDS_ARCHIVE" >&5
|
||||
$ECHO "Command: $JAVA -XX:+UnlockDiagnosticVMOptions -XX:-VerifySharedSpaces -XX:SharedArchiveFile=$BOOT_JDK_CDS_ARCHIVE -version" >&5
|
||||
OUTPUT=`$JAVA -XX:+UnlockDiagnosticVMOptions -XX:-VerifySharedSpaces -XX:SharedArchiveFile=$BOOT_JDK_CDS_ARCHIVE -version 2>&1`
|
||||
FOUND_WARN=`$ECHO "$OUTPUT" | $GREP -i warn`
|
||||
FOUND_VERSION=`$ECHO $OUTPUT | $GREP " version \""`
|
||||
if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
|
||||
boot_jdk_cds_args="$boot_jdk_cds_args -XX:+UnlockDiagnosticVMOptions -XX:-VerifySharedSpaces -XX:SharedArchiveFile=$BOOT_JDK_CDS_ARCHIVE"
|
||||
JVM_ARG_OK=true
|
||||
else
|
||||
$ECHO "Arg failed:" >&5
|
||||
$ECHO "$OUTPUT" >&5
|
||||
JVM_ARG_OK=false
|
||||
fi
|
||||
|
||||
|
||||
if test "x$boot_jdk_cds_args" != x; then
|
||||
# Try creating a CDS archive
|
||||
"$JAVA" $boot_jdk_cds_args -Xshare:dump > /dev/null 2>&1
|
||||
if test $? -eq 0; then
|
||||
BOOTJDK_USE_LOCAL_CDS=true
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, created" >&5
|
||||
$as_echo "yes, created" >&6; }
|
||||
else
|
||||
# Generation failed, don't use CDS.
|
||||
BOOTJDK_USE_LOCAL_CDS=false
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no, creation failed" >&5
|
||||
$as_echo "no, creation failed" >&6; }
|
||||
fi
|
||||
else
|
||||
BOOTJDK_USE_LOCAL_CDS=false
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no, -XX:SharedArchiveFile not supported" >&5
|
||||
$as_echo "no, -XX:SharedArchiveFile not supported" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Check whether --with-build-jdk was given.
|
||||
@ -66232,6 +66266,42 @@ $as_echo_n "checking flags for boot jdk java command ... " >&6; }
|
||||
fi
|
||||
|
||||
|
||||
if test "x$BOOTJDK_USE_LOCAL_CDS" = xtrue; then
|
||||
# Use our own CDS archive
|
||||
|
||||
$ECHO "Check if jvm arg is ok: $boot_jdk_cds_args -Xshare:auto" >&5
|
||||
$ECHO "Command: $JAVA $boot_jdk_cds_args -Xshare:auto -version" >&5
|
||||
OUTPUT=`$JAVA $boot_jdk_cds_args -Xshare:auto -version 2>&1`
|
||||
FOUND_WARN=`$ECHO "$OUTPUT" | $GREP -i warn`
|
||||
FOUND_VERSION=`$ECHO $OUTPUT | $GREP " version \""`
|
||||
if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
|
||||
boot_jdk_jvmargs="$boot_jdk_jvmargs $boot_jdk_cds_args -Xshare:auto"
|
||||
JVM_ARG_OK=true
|
||||
else
|
||||
$ECHO "Arg failed:" >&5
|
||||
$ECHO "$OUTPUT" >&5
|
||||
JVM_ARG_OK=false
|
||||
fi
|
||||
|
||||
else
|
||||
# Otherwise optimistically use the system-wide one, if one is present
|
||||
|
||||
$ECHO "Check if jvm arg is ok: -Xshare:auto" >&5
|
||||
$ECHO "Command: $JAVA -Xshare:auto -version" >&5
|
||||
OUTPUT=`$JAVA -Xshare:auto -version 2>&1`
|
||||
FOUND_WARN=`$ECHO "$OUTPUT" | $GREP -i warn`
|
||||
FOUND_VERSION=`$ECHO $OUTPUT | $GREP " version \""`
|
||||
if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
|
||||
boot_jdk_jvmargs="$boot_jdk_jvmargs -Xshare:auto"
|
||||
JVM_ARG_OK=true
|
||||
else
|
||||
$ECHO "Arg failed:" >&5
|
||||
$ECHO "$OUTPUT" >&5
|
||||
JVM_ARG_OK=false
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# Apply user provided options.
|
||||
|
||||
$ECHO "Check if jvm arg is ok: $with_boot_jdk_jvmargs" >&5
|
||||
@ -66256,7 +66326,6 @@ $as_echo "$boot_jdk_jvmargs" >&6; }
|
||||
JAVA_FLAGS=$boot_jdk_jvmargs
|
||||
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command for big workloads" >&5
|
||||
$as_echo_n "checking flags for boot jdk java command for big workloads... " >&6; }
|
||||
|
||||
|
@ -842,8 +842,6 @@ JRE_SYMBOLS_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(JRE_SYMBOLS_BUNDLE_NAME)
|
||||
TEST_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(TEST_BUNDLE_NAME)
|
||||
DOCS_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(DOCS_BUNDLE_NAME)
|
||||
|
||||
CONFIGURE_CMD := $(TOPDIR)/configure
|
||||
|
||||
# This macro is called to allow inclusion of closed source counterparts.
|
||||
# Unless overridden in closed sources, it expands to nothing.
|
||||
# Usage: This function is called in an open makefile, with the following
|
||||
|
@ -462,12 +462,23 @@ define NamedParamsMacroTemplate
|
||||
$(call $(0)Body,$(strip $1))
|
||||
endef
|
||||
|
||||
################################################################################
|
||||
# Replace question marks with space in string. This macro needs to be called on
|
||||
# files from CacheFind in case any of them contains space in their file name,
|
||||
# since CacheFind replaces space with ?.
|
||||
# Param 1 - String to replace in
|
||||
DecodeSpace = \
|
||||
$(subst ?,$(SPACE),$(strip $1))
|
||||
EncodeSpace = \
|
||||
$(subst $(SPACE),?,$(strip $1))
|
||||
|
||||
################################################################################
|
||||
# Make directory without forking mkdir if not needed
|
||||
# 1: List of directories to create
|
||||
MakeDir = \
|
||||
$(strip \
|
||||
$(eval MakeDir_dirs_to_make := $(strip $(foreach d, $1, $(if $(wildcard $d), , $d)))) \
|
||||
$(eval MakeDir_dirs_to_make := $(strip $(foreach d, $1, $(if $(wildcard $d), , \
|
||||
"$(call DecodeSpace, $d)")))) \
|
||||
$(if $(MakeDir_dirs_to_make), $(shell $(MKDIR) -p $(MakeDir_dirs_to_make))) \
|
||||
)
|
||||
|
||||
@ -479,6 +490,7 @@ SetIfEmpty = \
|
||||
$(if $($(strip $1)),,$(eval $(strip $1) := $2))
|
||||
|
||||
################################################################################
|
||||
# All install-file and related macros automatically call DecodeSpace when needed.
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS),solaris)
|
||||
# On Solaris, if the target is a symlink and exists, cp won't overwrite.
|
||||
@ -487,19 +499,21 @@ ifeq ($(OPENJDK_TARGET_OS),solaris)
|
||||
# If the source and target parent directories are the same, recursive copy doesn't work
|
||||
# so we fall back on regular copy, which isn't preserving symlinks.
|
||||
define install-file
|
||||
$(MKDIR) -p '$(@D)'
|
||||
$(RM) '$@'
|
||||
if [ "$(@D)" != "$(<D)" ]; then \
|
||||
$(CP) -f -r -P '$<' '$(@D)'; \
|
||||
if [ "$(@F)" != "$(<F)" ]; then \
|
||||
$(MV) '$(@D)/$(<F)' '$@'; \
|
||||
$(call MakeDir, $(@D))
|
||||
$(RM) '$(call DecodeSpace, $@)'
|
||||
if [ '$(call DecodeSpace, $(dir $@))' != \
|
||||
'$(call DecodeSpace, $(dir $(call EncodeSpace, $<)))' ]; then \
|
||||
$(CP) -f -r -P '$(call DecodeSpace, $<)' '$(call DecodeSpace, $(@D))'; \
|
||||
if [ '$(call DecodeSpace, $(@F))' != \
|
||||
'$(call DecodeSpace, $(notdir $(call EncodeSpace, $(<))))' ]; then \
|
||||
$(MV) '$(call DecodeSpace, $(@D)/$(<F))' '$(call DecodeSpace, $@)'; \
|
||||
fi; \
|
||||
else \
|
||||
if [ -L '$<' ]; then \
|
||||
if [ -L '$(call DecodeSpace, $<)' ]; then \
|
||||
$(ECHO) "Source file is a symlink and target is in the same directory: $< $@" ; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
$(CP) -f '$<' '$@'; \
|
||||
$(CP) -f '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'; \
|
||||
fi
|
||||
endef
|
||||
else ifeq ($(OPENJDK_TARGET_OS),macosx)
|
||||
@ -512,22 +526,22 @@ else ifeq ($(OPENJDK_TARGET_OS),macosx)
|
||||
# If copying a soft link to a directory, need to delete the target first to avoid
|
||||
# weird errors.
|
||||
define install-file
|
||||
$(MKDIR) -p '$(@D)'
|
||||
$(RM) '$@'
|
||||
$(CP) -fRP '$<' '$@'
|
||||
if [ -n "`$(XATTR) -l '$@'`" ]; then $(XATTR) -c '$@'; fi
|
||||
$(call MakeDir, $(@D))
|
||||
$(RM) '$(call DecodeSpace, $@)'
|
||||
$(CP) -fRP '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'
|
||||
if [ -n "`$(XATTR) -l '$(call DecodeSpace, $@)'`" ]; then $(XATTR) -c '$(call DecodeSpace, $@)'; fi
|
||||
endef
|
||||
else
|
||||
define install-file
|
||||
$(call MakeDir, $(@D))
|
||||
$(CP) -fP '$<' '$@'
|
||||
$(CP) -fP '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'
|
||||
endef
|
||||
endif
|
||||
|
||||
# Variant of install file that does not preserve symlinks
|
||||
define install-file-nolink
|
||||
$(call MakeDir, $(@D))
|
||||
$(CP) -f '$<' '$@'
|
||||
$(CP) -f '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'
|
||||
endef
|
||||
|
||||
################################################################################
|
||||
@ -577,14 +591,14 @@ RelativePath = \
|
||||
# the unix emulation environment.
|
||||
define link-file-relative
|
||||
$(call MakeDir, $(@D))
|
||||
$(RM) $@
|
||||
$(LN) -s $(call RelativePath, $<, $(@D)) $@
|
||||
$(RM) '$(call DecodeSpace, $@)'
|
||||
$(LN) -s '$(call DecodeSpace, $(call RelativePath, $<, $(@D)))' '$(call DecodeSpace, $@)'
|
||||
endef
|
||||
|
||||
define link-file-absolute
|
||||
$(call MakeDir, $(@D))
|
||||
$(RM) $@
|
||||
$(LN) -s $< $@
|
||||
$(RM) '$(call DecodeSpace, $@)'
|
||||
$(LN) -s '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'
|
||||
endef
|
||||
|
||||
################################################################################
|
||||
@ -651,6 +665,13 @@ ifneq ($(DISABLE_CACHE_FIND), true)
|
||||
# This macro can be called multiple times to add to the cache. Only finds files
|
||||
# with no filters.
|
||||
#
|
||||
# Files containing space will get spaces replaced with ? because GNU Make
|
||||
# cannot handle lists of files with space in them. By using ?, make will match
|
||||
# the wildcard to space in many situations so we don't need to replace back
|
||||
# to space on every use. While not a complete solution it does allow some uses
|
||||
# of CacheFind to function with spaces in file names, including for
|
||||
# SetupCopyFiles.
|
||||
#
|
||||
# Needs to be called with $(eval )
|
||||
#
|
||||
# Even if the performance benifit is negligible on other platforms, keep the
|
||||
@ -668,7 +689,8 @@ ifneq ($(DISABLE_CACHE_FIND), true)
|
||||
ifneq ($$(FIND_CACHE_NEW_DIRS), )
|
||||
# Remove any trailing slash from dirs in the cache dir list
|
||||
FIND_CACHE_DIRS += $$(patsubst %/,%, $$(FIND_CACHE_NEW_DIRS))
|
||||
FIND_CACHE := $$(sort $$(FIND_CACHE) $$(shell $(FIND) $$(FIND_CACHE_NEW_DIRS) \( -type f -o -type l \) $2))
|
||||
FIND_CACHE := $$(sort $$(FIND_CACHE) $$(shell $(FIND) $$(FIND_CACHE_NEW_DIRS) \
|
||||
\( -type f -o -type l \) $2 | $(TR) ' ' '?'))
|
||||
endif
|
||||
endef
|
||||
|
||||
@ -684,7 +706,8 @@ ifneq ($(DISABLE_CACHE_FIND), true)
|
||||
# Param 2 - (optional) specialization. Normally "-a \( ... \)" expression.
|
||||
define CacheFind
|
||||
$(if $(filter-out $(addsuffix /%,- $(FIND_CACHE_DIRS)) $(FIND_CACHE_DIRS),$1), \
|
||||
$(if $(wildcard $1), $(shell $(FIND) $1 \( -type f -o -type l \) $2)), \
|
||||
$(if $(wildcard $1), $(shell $(FIND) $1 \( -type f -o -type l \) $2 \
|
||||
| $(TR) ' ' '?')), \
|
||||
$(filter $(addsuffix /%,$(patsubst %/,%,$1)) $1,$(FIND_CACHE)))
|
||||
endef
|
||||
|
||||
@ -693,7 +716,7 @@ else
|
||||
# Param 1 - Dirs to find in
|
||||
# Param 2 - (optional) specialization. Normally "-a \( ... \)" expression.
|
||||
define CacheFind
|
||||
$(shell $(FIND) $1 \( -type f -o -type l \) $2)
|
||||
$(shell $(FIND) $1 \( -type f -o -type l \) $2 | $(TR) ' ' '?')
|
||||
endef
|
||||
endif
|
||||
|
||||
@ -707,7 +730,7 @@ define AddFileToCopy
|
||||
# 4 : Macro to call for copy operation
|
||||
# 5 : Action text to log
|
||||
$2: $1
|
||||
$$(call LogInfo, $(strip $5) $$(patsubst $(OUTPUTDIR)/%,%,$$@))
|
||||
$$(call LogInfo, $(strip $5) $$(patsubst $(OUTPUTDIR)/%,%,$$(call DecodeSpace, $$@)))
|
||||
$$($$(strip $4))
|
||||
|
||||
$3 += $2
|
||||
|
@ -58,6 +58,7 @@ JVM_CFLAGS_INCLUDES += \
|
||||
-I$(JVM_VARIANT_OUTPUTDIR)/gensrc \
|
||||
-I$(TOPDIR)/src/hotspot/share/precompiled \
|
||||
-I$(TOPDIR)/src/hotspot/share/prims \
|
||||
-I$(TOPDIR)/src/java.base/share/native/include \
|
||||
#
|
||||
|
||||
# INCLUDE_SUFFIX_* is only meant for including the proper
|
||||
|
@ -132,6 +132,7 @@ ifneq ($(call check-jvm-feature, all-gcs), true)
|
||||
cms/ g1/ parallel/
|
||||
JVM_EXCLUDE_FILES += \
|
||||
concurrentGCThread.cpp \
|
||||
suspendibleThreadSet.cpp \
|
||||
plab.cpp
|
||||
JVM_EXCLUDE_FILES += \
|
||||
g1MemoryPool.cpp \
|
||||
|
@ -25,9 +25,13 @@
|
||||
|
||||
include LibCommon.gmk
|
||||
|
||||
# Hook to include the corresponding custom file, if present.
|
||||
$(eval $(call IncludeCustomExtension, lib/Lib-java.base.gmk))
|
||||
|
||||
# Prepare the find cache.
|
||||
$(eval $(call FillCacheFind, $(wildcard $(TOPDIR)/src/java.base/*/native \
|
||||
$(TOPDIR)/src/*/java.base/*/native)))
|
||||
LIB_java.base_SRC_DIRS += $(TOPDIR)/src/java.base/*/native
|
||||
|
||||
$(eval $(call FillCacheFind, $(wildcard $(LIB_java.base_SRC_DIRS))))
|
||||
|
||||
include CoreLibraries.gmk
|
||||
include NetworkingLibraries.gmk
|
||||
|
@ -25,9 +25,13 @@
|
||||
|
||||
include LibCommon.gmk
|
||||
|
||||
# Hook to include the corresponding custom file, if present.
|
||||
$(eval $(call IncludeCustomExtension, lib/Lib-java.desktop.gmk))
|
||||
|
||||
# Prepare the find cache.
|
||||
$(eval $(call FillCacheFind, $(wildcard $(TOPDIR)/src/java.desktop/*/native \
|
||||
$(TOPDIR)/src/*/java.desktop/*/native)))
|
||||
LIB_java.desktop_SRC_DIRS += $(TOPDIR)/src/java.desktop/*/native
|
||||
|
||||
$(eval $(call FillCacheFind, $(wildcard $(LIB_java.desktop_SRC_DIRS))))
|
||||
|
||||
include LibosxLibraries.gmk
|
||||
include PlatformLibraries.gmk
|
||||
|
@ -35,7 +35,7 @@ include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
include TestFilesCompilation.gmk
|
||||
|
||||
$(eval $(call IncludeCustomExtension, hotspot/test/JtregNative.gmk))
|
||||
$(eval $(call IncludeCustomExtension, test/JtregNativeHotspot.gmk))
|
||||
|
||||
################################################################################
|
||||
# Targets for building the native tests themselves.
|
||||
@ -50,6 +50,7 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC += \
|
||||
$(TOPDIR)/test/hotspot/jtreg/runtime/jni/8025979 \
|
||||
$(TOPDIR)/test/hotspot/jtreg/runtime/jni/8033445 \
|
||||
$(TOPDIR)/test/hotspot/jtreg/runtime/jni/checked \
|
||||
$(TOPDIR)/test/hotspot/jtreg/runtime/jni/FindClass \
|
||||
$(TOPDIR)/test/hotspot/jtreg/runtime/jni/PrivateInterfaceMethods \
|
||||
$(TOPDIR)/test/hotspot/jtreg/runtime/jni/ToStringInInterfaceTest \
|
||||
$(TOPDIR)/test/hotspot/jtreg/runtime/jni/CalleeSavedRegisters \
|
||||
|
@ -35,7 +35,7 @@ include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
include TestFilesCompilation.gmk
|
||||
|
||||
$(eval $(call IncludeCustomExtension, test/JtregNative.gmk))
|
||||
$(eval $(call IncludeCustomExtension, test/JtregNativeJdk.gmk))
|
||||
|
||||
################################################################################
|
||||
# Targets for building the native tests themselves.
|
||||
|
@ -70,7 +70,7 @@
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<sourceEntries>
|
||||
<entry excluding="cpu/vm/templateTable_x86_32.cpp|cpu/vm/templateInterpreter_x86_32.cpp|cpu/vm/stubRoutines_x86_32.cpp|cpu/vm/stubGenerator_x86_32.cpp|cpu/vm/sharedRuntime_x86_32.cpp|cpu/vm/jniFastGetField_x86_32.cpp|cpu/vm/interpreterRT_x86_32.cpp|cpu/vm/interpreter_x86_32.cpp|cpu/vm/interp_masm_x86_32.cpp|cpu/vm/vtableStubs_x86_32.cpp" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
|
||||
<entry excluding="cpu/x86/templateTable_x86_32.cpp|cpu/x86/templateInterpreter_x86_32.cpp|cpu/x86/stubRoutines_x86_32.cpp|cpu/x86/stubGenerator_x86_32.cpp|cpu/x86/sharedRuntime_x86_32.cpp|cpu/x86/jniFastGetField_x86_32.cpp|cpu/x86/interpreterRT_x86_32.cpp|cpu/x86/interpreter_x86_32.cpp|cpu/x86/interp_masm_x86_32.cpp|cpu/x86/vtableStubs_x86_32.cpp" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
|
@ -256,14 +256,10 @@ class HotSpotProject(mx.NativeProject):
|
||||
"""
|
||||
|
||||
roots = [
|
||||
'ASSEMBLY_EXCEPTION',
|
||||
'LICENSE',
|
||||
'README',
|
||||
'THIRD_PARTY_README',
|
||||
'agent',
|
||||
'make',
|
||||
'src',
|
||||
'test'
|
||||
'cpu',
|
||||
'os',
|
||||
'os_cpu',
|
||||
'share'
|
||||
]
|
||||
|
||||
for jvmVariant in _jdkJvmVariants:
|
||||
@ -605,6 +601,16 @@ def _get_openjdk_cpu():
|
||||
def _get_openjdk_os_cpu():
|
||||
return _get_openjdk_os() + '-' + _get_openjdk_cpu()
|
||||
|
||||
def _get_jdk_dir():
|
||||
suiteParentDir = dirname(_suite.dir)
|
||||
# suitParentDir is now something like: /some_prefix/jdk10-hs/open/src
|
||||
pathComponents = suiteParentDir.split(os.sep)
|
||||
for i in range(0, len(pathComponents)):
|
||||
if pathComponents[i] in ["open", "src"]:
|
||||
del pathComponents[i:]
|
||||
break
|
||||
return os.path.join(os.sep, *pathComponents)
|
||||
|
||||
def _get_jdk_build_dir(debugLevel=None):
|
||||
"""
|
||||
Gets the directory into which the JDK is built. This directory contains
|
||||
@ -613,7 +619,7 @@ def _get_jdk_build_dir(debugLevel=None):
|
||||
if debugLevel is None:
|
||||
debugLevel = _vm.debugLevel
|
||||
name = '{}-{}-{}-{}'.format(_get_openjdk_os_cpu(), 'normal', _vm.jvmVariant, debugLevel)
|
||||
return join(dirname(_suite.dir), 'build', name)
|
||||
return join(_get_jdk_dir(), 'build', name)
|
||||
|
||||
_jvmci_bootclasspath_prepends = []
|
||||
|
||||
|
@ -24,9 +24,7 @@ suite = {
|
||||
|
||||
"defaultLicense" : "GPLv2-CPE",
|
||||
|
||||
# This puts mx/ as a sibling of the JDK build configuration directories
|
||||
# (e.g., macosx-x86_64-normal-server-release).
|
||||
"outputRoot" : "../build/mx/hotspot",
|
||||
"outputRoot" : "../../build/mx/hotspot",
|
||||
|
||||
# ------------- Libraries -------------
|
||||
|
||||
@ -43,7 +41,7 @@ suite = {
|
||||
# ------------- JVMCI:Service -------------
|
||||
|
||||
"jdk.vm.ci.services" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"javaCompliance" : "9",
|
||||
"workingSets" : "API,JVMCI",
|
||||
@ -52,7 +50,7 @@ suite = {
|
||||
# ------------- JVMCI:API -------------
|
||||
|
||||
"jdk.vm.ci.common" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"checkstyle" : "jdk.vm.ci.services",
|
||||
"javaCompliance" : "9",
|
||||
@ -60,7 +58,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.meta" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"checkstyle" : "jdk.vm.ci.services",
|
||||
"javaCompliance" : "9",
|
||||
@ -68,7 +66,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.code" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : ["jdk.vm.ci.meta"],
|
||||
"checkstyle" : "jdk.vm.ci.services",
|
||||
@ -77,7 +75,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.code.test" : {
|
||||
"subDir" : "test/compiler/jvmci",
|
||||
"subDir" : "../../test/hotspot/jtreg/compiler/jvmci",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"mx:JUNIT",
|
||||
@ -92,7 +90,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.runtime" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"jdk.vm.ci.code",
|
||||
@ -104,7 +102,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.runtime.test" : {
|
||||
"subDir" : "test/compiler/jvmci",
|
||||
"subDir" : "../../test/hotspot/jtreg/compiler/jvmci",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"mx:JUNIT",
|
||||
@ -119,7 +117,7 @@ suite = {
|
||||
# ------------- JVMCI:HotSpot -------------
|
||||
|
||||
"jdk.vm.ci.aarch64" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : ["jdk.vm.ci.code"],
|
||||
"checkstyle" : "jdk.vm.ci.services",
|
||||
@ -128,7 +126,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.amd64" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : ["jdk.vm.ci.code"],
|
||||
"checkstyle" : "jdk.vm.ci.services",
|
||||
@ -137,7 +135,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.sparc" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : ["jdk.vm.ci.code"],
|
||||
"checkstyle" : "jdk.vm.ci.services",
|
||||
@ -146,7 +144,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.hotspot" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"jdk.vm.ci.common",
|
||||
@ -163,7 +161,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.hotspot.test" : {
|
||||
"subDir" : "test/compiler/jvmci",
|
||||
"subDir" : "../../test/hotspot/jtreg/compiler/jvmci",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"TESTNG",
|
||||
@ -175,7 +173,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.hotspot.aarch64" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"jdk.vm.ci.aarch64",
|
||||
@ -187,7 +185,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.hotspot.amd64" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"jdk.vm.ci.amd64",
|
||||
@ -199,7 +197,7 @@ suite = {
|
||||
},
|
||||
|
||||
"jdk.vm.ci.hotspot.sparc" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"sourceDirs" : ["src"],
|
||||
"dependencies" : [
|
||||
"jdk.vm.ci.sparc",
|
||||
@ -221,12 +219,12 @@ suite = {
|
||||
# ------------- Distributions -------------
|
||||
|
||||
"JVMCI_SERVICES" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"dependencies" : ["jdk.vm.ci.services"],
|
||||
},
|
||||
|
||||
"JVMCI_API" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"dependencies" : [
|
||||
"jdk.vm.ci.runtime",
|
||||
"jdk.vm.ci.common",
|
||||
@ -240,7 +238,7 @@ suite = {
|
||||
},
|
||||
|
||||
"JVMCI_HOTSPOT" : {
|
||||
"subDir" : "src/jdk.internal.vm.ci/share/classes",
|
||||
"subDir" : "../jdk.internal.vm.ci/share/classes",
|
||||
"dependencies" : [
|
||||
"jdk.vm.ci.hotspot.aarch64",
|
||||
"jdk.vm.ci.hotspot.amd64",
|
||||
@ -253,7 +251,7 @@ suite = {
|
||||
},
|
||||
|
||||
"JVMCI_TEST" : {
|
||||
"subDir" : "test/compiler/jvmci",
|
||||
"subDir" : "../../test/hotspot/jtreg/compiler/jvmci",
|
||||
"dependencies" : [
|
||||
"jdk.vm.ci.runtime.test",
|
||||
],
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -26,9 +26,9 @@
|
||||
#ifndef CPU_AARCH64_VM_JNITYPES_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_JNITYPES_AARCH64_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "prims/jni.h"
|
||||
|
||||
// This file holds platform-dependent routines used to write primitive jni
|
||||
// types to the array of arguments passed into JavaCalls::call
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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,9 +25,9 @@
|
||||
#ifndef CPU_ARM_VM_JNITYPES_ARM_HPP
|
||||
#define CPU_ARM_VM_JNITYPES_ARM_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "prims/jni.h"
|
||||
|
||||
// This file holds platform-dependent routines used to write primitive jni
|
||||
// types to the array of arguments passed into JavaCalls::call
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -2867,46 +2867,51 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR) except for callee_saved_regs.
|
||||
void gen_write_ref_array_pre_barrier(Register addr, Register count, int callee_saved_regs) {
|
||||
BarrierSet* bs = Universe::heap()->barrier_set();
|
||||
if (bs->has_write_ref_pre_barrier()) {
|
||||
assert(bs->has_write_ref_array_pre_opt(),
|
||||
"Else unsupported barrier set.");
|
||||
switch (bs->kind()) {
|
||||
case BarrierSet::G1SATBCTLogging:
|
||||
{
|
||||
assert( addr->encoding() < callee_saved_regs, "addr must be saved");
|
||||
assert(count->encoding() < callee_saved_regs, "count must be saved");
|
||||
|
||||
assert( addr->encoding() < callee_saved_regs, "addr must be saved");
|
||||
assert(count->encoding() < callee_saved_regs, "count must be saved");
|
||||
|
||||
BLOCK_COMMENT("PreBarrier");
|
||||
BLOCK_COMMENT("PreBarrier");
|
||||
|
||||
#ifdef AARCH64
|
||||
callee_saved_regs = align_up(callee_saved_regs, 2);
|
||||
for (int i = 0; i < callee_saved_regs; i += 2) {
|
||||
__ raw_push(as_Register(i), as_Register(i+1));
|
||||
}
|
||||
callee_saved_regs = align_up(callee_saved_regs, 2);
|
||||
for (int i = 0; i < callee_saved_regs; i += 2) {
|
||||
__ raw_push(as_Register(i), as_Register(i+1));
|
||||
}
|
||||
#else
|
||||
RegisterSet saved_regs = RegisterSet(R0, as_Register(callee_saved_regs-1));
|
||||
__ push(saved_regs | R9ifScratched);
|
||||
RegisterSet saved_regs = RegisterSet(R0, as_Register(callee_saved_regs-1));
|
||||
__ push(saved_regs | R9ifScratched);
|
||||
#endif // AARCH64
|
||||
|
||||
if (addr != R0) {
|
||||
assert_different_registers(count, R0);
|
||||
__ mov(R0, addr);
|
||||
}
|
||||
if (addr != R0) {
|
||||
assert_different_registers(count, R0);
|
||||
__ mov(R0, addr);
|
||||
}
|
||||
#ifdef AARCH64
|
||||
__ zero_extend(R1, count, 32); // BarrierSet::static_write_ref_array_pre takes size_t
|
||||
__ zero_extend(R1, count, 32); // BarrierSet::static_write_ref_array_pre takes size_t
|
||||
#else
|
||||
if (count != R1) {
|
||||
__ mov(R1, count);
|
||||
}
|
||||
if (count != R1) {
|
||||
__ mov(R1, count);
|
||||
}
|
||||
#endif // AARCH64
|
||||
|
||||
__ call(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre));
|
||||
__ call(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre));
|
||||
|
||||
#ifdef AARCH64
|
||||
for (int i = callee_saved_regs - 2; i >= 0; i -= 2) {
|
||||
__ raw_pop(as_Register(i), as_Register(i+1));
|
||||
}
|
||||
for (int i = callee_saved_regs - 2; i >= 0; i -= 2) {
|
||||
__ raw_pop(as_Register(i), as_Register(i+1));
|
||||
}
|
||||
#else
|
||||
__ pop(saved_regs | R9ifScratched);
|
||||
__ pop(saved_regs | R9ifScratched);
|
||||
#endif // AARCH64
|
||||
}
|
||||
case BarrierSet::CardTableForRS:
|
||||
case BarrierSet::CardTableExtension:
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
@ -863,7 +863,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
|
||||
//
|
||||
// markOop displaced_header = obj->mark().set_unlocked();
|
||||
// monitor->lock()->set_displaced_header(displaced_header);
|
||||
// if (Atomic::cmpxchg_ptr(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) {
|
||||
// if (Atomic::cmpxchg(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) {
|
||||
// // We stored the monitor address into the object's mark word.
|
||||
// } else if (THREAD->is_lock_owned((address)displaced_header))
|
||||
// // Simple recursive case.
|
||||
@ -901,7 +901,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
|
||||
std(displaced_header, BasicObjectLock::lock_offset_in_bytes() +
|
||||
BasicLock::displaced_header_offset_in_bytes(), monitor);
|
||||
|
||||
// if (Atomic::cmpxchg_ptr(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) {
|
||||
// if (Atomic::cmpxchg(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) {
|
||||
|
||||
// Store stack address of the BasicObjectLock (this is monitor) into object.
|
||||
addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes());
|
||||
@ -977,7 +977,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e
|
||||
// if ((displaced_header = monitor->displaced_header()) == NULL) {
|
||||
// // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL.
|
||||
// monitor->set_obj(NULL);
|
||||
// } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) {
|
||||
// } else if (Atomic::cmpxchg(displaced_header, obj->mark_addr(), monitor) == monitor) {
|
||||
// // We swapped the unlocked mark in displaced_header into the object's mark word.
|
||||
// monitor->set_obj(NULL);
|
||||
// } else {
|
||||
@ -1010,7 +1010,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e
|
||||
cmpdi(CCR0, displaced_header, 0);
|
||||
beq(CCR0, free_slot); // recursive unlock
|
||||
|
||||
// } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) {
|
||||
// } else if (Atomic::cmpxchg(displaced_header, obj->mark_addr(), monitor) == monitor) {
|
||||
// // We swapped the unlocked mark in displaced_header into the object's mark word.
|
||||
// monitor->set_obj(NULL);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -26,9 +26,9 @@
|
||||
#ifndef CPU_PPC_VM_JNITYPES_PPC_HPP
|
||||
#define CPU_PPC_VM_JNITYPES_PPC_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "prims/jni.h"
|
||||
|
||||
// This file holds platform-dependent routines used to write primitive
|
||||
// jni types to the array of arguments passed into JavaCalls::call.
|
||||
|
@ -149,8 +149,7 @@ void VM_Version::initialize() {
|
||||
print_features();
|
||||
}
|
||||
|
||||
// PPC64 supports 8-byte compare-exchange operations (see
|
||||
// Atomic::cmpxchg and StubGenerator::generate_atomic_cmpxchg_ptr)
|
||||
// PPC64 supports 8-byte compare-exchange operations (see Atomic::cmpxchg)
|
||||
// and 'atomic long memory ops' (see Unsafe_GetLongVolatile).
|
||||
_supports_cx8 = true;
|
||||
|
||||
|
@ -914,7 +914,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
|
||||
//
|
||||
// markOop displaced_header = obj->mark().set_unlocked();
|
||||
// monitor->lock()->set_displaced_header(displaced_header);
|
||||
// if (Atomic::cmpxchg_ptr(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) {
|
||||
// if (Atomic::cmpxchg(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) {
|
||||
// // We stored the monitor address into the object's mark word.
|
||||
// } else if (THREAD->is_lock_owned((address)displaced_header))
|
||||
// // Simple recursive case.
|
||||
@ -949,7 +949,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
|
||||
z_stg(displaced_header, BasicObjectLock::lock_offset_in_bytes() +
|
||||
BasicLock::displaced_header_offset_in_bytes(), monitor);
|
||||
|
||||
// if (Atomic::cmpxchg_ptr(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) {
|
||||
// if (Atomic::cmpxchg(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) {
|
||||
|
||||
// Store stack address of the BasicObjectLock (this is monitor) into object.
|
||||
add2reg(object_mark_addr, oopDesc::mark_offset_in_bytes(), object);
|
||||
@ -1021,7 +1021,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object)
|
||||
// if ((displaced_header = monitor->displaced_header()) == NULL) {
|
||||
// // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL.
|
||||
// monitor->set_obj(NULL);
|
||||
// } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) {
|
||||
// } else if (Atomic::cmpxchg(displaced_header, obj->mark_addr(), monitor) == monitor) {
|
||||
// // We swapped the unlocked mark in displaced_header into the object's mark word.
|
||||
// monitor->set_obj(NULL);
|
||||
// } else {
|
||||
@ -1062,7 +1062,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object)
|
||||
BasicLock::displaced_header_offset_in_bytes()));
|
||||
z_bre(done); // displaced_header == 0 -> goto done
|
||||
|
||||
// } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) {
|
||||
// } else if (Atomic::cmpxchg(displaced_header, obj->mark_addr(), monitor) == monitor) {
|
||||
// // We swapped the unlocked mark in displaced_header into the object's mark word.
|
||||
// monitor->set_obj(NULL);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -29,9 +29,9 @@
|
||||
// This file holds platform-dependent routines used to write primitive
|
||||
// jni types to the array of arguments passed into JavaCalls::call.
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "prims/jni.h"
|
||||
|
||||
class JNITypes : AllStatic {
|
||||
// These functions write a java primitive type (in native format) to
|
||||
|
@ -224,7 +224,7 @@ void VM_Version::initialize() {
|
||||
}
|
||||
|
||||
// z/Architecture supports 8-byte compare-exchange operations
|
||||
// (see Atomic::cmpxchg and StubGenerator::generate_atomic_cmpxchg_ptr)
|
||||
// (see Atomic::cmpxchg)
|
||||
// and 'atomic long memory ops' (see Unsafe_GetLongVolatile).
|
||||
_supports_cx8 = true;
|
||||
|
||||
|
@ -25,9 +25,9 @@
|
||||
#ifndef CPU_SPARC_VM_JNITYPES_SPARC_HPP
|
||||
#define CPU_SPARC_VM_JNITYPES_SPARC_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "prims/jni.h"
|
||||
|
||||
// This file holds platform-dependent routines used to write primitive jni
|
||||
// types to the array of arguments passed into JavaCalls::call
|
||||
|
@ -383,6 +383,7 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// frame::adjust_unextended_sp
|
||||
#ifdef ASSERT
|
||||
void frame::adjust_unextended_sp() {
|
||||
// On x86, sites calling method handle intrinsics and lambda forms are treated
|
||||
// as any other call site. Therefore, no special action is needed when we are
|
||||
@ -394,11 +395,12 @@ void frame::adjust_unextended_sp() {
|
||||
// If the sender PC is a deoptimization point, get the original PC.
|
||||
if (sender_cm->is_deopt_entry(_pc) ||
|
||||
sender_cm->is_deopt_mh_entry(_pc)) {
|
||||
DEBUG_ONLY(verify_deopt_original_pc(sender_cm, _unextended_sp));
|
||||
verify_deopt_original_pc(sender_cm, _unextended_sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// frame::update_map_with_saved_link
|
||||
|
@ -117,7 +117,7 @@
|
||||
// original sp we use that convention.
|
||||
|
||||
intptr_t* _unextended_sp;
|
||||
void adjust_unextended_sp();
|
||||
void adjust_unextended_sp() NOT_DEBUG_RETURN;
|
||||
|
||||
intptr_t* ptr_at_addr(int offset) const {
|
||||
return (intptr_t*) addr_at(offset);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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,9 +25,9 @@
|
||||
#ifndef CPU_X86_VM_JNITYPES_X86_HPP
|
||||
#define CPU_X86_VM_JNITYPES_X86_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "prims/jni.h"
|
||||
|
||||
// This file holds platform-dependent routines used to write primitive jni
|
||||
// types to the array of arguments passed into JavaCalls::call
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -566,7 +566,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
// Support for intptr_t atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest)
|
||||
// Support for intptr_t atomic::xchg_long(jlong exchange_value, volatile jlong* dest)
|
||||
//
|
||||
// Arguments :
|
||||
// c_rarg0: exchange_value
|
||||
@ -574,8 +574,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
// Result:
|
||||
// *dest <- ex, return (orig *dest)
|
||||
address generate_atomic_xchg_ptr() {
|
||||
StubCodeMark mark(this, "StubRoutines", "atomic_xchg_ptr");
|
||||
address generate_atomic_xchg_long() {
|
||||
StubCodeMark mark(this, "StubRoutines", "atomic_xchg_long");
|
||||
address start = __ pc();
|
||||
|
||||
__ movptr(rax, c_rarg0); // Copy to eax we need a return value anyhow
|
||||
@ -4998,7 +4998,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
// atomic calls
|
||||
StubRoutines::_atomic_xchg_entry = generate_atomic_xchg();
|
||||
StubRoutines::_atomic_xchg_ptr_entry = generate_atomic_xchg_ptr();
|
||||
StubRoutines::_atomic_xchg_long_entry = generate_atomic_xchg_long();
|
||||
StubRoutines::_atomic_cmpxchg_entry = generate_atomic_cmpxchg();
|
||||
StubRoutines::_atomic_cmpxchg_byte_entry = generate_atomic_cmpxchg_byte();
|
||||
StubRoutines::_atomic_cmpxchg_long_entry = generate_atomic_cmpxchg_long();
|
||||
|
@ -276,7 +276,7 @@ int CppInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) {
|
||||
markOop disp = lockee->mark()->set_unlocked();
|
||||
|
||||
monitor->lock()->set_displaced_header(disp);
|
||||
if (Atomic::cmpxchg_ptr(monitor, lockee->mark_addr(), disp) != disp) {
|
||||
if (Atomic::cmpxchg((markOop)monitor, lockee->mark_addr(), disp) != disp) {
|
||||
if (thread->is_lock_owned((address) disp->clear_lock_bits())) {
|
||||
monitor->lock()->set_displaced_header(NULL);
|
||||
}
|
||||
@ -420,7 +420,8 @@ int CppInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) {
|
||||
monitor->set_obj(NULL);
|
||||
|
||||
if (header != NULL) {
|
||||
if (Atomic::cmpxchg_ptr(header, rcvr->mark_addr(), lock) != lock) {
|
||||
markOop old_header = markOopDesc::encode(lock);
|
||||
if (rcvr->cas_set_mark(header, old_header) != old_header) {
|
||||
monitor->set_obj(rcvr); {
|
||||
HandleMark hm(thread);
|
||||
CALL_VM_NOCHECK(InterpreterRuntime::monitorexit(thread, monitor));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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,9 +25,9 @@
|
||||
#ifndef CPU_ZERO_VM_JNITYPES_ZERO_HPP
|
||||
#define CPU_ZERO_VM_JNITYPES_ZERO_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "prims/jni.h"
|
||||
|
||||
// This file holds platform-dependent routines used to write primitive jni
|
||||
// types to the array of arguments passed into JavaCalls::call
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008, 2010, 2015 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -253,9 +253,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
// atomic calls
|
||||
StubRoutines::_atomic_xchg_entry = ShouldNotCallThisStub();
|
||||
StubRoutines::_atomic_xchg_ptr_entry = ShouldNotCallThisStub();
|
||||
StubRoutines::_atomic_xchg_long_entry = ShouldNotCallThisStub();
|
||||
StubRoutines::_atomic_cmpxchg_entry = ShouldNotCallThisStub();
|
||||
StubRoutines::_atomic_cmpxchg_ptr_entry = ShouldNotCallThisStub();
|
||||
StubRoutines::_atomic_cmpxchg_byte_entry = ShouldNotCallThisStub();
|
||||
StubRoutines::_atomic_cmpxchg_long_entry = ShouldNotCallThisStub();
|
||||
StubRoutines::_atomic_add_entry = ShouldNotCallThisStub();
|
||||
|
@ -34,8 +34,6 @@ class AIXDecoder: public AbstractDecoder {
|
||||
}
|
||||
virtual ~AIXDecoder() {}
|
||||
|
||||
virtual bool can_decode_C_frame_in_vm() const { return true; }
|
||||
|
||||
virtual bool demangle(const char* symbol, char* buf, int buflen) { return false; } // use AixSymbols::get_function_name to demangle
|
||||
|
||||
virtual bool decode(address addr, char* buf, int buflen, int* offset, const char* modulepath, bool demangle) {
|
||||
|
@ -889,8 +889,12 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
|
||||
stack_size / K);
|
||||
}
|
||||
|
||||
// Configure libc guard page.
|
||||
ret = pthread_attr_setguardsize(&attr, os::Aix::default_guard_size(thr_type));
|
||||
// Save some cycles and a page by disabling OS guard pages where we have our own
|
||||
// VM guard pages (in java threads). For other threads, keep system default guard
|
||||
// pages in place.
|
||||
if (thr_type == java_thread || thr_type == compiler_thread) {
|
||||
ret = pthread_attr_setguardsize(&attr, 0);
|
||||
}
|
||||
|
||||
pthread_t tid = 0;
|
||||
if (ret == 0) {
|
||||
@ -3019,19 +3023,6 @@ bool os::Aix::chained_handler(int sig, siginfo_t* siginfo, void* context) {
|
||||
return chained;
|
||||
}
|
||||
|
||||
size_t os::Aix::default_guard_size(os::ThreadType thr_type) {
|
||||
// Creating guard page is very expensive. Java thread has HotSpot
|
||||
// guard pages, only enable glibc guard page for non-Java threads.
|
||||
// (Remember: compiler thread is a Java thread, too!)
|
||||
//
|
||||
// Aix can have different page sizes for stack (4K) and heap (64K).
|
||||
// As Hotspot knows only one page size, we assume the stack has
|
||||
// the same page size as the heap. Returning page_size() here can
|
||||
// cause 16 guard pages which we want to avoid. Thus we return 4K
|
||||
// which will be rounded to the real page size by the OS.
|
||||
return ((thr_type == java_thread || thr_type == compiler_thread) ? 0 : 4 * K);
|
||||
}
|
||||
|
||||
struct sigaction* os::Aix::get_preinstalled_handler(int sig) {
|
||||
if (sigismember(&sigs, sig)) {
|
||||
return &sigact[sig];
|
||||
|
@ -139,9 +139,6 @@ class Aix {
|
||||
// libpthread version string
|
||||
static void libpthread_init();
|
||||
|
||||
// Return default libc guard size for the specified thread type.
|
||||
static size_t default_guard_size(os::ThreadType thr_type);
|
||||
|
||||
// Function returns true if we run on OS/400 (pase), false if we run
|
||||
// on AIX.
|
||||
static bool on_pase() {
|
||||
|
@ -35,9 +35,6 @@ class MachODecoder : public AbstractDecoder {
|
||||
public:
|
||||
MachODecoder() { }
|
||||
virtual ~MachODecoder() { }
|
||||
virtual bool can_decode_C_frame_in_vm() const {
|
||||
return true;
|
||||
}
|
||||
virtual bool demangle(const char* symbol, char* buf, int buflen);
|
||||
virtual bool decode(address pc, char* buf, int buflen, int* offset,
|
||||
const void* base);
|
||||
|
@ -98,6 +98,11 @@ inline int os::ftruncate(int fd, jlong length) {
|
||||
|
||||
inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf)
|
||||
{
|
||||
// readdir_r has been deprecated since glibc 2.24.
|
||||
// See https://sourceware.org/bugzilla/show_bug.cgi?id=19056 for more details.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
dirent* p;
|
||||
int status;
|
||||
assert(dirp != NULL, "just checking");
|
||||
@ -111,6 +116,8 @@ inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf)
|
||||
return NULL;
|
||||
} else
|
||||
return p;
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
inline int os::closedir(DIR *dirp) {
|
||||
|
@ -23,136 +23,28 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "prims/jvm.h"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "decoder_windows.hpp"
|
||||
#include "utilities/decoder.hpp"
|
||||
#include "symbolengine.hpp"
|
||||
#include "windbghelp.hpp"
|
||||
|
||||
WindowsDecoder::WindowsDecoder() {
|
||||
_can_decode_in_vm = true;
|
||||
_decoder_status = no_error;
|
||||
initialize();
|
||||
bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const char* modulepath, bool demangle) {
|
||||
return SymbolEngine::decode(addr, buf, buflen, offset, demangle);
|
||||
}
|
||||
|
||||
void WindowsDecoder::initialize() {
|
||||
if (!has_error()) {
|
||||
HANDLE hProcess = ::GetCurrentProcess();
|
||||
WindowsDbgHelp::symSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
|
||||
if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) {
|
||||
_decoder_status = helper_init_error;
|
||||
return;
|
||||
}
|
||||
|
||||
// set pdb search paths
|
||||
char paths[MAX_PATH];
|
||||
int len = sizeof(paths);
|
||||
if (!WindowsDbgHelp::symGetSearchPath(hProcess, paths, len)) {
|
||||
paths[0] = '\0';
|
||||
} else {
|
||||
// available spaces in path buffer
|
||||
len -= (int)strlen(paths);
|
||||
}
|
||||
|
||||
char tmp_path[MAX_PATH];
|
||||
DWORD dwSize;
|
||||
HMODULE hJVM = ::GetModuleHandle("jvm.dll");
|
||||
tmp_path[0] = '\0';
|
||||
// append the path where jvm.dll is located
|
||||
if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) {
|
||||
while (dwSize > 0 && tmp_path[dwSize] != '\\') {
|
||||
dwSize --;
|
||||
}
|
||||
|
||||
tmp_path[dwSize] = '\0';
|
||||
|
||||
if (dwSize > 0 && len > (int)dwSize + 1) {
|
||||
strncat(paths, os::path_separator(), 1);
|
||||
strncat(paths, tmp_path, dwSize);
|
||||
len -= dwSize + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// append $JRE/bin. Arguments::get_java_home actually returns $JRE
|
||||
// path
|
||||
char *p = Arguments::get_java_home();
|
||||
assert(p != NULL, "empty java home");
|
||||
size_t java_home_len = strlen(p);
|
||||
if (len > (int)java_home_len + 5) {
|
||||
strncat(paths, os::path_separator(), 1);
|
||||
strncat(paths, p, java_home_len);
|
||||
strncat(paths, "\\bin", 4);
|
||||
len -= (int)(java_home_len + 5);
|
||||
}
|
||||
|
||||
// append $JDK/bin path if it exists
|
||||
assert(java_home_len < MAX_PATH, "Invalid path length");
|
||||
// assume $JRE is under $JDK, construct $JDK/bin path and
|
||||
// see if it exists or not
|
||||
if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) {
|
||||
strncpy(tmp_path, p, java_home_len - 3);
|
||||
tmp_path[java_home_len - 3] = '\0';
|
||||
strncat(tmp_path, "bin", 3);
|
||||
|
||||
// if the directory exists
|
||||
DWORD dwAttrib = GetFileAttributes(tmp_path);
|
||||
if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
|
||||
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
// tmp_path should have the same length as java_home_len, since we only
|
||||
// replaced 'jre' with 'bin'
|
||||
if (len > (int)java_home_len + 1) {
|
||||
strncat(paths, os::path_separator(), 1);
|
||||
strncat(paths, tmp_path, java_home_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WindowsDbgHelp::symSetSearchPath(hProcess, paths);
|
||||
|
||||
// find out if jvm.dll contains private symbols, by decoding
|
||||
// current function and comparing the result
|
||||
address addr = (address)Decoder::demangle;
|
||||
char buf[MAX_PATH];
|
||||
if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) {
|
||||
_can_decode_in_vm = !strcmp(buf, "Decoder::demangle");
|
||||
}
|
||||
}
|
||||
bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const void* base) {
|
||||
return SymbolEngine::decode(addr, buf, buflen, offset, true);
|
||||
}
|
||||
|
||||
void WindowsDecoder::uninitialize() {}
|
||||
|
||||
bool WindowsDecoder::can_decode_C_frame_in_vm() const {
|
||||
return (!has_error() && _can_decode_in_vm);
|
||||
bool Decoder::get_source_info(address pc, char* buf, size_t buflen, int* line) {
|
||||
return SymbolEngine::get_source_info(pc, buf, buflen, line);
|
||||
}
|
||||
|
||||
|
||||
bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle_name) {
|
||||
if (!has_error()) {
|
||||
PIMAGEHLP_SYMBOL64 pSymbol;
|
||||
char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)];
|
||||
pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo;
|
||||
pSymbol->MaxNameLength = MAX_PATH;
|
||||
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
DWORD64 displacement;
|
||||
if (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
|
||||
if (buf != NULL) {
|
||||
if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) {
|
||||
jio_snprintf(buf, buflen, "%s", pSymbol->Name);
|
||||
}
|
||||
}
|
||||
if(offset != NULL) *offset = (int)displacement;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (buf != NULL && buflen > 0) buf[0] = '\0';
|
||||
if (offset != NULL) *offset = -1;
|
||||
return false;
|
||||
bool Decoder::demangle(const char* symbol, char* buf, int buflen) {
|
||||
return SymbolEngine::demangle(symbol, buf, buflen);
|
||||
}
|
||||
|
||||
bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) {
|
||||
if (!has_error()) {
|
||||
return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0;
|
||||
}
|
||||
return false;
|
||||
void Decoder::print_state_on(outputStream* st) {
|
||||
WindowsDbgHelp::print_state_on(st);
|
||||
SymbolEngine::print_state_on(st);
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,7 @@
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
#include "symbolengine.hpp"
|
||||
#include "windbghelp.hpp"
|
||||
|
||||
|
||||
@ -134,6 +135,8 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) {
|
||||
if (ForceTimeHighResolution) {
|
||||
timeBeginPeriod(1L);
|
||||
}
|
||||
WindowsDbgHelp::pre_initialize();
|
||||
SymbolEngine::pre_initialize();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (ForceTimeHighResolution) {
|
||||
@ -1319,6 +1322,8 @@ static int _print_module(const char* fname, address base_address,
|
||||
void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
|
||||
void * result = LoadLibrary(name);
|
||||
if (result != NULL) {
|
||||
// Recalculate pdb search path if a DLL was loaded successfully.
|
||||
SymbolEngine::recalc_search_path();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -4032,6 +4037,8 @@ jint os::init_2(void) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
SymbolEngine::recalc_search_path();
|
||||
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
|
641
src/hotspot/os/windows/symbolengine.cpp
Normal file
641
src/hotspot/os/windows/symbolengine.cpp
Normal file
@ -0,0 +1,641 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "symbolengine.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "windbghelp.hpp"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <imagehlp.h>
|
||||
#include <psapi.h>
|
||||
|
||||
|
||||
|
||||
// This code may be invoked normally but also as part of error reporting
|
||||
// In the latter case, we may run under tight memory constraints (native oom)
|
||||
// or in a stack overflow situation or the C heap may be corrupted. We may
|
||||
// run very early before VM initialization or very late when C exit handlers
|
||||
// run. In all these cases, callstacks would still be nice, so lets be robust.
|
||||
//
|
||||
// We need a number of buffers - for the pdb search path, module handle
|
||||
// lists, for demangled symbols, etc.
|
||||
//
|
||||
// These buffers, while typically small, may need to be large for corner
|
||||
// cases (e.g. templatized C++ symbols, or many DLLs loaded). Where do we
|
||||
// allocate them?
|
||||
//
|
||||
// We may be in error handling for a stack overflow, so lets not put them on
|
||||
// the stack.
|
||||
//
|
||||
// Dynamically allocating them may fail if we are handling a native OOM. It
|
||||
// is also a bit dangerous, as the C heap may be corrupted already.
|
||||
//
|
||||
// That leaves pre-allocating them globally, which is safe and should always
|
||||
// work (if we synchronize access) but incurs an undesirable footprint for
|
||||
// non-error cases.
|
||||
//
|
||||
// We follow a two-way strategy: Allocate the buffers on the C heap in a
|
||||
// reasonable large size. Failing that, fall back to static preallocated
|
||||
// buffers. The size of the latter is large enough to handle common scenarios
|
||||
// but small enough not to drive up the footprint too much (several kb).
|
||||
//
|
||||
// We keep these buffers around once allocated, for subsequent requests. This
|
||||
// means that by running the initialization early at a safe time - before
|
||||
// any error happens - buffers can be pre-allocated. This increases the chance
|
||||
// of useful callstacks in error scenarios in exchange for a some cycles spent
|
||||
// at startup. This behavior can be controlled with -XX:+InitializeDbgHelpEarly
|
||||
// and is off by default.
|
||||
|
||||
///////
|
||||
|
||||
// A simple buffer which attempts to allocate an optimal size but will
|
||||
// fall back to a static minimally sized array on allocation error.
|
||||
template <class T, int MINIMAL_CAPACITY, int OPTIMAL_CAPACITY>
|
||||
class SimpleBufferWithFallback {
|
||||
T _fallback_buffer[MINIMAL_CAPACITY];
|
||||
T* _p;
|
||||
int _capacity;
|
||||
|
||||
// A sentinel at the end of the buffer to catch overflows.
|
||||
void imprint_sentinel() {
|
||||
assert(_p && _capacity > 0, "Buffer must be allocated");
|
||||
_p[_capacity - 1] = (T)'X';
|
||||
_capacity --;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
SimpleBufferWithFallback<T, MINIMAL_CAPACITY, OPTIMAL_CAPACITY> ()
|
||||
: _p(NULL), _capacity(0)
|
||||
{}
|
||||
|
||||
// Note: no destructor because these buffers should, once
|
||||
// allocated, live until process end.
|
||||
// ~SimpleBufferWithFallback()
|
||||
|
||||
// Note: We use raw ::malloc/::free here instead of os::malloc()/os::free
|
||||
// to prevent circularities or secondary crashes during error reporting.
|
||||
virtual void initialize () {
|
||||
assert(_p == NULL && _capacity == 0, "Only call once.");
|
||||
const size_t bytes = OPTIMAL_CAPACITY * sizeof(T);
|
||||
T* q = (T*) ::malloc(bytes);
|
||||
if (q != NULL) {
|
||||
_p = q;
|
||||
_capacity = OPTIMAL_CAPACITY;
|
||||
} else {
|
||||
_p = _fallback_buffer;
|
||||
_capacity = (int)(sizeof(_fallback_buffer) / sizeof(T));
|
||||
}
|
||||
_p[0] = '\0';
|
||||
imprint_sentinel();
|
||||
}
|
||||
|
||||
// We need a way to reset the buffer to fallback size for one special
|
||||
// case, where two buffers need to be of identical capacity.
|
||||
void reset_to_fallback_capacity() {
|
||||
if (_p != _fallback_buffer) {
|
||||
::free(_p);
|
||||
}
|
||||
_p = _fallback_buffer;
|
||||
_capacity = (int)(sizeof(_fallback_buffer) / sizeof(T));
|
||||
_p[0] = '\0';
|
||||
imprint_sentinel();
|
||||
}
|
||||
|
||||
T* ptr() { return _p; }
|
||||
const T* ptr() const { return _p; }
|
||||
int capacity() const { return _capacity; }
|
||||
|
||||
#ifdef ASSERT
|
||||
void check() const {
|
||||
assert(_p[_capacity] == (T)'X', "sentinel lost");
|
||||
}
|
||||
#else
|
||||
void check() const {}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
////
|
||||
|
||||
// ModuleHandleArray: a list holding module handles. Needs to be large enough
|
||||
// to hold one handle per loaded DLL.
|
||||
// Note: a standard OpenJDK loads normally ~30 libraries, including system
|
||||
// libraries, without third party libraries.
|
||||
|
||||
typedef SimpleBufferWithFallback <HMODULE, 48, 512> ModuleHandleArrayBase;
|
||||
|
||||
class ModuleHandleArray : public ModuleHandleArrayBase {
|
||||
|
||||
int _num; // Number of handles in this array (may be < capacity).
|
||||
|
||||
public:
|
||||
|
||||
void initialize() {
|
||||
ModuleHandleArrayBase::initialize();
|
||||
_num = 0;
|
||||
}
|
||||
|
||||
int num() const { return _num; }
|
||||
void set_num(int n) {
|
||||
assert(n <= capacity(), "Too large");
|
||||
_num = n;
|
||||
}
|
||||
|
||||
// Compare with another list; returns true if all handles are equal (incl.
|
||||
// sort order)
|
||||
bool equals(const ModuleHandleArray& other) const {
|
||||
if (_num != other._num) {
|
||||
return false;
|
||||
}
|
||||
if (::memcmp(ptr(), other.ptr(), _num * sizeof(HMODULE)) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy content from other list.
|
||||
void copy_content_from(ModuleHandleArray& other) {
|
||||
assert(capacity() == other.capacity(), "Different capacities.");
|
||||
memcpy(ptr(), other.ptr(), other._num * sizeof(HMODULE));
|
||||
_num = other._num;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
////
|
||||
|
||||
// PathBuffer: a buffer to hold and work with a pdb search PATH - a concatenation
|
||||
// of multiple directories separated by ';'.
|
||||
// A single directory name can be (NTFS) as long as 32K, but in reality is
|
||||
// seldom larger than the (historical) MAX_PATH of 260.
|
||||
|
||||
#define MINIMUM_PDB_PATH_LENGTH MAX_PATH * 4
|
||||
#define OPTIMAL_PDB_PATH_LENGTH MAX_PATH * 64
|
||||
|
||||
typedef SimpleBufferWithFallback<char, MINIMUM_PDB_PATH_LENGTH, OPTIMAL_PDB_PATH_LENGTH> PathBufferBase;
|
||||
|
||||
class PathBuffer: public PathBufferBase {
|
||||
public:
|
||||
|
||||
// Search PDB path for a directory. Search is case insensitive. Returns
|
||||
// true if directory was found in the path, false otherwise.
|
||||
bool contains_directory(const char* directory) {
|
||||
if (ptr() == NULL) {
|
||||
return false;
|
||||
}
|
||||
const size_t len = strlen(directory);
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
char* p = ptr();
|
||||
for(;;) {
|
||||
char* q = strchr(p, ';');
|
||||
if (q != NULL) {
|
||||
if (len == (q - p)) {
|
||||
if (strnicmp(p, directory, len) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
p = q + 1;
|
||||
} else {
|
||||
// tail
|
||||
return stricmp(p, directory) == 0 ? true : false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Appends the given directory to the path. Returns false if internal
|
||||
// buffer size was not sufficient.
|
||||
bool append_directory(const char* directory) {
|
||||
const size_t len = strlen(directory);
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
char* p = ptr();
|
||||
const size_t len_now = strlen(p);
|
||||
const size_t needs_capacity = len_now + 1 + len + 1; // xxx;yy\0
|
||||
if (needs_capacity > (size_t)capacity()) {
|
||||
return false; // OOM
|
||||
}
|
||||
if (len_now > 0) { // Not the first path element.
|
||||
p += len_now;
|
||||
*p = ';';
|
||||
p ++;
|
||||
}
|
||||
strcpy(p, directory);
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// A simple buffer to hold one single file name. A file name can be (NTFS) as
|
||||
// long as 32K, but in reality is seldom larger than MAX_PATH.
|
||||
typedef SimpleBufferWithFallback<char, MAX_PATH, 8 * K> FileNameBuffer;
|
||||
|
||||
// A buffer to hold a C++ symbol. Usually small, but symbols may be larger for
|
||||
// templates.
|
||||
#define MINIMUM_SYMBOL_NAME_LEN 128
|
||||
#define OPTIMAL_SYMBOL_NAME_LEN 1024
|
||||
|
||||
typedef SimpleBufferWithFallback<uint8_t,
|
||||
sizeof(IMAGEHLP_SYMBOL64) + MINIMUM_SYMBOL_NAME_LEN,
|
||||
sizeof(IMAGEHLP_SYMBOL64) + OPTIMAL_SYMBOL_NAME_LEN> SymbolBuffer;
|
||||
|
||||
static struct {
|
||||
|
||||
// Two buffers to hold lists of loaded modules. handles across invocations of
|
||||
// SymbolEngine::recalc_search_path().
|
||||
ModuleHandleArray loaded_modules;
|
||||
ModuleHandleArray last_loaded_modules;
|
||||
// Buffer to retrieve and assemble the pdb search path.
|
||||
PathBuffer search_path;
|
||||
// Buffer to retrieve directory names for loaded modules.
|
||||
FileNameBuffer dir_name;
|
||||
// Buffer to retrieve decoded symbol information (in SymbolEngine::decode)
|
||||
SymbolBuffer decode_buffer;
|
||||
|
||||
void initialize() {
|
||||
search_path.initialize();
|
||||
dir_name.initialize();
|
||||
decode_buffer.initialize();
|
||||
|
||||
loaded_modules.initialize();
|
||||
last_loaded_modules.initialize();
|
||||
|
||||
// Note: both module lists must have the same capacity. If one allocation
|
||||
// did fail, let them both fall back to the fallback size.
|
||||
if (loaded_modules.capacity() != last_loaded_modules.capacity()) {
|
||||
loaded_modules.reset_to_fallback_capacity();
|
||||
last_loaded_modules.reset_to_fallback_capacity();
|
||||
}
|
||||
|
||||
assert(search_path.capacity() > 0 && dir_name.capacity() > 0 &&
|
||||
decode_buffer.capacity() > 0 && loaded_modules.capacity() > 0 &&
|
||||
last_loaded_modules.capacity() > 0, "Init error.");
|
||||
}
|
||||
|
||||
} g_buffers;
|
||||
|
||||
|
||||
// Scan the loaded modules.
|
||||
//
|
||||
// For each loaded module, add the directory it is located in to the pdb search
|
||||
// path, but avoid duplicates. Prior search path content is preserved.
|
||||
//
|
||||
// If p_search_path_was_updated is not NULL, points to a bool which, upon
|
||||
// successful return from the function, contains true if the search path
|
||||
// was updated, false if no update was needed because no new DLLs were
|
||||
// loaded or unloaded.
|
||||
//
|
||||
// Returns true for success, false for error.
|
||||
static bool recalc_search_path_locked(bool* p_search_path_was_updated) {
|
||||
|
||||
if (p_search_path_was_updated) {
|
||||
*p_search_path_was_updated = false;
|
||||
}
|
||||
|
||||
HANDLE hProcess = ::GetCurrentProcess();
|
||||
|
||||
BOOL success = false;
|
||||
|
||||
// 1) Retrieve current set search path.
|
||||
// (PDB search path is a global setting and someone might have modified
|
||||
// it, so take care not to remove directories, just to add our own).
|
||||
|
||||
if (!WindowsDbgHelp::symGetSearchPath(hProcess, g_buffers.search_path.ptr(),
|
||||
(int)g_buffers.search_path.capacity())) {
|
||||
return false;
|
||||
}
|
||||
DEBUG_ONLY(g_buffers.search_path.check();)
|
||||
|
||||
// 2) Retrieve list of modules handles of all currently loaded modules.
|
||||
DWORD bytes_needed = 0;
|
||||
const DWORD buffer_capacity_bytes = (DWORD)g_buffers.loaded_modules.capacity() * sizeof(HMODULE);
|
||||
success = ::EnumProcessModules(hProcess, g_buffers.loaded_modules.ptr(),
|
||||
buffer_capacity_bytes, &bytes_needed);
|
||||
DEBUG_ONLY(g_buffers.loaded_modules.check();)
|
||||
|
||||
// Note: EnumProcessModules is sloppily defined in terms of whether a
|
||||
// too-small output buffer counts as error. Will it truncate but still
|
||||
// return TRUE? Nobody knows and the manpage is not telling. So we count
|
||||
// truncation it as error, disregarding the return value.
|
||||
if (!success || bytes_needed > buffer_capacity_bytes) {
|
||||
return false;
|
||||
} else {
|
||||
const int num_modules = bytes_needed / sizeof(HMODULE);
|
||||
g_buffers.loaded_modules.set_num(num_modules);
|
||||
}
|
||||
|
||||
// Compare the list of module handles with the last list. If the lists are
|
||||
// identical, no additional dlls were loaded and we can stop.
|
||||
if (g_buffers.loaded_modules.equals(g_buffers.last_loaded_modules)) {
|
||||
return true;
|
||||
} else {
|
||||
// Remember the new set of module handles and continue.
|
||||
g_buffers.last_loaded_modules.copy_content_from(g_buffers.loaded_modules);
|
||||
}
|
||||
|
||||
// 3) For each loaded module: retrieve directory from which it was loaded.
|
||||
// Add directory to search path (but avoid duplicates).
|
||||
|
||||
bool did_modify_searchpath = false;
|
||||
|
||||
for (int i = 0; i < (int)g_buffers.loaded_modules.num(); i ++) {
|
||||
|
||||
const HMODULE hMod = g_buffers.loaded_modules.ptr()[i];
|
||||
char* const filebuffer = g_buffers.dir_name.ptr();
|
||||
const int file_buffer_capacity = g_buffers.dir_name.capacity();
|
||||
const int len_returned = (int)::GetModuleFileName(hMod, filebuffer, (DWORD)file_buffer_capacity);
|
||||
DEBUG_ONLY(g_buffers.dir_name.check();)
|
||||
if (len_returned == 0) {
|
||||
// Error. This is suspicious - this may happen if a module has just been
|
||||
// unloaded concurrently after our call to EnumProcessModules and
|
||||
// GetModuleFileName, but probably just indicates a coding error.
|
||||
assert(false, "GetModuleFileName failed (%u)", ::GetLastError());
|
||||
} else if (len_returned == file_buffer_capacity) {
|
||||
// Truncation. Just skip this module and continue with the next module.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cut file name part off.
|
||||
char* last_slash = ::strrchr(filebuffer, '\\');
|
||||
if (last_slash == NULL) {
|
||||
last_slash = ::strrchr(filebuffer, '/');
|
||||
}
|
||||
if (last_slash) {
|
||||
*last_slash = '\0';
|
||||
}
|
||||
|
||||
// If this is already part of the search path, ignore it, otherwise
|
||||
// append to search path.
|
||||
if (!g_buffers.search_path.contains_directory(filebuffer)) {
|
||||
if (!g_buffers.search_path.append_directory(filebuffer)) {
|
||||
return false; // oom
|
||||
}
|
||||
DEBUG_ONLY(g_buffers.search_path.check();)
|
||||
did_modify_searchpath = true;
|
||||
}
|
||||
|
||||
} // for each loaded module.
|
||||
|
||||
// If we did not modify the search path, nothing further needs to be done.
|
||||
if (!did_modify_searchpath) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set the search path to its new value.
|
||||
if (!WindowsDbgHelp::symSetSearchPath(hProcess, g_buffers.search_path.ptr())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_search_path_was_updated) {
|
||||
*p_search_path_was_updated = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static bool demangle_locked(const char* symbol, char *buf, int buflen) {
|
||||
|
||||
return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0;
|
||||
|
||||
}
|
||||
|
||||
static bool decode_locked(const void* addr, char* buf, int buflen, int* offset, bool do_demangle) {
|
||||
|
||||
assert(g_buffers.decode_buffer.capacity() >= (sizeof(IMAGEHLP_SYMBOL64) + MINIMUM_SYMBOL_NAME_LEN),
|
||||
"Decode buffer too small.");
|
||||
assert(buf != NULL && buflen > 0 && offset != NULL, "invalid output buffer.");
|
||||
|
||||
DWORD64 displacement;
|
||||
PIMAGEHLP_SYMBOL64 pSymbol = NULL;
|
||||
bool success = false;
|
||||
|
||||
pSymbol = (PIMAGEHLP_SYMBOL64) g_buffers.decode_buffer.ptr();
|
||||
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
pSymbol->MaxNameLength = (DWORD)(g_buffers.decode_buffer.capacity() - sizeof(IMAGEHLP_SYMBOL64) - 1);
|
||||
|
||||
// It is unclear how SymGetSymFromAddr64 handles truncation. Experiments
|
||||
// show it will return TRUE but not zero terminate (which is a really bad
|
||||
// combination). Lets be super careful.
|
||||
::memset(pSymbol->Name, 0, pSymbol->MaxNameLength); // To catch truncation.
|
||||
|
||||
if (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
|
||||
success = true;
|
||||
if (pSymbol->Name[pSymbol->MaxNameLength - 1] != '\0') {
|
||||
// Symbol was truncated. Do not attempt to demangle. Instead, zero terminate the
|
||||
// truncated string. We still return success - the truncated string may still
|
||||
// be usable for the caller.
|
||||
pSymbol->Name[pSymbol->MaxNameLength - 1] = '\0';
|
||||
do_demangle = false;
|
||||
}
|
||||
|
||||
// Attempt to demangle.
|
||||
if (do_demangle && demangle_locked(pSymbol->Name, buf, buflen)) {
|
||||
// ok.
|
||||
} else {
|
||||
::strncpy(buf, pSymbol->Name, buflen - 1);
|
||||
}
|
||||
buf[buflen - 1] = '\0';
|
||||
|
||||
*offset = (int)displacement;
|
||||
}
|
||||
|
||||
DEBUG_ONLY(g_buffers.decode_buffer.check();)
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static enum {
|
||||
state_uninitialized = 0,
|
||||
state_ready = 1,
|
||||
state_error = 2
|
||||
} g_state = state_uninitialized;
|
||||
|
||||
static void initialize() {
|
||||
|
||||
assert(g_state == state_uninitialized, "wrong sequence");
|
||||
g_state = state_error;
|
||||
|
||||
// 1) Initialize buffers.
|
||||
g_buffers.initialize();
|
||||
|
||||
// 1) Call SymInitialize
|
||||
HANDLE hProcess = ::GetCurrentProcess();
|
||||
WindowsDbgHelp::symSetOptions(SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_DEFERRED_LOADS |
|
||||
SYMOPT_EXACT_SYMBOLS | SYMOPT_LOAD_LINES);
|
||||
if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: we ignore any errors from this point on. The symbol engine may be
|
||||
// usable enough.
|
||||
g_state = state_ready;
|
||||
|
||||
(void)recalc_search_path_locked(NULL);
|
||||
|
||||
}
|
||||
|
||||
///////////////////// External functions //////////////////////////
|
||||
|
||||
// All outside facing functions are synchronized. Also, we run
|
||||
// initialization on first touch.
|
||||
|
||||
static CRITICAL_SECTION g_cs;
|
||||
|
||||
namespace { // Do not export.
|
||||
class SymbolEngineEntry {
|
||||
public:
|
||||
SymbolEngineEntry() {
|
||||
::EnterCriticalSection(&g_cs);
|
||||
if (g_state == state_uninitialized) {
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
~SymbolEngineEntry() {
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Called at DLL_PROCESS_ATTACH.
|
||||
void SymbolEngine::pre_initialize() {
|
||||
::InitializeCriticalSection(&g_cs);
|
||||
}
|
||||
|
||||
bool SymbolEngine::decode(const void* addr, char* buf, int buflen, int* offset, bool do_demangle) {
|
||||
|
||||
assert(buf != NULL && buflen > 0 && offset != NULL, "Argument error");
|
||||
buf[0] = '\0';
|
||||
*offset = -1;
|
||||
|
||||
if (addr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SymbolEngineEntry entry_guard;
|
||||
|
||||
// Try decoding the symbol once. If we fail, attempt to rebuild the
|
||||
// symbol search path - maybe the pc points to a dll whose pdb file is
|
||||
// outside our search path. Then do attempt the decode again.
|
||||
bool success = decode_locked(addr, buf, buflen, offset, do_demangle);
|
||||
if (!success) {
|
||||
bool did_update_search_path = false;
|
||||
if (recalc_search_path_locked(&did_update_search_path)) {
|
||||
if (did_update_search_path) {
|
||||
success = decode_locked(addr, buf, buflen, offset, do_demangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
|
||||
}
|
||||
|
||||
bool SymbolEngine::demangle(const char* symbol, char *buf, int buflen) {
|
||||
|
||||
SymbolEngineEntry entry_guard;
|
||||
|
||||
return demangle_locked(symbol, buf, buflen);
|
||||
|
||||
}
|
||||
|
||||
bool SymbolEngine::recalc_search_path(bool* p_search_path_was_updated) {
|
||||
|
||||
SymbolEngineEntry entry_guard;
|
||||
|
||||
return recalc_search_path_locked(p_search_path_was_updated);
|
||||
|
||||
}
|
||||
|
||||
bool SymbolEngine::get_source_info(const void* addr, char* buf, size_t buflen,
|
||||
int* line_no)
|
||||
{
|
||||
assert(buf != NULL && buflen > 0 && line_no != NULL, "Argument error");
|
||||
buf[0] = '\0';
|
||||
*line_no = -1;
|
||||
|
||||
if (addr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SymbolEngineEntry entry_guard;
|
||||
|
||||
IMAGEHLP_LINE64 lineinfo;
|
||||
memset(&lineinfo, 0, sizeof(lineinfo));
|
||||
lineinfo.SizeOfStruct = sizeof(lineinfo);
|
||||
DWORD displacement;
|
||||
if (WindowsDbgHelp::symGetLineFromAddr64(::GetCurrentProcess(), (DWORD64)addr,
|
||||
&displacement, &lineinfo)) {
|
||||
if (buf != NULL && buflen > 0 && lineinfo.FileName != NULL) {
|
||||
// We only return the file name, not the whole path.
|
||||
char* p = lineinfo.FileName;
|
||||
char* q = strrchr(lineinfo.FileName, '\\');
|
||||
if (q) {
|
||||
p = q + 1;
|
||||
}
|
||||
::strncpy(buf, p, buflen - 1);
|
||||
buf[buflen - 1] = '\0';
|
||||
}
|
||||
if (line_no != 0) {
|
||||
*line_no = lineinfo.LineNumber;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Print one liner describing state (if library loaded, which functions are
|
||||
// missing - if any, and the dbhelp API version)
|
||||
void SymbolEngine::print_state_on(outputStream* st) {
|
||||
|
||||
SymbolEngineEntry entry_guard;
|
||||
|
||||
st->print("symbol engine: ");
|
||||
|
||||
if (g_state == state_uninitialized) {
|
||||
st->print("uninitialized.");
|
||||
} else if (g_state == state_error) {
|
||||
st->print("initialization error.");
|
||||
} else {
|
||||
st->print("initialized successfully");
|
||||
st->print(" - sym options: 0x%X", WindowsDbgHelp::symGetOptions());
|
||||
st->print(" - pdb path: ");
|
||||
if (WindowsDbgHelp::symGetSearchPath(::GetCurrentProcess(),
|
||||
g_buffers.search_path.ptr(),
|
||||
(int)g_buffers.search_path.capacity())) {
|
||||
st->print_raw(g_buffers.search_path.ptr());
|
||||
} else {
|
||||
st->print_raw("(cannot be retrieved)");
|
||||
}
|
||||
}
|
||||
st->cr();
|
||||
|
||||
}
|
63
src/hotspot/os/windows/symbolengine.hpp
Normal file
63
src/hotspot/os/windows/symbolengine.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OS_WINDOWS_VM_SYMBOLENGINE_HPP
|
||||
#define OS_WINDOWS_VM_SYMBOLENGINE_HPP
|
||||
|
||||
class outputStream;
|
||||
|
||||
namespace SymbolEngine {
|
||||
|
||||
bool decode(const void* addr, char* buf, int buflen, int* offset, bool do_demangle);
|
||||
|
||||
bool demangle(const char* symbol, char *buf, int buflen);
|
||||
|
||||
// given an address, attempts to retrieve the source file and line number.
|
||||
bool get_source_info(const void* addr, char* filename, size_t filename_len,
|
||||
int* line_no);
|
||||
|
||||
// Scan the loaded modules. Add all directories for all loaded modules
|
||||
// to the current search path, unless they are already part of the search
|
||||
// path. Prior search path content is preserved, directories are only
|
||||
// added, never removed.
|
||||
// If p_search_path_was_updated is not NULL, points to a bool which, upon
|
||||
// successful return from the function, contains true if the search path
|
||||
// was updated, false if no update was needed because no new DLLs were
|
||||
// loaded or unloaded.
|
||||
// Returns true for success, false for error.
|
||||
bool recalc_search_path(bool* p_search_path_was_updated = NULL);
|
||||
|
||||
// Print one liner describing state (if library loaded, which functions are
|
||||
// missing - if any, and the dbhelp API version)
|
||||
void print_state_on(outputStream* st);
|
||||
|
||||
// Call at DLL_PROCESS_ATTACH.
|
||||
void pre_initialize();
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifndef OS_WINDOWS_VM_SYMBOLENGINE_HPP
|
||||
|
||||
|
@ -116,38 +116,36 @@ static void initialize() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
///////////////////// External functions //////////////////////////
|
||||
|
||||
// All outside facing functions are synchronized. Also, we run
|
||||
// initialization on first touch.
|
||||
|
||||
static CRITICAL_SECTION g_cs;
|
||||
|
||||
// Call InitializeCriticalSection as early as possible.
|
||||
class CritSect {
|
||||
CRITICAL_SECTION cs;
|
||||
public:
|
||||
CritSect() { ::InitializeCriticalSection(&cs); }
|
||||
void enter() { ::EnterCriticalSection(&cs); }
|
||||
void leave() { ::LeaveCriticalSection(&cs); }
|
||||
};
|
||||
|
||||
static CritSect g_cs;
|
||||
|
||||
class EntryGuard {
|
||||
public:
|
||||
EntryGuard() {
|
||||
g_cs.enter();
|
||||
if (g_state == state_uninitialized) {
|
||||
initialize();
|
||||
namespace { // Do not export.
|
||||
class WindowsDbgHelpEntry {
|
||||
public:
|
||||
WindowsDbgHelpEntry() {
|
||||
::EnterCriticalSection(&g_cs);
|
||||
if (g_state == state_uninitialized) {
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
~EntryGuard() {
|
||||
g_cs.leave();
|
||||
}
|
||||
};
|
||||
~WindowsDbgHelpEntry() {
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Called at DLL_PROCESS_ATTACH.
|
||||
void WindowsDbgHelp::pre_initialize() {
|
||||
::InitializeCriticalSection(&g_cs);
|
||||
}
|
||||
|
||||
DWORD WindowsDbgHelp::symSetOptions(DWORD arg) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_SymSetOptions != NULL) {
|
||||
return g_pfn_SymSetOptions(arg);
|
||||
}
|
||||
@ -155,7 +153,7 @@ DWORD WindowsDbgHelp::symSetOptions(DWORD arg) {
|
||||
}
|
||||
|
||||
DWORD WindowsDbgHelp::symGetOptions(void) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_SymGetOptions != NULL) {
|
||||
return g_pfn_SymGetOptions();
|
||||
}
|
||||
@ -163,7 +161,7 @@ DWORD WindowsDbgHelp::symGetOptions(void) {
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::symInitialize(HANDLE hProcess, PCTSTR UserSearchPath, BOOL fInvadeProcess) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_SymInitialize != NULL) {
|
||||
return g_pfn_SymInitialize(hProcess, UserSearchPath, fInvadeProcess);
|
||||
}
|
||||
@ -172,7 +170,7 @@ BOOL WindowsDbgHelp::symInitialize(HANDLE hProcess, PCTSTR UserSearchPath, BOOL
|
||||
|
||||
BOOL WindowsDbgHelp::symGetSymFromAddr64(HANDLE hProcess, DWORD64 the_address,
|
||||
PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_SymGetSymFromAddr64 != NULL) {
|
||||
return g_pfn_SymGetSymFromAddr64(hProcess, the_address, Displacement, Symbol);
|
||||
}
|
||||
@ -181,7 +179,7 @@ BOOL WindowsDbgHelp::symGetSymFromAddr64(HANDLE hProcess, DWORD64 the_address,
|
||||
|
||||
DWORD WindowsDbgHelp::unDecorateSymbolName(const char* DecoratedName, char* UnDecoratedName,
|
||||
DWORD UndecoratedLength, DWORD Flags) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_UnDecorateSymbolName != NULL) {
|
||||
return g_pfn_UnDecorateSymbolName(DecoratedName, UnDecoratedName, UndecoratedLength, Flags);
|
||||
}
|
||||
@ -192,7 +190,7 @@ DWORD WindowsDbgHelp::unDecorateSymbolName(const char* DecoratedName, char* UnDe
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::symSetSearchPath(HANDLE hProcess, PCTSTR SearchPath) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_SymSetSearchPath != NULL) {
|
||||
return g_pfn_SymSetSearchPath(hProcess, SearchPath);
|
||||
}
|
||||
@ -200,7 +198,7 @@ BOOL WindowsDbgHelp::symSetSearchPath(HANDLE hProcess, PCTSTR SearchPath) {
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::symGetSearchPath(HANDLE hProcess, PTSTR SearchPath, int SearchPathLength) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_SymGetSearchPath != NULL) {
|
||||
return g_pfn_SymGetSearchPath(hProcess, SearchPath, SearchPathLength);
|
||||
}
|
||||
@ -212,7 +210,7 @@ BOOL WindowsDbgHelp::stackWalk64(DWORD MachineType,
|
||||
HANDLE hThread,
|
||||
LPSTACKFRAME64 StackFrame,
|
||||
PVOID ContextRecord) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_StackWalk64 != NULL) {
|
||||
return g_pfn_StackWalk64(MachineType, hProcess, hThread, StackFrame,
|
||||
ContextRecord,
|
||||
@ -226,7 +224,7 @@ BOOL WindowsDbgHelp::stackWalk64(DWORD MachineType,
|
||||
}
|
||||
|
||||
PVOID WindowsDbgHelp::symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_SymFunctionTableAccess64 != NULL) {
|
||||
return g_pfn_SymFunctionTableAccess64(hProcess, AddrBase);
|
||||
}
|
||||
@ -234,7 +232,7 @@ PVOID WindowsDbgHelp::symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase
|
||||
}
|
||||
|
||||
DWORD64 WindowsDbgHelp::symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_SymGetModuleBase64 != NULL) {
|
||||
return g_pfn_SymGetModuleBase64(hProcess, dwAddr);
|
||||
}
|
||||
@ -245,7 +243,7 @@ BOOL WindowsDbgHelp::miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE
|
||||
MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
PMINIDUMP_CALLBACK_INFORMATION CallbackParam) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_MiniDumpWriteDump != NULL) {
|
||||
return g_pfn_MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType,
|
||||
ExceptionParam, UserStreamParam, CallbackParam);
|
||||
@ -255,7 +253,7 @@ BOOL WindowsDbgHelp::miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE
|
||||
|
||||
BOOL WindowsDbgHelp::symGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr,
|
||||
PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) {
|
||||
EntryGuard entry_guard;
|
||||
WindowsDbgHelpEntry entry_guard;
|
||||
if (g_pfn_SymGetLineFromAddr64 != NULL) {
|
||||
return g_pfn_SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, Line);
|
||||
}
|
||||
|
@ -66,6 +66,9 @@ namespace WindowsDbgHelp {
|
||||
// missing - if any, and the dbhelp API version)
|
||||
void print_state_on(outputStream* st);
|
||||
|
||||
// Call at DLL_PROCESS_ATTACH.
|
||||
void pre_initialize();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -137,7 +137,7 @@ template<typename T>
|
||||
inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
|
||||
T volatile* dest) const {
|
||||
STATIC_ASSERT(4 == sizeof(T));
|
||||
// Note that xchg_ptr doesn't necessarily do an acquire
|
||||
// Note that xchg doesn't necessarily do an acquire
|
||||
// (see synchronizer.cpp).
|
||||
|
||||
T old_value;
|
||||
@ -176,7 +176,7 @@ template<typename T>
|
||||
inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
|
||||
T volatile* dest) const {
|
||||
STATIC_ASSERT(8 == sizeof(T));
|
||||
// Note that xchg_ptr doesn't necessarily do an acquire
|
||||
// Note that xchg doesn't necessarily do an acquire
|
||||
// (see synchronizer.cpp).
|
||||
|
||||
T old_value;
|
||||
|
@ -134,7 +134,7 @@ template<>
|
||||
template<typename T>
|
||||
inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
|
||||
T volatile* dest) const {
|
||||
// Note that xchg_ptr doesn't necessarily do an acquire
|
||||
// Note that xchg doesn't necessarily do an acquire
|
||||
// (see synchronizer.cpp).
|
||||
|
||||
T old_value;
|
||||
@ -173,7 +173,7 @@ template<typename T>
|
||||
inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
|
||||
T volatile* dest) const {
|
||||
STATIC_ASSERT(8 == sizeof(T));
|
||||
// Note that xchg_ptr doesn't necessarily do an acquire
|
||||
// Note that xchg doesn't necessarily do an acquire
|
||||
// (see synchronizer.cpp).
|
||||
|
||||
T old_value;
|
||||
|
@ -73,7 +73,7 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) co
|
||||
}
|
||||
|
||||
DEFINE_STUB_XCHG(4, jint, os::atomic_xchg_func)
|
||||
DEFINE_STUB_XCHG(8, jlong, os::atomic_xchg_ptr_func)
|
||||
DEFINE_STUB_XCHG(8, jlong, os::atomic_xchg_long_func)
|
||||
|
||||
#undef DEFINE_STUB_XCHG
|
||||
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/timer.hpp"
|
||||
#include "symbolengine.hpp"
|
||||
#include "unwind_windows_x86.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
@ -219,7 +220,7 @@ void os::initialize_thread(Thread* thr) {
|
||||
// Atomics and Stub Functions
|
||||
|
||||
typedef jint xchg_func_t (jint, volatile jint*);
|
||||
typedef intptr_t xchg_ptr_func_t (intptr_t, volatile intptr_t*);
|
||||
typedef intptr_t xchg_long_func_t (jlong, volatile jlong*);
|
||||
typedef jint cmpxchg_func_t (jint, volatile jint*, jint);
|
||||
typedef jbyte cmpxchg_byte_func_t (jbyte, volatile jbyte*, jbyte);
|
||||
typedef jlong cmpxchg_long_func_t (jlong, volatile jlong*, jlong);
|
||||
@ -243,12 +244,12 @@ jint os::atomic_xchg_bootstrap(jint exchange_value, volatile jint* dest) {
|
||||
return old_value;
|
||||
}
|
||||
|
||||
intptr_t os::atomic_xchg_ptr_bootstrap(intptr_t exchange_value, volatile intptr_t* dest) {
|
||||
intptr_t os::atomic_xchg_long_bootstrap(jlong exchange_value, volatile jlong* dest) {
|
||||
// try to use the stub:
|
||||
xchg_ptr_func_t* func = CAST_TO_FN_PTR(xchg_ptr_func_t*, StubRoutines::atomic_xchg_ptr_entry());
|
||||
xchg_long_func_t* func = CAST_TO_FN_PTR(xchg_long_func_t*, StubRoutines::atomic_xchg_long_entry());
|
||||
|
||||
if (func != NULL) {
|
||||
os::atomic_xchg_ptr_func = func;
|
||||
os::atomic_xchg_long_func = func;
|
||||
return (*func)(exchange_value, dest);
|
||||
}
|
||||
assert(Threads::number_of_threads() == 0, "for bootstrap only");
|
||||
@ -338,7 +339,7 @@ intptr_t os::atomic_add_ptr_bootstrap(intptr_t add_value, volatile intptr_t* des
|
||||
}
|
||||
|
||||
xchg_func_t* os::atomic_xchg_func = os::atomic_xchg_bootstrap;
|
||||
xchg_ptr_func_t* os::atomic_xchg_ptr_func = os::atomic_xchg_ptr_bootstrap;
|
||||
xchg_long_func_t* os::atomic_xchg_long_func = os::atomic_xchg_long_bootstrap;
|
||||
cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap;
|
||||
cmpxchg_byte_func_t* os::atomic_cmpxchg_byte_func = os::atomic_cmpxchg_byte_bootstrap;
|
||||
add_func_t* os::atomic_add_func = os::atomic_add_bootstrap;
|
||||
@ -397,6 +398,12 @@ bool os::platform_print_native_stack(outputStream* st, const void* context,
|
||||
// may not contain what Java expects, and may cause the frame() constructor
|
||||
// to crash. Let's just print out the symbolic address.
|
||||
frame::print_C_frame(st, buf, buf_size, pc);
|
||||
// print source file and line, if available
|
||||
char buf[128];
|
||||
int line_no;
|
||||
if (SymbolEngine::get_source_info(pc, buf, sizeof(buf), &line_no)) {
|
||||
st->print(" (%s:%d)", buf, line_no);
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
lastpc = pc;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,7 +30,7 @@
|
||||
//
|
||||
#ifdef AMD64
|
||||
static jint (*atomic_xchg_func) (jint, volatile jint*);
|
||||
static intptr_t (*atomic_xchg_ptr_func) (intptr_t, volatile intptr_t*);
|
||||
static intptr_t (*atomic_xchg_long_func) (jlong, volatile jlong*);
|
||||
|
||||
static jint (*atomic_cmpxchg_func) (jint, volatile jint*, jint);
|
||||
static jbyte (*atomic_cmpxchg_byte_func) (jbyte, volatile jbyte*, jbyte);
|
||||
@ -40,7 +40,7 @@
|
||||
static intptr_t (*atomic_add_ptr_func) (intptr_t, volatile intptr_t*);
|
||||
|
||||
static jint atomic_xchg_bootstrap (jint, volatile jint*);
|
||||
static intptr_t atomic_xchg_ptr_bootstrap (intptr_t, volatile intptr_t*);
|
||||
static intptr_t atomic_xchg_long_bootstrap (jlong, volatile jlong*);
|
||||
|
||||
static jint atomic_cmpxchg_bootstrap (jint, volatile jint*, jint);
|
||||
static jbyte atomic_cmpxchg_byte_bootstrap(jbyte, volatile jbyte*, jbyte);
|
||||
|
@ -60,7 +60,14 @@ Klass* AOTCodeHeap::get_klass_from_got(const char* klass_name, int klass_len, co
|
||||
fatal("Shared file %s error: klass %s should be resolved already", _lib->name(), klass_name);
|
||||
vm_exit(1);
|
||||
}
|
||||
// Patch now to avoid extra runtime lookup
|
||||
_klasses_got[klass_data->_got_index] = k;
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
if (ik->is_initialized()) {
|
||||
_klasses_got[klass_data->_got_index - 1] = ik;
|
||||
}
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
@ -433,6 +440,7 @@ void AOTCodeHeap::link_shared_runtime_symbols() {
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_exception_handler_for_return_address", address, SharedRuntime::exception_handler_for_return_address);
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_register_finalizer", address, SharedRuntime::register_finalizer);
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_OSR_migration_end", address, SharedRuntime::OSR_migration_end);
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_dynamic_invoke", address, CompilerRuntime::resolve_dynamic_invoke);
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_string_by_symbol", address, CompilerRuntime::resolve_string_by_symbol);
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_klass_by_symbol", address, CompilerRuntime::resolve_klass_by_symbol);
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_method_by_symbol_and_load_counters", address, CompilerRuntime::resolve_method_by_symbol_and_load_counters);
|
||||
@ -609,9 +617,13 @@ Method* AOTCodeHeap::find_method(Klass* klass, Thread* thread, const char* metho
|
||||
return m;
|
||||
}
|
||||
|
||||
AOTKlassData* AOTCodeHeap::find_klass(const char *name) {
|
||||
return (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), name);
|
||||
}
|
||||
|
||||
AOTKlassData* AOTCodeHeap::find_klass(InstanceKlass* ik) {
|
||||
ResourceMark rm;
|
||||
AOTKlassData* klass_data = (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), ik->signature_name());
|
||||
AOTKlassData* klass_data = find_klass(ik->signature_name());
|
||||
return klass_data;
|
||||
}
|
||||
|
||||
@ -640,35 +652,52 @@ bool AOTCodeHeap::is_dependent_method(Klass* dependee, AOTCompiledMethod* aot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void AOTCodeHeap::sweep_dependent_methods(int* indexes, int methods_cnt) {
|
||||
int marked = 0;
|
||||
for (int i = 0; i < methods_cnt; ++i) {
|
||||
int code_id = indexes[i];
|
||||
// Invalidate aot code.
|
||||
if (Atomic::cmpxchg(invalid, &_code_to_aot[code_id]._state, not_set) != not_set) {
|
||||
if (_code_to_aot[code_id]._state == in_use) {
|
||||
AOTCompiledMethod* aot = _code_to_aot[code_id]._aot;
|
||||
assert(aot != NULL, "aot should be set");
|
||||
if (!aot->is_runtime_stub()) { // Something is wrong - should not invalidate stubs.
|
||||
aot->mark_for_deoptimization(false);
|
||||
marked++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (marked > 0) {
|
||||
VM_Deoptimize op;
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
}
|
||||
|
||||
void AOTCodeHeap::sweep_dependent_methods(AOTKlassData* klass_data) {
|
||||
// Make dependent methods non_entrant forever.
|
||||
int methods_offset = klass_data->_dependent_methods_offset;
|
||||
if (methods_offset >= 0) {
|
||||
int marked = 0;
|
||||
address methods_cnt_adr = _dependencies + methods_offset;
|
||||
int methods_cnt = *(int*)methods_cnt_adr;
|
||||
int* indexes = (int*)(methods_cnt_adr + 4);
|
||||
for (int i = 0; i < methods_cnt; ++i) {
|
||||
int code_id = indexes[i];
|
||||
// Invalidate aot code.
|
||||
if (Atomic::cmpxchg(invalid, &_code_to_aot[code_id]._state, not_set) != not_set) {
|
||||
if (_code_to_aot[code_id]._state == in_use) {
|
||||
AOTCompiledMethod* aot = _code_to_aot[code_id]._aot;
|
||||
assert(aot != NULL, "aot should be set");
|
||||
if (!aot->is_runtime_stub()) { // Something is wrong - should not invalidate stubs.
|
||||
aot->mark_for_deoptimization(false);
|
||||
marked++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (marked > 0) {
|
||||
VM_Deoptimize op;
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
sweep_dependent_methods(indexes, methods_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
void AOTCodeHeap::sweep_dependent_methods(InstanceKlass* ik) {
|
||||
AOTKlassData* klass_data = find_klass(ik);
|
||||
vmassert(klass_data != NULL, "dependency data missing");
|
||||
sweep_dependent_methods(klass_data);
|
||||
}
|
||||
|
||||
void AOTCodeHeap::sweep_method(AOTCompiledMethod *aot) {
|
||||
int indexes[] = {aot->method_index()};
|
||||
sweep_dependent_methods(indexes, 1);
|
||||
vmassert(aot->method()->code() != aot && aot->method()->aot_code() == NULL, "method still active");
|
||||
}
|
||||
|
||||
|
||||
bool AOTCodeHeap::load_klass_data(InstanceKlass* ik, Thread* thread) {
|
||||
ResourceMark rm;
|
||||
|
||||
@ -718,6 +747,9 @@ bool AOTCodeHeap::load_klass_data(InstanceKlass* ik, Thread* thread) {
|
||||
aot_class->_classloader = ik->class_loader_data();
|
||||
// Set klass's Resolve (second) got cell.
|
||||
_klasses_got[klass_data->_got_index] = ik;
|
||||
if (ik->is_initialized()) {
|
||||
_klasses_got[klass_data->_got_index - 1] = ik;
|
||||
}
|
||||
|
||||
// Initialize global symbols of the DSO to the corresponding VM symbol values.
|
||||
link_global_lib_symbols();
|
||||
@ -837,7 +869,7 @@ void AOTCodeHeap::got_metadata_do(void f(Metadata*)) {
|
||||
f(md);
|
||||
} else {
|
||||
intptr_t meta = (intptr_t)md;
|
||||
fatal("Invalid value in _metaspace_got[%d] = " INTPTR_FORMAT, i, meta);
|
||||
fatal("Invalid value in _klasses_got[%d] = " INTPTR_FORMAT, i, meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -886,6 +918,127 @@ void AOTCodeHeap::metadata_do(void f(Metadata*)) {
|
||||
aot->metadata_do(f);
|
||||
}
|
||||
}
|
||||
// Scan metaspace_got cells.
|
||||
// Scan klasses_got cells.
|
||||
got_metadata_do(f);
|
||||
}
|
||||
|
||||
bool AOTCodeHeap::reconcile_dynamic_klass(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Klass *dyno_klass, const char *descriptor1, const char *descriptor2) {
|
||||
const char * const descriptors[2] = {descriptor1, descriptor2};
|
||||
JavaThread *thread = JavaThread::current();
|
||||
ResourceMark rm(thread);
|
||||
|
||||
AOTKlassData* holder_data = find_klass(holder);
|
||||
vmassert(holder_data != NULL, "klass %s not found", holder->signature_name());
|
||||
vmassert(is_dependent_method(holder, caller), "sanity");
|
||||
|
||||
AOTKlassData* dyno_data = NULL;
|
||||
bool adapter_failed = false;
|
||||
char buf[64];
|
||||
int descriptor_index = 0;
|
||||
// descriptors[0] specific name ("adapter:<method_id>") for matching
|
||||
// descriptors[1] fall-back name ("adapter") for depdencies
|
||||
while (descriptor_index < 2) {
|
||||
const char *descriptor = descriptors[descriptor_index];
|
||||
if (descriptor == NULL) {
|
||||
break;
|
||||
}
|
||||
jio_snprintf(buf, sizeof buf, "%s<%d:%d>", descriptor, holder_data->_class_id, index);
|
||||
dyno_data = find_klass(buf);
|
||||
if (dyno_data != NULL) {
|
||||
break;
|
||||
}
|
||||
// If match failed then try fall-back for dependencies
|
||||
++descriptor_index;
|
||||
adapter_failed = true;
|
||||
}
|
||||
|
||||
if (dyno_data == NULL && dyno_klass == NULL) {
|
||||
// all is well, no (appendix) at compile-time, and still none
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dyno_data == NULL) {
|
||||
// no (appendix) at build-time, but now there is
|
||||
sweep_dependent_methods(holder_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (adapter_failed) {
|
||||
// adapter method mismatch
|
||||
sweep_dependent_methods(holder_data);
|
||||
sweep_dependent_methods(dyno_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dyno_klass == NULL) {
|
||||
// (appendix) at build-time, none now
|
||||
sweep_dependent_methods(holder_data);
|
||||
sweep_dependent_methods(dyno_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: support array appendix object
|
||||
if (!dyno_klass->is_instance_klass()) {
|
||||
sweep_dependent_methods(holder_data);
|
||||
sweep_dependent_methods(dyno_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
InstanceKlass* dyno = InstanceKlass::cast(dyno_klass);
|
||||
|
||||
if (!dyno->is_anonymous()) {
|
||||
if (_klasses_got[dyno_data->_got_index] != dyno) {
|
||||
// compile-time class different from runtime class, fail and deoptimize
|
||||
sweep_dependent_methods(holder_data);
|
||||
sweep_dependent_methods(dyno_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dyno->is_initialized()) {
|
||||
_klasses_got[dyno_data->_got_index - 1] = dyno;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: support anonymous supers
|
||||
if (!dyno->supers_have_passed_fingerprint_checks() || dyno->get_stored_fingerprint() != dyno_data->_fingerprint) {
|
||||
NOT_PRODUCT( aot_klasses_fp_miss++; )
|
||||
log_trace(aot, class, fingerprint)("class %s%s has bad fingerprint in %s tid=" INTPTR_FORMAT,
|
||||
dyno->internal_name(), dyno->is_shared() ? " (shared)" : "",
|
||||
_lib->name(), p2i(thread));
|
||||
sweep_dependent_methods(holder_data);
|
||||
sweep_dependent_methods(dyno_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
_klasses_got[dyno_data->_got_index] = dyno;
|
||||
if (dyno->is_initialized()) {
|
||||
_klasses_got[dyno_data->_got_index - 1] = dyno;
|
||||
}
|
||||
|
||||
// TODO: hook up any AOT code
|
||||
// load_klass_data(dyno_data, thread);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AOTCodeHeap::reconcile_dynamic_method(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Method *adapter_method) {
|
||||
InstanceKlass *adapter_klass = adapter_method->method_holder();
|
||||
char buf[64];
|
||||
jio_snprintf(buf, sizeof buf, "adapter:%d", adapter_method->method_idnum());
|
||||
if (!reconcile_dynamic_klass(caller, holder, index, adapter_klass, buf, "adapter")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AOTCodeHeap::reconcile_dynamic_invoke(AOTCompiledMethod* caller, InstanceKlass* holder, int index, Method* adapter_method, Klass *appendix_klass) {
|
||||
if (!reconcile_dynamic_klass(caller, holder, index, appendix_klass, "appendix")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reconcile_dynamic_method(caller, holder, index, adapter_method)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -241,13 +241,14 @@ public:
|
||||
AOTKlassData* find_klass(InstanceKlass* ik);
|
||||
bool load_klass_data(InstanceKlass* ik, Thread* thread);
|
||||
Klass* get_klass_from_got(const char* klass_name, int klass_len, const Method* method);
|
||||
void sweep_dependent_methods(AOTKlassData* klass_data);
|
||||
|
||||
bool is_dependent_method(Klass* dependee, AOTCompiledMethod* aot);
|
||||
|
||||
const char* get_name_at(int offset) {
|
||||
return _metaspace_names + offset;
|
||||
}
|
||||
|
||||
|
||||
void oops_do(OopClosure* f);
|
||||
void metadata_do(void f(Metadata*));
|
||||
void got_metadata_do(void f(Metadata*));
|
||||
@ -294,6 +295,21 @@ public:
|
||||
|
||||
static void print_statistics();
|
||||
#endif
|
||||
|
||||
bool reconcile_dynamic_invoke(AOTCompiledMethod* caller, InstanceKlass* holder, int index, Method* adapter_method, Klass *appendix_klass);
|
||||
|
||||
private:
|
||||
AOTKlassData* find_klass(const char* name);
|
||||
|
||||
void sweep_dependent_methods(int* indexes, int methods_cnt);
|
||||
void sweep_dependent_methods(AOTKlassData* klass_data);
|
||||
void sweep_dependent_methods(InstanceKlass* ik);
|
||||
void sweep_method(AOTCompiledMethod* aot);
|
||||
|
||||
bool reconcile_dynamic_klass(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Klass *dyno, const char *descriptor1, const char *descriptor2 = NULL);
|
||||
|
||||
bool reconcile_dynamic_method(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Method *adapter_method);
|
||||
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_AOT_AOTCODEHEAP_HPP
|
||||
|
@ -40,6 +40,10 @@ GrowableArray<AOTLib*>* AOTLoader::_libraries = new(ResourceObj::C_HEAP, mtCode)
|
||||
#define FOR_ALL_AOT_LIBRARIES(lib) for (GrowableArrayIterator<AOTLib*> lib = libraries()->begin(); lib != libraries()->end(); ++lib)
|
||||
|
||||
void AOTLoader::load_for_klass(InstanceKlass* ik, Thread* thread) {
|
||||
if (ik->is_anonymous()) {
|
||||
// don't even bother
|
||||
return;
|
||||
}
|
||||
if (UseAOT) {
|
||||
FOR_ALL_AOT_HEAPS(heap) {
|
||||
(*heap)->load_klass_data(ik, thread);
|
||||
@ -48,6 +52,10 @@ void AOTLoader::load_for_klass(InstanceKlass* ik, Thread* thread) {
|
||||
}
|
||||
|
||||
uint64_t AOTLoader::get_saved_fingerprint(InstanceKlass* ik) {
|
||||
if (ik->is_anonymous()) {
|
||||
// don't even bother
|
||||
return 0;
|
||||
}
|
||||
FOR_ALL_AOT_HEAPS(heap) {
|
||||
AOTKlassData* klass_data = (*heap)->find_klass(ik);
|
||||
if (klass_data != NULL) {
|
||||
@ -259,3 +267,34 @@ void AOTLoader::print_statistics() {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool AOTLoader::reconcile_dynamic_invoke(InstanceKlass* holder, int index, Method* adapter_method, Klass* appendix_klass) {
|
||||
if (!UseAOT) {
|
||||
return true;
|
||||
}
|
||||
JavaThread* thread = JavaThread::current();
|
||||
ResourceMark rm(thread);
|
||||
RegisterMap map(thread, false);
|
||||
frame caller_frame = thread->last_frame().sender(&map); // Skip stub
|
||||
CodeBlob* caller_cb = caller_frame.cb();
|
||||
guarantee(caller_cb != NULL && caller_cb->is_compiled(), "must be called from compiled method");
|
||||
CompiledMethod* cm = caller_cb->as_compiled_method();
|
||||
|
||||
if (!cm->is_aot()) {
|
||||
return true;
|
||||
}
|
||||
AOTCompiledMethod* aot = (AOTCompiledMethod*)cm;
|
||||
|
||||
AOTCodeHeap* caller_heap = NULL;
|
||||
FOR_ALL_AOT_HEAPS(heap) {
|
||||
if ((*heap)->contains_blob(aot)) {
|
||||
caller_heap = *heap;
|
||||
break;
|
||||
}
|
||||
}
|
||||
guarantee(caller_heap != NULL, "CodeHeap not found");
|
||||
bool success = caller_heap->reconcile_dynamic_invoke(aot, holder, index, adapter_method, appendix_klass);
|
||||
vmassert(success || thread->last_frame().sender(&map).is_deoptimized_frame(), "caller not deoptimized on failure");
|
||||
return success;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "runtime/handles.hpp"
|
||||
|
||||
class AOTCodeHeap;
|
||||
class AOTCompiledMethod;
|
||||
class AOTLib;
|
||||
class CodeBlob;
|
||||
template <class T> class GrowableArray;
|
||||
@ -71,6 +72,7 @@ public:
|
||||
static void flush_evol_dependents_on(InstanceKlass* dependee) NOT_AOT_RETURN;
|
||||
#endif // HOTSWAP
|
||||
|
||||
static bool reconcile_dynamic_invoke(InstanceKlass* holder, int index, Method* adapter_method, Klass *appendix_klass) NOT_AOT({ return true; });
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_AOT_AOTLOADER_HPP
|
||||
|
@ -236,11 +236,9 @@ DelayedConstant* DelayedConstant::add(BasicType type,
|
||||
if (dcon->match(type, cfn))
|
||||
return dcon;
|
||||
if (dcon->value_fn == NULL) {
|
||||
// (cmpxchg not because this is multi-threaded but because I'm paranoid)
|
||||
if (Atomic::cmpxchg_ptr(CAST_FROM_FN_PTR(void*, cfn), &dcon->value_fn, NULL) == NULL) {
|
||||
dcon->value_fn = cfn;
|
||||
dcon->type = type;
|
||||
return dcon;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If this assert is hit (in pre-integration testing!) then re-evaluate
|
||||
|
@ -1221,11 +1221,6 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
|
||||
MutexLockerEx ml_code (CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
|
||||
guarantee(nm != NULL, "only nmethods can contain non-perm oops");
|
||||
if (!nm->on_scavenge_root_list() &&
|
||||
((mirror.not_null() && mirror()->is_scavengable()) ||
|
||||
(appendix.not_null() && appendix->is_scavengable()))) {
|
||||
CodeCache::add_scavenge_root_nmethod(nm);
|
||||
}
|
||||
|
||||
// Since we've patched some oops in the nmethod,
|
||||
// (re)register it with the heap.
|
||||
@ -1377,8 +1372,6 @@ template <class T> int obj_arraycopy_work(oopDesc* src, T* src_addr,
|
||||
// barrier. The assert will fail if this is not the case.
|
||||
// Note that we use the non-virtual inlineable variant of write_ref_array.
|
||||
BarrierSet* bs = Universe::heap()->barrier_set();
|
||||
assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");
|
||||
assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well.");
|
||||
if (src == dst) {
|
||||
// same object, no check
|
||||
bs->write_ref_array_pre(dst_addr, length);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,7 +25,7 @@
|
||||
#ifndef SHARE_VM_CLASSFILE_ALTHASHING_HPP
|
||||
#define SHARE_VM_CLASSFILE_ALTHASHING_HPP
|
||||
|
||||
#include "prims/jni.h"
|
||||
#include "jni.h"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
|
||||
/**
|
||||
|
@ -48,13 +48,11 @@ private:
|
||||
ClassPathEntry* volatile _next;
|
||||
public:
|
||||
// Next entry in class path
|
||||
ClassPathEntry* next() const {
|
||||
return (ClassPathEntry*) OrderAccess::load_ptr_acquire(&_next);
|
||||
}
|
||||
ClassPathEntry* next() const { return OrderAccess::load_acquire(&_next); }
|
||||
virtual ~ClassPathEntry() {}
|
||||
void set_next(ClassPathEntry* next) {
|
||||
// may have unlocked readers, so ensure visibility.
|
||||
OrderAccess::release_store_ptr(&_next, next);
|
||||
OrderAccess::release_store(&_next, next);
|
||||
}
|
||||
virtual bool is_jrt() = 0;
|
||||
virtual bool is_jar_file() const = 0;
|
||||
|
@ -82,11 +82,6 @@
|
||||
#include "trace/tracing.hpp"
|
||||
#endif
|
||||
|
||||
// helper function to avoid in-line casts
|
||||
template <typename T> static T* load_ptr_acquire(T* volatile *p) {
|
||||
return static_cast<T*>(OrderAccess::load_ptr_acquire(p));
|
||||
}
|
||||
|
||||
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
|
||||
|
||||
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) :
|
||||
@ -152,7 +147,7 @@ ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
|
||||
oop* ClassLoaderData::ChunkedHandleList::add(oop o) {
|
||||
if (_head == NULL || _head->_size == Chunk::CAPACITY) {
|
||||
Chunk* next = new Chunk(_head);
|
||||
OrderAccess::release_store_ptr(&_head, next);
|
||||
OrderAccess::release_store(&_head, next);
|
||||
}
|
||||
oop* handle = &_head->_data[_head->_size];
|
||||
*handle = o;
|
||||
@ -169,7 +164,7 @@ inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chu
|
||||
}
|
||||
|
||||
void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) {
|
||||
Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head);
|
||||
Chunk* head = OrderAccess::load_acquire(&_head);
|
||||
if (head != NULL) {
|
||||
// Must be careful when reading size of head
|
||||
oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size));
|
||||
@ -257,24 +252,24 @@ void ClassLoaderData::Dependencies::oops_do(OopClosure* f) {
|
||||
}
|
||||
|
||||
void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
|
||||
// Lock-free access requires load_ptr_acquire
|
||||
for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
// Lock-free access requires load_acquire
|
||||
for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
klass_closure->do_klass(k);
|
||||
assert(k != k->next_link(), "no loops!");
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderData::classes_do(void f(Klass * const)) {
|
||||
// Lock-free access requires load_ptr_acquire
|
||||
for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
// Lock-free access requires load_acquire
|
||||
for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
f(k);
|
||||
assert(k != k->next_link(), "no loops!");
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderData::methods_do(void f(Method*)) {
|
||||
// Lock-free access requires load_ptr_acquire
|
||||
for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
// Lock-free access requires load_acquire
|
||||
for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
if (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded()) {
|
||||
InstanceKlass::cast(k)->methods_do(f);
|
||||
}
|
||||
@ -282,8 +277,8 @@ void ClassLoaderData::methods_do(void f(Method*)) {
|
||||
}
|
||||
|
||||
void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) {
|
||||
// Lock-free access requires load_ptr_acquire
|
||||
for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
// Lock-free access requires load_acquire
|
||||
for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
// Do not filter ArrayKlass oops here...
|
||||
if (k->is_array_klass() || (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded())) {
|
||||
klass_closure->do_klass(k);
|
||||
@ -292,8 +287,8 @@ void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) {
|
||||
}
|
||||
|
||||
void ClassLoaderData::classes_do(void f(InstanceKlass*)) {
|
||||
// Lock-free access requires load_ptr_acquire
|
||||
for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
// Lock-free access requires load_acquire
|
||||
for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
if (k->is_instance_klass()) {
|
||||
f(InstanceKlass::cast(k));
|
||||
}
|
||||
@ -449,7 +444,7 @@ void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
|
||||
k->set_next_link(old_value);
|
||||
// Link the new item into the list, making sure the linked class is stable
|
||||
// since the list can be walked without a lock
|
||||
OrderAccess::release_store_ptr(&_klasses, k);
|
||||
OrderAccess::release_store(&_klasses, k);
|
||||
}
|
||||
|
||||
if (publicize && k->class_loader_data() != NULL) {
|
||||
@ -589,8 +584,8 @@ void ClassLoaderData::unload() {
|
||||
|
||||
ModuleEntryTable* ClassLoaderData::modules() {
|
||||
// Lazily create the module entry table at first request.
|
||||
// Lock-free access requires load_ptr_acquire.
|
||||
ModuleEntryTable* modules = load_ptr_acquire(&_modules);
|
||||
// Lock-free access requires load_acquire.
|
||||
ModuleEntryTable* modules = OrderAccess::load_acquire(&_modules);
|
||||
if (modules == NULL) {
|
||||
MutexLocker m1(Module_lock);
|
||||
// Check if _modules got allocated while we were waiting for this lock.
|
||||
@ -600,7 +595,7 @@ ModuleEntryTable* ClassLoaderData::modules() {
|
||||
{
|
||||
MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
||||
// Ensure _modules is stable, since it is examined without a lock
|
||||
OrderAccess::release_store_ptr(&_modules, modules);
|
||||
OrderAccess::release_store(&_modules, modules);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -737,8 +732,8 @@ Metaspace* ClassLoaderData::metaspace_non_null() {
|
||||
// to create smaller arena for Reflection class loaders also.
|
||||
// The reason for the delayed allocation is because some class loaders are
|
||||
// simply for delegating with no metadata of their own.
|
||||
// Lock-free access requires load_ptr_acquire.
|
||||
Metaspace* metaspace = load_ptr_acquire(&_metaspace);
|
||||
// Lock-free access requires load_acquire.
|
||||
Metaspace* metaspace = OrderAccess::load_acquire(&_metaspace);
|
||||
if (metaspace == NULL) {
|
||||
MutexLockerEx ml(_metaspace_lock, Mutex::_no_safepoint_check_flag);
|
||||
// Check if _metaspace got allocated while we were waiting for this lock.
|
||||
@ -760,7 +755,7 @@ Metaspace* ClassLoaderData::metaspace_non_null() {
|
||||
metaspace = new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType);
|
||||
}
|
||||
// Ensure _metaspace is stable, since it is examined without a lock
|
||||
OrderAccess::release_store_ptr(&_metaspace, metaspace);
|
||||
OrderAccess::release_store(&_metaspace, metaspace);
|
||||
}
|
||||
}
|
||||
return metaspace;
|
||||
@ -914,8 +909,8 @@ void ClassLoaderData::verify() {
|
||||
}
|
||||
|
||||
bool ClassLoaderData::contains_klass(Klass* klass) {
|
||||
// Lock-free access requires load_ptr_acquire
|
||||
for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
// Lock-free access requires load_acquire
|
||||
for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
if (k == klass) return true;
|
||||
}
|
||||
return false;
|
||||
@ -948,7 +943,7 @@ ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRA
|
||||
if (!is_anonymous) {
|
||||
ClassLoaderData** cld_addr = java_lang_ClassLoader::loader_data_addr(loader());
|
||||
// First, Atomically set it
|
||||
ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
|
||||
ClassLoaderData* old = Atomic::cmpxchg(cld, cld_addr, (ClassLoaderData*)NULL);
|
||||
if (old != NULL) {
|
||||
delete cld;
|
||||
// Returns the data.
|
||||
@ -963,7 +958,7 @@ ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRA
|
||||
|
||||
do {
|
||||
cld->set_next(next);
|
||||
ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
|
||||
ClassLoaderData* exchanged = Atomic::cmpxchg(cld, list_head, next);
|
||||
if (exchanged == next) {
|
||||
LogTarget(Debug, class, loader, data) lt;
|
||||
if (lt.is_enabled()) {
|
||||
@ -1387,7 +1382,7 @@ Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() {
|
||||
while (head != NULL) {
|
||||
Klass* next = next_klass_in_cldg(head);
|
||||
|
||||
Klass* old_head = (Klass*)Atomic::cmpxchg_ptr(next, &_next_klass, head);
|
||||
Klass* old_head = Atomic::cmpxchg(next, &_next_klass, head);
|
||||
|
||||
if (old_head == head) {
|
||||
return head; // Won the CAS.
|
||||
|
@ -194,7 +194,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
Chunk(Chunk* c) : _next(c), _size(0) { }
|
||||
};
|
||||
|
||||
Chunk* _head;
|
||||
Chunk* volatile _head;
|
||||
|
||||
void oops_do_chunk(OopClosure* f, Chunk* c, const juint size);
|
||||
|
||||
|
@ -161,10 +161,10 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
|
||||
void set_pd_set(ProtectionDomainEntry* new_head) { _pd_set = new_head; }
|
||||
|
||||
ProtectionDomainEntry* pd_set_acquire() const {
|
||||
return (ProtectionDomainEntry*)OrderAccess::load_ptr_acquire(&_pd_set);
|
||||
return OrderAccess::load_acquire(&_pd_set);
|
||||
}
|
||||
void release_set_pd_set(ProtectionDomainEntry* new_head) {
|
||||
OrderAccess::release_store_ptr(&_pd_set, new_head);
|
||||
OrderAccess::release_store(&_pd_set, new_head);
|
||||
}
|
||||
|
||||
// Tells whether the initiating class' protection domain can access the klass in this entry
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,7 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "prims/jni.h"
|
||||
#include "jni.h"
|
||||
|
||||
// Opaque reference to a JImage file.
|
||||
class JImageFile;
|
||||
|
@ -223,8 +223,8 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
|
||||
result->set_cached_class_file(cached_class_file);
|
||||
}
|
||||
|
||||
if (InstanceKlass::should_store_fingerprint()) {
|
||||
result->store_fingerprint(!result->is_anonymous() ? stream->compute_fingerprint() : 0);
|
||||
if (result->should_store_fingerprint()) {
|
||||
result->store_fingerprint(stream->compute_fingerprint());
|
||||
}
|
||||
|
||||
TRACE_KLASS_CREATION(result, parser, THREAD);
|
||||
|
@ -23,13 +23,13 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jni.h"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/moduleEntry.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "prims/jni.h"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
|
@ -25,11 +25,11 @@
|
||||
#ifndef SHARE_VM_CLASSFILE_MODULEENTRY_HPP
|
||||
#define SHARE_VM_CLASSFILE_MODULEENTRY_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "oops/oopHandle.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "prims/jni.h"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
|
@ -69,14 +69,14 @@ static void* volatile _verify_byte_codes_fn = NULL;
|
||||
static volatile jint _is_new_verify_byte_codes_fn = (jint) true;
|
||||
|
||||
static void* verify_byte_codes_fn() {
|
||||
if (OrderAccess::load_ptr_acquire(&_verify_byte_codes_fn) == NULL) {
|
||||
if (OrderAccess::load_acquire(&_verify_byte_codes_fn) == NULL) {
|
||||
void *lib_handle = os::native_java_library();
|
||||
void *func = os::dll_lookup(lib_handle, "VerifyClassCodesForMajorVersion");
|
||||
OrderAccess::release_store_ptr(&_verify_byte_codes_fn, func);
|
||||
OrderAccess::release_store(&_verify_byte_codes_fn, func);
|
||||
if (func == NULL) {
|
||||
_is_new_verify_byte_codes_fn = false;
|
||||
func = os::dll_lookup(lib_handle, "VerifyClassCodes");
|
||||
OrderAccess::release_store_ptr(&_verify_byte_codes_fn, func);
|
||||
OrderAccess::release_store(&_verify_byte_codes_fn, func);
|
||||
}
|
||||
}
|
||||
return (void*)_verify_byte_codes_fn;
|
||||
|
@ -683,22 +683,19 @@ void CodeCache::blobs_do(CodeBlobClosure* f) {
|
||||
if (cb->is_alive()) {
|
||||
f->do_code_blob(cb);
|
||||
#ifdef ASSERT
|
||||
if (cb->is_nmethod())
|
||||
((nmethod*)cb)->verify_scavenge_root_oops();
|
||||
if (cb->is_nmethod()) {
|
||||
Universe::heap()->verify_nmethod((nmethod*)cb);
|
||||
}
|
||||
#endif //ASSERT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Walk the list of methods which might contain non-perm oops.
|
||||
// Walk the list of methods which might contain oops to the java heap.
|
||||
void CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure* f) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
|
||||
if (UseG1GC) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool fix_relocations = f->fix_relocations();
|
||||
debug_only(mark_scavenge_root_nmethods());
|
||||
|
||||
@ -735,13 +732,20 @@ void CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure* f) {
|
||||
debug_only(verify_perm_nmethods(NULL));
|
||||
}
|
||||
|
||||
void CodeCache::register_scavenge_root_nmethod(nmethod* nm) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
if (!nm->on_scavenge_root_list() && nm->detect_scavenge_root_oops()) {
|
||||
add_scavenge_root_nmethod(nm);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCache::verify_scavenge_root_nmethod(nmethod* nm) {
|
||||
nm->verify_scavenge_root_oops();
|
||||
}
|
||||
|
||||
void CodeCache::add_scavenge_root_nmethod(nmethod* nm) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
|
||||
if (UseG1GC) {
|
||||
return;
|
||||
}
|
||||
|
||||
nm->set_on_scavenge_root_list();
|
||||
nm->set_scavenge_root_link(_scavenge_root_nmethods);
|
||||
set_scavenge_root_nmethods(nm);
|
||||
@ -754,8 +758,6 @@ void CodeCache::unlink_scavenge_root_nmethod(nmethod* nm, nmethod* prev) {
|
||||
assert((prev == NULL && scavenge_root_nmethods() == nm) ||
|
||||
(prev != NULL && prev->scavenge_root_link() == nm), "precondition");
|
||||
|
||||
assert(!UseG1GC, "G1 does not use the scavenge_root_nmethods list");
|
||||
|
||||
print_trace("unlink_scavenge_root", nm);
|
||||
if (prev == NULL) {
|
||||
set_scavenge_root_nmethods(nm->scavenge_root_link());
|
||||
@ -769,10 +771,6 @@ void CodeCache::unlink_scavenge_root_nmethod(nmethod* nm, nmethod* prev) {
|
||||
void CodeCache::drop_scavenge_root_nmethod(nmethod* nm) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
|
||||
if (UseG1GC) {
|
||||
return;
|
||||
}
|
||||
|
||||
print_trace("drop_scavenge_root", nm);
|
||||
nmethod* prev = NULL;
|
||||
for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) {
|
||||
@ -788,10 +786,6 @@ void CodeCache::drop_scavenge_root_nmethod(nmethod* nm) {
|
||||
void CodeCache::prune_scavenge_root_nmethods() {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
|
||||
if (UseG1GC) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_only(mark_scavenge_root_nmethods());
|
||||
|
||||
nmethod* last = NULL;
|
||||
@ -820,10 +814,6 @@ void CodeCache::prune_scavenge_root_nmethods() {
|
||||
|
||||
#ifndef PRODUCT
|
||||
void CodeCache::asserted_non_scavengable_nmethods_do(CodeBlobClosure* f) {
|
||||
if (UseG1GC) {
|
||||
return;
|
||||
}
|
||||
|
||||
// While we are here, verify the integrity of the list.
|
||||
mark_scavenge_root_nmethods();
|
||||
for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) {
|
||||
@ -833,7 +823,7 @@ void CodeCache::asserted_non_scavengable_nmethods_do(CodeBlobClosure* f) {
|
||||
verify_perm_nmethods(f);
|
||||
}
|
||||
|
||||
// Temporarily mark nmethods that are claimed to be on the non-perm list.
|
||||
// Temporarily mark nmethods that are claimed to be on the scavenge list.
|
||||
void CodeCache::mark_scavenge_root_nmethods() {
|
||||
NMethodIterator iter;
|
||||
while(iter.next_alive()) {
|
||||
@ -854,7 +844,7 @@ void CodeCache::verify_perm_nmethods(CodeBlobClosure* f_or_null) {
|
||||
assert(nm->scavenge_root_not_marked(), "must be already processed");
|
||||
if (nm->on_scavenge_root_list())
|
||||
call_f = false; // don't show this one to the client
|
||||
nm->verify_scavenge_root_oops();
|
||||
Universe::heap()->verify_nmethod(nm);
|
||||
if (call_f) f_or_null->do_code_blob(nm);
|
||||
}
|
||||
}
|
||||
@ -1640,4 +1630,3 @@ void CodeCache::log_state(outputStream* st) {
|
||||
blob_count(), nmethod_count(), adapter_count(),
|
||||
unallocated_capacity());
|
||||
}
|
||||
|
||||
|
@ -181,6 +181,10 @@ class CodeCache : AllStatic {
|
||||
static void scavenge_root_nmethods_do(CodeBlobToOopClosure* f);
|
||||
|
||||
static nmethod* scavenge_root_nmethods() { return _scavenge_root_nmethods; }
|
||||
// register_scavenge_root_nmethod() conditionally adds the nmethod to the list
|
||||
// if it is not already on the list and has a scavengeable root
|
||||
static void register_scavenge_root_nmethod(nmethod* nm);
|
||||
static void verify_scavenge_root_nmethod(nmethod* nm);
|
||||
static void add_scavenge_root_nmethod(nmethod* nm);
|
||||
static void drop_scavenge_root_nmethod(nmethod* nm);
|
||||
|
||||
|
@ -288,7 +288,7 @@ public:
|
||||
// Note: _exception_cache may be read concurrently. We rely on memory_order_consume here.
|
||||
ExceptionCache* exception_cache() const { return _exception_cache; }
|
||||
void set_exception_cache(ExceptionCache *ec) { _exception_cache = ec; }
|
||||
void release_set_exception_cache(ExceptionCache *ec) { OrderAccess::release_store_ptr(&_exception_cache, ec); }
|
||||
void release_set_exception_cache(ExceptionCache *ec) { OrderAccess::release_store(&_exception_cache, ec); }
|
||||
address handler_for_exception_and_pc(Handle exception, address pc);
|
||||
void add_handler_for_exception_and_pc(Handle exception, address pc, address handler);
|
||||
void clean_exception_cache(BoolObjectClosure* is_alive);
|
||||
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header file defines the data structures sent by the VM
|
||||
* through the JVMTI CompiledMethodLoad callback function via the
|
||||
* "void * compile_info" parameter. The memory pointed to by the
|
||||
* compile_info parameter may not be referenced after returning from
|
||||
* the CompiledMethodLoad callback. These are VM implementation
|
||||
* specific data structures that may evolve in future releases. A
|
||||
* JVMTI agent should interpret a non-NULL compile_info as a pointer
|
||||
* to a region of memory containing a list of records. In a typical
|
||||
* usage scenario, a JVMTI agent would cast each record to a
|
||||
* jvmtiCompiledMethodLoadRecordHeader, a struct that represents
|
||||
* arbitrary information. This struct contains a kind field to indicate
|
||||
* the kind of information being passed, and a pointer to the next
|
||||
* record. If the kind field indicates inlining information, then the
|
||||
* agent would cast the record to a jvmtiCompiledMethodLoadInlineRecord.
|
||||
* This record contains an array of PCStackInfo structs, which indicate
|
||||
* for every pc address what are the methods on the invocation stack.
|
||||
* The "methods" and "bcis" fields in each PCStackInfo struct specify a
|
||||
* 1-1 mapping between these inlined methods and their bytecode indices.
|
||||
* This can be used to derive the proper source lines of the inlined
|
||||
* methods.
|
||||
*/
|
||||
|
||||
#ifndef _JVMTI_CMLR_H_
|
||||
#define _JVMTI_CMLR_H_
|
||||
|
||||
enum {
|
||||
JVMTI_CMLR_MAJOR_VERSION_1 = 0x00000001,
|
||||
JVMTI_CMLR_MINOR_VERSION_0 = 0x00000000,
|
||||
|
||||
JVMTI_CMLR_MAJOR_VERSION = 0x00000001,
|
||||
JVMTI_CMLR_MINOR_VERSION = 0x00000000
|
||||
|
||||
/*
|
||||
* This comment is for the "JDK import from HotSpot" sanity check:
|
||||
* version: 1.0.0
|
||||
*/
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
JVMTI_CMLR_DUMMY = 1,
|
||||
JVMTI_CMLR_INLINE_INFO = 2
|
||||
} jvmtiCMLRKind;
|
||||
|
||||
/*
|
||||
* Record that represents arbitrary information passed through JVMTI
|
||||
* CompiledMethodLoadEvent void pointer.
|
||||
*/
|
||||
typedef struct _jvmtiCompiledMethodLoadRecordHeader {
|
||||
jvmtiCMLRKind kind; /* id for the kind of info passed in the record */
|
||||
jint majorinfoversion; /* major and minor info version values. Init'ed */
|
||||
jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */
|
||||
|
||||
struct _jvmtiCompiledMethodLoadRecordHeader* next;
|
||||
} jvmtiCompiledMethodLoadRecordHeader;
|
||||
|
||||
/*
|
||||
* Record that gives information about the methods on the compile-time
|
||||
* stack at a specific pc address of a compiled method. Each element in
|
||||
* the methods array maps to same element in the bcis array.
|
||||
*/
|
||||
typedef struct _PCStackInfo {
|
||||
void* pc; /* the pc address for this compiled method */
|
||||
jint numstackframes; /* number of methods on the stack */
|
||||
jmethodID* methods; /* array of numstackframes method ids */
|
||||
jint* bcis; /* array of numstackframes bytecode indices */
|
||||
} PCStackInfo;
|
||||
|
||||
/*
|
||||
* Record that contains inlining information for each pc address of
|
||||
* an nmethod.
|
||||
*/
|
||||
typedef struct _jvmtiCompiledMethodLoadInlineRecord {
|
||||
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
|
||||
jint numpcs; /* number of pc descriptors in this nmethod */
|
||||
PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
|
||||
} jvmtiCompiledMethodLoadInlineRecord;
|
||||
|
||||
/*
|
||||
* Dummy record used to test that we can pass records with different
|
||||
* information through the void pointer provided that they can be cast
|
||||
* to a jvmtiCompiledMethodLoadRecordHeader.
|
||||
*/
|
||||
|
||||
typedef struct _jvmtiCompiledMethodLoadDummyRecord {
|
||||
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
|
||||
char message[50];
|
||||
} jvmtiCompiledMethodLoadDummyRecord;
|
||||
|
||||
#endif
|
@ -411,11 +411,8 @@ void nmethod::init_defaults() {
|
||||
_oops_do_mark_link = NULL;
|
||||
_jmethod_id = NULL;
|
||||
_osr_link = NULL;
|
||||
if (UseG1GC) {
|
||||
_unloading_next = NULL;
|
||||
} else {
|
||||
_scavenge_root_link = NULL;
|
||||
}
|
||||
_unloading_next = NULL;
|
||||
_scavenge_root_link = NULL;
|
||||
_scavenge_root_state = 0;
|
||||
#if INCLUDE_RTM_OPT
|
||||
_rtm_state = NoRTM;
|
||||
@ -599,12 +596,9 @@ nmethod::nmethod(
|
||||
code_buffer->copy_code_and_locs_to(this);
|
||||
code_buffer->copy_values_to(this);
|
||||
if (ScavengeRootsInCode) {
|
||||
if (detect_scavenge_root_oops()) {
|
||||
CodeCache::add_scavenge_root_nmethod(this);
|
||||
}
|
||||
Universe::heap()->register_nmethod(this);
|
||||
}
|
||||
debug_only(verify_scavenge_root_oops());
|
||||
debug_only(Universe::heap()->verify_nmethod(this));
|
||||
CodeCache::commit(this);
|
||||
}
|
||||
|
||||
@ -754,12 +748,9 @@ nmethod::nmethod(
|
||||
debug_info->copy_to(this);
|
||||
dependencies->copy_to(this);
|
||||
if (ScavengeRootsInCode) {
|
||||
if (detect_scavenge_root_oops()) {
|
||||
CodeCache::add_scavenge_root_nmethod(this);
|
||||
}
|
||||
Universe::heap()->register_nmethod(this);
|
||||
}
|
||||
debug_only(verify_scavenge_root_oops());
|
||||
debug_only(Universe::heap()->verify_nmethod(this));
|
||||
|
||||
CodeCache::commit(this);
|
||||
|
||||
@ -1661,20 +1652,16 @@ nmethod* volatile nmethod::_oops_do_mark_nmethods;
|
||||
// This code must be MP safe, because it is used from parallel GC passes.
|
||||
bool nmethod::test_set_oops_do_mark() {
|
||||
assert(nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called");
|
||||
nmethod* observed_mark_link = _oops_do_mark_link;
|
||||
if (observed_mark_link == NULL) {
|
||||
if (_oops_do_mark_link == NULL) {
|
||||
// Claim this nmethod for this thread to mark.
|
||||
observed_mark_link = (nmethod*)
|
||||
Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_link, NULL);
|
||||
if (observed_mark_link == NULL) {
|
||||
|
||||
if (Atomic::cmpxchg(NMETHOD_SENTINEL, &_oops_do_mark_link, (nmethod*)NULL) == NULL) {
|
||||
// Atomically append this nmethod (now claimed) to the head of the list:
|
||||
nmethod* observed_mark_nmethods = _oops_do_mark_nmethods;
|
||||
for (;;) {
|
||||
nmethod* required_mark_nmethods = observed_mark_nmethods;
|
||||
_oops_do_mark_link = required_mark_nmethods;
|
||||
observed_mark_nmethods = (nmethod*)
|
||||
Atomic::cmpxchg_ptr(this, &_oops_do_mark_nmethods, required_mark_nmethods);
|
||||
observed_mark_nmethods =
|
||||
Atomic::cmpxchg(this, &_oops_do_mark_nmethods, required_mark_nmethods);
|
||||
if (observed_mark_nmethods == required_mark_nmethods)
|
||||
break;
|
||||
}
|
||||
@ -1690,9 +1677,9 @@ bool nmethod::test_set_oops_do_mark() {
|
||||
void nmethod::oops_do_marking_prologue() {
|
||||
if (TraceScavenge) { tty->print_cr("[oops_do_marking_prologue"); }
|
||||
assert(_oops_do_mark_nmethods == NULL, "must not call oops_do_marking_prologue twice in a row");
|
||||
// We use cmpxchg_ptr instead of regular assignment here because the user
|
||||
// We use cmpxchg instead of regular assignment here because the user
|
||||
// may fork a bunch of threads, and we need them all to see the same state.
|
||||
void* observed = Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_nmethods, NULL);
|
||||
nmethod* observed = Atomic::cmpxchg(NMETHOD_SENTINEL, &_oops_do_mark_nmethods, (nmethod*)NULL);
|
||||
guarantee(observed == NULL, "no races in this sequential code");
|
||||
}
|
||||
|
||||
@ -1707,8 +1694,8 @@ void nmethod::oops_do_marking_epilogue() {
|
||||
NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark"));
|
||||
cur = next;
|
||||
}
|
||||
void* required = _oops_do_mark_nmethods;
|
||||
void* observed = Atomic::cmpxchg_ptr(NULL, &_oops_do_mark_nmethods, required);
|
||||
nmethod* required = _oops_do_mark_nmethods;
|
||||
nmethod* observed = Atomic::cmpxchg((nmethod*)NULL, &_oops_do_mark_nmethods, required);
|
||||
guarantee(observed == required, "no races in this sequential code");
|
||||
if (TraceScavenge) { tty->print_cr("oops_do_marking_epilogue]"); }
|
||||
}
|
||||
@ -2137,7 +2124,7 @@ void nmethod::verify() {
|
||||
VerifyOopsClosure voc(this);
|
||||
oops_do(&voc);
|
||||
assert(voc.ok(), "embedded oops must be OK");
|
||||
verify_scavenge_root_oops();
|
||||
Universe::heap()->verify_nmethod(this);
|
||||
|
||||
verify_scopes();
|
||||
}
|
||||
@ -2230,10 +2217,6 @@ public:
|
||||
};
|
||||
|
||||
void nmethod::verify_scavenge_root_oops() {
|
||||
if (UseG1GC) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!on_scavenge_root_list()) {
|
||||
// Actually look inside, to verify the claim that it's clean.
|
||||
DebugScavengeRoot debug_scavenge_root(this);
|
||||
|
185
src/hotspot/share/gc/cms/cmsHeap.cpp
Normal file
185
src/hotspot/share/gc/cms/cmsHeap.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepThread.hpp"
|
||||
#include "gc/cms/cmsHeap.hpp"
|
||||
#include "gc/cms/vmCMSOperations.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "gc/shared/strongRootsScope.hpp"
|
||||
#include "gc/shared/workgroup.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "utilities/stack.inline.hpp"
|
||||
|
||||
CMSHeap::CMSHeap(GenCollectorPolicy *policy) : GenCollectedHeap(policy) {
|
||||
_workers = new WorkGang("GC Thread", ParallelGCThreads,
|
||||
/* are_GC_task_threads */true,
|
||||
/* are_ConcurrentGC_threads */false);
|
||||
_workers->initialize_workers();
|
||||
}
|
||||
|
||||
jint CMSHeap::initialize() {
|
||||
jint status = GenCollectedHeap::initialize();
|
||||
if (status != JNI_OK) return status;
|
||||
|
||||
// If we are running CMS, create the collector responsible
|
||||
// for collecting the CMS generations.
|
||||
assert(collector_policy()->is_concurrent_mark_sweep_policy(), "must be CMS policy");
|
||||
if (!create_cms_collector()) {
|
||||
return JNI_ENOMEM;
|
||||
}
|
||||
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
void CMSHeap::check_gen_kinds() {
|
||||
assert(young_gen()->kind() == Generation::ParNew,
|
||||
"Wrong youngest generation type");
|
||||
assert(old_gen()->kind() == Generation::ConcurrentMarkSweep,
|
||||
"Wrong generation kind");
|
||||
}
|
||||
|
||||
CMSHeap* CMSHeap::heap() {
|
||||
CollectedHeap* heap = Universe::heap();
|
||||
assert(heap != NULL, "Uninitialized access to CMSHeap::heap()");
|
||||
assert(heap->kind() == CollectedHeap::CMSHeap, "Not a CMSHeap");
|
||||
return (CMSHeap*) heap;
|
||||
}
|
||||
|
||||
void CMSHeap::gc_threads_do(ThreadClosure* tc) const {
|
||||
assert(workers() != NULL, "should have workers here");
|
||||
workers()->threads_do(tc);
|
||||
ConcurrentMarkSweepThread::threads_do(tc);
|
||||
}
|
||||
|
||||
void CMSHeap::print_gc_threads_on(outputStream* st) const {
|
||||
assert(workers() != NULL, "should have workers here");
|
||||
workers()->print_worker_threads_on(st);
|
||||
ConcurrentMarkSweepThread::print_all_on(st);
|
||||
}
|
||||
|
||||
void CMSHeap::print_on_error(outputStream* st) const {
|
||||
GenCollectedHeap::print_on_error(st);
|
||||
st->cr();
|
||||
CMSCollector::print_on_error(st);
|
||||
}
|
||||
|
||||
bool CMSHeap::create_cms_collector() {
|
||||
assert(old_gen()->kind() == Generation::ConcurrentMarkSweep,
|
||||
"Unexpected generation kinds");
|
||||
assert(gen_policy()->is_concurrent_mark_sweep_policy(), "Unexpected policy type");
|
||||
CMSCollector* collector =
|
||||
new CMSCollector((ConcurrentMarkSweepGeneration*) old_gen(),
|
||||
rem_set(),
|
||||
gen_policy()->as_concurrent_mark_sweep_policy());
|
||||
|
||||
if (collector == NULL || !collector->completed_initialization()) {
|
||||
if (collector) {
|
||||
delete collector; // Be nice in embedded situation
|
||||
}
|
||||
vm_shutdown_during_initialization("Could not create CMS collector");
|
||||
return false;
|
||||
}
|
||||
return true; // success
|
||||
}
|
||||
|
||||
void CMSHeap::collect(GCCause::Cause cause) {
|
||||
if (should_do_concurrent_full_gc(cause)) {
|
||||
// Mostly concurrent full collection.
|
||||
collect_mostly_concurrent(cause);
|
||||
} else {
|
||||
GenCollectedHeap::collect(cause);
|
||||
}
|
||||
}
|
||||
|
||||
bool CMSHeap::should_do_concurrent_full_gc(GCCause::Cause cause) {
|
||||
switch (cause) {
|
||||
case GCCause::_gc_locker: return GCLockerInvokesConcurrent;
|
||||
case GCCause::_java_lang_system_gc:
|
||||
case GCCause::_dcmd_gc_run: return ExplicitGCInvokesConcurrent;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CMSHeap::collect_mostly_concurrent(GCCause::Cause cause) {
|
||||
assert(!Heap_lock->owned_by_self(), "Should not own Heap_lock");
|
||||
|
||||
MutexLocker ml(Heap_lock);
|
||||
// Read the GC counts while holding the Heap_lock
|
||||
unsigned int full_gc_count_before = total_full_collections();
|
||||
unsigned int gc_count_before = total_collections();
|
||||
{
|
||||
MutexUnlocker mu(Heap_lock);
|
||||
VM_GenCollectFullConcurrent op(gc_count_before, full_gc_count_before, cause);
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
}
|
||||
|
||||
void CMSHeap::stop() {
|
||||
ConcurrentMarkSweepThread::cmst()->stop();
|
||||
}
|
||||
|
||||
void CMSHeap::safepoint_synchronize_begin() {
|
||||
ConcurrentMarkSweepThread::synchronize(false);
|
||||
}
|
||||
|
||||
void CMSHeap::safepoint_synchronize_end() {
|
||||
ConcurrentMarkSweepThread::desynchronize(false);
|
||||
}
|
||||
|
||||
void CMSHeap::cms_process_roots(StrongRootsScope* scope,
|
||||
bool young_gen_as_roots,
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure) {
|
||||
MarkingCodeBlobClosure mark_code_closure(root_closure, !CodeBlobToOopClosure::FixRelocations);
|
||||
OopsInGenClosure* weak_roots = only_strong_roots ? NULL : root_closure;
|
||||
CLDClosure* weak_cld_closure = only_strong_roots ? NULL : cld_closure;
|
||||
|
||||
process_roots(scope, so, root_closure, weak_roots, cld_closure, weak_cld_closure, &mark_code_closure);
|
||||
if (!only_strong_roots) {
|
||||
process_string_table_roots(scope, root_closure);
|
||||
}
|
||||
|
||||
if (young_gen_as_roots &&
|
||||
!_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) {
|
||||
root_closure->set_generation(young_gen());
|
||||
young_gen()->oop_iterate(root_closure);
|
||||
root_closure->reset_generation();
|
||||
}
|
||||
|
||||
_process_strong_tasks->all_tasks_completed(scope->n_threads());
|
||||
}
|
||||
|
||||
void CMSHeap::gc_prologue(bool full) {
|
||||
always_do_update_barrier = false;
|
||||
GenCollectedHeap::gc_prologue(full);
|
||||
};
|
||||
|
||||
void CMSHeap::gc_epilogue(bool full) {
|
||||
GenCollectedHeap::gc_epilogue(full);
|
||||
always_do_update_barrier = true;
|
||||
};
|
117
src/hotspot/share/gc/cms/cmsHeap.hpp
Normal file
117
src/hotspot/share/gc/cms/cmsHeap.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_GC_CMS_CMSHEAP_HPP
|
||||
#define SHARE_VM_GC_CMS_CMSHEAP_HPP
|
||||
|
||||
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/gcCause.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
|
||||
class CLDClosure;
|
||||
class GenCollectorPolicy;
|
||||
class OopsInGenClosure;
|
||||
class outputStream;
|
||||
class StrongRootsScope;
|
||||
class ThreadClosure;
|
||||
class WorkGang;
|
||||
|
||||
class CMSHeap : public GenCollectedHeap {
|
||||
public:
|
||||
CMSHeap(GenCollectorPolicy *policy);
|
||||
|
||||
// Returns JNI_OK on success
|
||||
virtual jint initialize();
|
||||
|
||||
virtual void check_gen_kinds();
|
||||
|
||||
// Convenience function to be used in situations where the heap type can be
|
||||
// asserted to be this type.
|
||||
static CMSHeap* heap();
|
||||
|
||||
virtual Name kind() const {
|
||||
return CollectedHeap::CMSHeap;
|
||||
}
|
||||
|
||||
virtual const char* name() const {
|
||||
return "Concurrent Mark Sweep";
|
||||
}
|
||||
|
||||
WorkGang* workers() const { return _workers; }
|
||||
|
||||
virtual void print_gc_threads_on(outputStream* st) const;
|
||||
virtual void gc_threads_do(ThreadClosure* tc) const;
|
||||
virtual void print_on_error(outputStream* st) const;
|
||||
|
||||
// Perform a full collection of the heap; intended for use in implementing
|
||||
// "System.gc". This implies as full a collection as the CollectedHeap
|
||||
// supports. Caller does not hold the Heap_lock on entry.
|
||||
void collect(GCCause::Cause cause);
|
||||
|
||||
bool is_in_closed_subset(const void* p) const {
|
||||
return is_in_reserved(p);
|
||||
}
|
||||
|
||||
bool card_mark_must_follow_store() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void stop();
|
||||
void safepoint_synchronize_begin();
|
||||
void safepoint_synchronize_end();
|
||||
|
||||
// If "young_gen_as_roots" is false, younger generations are
|
||||
// not scanned as roots; in this case, the caller must be arranging to
|
||||
// scan the younger generations itself. (For example, a generation might
|
||||
// explicitly mark reachable objects in younger generations, to avoid
|
||||
// excess storage retention.)
|
||||
void cms_process_roots(StrongRootsScope* scope,
|
||||
bool young_gen_as_roots,
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure);
|
||||
|
||||
private:
|
||||
WorkGang* _workers;
|
||||
|
||||
virtual void gc_prologue(bool full);
|
||||
virtual void gc_epilogue(bool full);
|
||||
|
||||
// Accessor for memory state verification support
|
||||
NOT_PRODUCT(
|
||||
virtual size_t skip_header_HeapWords() { return CMSCollector::skip_header_HeapWords(); }
|
||||
)
|
||||
|
||||
// Returns success or failure.
|
||||
bool create_cms_collector();
|
||||
|
||||
// In support of ExplicitGCInvokesConcurrent functionality
|
||||
bool should_do_concurrent_full_gc(GCCause::Cause cause);
|
||||
|
||||
void collect_mostly_concurrent(GCCause::Cause cause);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_CMS_CMSHEAP_HPP
|
@ -23,13 +23,13 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/cms/cmsHeap.hpp"
|
||||
#include "gc/cms/cmsLockVerifier.hpp"
|
||||
#include "gc/cms/compactibleFreeListSpace.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepThread.hpp"
|
||||
#include "gc/shared/blockOffsetTable.inline.hpp"
|
||||
#include "gc/shared/collectedHeap.inline.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "gc/shared/space.inline.hpp"
|
||||
#include "gc/shared/spaceDecorator.hpp"
|
||||
#include "logging/log.hpp"
|
||||
@ -154,7 +154,7 @@ HeapWord* CompactibleFreeListSpace::forward(oop q, size_t size,
|
||||
cp->space->set_compaction_top(compact_top);
|
||||
cp->space = cp->space->next_compaction_space();
|
||||
if (cp->space == NULL) {
|
||||
cp->gen = GenCollectedHeap::heap()->young_gen();
|
||||
cp->gen = CMSHeap::heap()->young_gen();
|
||||
assert(cp->gen != NULL, "compaction must succeed");
|
||||
cp->space = cp->gen->first_compaction_space();
|
||||
assert(cp->space != NULL, "generation must have a first compaction space");
|
||||
@ -2298,7 +2298,7 @@ void CompactibleFreeListSpace::verify() const {
|
||||
|
||||
// Iterate over all oops in the heap. Uses the _no_header version
|
||||
// since we are not interested in following the klass pointers.
|
||||
GenCollectedHeap::heap()->oop_iterate_no_header(&cl);
|
||||
CMSHeap::heap()->oop_iterate_no_header(&cl);
|
||||
}
|
||||
|
||||
if (VerifyObjectStartArray) {
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "gc/cms/cmsCollectorPolicy.hpp"
|
||||
#include "gc/cms/cmsHeap.hpp"
|
||||
#include "gc/cms/cmsOopClosures.inline.hpp"
|
||||
#include "gc/cms/compactibleFreeListSpace.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
|
||||
@ -54,6 +55,7 @@
|
||||
#include "gc/shared/referencePolicy.hpp"
|
||||
#include "gc/shared/strongRootsScope.hpp"
|
||||
#include "gc/shared/taskqueue.inline.hpp"
|
||||
#include "gc/shared/weakProcessor.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
@ -298,14 +300,14 @@ void CMSCollector::ref_processor_init() {
|
||||
}
|
||||
|
||||
AdaptiveSizePolicy* CMSCollector::size_policy() {
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
return gch->gen_policy()->size_policy();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
return heap->gen_policy()->size_policy();
|
||||
}
|
||||
|
||||
void ConcurrentMarkSweepGeneration::initialize_performance_counters() {
|
||||
|
||||
const char* gen_name = "old";
|
||||
GenCollectorPolicy* gcp = GenCollectedHeap::heap()->gen_policy();
|
||||
GenCollectorPolicy* gcp = CMSHeap::heap()->gen_policy();
|
||||
// Generation Counters - generation 1, 1 subspace
|
||||
_gen_counters = new GenerationCounters(gen_name, 1, 1,
|
||||
gcp->min_old_size(), gcp->max_old_size(), &_virtual_space);
|
||||
@ -354,8 +356,8 @@ void CMSStats::adjust_cms_free_adjustment_factor(bool fail, size_t free) {
|
||||
// young generation collection.
|
||||
double CMSStats::time_until_cms_gen_full() const {
|
||||
size_t cms_free = _cms_gen->cmsSpace()->free();
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
size_t expected_promotion = MIN2(gch->young_gen()->capacity(),
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
size_t expected_promotion = MIN2(heap->young_gen()->capacity(),
|
||||
(size_t) _cms_gen->gc_stats()->avg_promoted()->padded_average());
|
||||
if (cms_free > expected_promotion) {
|
||||
// Start a cms collection if there isn't enough space to promote
|
||||
@ -595,12 +597,12 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
assert(CGC_lock != NULL, "Where's the CGC_lock?");
|
||||
|
||||
// Support for parallelizing young gen rescan
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
assert(gch->young_gen()->kind() == Generation::ParNew, "CMS can only be used with ParNew");
|
||||
_young_gen = (ParNewGeneration*)gch->young_gen();
|
||||
if (gch->supports_inline_contig_alloc()) {
|
||||
_top_addr = gch->top_addr();
|
||||
_end_addr = gch->end_addr();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
assert(heap->young_gen()->kind() == Generation::ParNew, "CMS can only be used with ParNew");
|
||||
_young_gen = (ParNewGeneration*)heap->young_gen();
|
||||
if (heap->supports_inline_contig_alloc()) {
|
||||
_top_addr = heap->top_addr();
|
||||
_end_addr = heap->end_addr();
|
||||
assert(_young_gen != NULL, "no _young_gen");
|
||||
_eden_chunk_index = 0;
|
||||
_eden_chunk_capacity = (_young_gen->max_capacity() + CMSSamplingGrain) / CMSSamplingGrain;
|
||||
@ -762,9 +764,9 @@ void ConcurrentMarkSweepGeneration::compute_new_size_free_list() {
|
||||
log.trace(" Maximum free fraction %f", maximum_free_percentage);
|
||||
log.trace(" Capacity " SIZE_FORMAT, capacity() / 1000);
|
||||
log.trace(" Desired capacity " SIZE_FORMAT, desired_capacity / 1000);
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
assert(gch->is_old_gen(this), "The CMS generation should always be the old generation");
|
||||
size_t young_size = gch->young_gen()->capacity();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
assert(heap->is_old_gen(this), "The CMS generation should always be the old generation");
|
||||
size_t young_size = heap->young_gen()->capacity();
|
||||
log.trace(" Young gen size " SIZE_FORMAT, young_size / 1000);
|
||||
log.trace(" unsafe_max_alloc_nogc " SIZE_FORMAT, unsafe_max_alloc_nogc() / 1000);
|
||||
log.trace(" contiguous available " SIZE_FORMAT, contiguous_available() / 1000);
|
||||
@ -923,7 +925,7 @@ oop ConcurrentMarkSweepGeneration::promote(oop obj, size_t obj_size) {
|
||||
assert_lock_strong(freelistLock());
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (GenCollectedHeap::heap()->promotion_should_fail()) {
|
||||
if (CMSHeap::heap()->promotion_should_fail()) {
|
||||
return NULL;
|
||||
}
|
||||
#endif // #ifndef PRODUCT
|
||||
@ -1000,7 +1002,7 @@ ConcurrentMarkSweepGeneration::par_promote(int thread_num,
|
||||
oop old, markOop m,
|
||||
size_t word_sz) {
|
||||
#ifndef PRODUCT
|
||||
if (GenCollectedHeap::heap()->promotion_should_fail()) {
|
||||
if (CMSHeap::heap()->promotion_should_fail()) {
|
||||
return NULL;
|
||||
}
|
||||
#endif // #ifndef PRODUCT
|
||||
@ -1076,7 +1078,7 @@ ConcurrentMarkSweepGeneration::par_promote(int thread_num,
|
||||
|
||||
NOT_PRODUCT(
|
||||
Atomic::inc(&_numObjectsPromoted);
|
||||
Atomic::add_ptr(alloc_sz, &_numWordsPromoted);
|
||||
Atomic::add(alloc_sz, &_numWordsPromoted);
|
||||
)
|
||||
|
||||
return obj;
|
||||
@ -1179,10 +1181,10 @@ bool CMSCollector::shouldConcurrentCollect() {
|
||||
// We start a collection if we believe an incremental collection may fail;
|
||||
// this is not likely to be productive in practice because it's probably too
|
||||
// late anyway.
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
assert(gch->collector_policy()->is_generation_policy(),
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
assert(heap->collector_policy()->is_generation_policy(),
|
||||
"You may want to check the correctness of the following");
|
||||
if (gch->incremental_collection_will_fail(true /* consult_young */)) {
|
||||
if (heap->incremental_collection_will_fail(true /* consult_young */)) {
|
||||
log.print("CMSCollector: collect because incremental collection will fail ");
|
||||
return true;
|
||||
}
|
||||
@ -1294,8 +1296,8 @@ void CMSCollector::collect(bool full,
|
||||
}
|
||||
|
||||
void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause cause) {
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
unsigned int gc_count = gch->total_full_collections();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
unsigned int gc_count = heap->total_full_collections();
|
||||
if (gc_count == full_gc_count) {
|
||||
MutexLockerEx y(CGC_lock, Mutex::_no_safepoint_check_flag);
|
||||
_full_gc_requested = true;
|
||||
@ -1307,7 +1309,7 @@ void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause ca
|
||||
}
|
||||
|
||||
bool CMSCollector::is_external_interruption() {
|
||||
GCCause::Cause cause = GenCollectedHeap::heap()->gc_cause();
|
||||
GCCause::Cause cause = CMSHeap::heap()->gc_cause();
|
||||
return GCCause::is_user_requested_gc(cause) ||
|
||||
GCCause::is_serviceability_requested_gc(cause);
|
||||
}
|
||||
@ -1456,8 +1458,8 @@ void CMSCollector::acquire_control_and_collect(bool full,
|
||||
|
||||
// Inform cms gen if this was due to partial collection failing.
|
||||
// The CMS gen may use this fact to determine its expansion policy.
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
if (gch->incremental_collection_will_fail(false /* don't consult_young */)) {
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
if (heap->incremental_collection_will_fail(false /* don't consult_young */)) {
|
||||
assert(!_cmsGen->incremental_collection_failed(),
|
||||
"Should have been noticed, reacted to and cleared");
|
||||
_cmsGen->set_incremental_collection_failed();
|
||||
@ -1489,14 +1491,14 @@ void CMSCollector::acquire_control_and_collect(bool full,
|
||||
|
||||
// Has the GC time limit been exceeded?
|
||||
size_t max_eden_size = _young_gen->max_eden_size();
|
||||
GCCause::Cause gc_cause = gch->gc_cause();
|
||||
GCCause::Cause gc_cause = heap->gc_cause();
|
||||
size_policy()->check_gc_overhead_limit(_young_gen->used(),
|
||||
_young_gen->eden()->used(),
|
||||
_cmsGen->max_capacity(),
|
||||
max_eden_size,
|
||||
full,
|
||||
gc_cause,
|
||||
gch->collector_policy());
|
||||
heap->collector_policy());
|
||||
|
||||
// Reset the expansion cause, now that we just completed
|
||||
// a collection cycle.
|
||||
@ -1518,21 +1520,21 @@ void CMSCollector::compute_new_size() {
|
||||
// A work method used by the foreground collector to do
|
||||
// a mark-sweep-compact.
|
||||
void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
|
||||
STWGCTimer* gc_timer = GenMarkSweep::gc_timer();
|
||||
gc_timer->register_gc_start();
|
||||
|
||||
SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer();
|
||||
gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
|
||||
gc_tracer->report_gc_start(heap->gc_cause(), gc_timer->gc_start());
|
||||
|
||||
gch->pre_full_gc_dump(gc_timer);
|
||||
heap->pre_full_gc_dump(gc_timer);
|
||||
|
||||
GCTraceTime(Trace, gc, phases) t("CMS:MSC");
|
||||
|
||||
// Temporarily widen the span of the weak reference processing to
|
||||
// the entire heap.
|
||||
MemRegion new_span(GenCollectedHeap::heap()->reserved_region());
|
||||
MemRegion new_span(CMSHeap::heap()->reserved_region());
|
||||
ReferenceProcessorSpanMutator rp_mut_span(ref_processor(), new_span);
|
||||
// Temporarily, clear the "is_alive_non_header" field of the
|
||||
// reference processor.
|
||||
@ -1608,7 +1610,7 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
||||
// No longer a need to do a concurrent collection for Metaspace.
|
||||
MetaspaceGC::set_should_concurrent_collect(false);
|
||||
|
||||
gch->post_full_gc_dump(gc_timer);
|
||||
heap->post_full_gc_dump(gc_timer);
|
||||
|
||||
gc_timer->register_gc_end();
|
||||
|
||||
@ -1702,7 +1704,7 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) {
|
||||
assert(Thread::current()->is_ConcurrentGC_thread(),
|
||||
"A CMS asynchronous collection is only allowed on a CMS thread.");
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
{
|
||||
bool safepoint_check = Mutex::_no_safepoint_check_flag;
|
||||
MutexLockerEx hl(Heap_lock, safepoint_check);
|
||||
@ -1731,8 +1733,8 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) {
|
||||
_full_gc_requested = false; // acks all outstanding full gc requests
|
||||
_full_gc_cause = GCCause::_no_gc;
|
||||
// Signal that we are about to start a collection
|
||||
gch->increment_total_full_collections(); // ... starting a collection cycle
|
||||
_collection_count_start = gch->total_full_collections();
|
||||
heap->increment_total_full_collections(); // ... starting a collection cycle
|
||||
_collection_count_start = heap->total_full_collections();
|
||||
}
|
||||
|
||||
size_t prev_used = _cmsGen->used();
|
||||
@ -1925,9 +1927,9 @@ void CMSCollector::register_gc_end() {
|
||||
}
|
||||
|
||||
void CMSCollector::save_heap_summary() {
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
_last_heap_summary = gch->create_heap_summary();
|
||||
_last_metaspace_summary = gch->create_metaspace_summary();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
_last_heap_summary = heap->create_heap_summary();
|
||||
_last_metaspace_summary = heap->create_metaspace_summary();
|
||||
}
|
||||
|
||||
void CMSCollector::report_heap_summary(GCWhen::Type when) {
|
||||
@ -2303,10 +2305,10 @@ bool CMSCollector::verify_after_remark() {
|
||||
assert(verification_mark_stack()->isEmpty(), "markStack should be empty");
|
||||
verify_work_stacks_empty();
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
gch->ensure_parsability(false); // fill TLABs, but no need to retire them
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
heap->ensure_parsability(false); // fill TLABs, but no need to retire them
|
||||
// Update the saved marks which may affect the root scans.
|
||||
gch->save_marks();
|
||||
heap->save_marks();
|
||||
|
||||
if (CMSRemarkVerifyVariant == 1) {
|
||||
// In this first variant of verification, we complete
|
||||
@ -2329,19 +2331,19 @@ bool CMSCollector::verify_after_remark() {
|
||||
void CMSCollector::verify_after_remark_work_1() {
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
|
||||
// Get a clear set of claim bits for the roots processing to work with.
|
||||
ClassLoaderDataGraph::clear_claimed_marks();
|
||||
|
||||
// Mark from roots one level into CMS
|
||||
MarkRefsIntoClosure notOlder(_span, verification_mark_bm());
|
||||
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
|
||||
heap->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
|
||||
|
||||
{
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->cms_process_roots(&srs,
|
||||
heap->cms_process_roots(&srs,
|
||||
true, // young gen as roots
|
||||
GenCollectedHeap::ScanningOption(roots_scanning_options()),
|
||||
should_unload_classes(),
|
||||
@ -2376,7 +2378,7 @@ void CMSCollector::verify_after_remark_work_1() {
|
||||
log.error("Failed marking verification after remark");
|
||||
ResourceMark rm;
|
||||
LogStream ls(log.error());
|
||||
gch->print_on(&ls);
|
||||
heap->print_on(&ls);
|
||||
fatal("CMS: failed marking verification after remark");
|
||||
}
|
||||
}
|
||||
@ -2399,7 +2401,7 @@ class VerifyCLDOopsCLDClosure : public CLDClosure {
|
||||
void CMSCollector::verify_after_remark_work_2() {
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
|
||||
// Get a clear set of claim bits for the roots processing to work with.
|
||||
ClassLoaderDataGraph::clear_claimed_marks();
|
||||
@ -2409,12 +2411,12 @@ void CMSCollector::verify_after_remark_work_2() {
|
||||
markBitMap());
|
||||
CLDToOopClosure cld_closure(¬Older, true);
|
||||
|
||||
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
|
||||
heap->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
|
||||
|
||||
{
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->cms_process_roots(&srs,
|
||||
heap->cms_process_roots(&srs,
|
||||
true, // young gen as roots
|
||||
GenCollectedHeap::ScanningOption(roots_scanning_options()),
|
||||
should_unload_classes(),
|
||||
@ -2803,7 +2805,7 @@ class CMSParInitialMarkTask: public CMSParMarkTask {
|
||||
void CMSCollector::checkpointRootsInitial() {
|
||||
assert(_collectorState == InitialMarking, "Wrong collector state");
|
||||
check_correct_thread_executing();
|
||||
TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause());
|
||||
TraceCMSMemoryManagerStats tms(_collectorState, CMSHeap::heap()->gc_cause());
|
||||
|
||||
save_heap_summary();
|
||||
report_heap_summary(GCWhen::BeforeGC);
|
||||
@ -2844,14 +2846,14 @@ void CMSCollector::checkpointRootsInitialWork() {
|
||||
HandleMark hm;
|
||||
|
||||
MarkRefsIntoClosure notOlder(_span, &_markBitMap);
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
|
||||
verify_work_stacks_empty();
|
||||
verify_overflow_empty();
|
||||
|
||||
gch->ensure_parsability(false); // fill TLABs, but no need to retire them
|
||||
heap->ensure_parsability(false); // fill TLABs, but no need to retire them
|
||||
// Update the saved marks which may affect the root scans.
|
||||
gch->save_marks();
|
||||
heap->save_marks();
|
||||
|
||||
// weak reference processing has not started yet.
|
||||
ref_processor()->set_enqueuing_is_done(false);
|
||||
@ -2872,7 +2874,7 @@ void CMSCollector::checkpointRootsInitialWork() {
|
||||
#endif
|
||||
if (CMSParallelInitialMarkEnabled) {
|
||||
// The parallel version.
|
||||
WorkGang* workers = gch->workers();
|
||||
WorkGang* workers = heap->workers();
|
||||
assert(workers != NULL, "Need parallel worker threads.");
|
||||
uint n_workers = workers->active_workers();
|
||||
|
||||
@ -2891,11 +2893,11 @@ void CMSCollector::checkpointRootsInitialWork() {
|
||||
} else {
|
||||
// The serial version.
|
||||
CLDToOopClosure cld_closure(¬Older, true);
|
||||
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
|
||||
heap->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
|
||||
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->cms_process_roots(&srs,
|
||||
heap->cms_process_roots(&srs,
|
||||
true, // young gen as roots
|
||||
GenCollectedHeap::ScanningOption(roots_scanning_options()),
|
||||
should_unload_classes(),
|
||||
@ -3179,7 +3181,7 @@ void CMSConcMarkingTask::bump_global_finger(HeapWord* f) {
|
||||
HeapWord* cur = read;
|
||||
while (f > read) {
|
||||
cur = read;
|
||||
read = (HeapWord*) Atomic::cmpxchg_ptr(f, &_global_finger, cur);
|
||||
read = Atomic::cmpxchg(f, &_global_finger, cur);
|
||||
if (cur == read) {
|
||||
// our cas succeeded
|
||||
assert(_global_finger >= f, "protocol consistency");
|
||||
@ -3800,7 +3802,7 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) {
|
||||
bitMapLock());
|
||||
startTimer();
|
||||
unsigned int before_count =
|
||||
GenCollectedHeap::heap()->total_collections();
|
||||
CMSHeap::heap()->total_collections();
|
||||
SurvivorSpacePrecleanClosure
|
||||
sss_cl(this, _span, &_markBitMap, &_markStack,
|
||||
&pam_cl, before_count, CMSYield);
|
||||
@ -4103,7 +4105,7 @@ void CMSCollector::checkpointRootsFinal() {
|
||||
// world is stopped at this checkpoint
|
||||
assert(SafepointSynchronize::is_at_safepoint(),
|
||||
"world should be stopped");
|
||||
TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause());
|
||||
TraceCMSMemoryManagerStats tms(_collectorState, CMSHeap::heap()->gc_cause());
|
||||
|
||||
verify_work_stacks_empty();
|
||||
verify_overflow_empty();
|
||||
@ -4112,16 +4114,16 @@ void CMSCollector::checkpointRootsFinal() {
|
||||
_young_gen->used() / K, _young_gen->capacity() / K);
|
||||
{
|
||||
if (CMSScavengeBeforeRemark) {
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
// Temporarily set flag to false, GCH->do_collection will
|
||||
// expect it to be false and set to true
|
||||
FlagSetting fl(gch->_is_gc_active, false);
|
||||
FlagSetting fl(heap->_is_gc_active, false);
|
||||
|
||||
gch->do_collection(true, // full (i.e. force, see below)
|
||||
false, // !clear_all_soft_refs
|
||||
0, // size
|
||||
false, // is_tlab
|
||||
GenCollectedHeap::YoungGen // type
|
||||
heap->do_collection(true, // full (i.e. force, see below)
|
||||
false, // !clear_all_soft_refs
|
||||
0, // size
|
||||
false, // is_tlab
|
||||
GenCollectedHeap::YoungGen // type
|
||||
);
|
||||
}
|
||||
FreelistLocker x(this);
|
||||
@ -4142,7 +4144,7 @@ void CMSCollector::checkpointRootsFinalWork() {
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
|
||||
if (should_unload_classes()) {
|
||||
CodeCache::gc_prologue();
|
||||
@ -4162,9 +4164,9 @@ void CMSCollector::checkpointRootsFinalWork() {
|
||||
// or of an indication of whether the scavenge did indeed occur,
|
||||
// we cannot rely on TLAB's having been filled and must do
|
||||
// so here just in case a scavenge did not happen.
|
||||
gch->ensure_parsability(false); // fill TLAB's, but no need to retire them
|
||||
heap->ensure_parsability(false); // fill TLAB's, but no need to retire them
|
||||
// Update the saved marks which may affect the root scans.
|
||||
gch->save_marks();
|
||||
heap->save_marks();
|
||||
|
||||
print_eden_and_survivor_chunk_arrays();
|
||||
|
||||
@ -4240,7 +4242,7 @@ void CMSCollector::checkpointRootsFinalWork() {
|
||||
_markStack._failed_double = 0;
|
||||
|
||||
if ((VerifyAfterGC || VerifyDuringGC) &&
|
||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
CMSHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
verify_after_remark();
|
||||
}
|
||||
|
||||
@ -4262,7 +4264,7 @@ void CMSParInitialMarkTask::work(uint worker_id) {
|
||||
|
||||
// ---------- scan from roots --------------
|
||||
_timer.start();
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
ParMarkRefsIntoClosure par_mri_cl(_collector->_span, &(_collector->_markBitMap));
|
||||
|
||||
// ---------- young gen roots --------------
|
||||
@ -4278,12 +4280,12 @@ void CMSParInitialMarkTask::work(uint worker_id) {
|
||||
|
||||
CLDToOopClosure cld_closure(&par_mri_cl, true);
|
||||
|
||||
gch->cms_process_roots(_strong_roots_scope,
|
||||
false, // yg was scanned above
|
||||
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
|
||||
_collector->should_unload_classes(),
|
||||
&par_mri_cl,
|
||||
&cld_closure);
|
||||
heap->cms_process_roots(_strong_roots_scope,
|
||||
false, // yg was scanned above
|
||||
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
|
||||
_collector->should_unload_classes(),
|
||||
&par_mri_cl,
|
||||
&cld_closure);
|
||||
assert(_collector->should_unload_classes()
|
||||
|| (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
|
||||
"if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops");
|
||||
@ -4387,7 +4389,7 @@ void CMSParRemarkTask::work(uint worker_id) {
|
||||
|
||||
// ---------- rescan from roots --------------
|
||||
_timer.start();
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
ParMarkRefsIntoAndScanClosure par_mrias_cl(_collector,
|
||||
_collector->_span, _collector->ref_processor(),
|
||||
&(_collector->_markBitMap),
|
||||
@ -4407,12 +4409,12 @@ void CMSParRemarkTask::work(uint worker_id) {
|
||||
// ---------- remaining roots --------------
|
||||
_timer.reset();
|
||||
_timer.start();
|
||||
gch->cms_process_roots(_strong_roots_scope,
|
||||
false, // yg was scanned above
|
||||
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
|
||||
_collector->should_unload_classes(),
|
||||
&par_mrias_cl,
|
||||
NULL); // The dirty klasses will be handled below
|
||||
heap->cms_process_roots(_strong_roots_scope,
|
||||
false, // yg was scanned above
|
||||
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
|
||||
_collector->should_unload_classes(),
|
||||
&par_mrias_cl,
|
||||
NULL); // The dirty klasses will be handled below
|
||||
|
||||
assert(_collector->should_unload_classes()
|
||||
|| (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
|
||||
@ -4839,8 +4841,8 @@ initialize_sequential_subtasks_for_young_gen_rescan(int n_threads) {
|
||||
|
||||
// Parallel version of remark
|
||||
void CMSCollector::do_remark_parallel() {
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
WorkGang* workers = gch->workers();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
WorkGang* workers = heap->workers();
|
||||
assert(workers != NULL, "Need parallel worker threads.");
|
||||
// Choose to use the number of GC workers most recently set
|
||||
// into "active_workers".
|
||||
@ -4856,7 +4858,7 @@ void CMSCollector::do_remark_parallel() {
|
||||
// the younger_gen cards, so we shouldn't call the following else
|
||||
// the verification code as well as subsequent younger_refs_iterate
|
||||
// code would get confused. XXX
|
||||
// gch->rem_set()->prepare_for_younger_refs_iterate(true); // parallel
|
||||
// heap->rem_set()->prepare_for_younger_refs_iterate(true); // parallel
|
||||
|
||||
// The young gen rescan work will not be done as part of
|
||||
// process_roots (which currently doesn't know how to
|
||||
@ -4898,7 +4900,7 @@ void CMSCollector::do_remark_parallel() {
|
||||
void CMSCollector::do_remark_non_parallel() {
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
ReferenceProcessorMTDiscoveryMutator mt(ref_processor(), false);
|
||||
|
||||
MarkRefsIntoAndScanClosure
|
||||
@ -4939,7 +4941,7 @@ void CMSCollector::do_remark_non_parallel() {
|
||||
}
|
||||
}
|
||||
if (VerifyDuringGC &&
|
||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
CMSHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
HandleMark hm; // Discard invalid handles created during verification
|
||||
Universe::verify();
|
||||
}
|
||||
@ -4948,15 +4950,15 @@ void CMSCollector::do_remark_non_parallel() {
|
||||
|
||||
verify_work_stacks_empty();
|
||||
|
||||
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
|
||||
heap->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->cms_process_roots(&srs,
|
||||
true, // young gen as roots
|
||||
GenCollectedHeap::ScanningOption(roots_scanning_options()),
|
||||
should_unload_classes(),
|
||||
&mrias_cl,
|
||||
NULL); // The dirty klasses will be handled below
|
||||
heap->cms_process_roots(&srs,
|
||||
true, // young gen as roots
|
||||
GenCollectedHeap::ScanningOption(roots_scanning_options()),
|
||||
should_unload_classes(),
|
||||
&mrias_cl,
|
||||
NULL); // The dirty klasses will be handled below
|
||||
|
||||
assert(should_unload_classes()
|
||||
|| (roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
|
||||
@ -5148,8 +5150,8 @@ void CMSRefProcTaskProxy::do_work_steal(int i,
|
||||
|
||||
void CMSRefProcTaskExecutor::execute(ProcessTask& task)
|
||||
{
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
WorkGang* workers = gch->workers();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
WorkGang* workers = heap->workers();
|
||||
assert(workers != NULL, "Need parallel worker threads.");
|
||||
CMSRefProcTaskProxy rp_task(task, &_collector,
|
||||
_collector.ref_processor()->span(),
|
||||
@ -5161,8 +5163,8 @@ void CMSRefProcTaskExecutor::execute(ProcessTask& task)
|
||||
void CMSRefProcTaskExecutor::execute(EnqueueTask& task)
|
||||
{
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
WorkGang* workers = gch->workers();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
WorkGang* workers = heap->workers();
|
||||
assert(workers != NULL, "Need parallel worker threads.");
|
||||
CMSRefEnqueueTaskProxy enq_task(task);
|
||||
workers->run_task(&enq_task);
|
||||
@ -5195,9 +5197,9 @@ void CMSCollector::refProcessingWork() {
|
||||
// and a different number of discovered lists may have Ref objects.
|
||||
// That is OK as long as the Reference lists are balanced (see
|
||||
// balance_all_queues() and balance_queues()).
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
uint active_workers = ParallelGCThreads;
|
||||
WorkGang* workers = gch->workers();
|
||||
WorkGang* workers = heap->workers();
|
||||
if (workers != NULL) {
|
||||
active_workers = workers->active_workers();
|
||||
// The expectation is that active_workers will have already
|
||||
@ -5223,6 +5225,11 @@ void CMSCollector::refProcessingWork() {
|
||||
pt.print_all_references();
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("Weak Processing", _gc_timer_cm);
|
||||
WeakProcessor::weak_oops_do(&_is_alive_closure, &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure);
|
||||
}
|
||||
|
||||
// This is the point where the entire marking should have completed.
|
||||
verify_work_stacks_empty();
|
||||
|
||||
@ -5305,7 +5312,7 @@ void CMSCollector::sweep() {
|
||||
verify_work_stacks_empty();
|
||||
verify_overflow_empty();
|
||||
increment_sweep_count();
|
||||
TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause());
|
||||
TraceCMSMemoryManagerStats tms(_collectorState, CMSHeap::heap()->gc_cause());
|
||||
|
||||
_inter_sweep_timer.stop();
|
||||
_inter_sweep_estimate.sample(_inter_sweep_timer.seconds());
|
||||
@ -5378,9 +5385,9 @@ void CMSCollector::sweep() {
|
||||
// this generation. If such a promotion may still fail,
|
||||
// the flag will be set again when a young collection is
|
||||
// attempted.
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
gch->clear_incremental_collection_failed(); // Worth retrying as fresh space may have been freed up
|
||||
gch->update_full_collections_completed(_collection_count_start);
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
heap->clear_incremental_collection_failed(); // Worth retrying as fresh space may have been freed up
|
||||
heap->update_full_collections_completed(_collection_count_start);
|
||||
}
|
||||
|
||||
// FIX ME!!! Looks like this belongs in CFLSpace, with
|
||||
@ -5415,7 +5422,7 @@ void ConcurrentMarkSweepGeneration::update_gc_stats(Generation* current_generati
|
||||
bool full) {
|
||||
// If the young generation has been collected, gather any statistics
|
||||
// that are of interest at this point.
|
||||
bool current_is_young = GenCollectedHeap::heap()->is_young_gen(current_generation);
|
||||
bool current_is_young = CMSHeap::heap()->is_young_gen(current_generation);
|
||||
if (!full && current_is_young) {
|
||||
// Gather statistics on the young generation collection.
|
||||
collector()->stats().record_gc0_end(used());
|
||||
@ -6188,7 +6195,7 @@ size_t SurvivorSpacePrecleanClosure::do_object_careful(oop p) {
|
||||
do_yield_check();
|
||||
}
|
||||
unsigned int after_count =
|
||||
GenCollectedHeap::heap()->total_collections();
|
||||
CMSHeap::heap()->total_collections();
|
||||
bool abort = (_before_count != after_count) ||
|
||||
_collector->should_abort_preclean();
|
||||
return abort ? 0 : size;
|
||||
@ -7852,7 +7859,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num,
|
||||
return false;
|
||||
}
|
||||
// Grab the entire list; we'll put back a suffix
|
||||
oop prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list));
|
||||
oop prefix = cast_to_oop(Atomic::xchg((oopDesc*)BUSY, &_overflow_list));
|
||||
Thread* tid = Thread::current();
|
||||
// Before "no_of_gc_threads" was introduced CMSOverflowSpinCount was
|
||||
// set to ParallelGCThreads.
|
||||
@ -7867,7 +7874,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num,
|
||||
return false;
|
||||
} else if (_overflow_list != BUSY) {
|
||||
// Try and grab the prefix
|
||||
prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list));
|
||||
prefix = cast_to_oop(Atomic::xchg((oopDesc*)BUSY, &_overflow_list));
|
||||
}
|
||||
}
|
||||
// If the list was found to be empty, or we spun long
|
||||
@ -7880,7 +7887,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num,
|
||||
if (prefix == NULL) {
|
||||
// Write back the NULL in case we overwrote it with BUSY above
|
||||
// and it is still the same value.
|
||||
(void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
|
||||
Atomic::cmpxchg((oopDesc*)NULL, &_overflow_list, (oopDesc*)BUSY);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -7895,7 +7902,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num,
|
||||
// Write back the NULL in lieu of the BUSY we wrote
|
||||
// above, if it is still the same value.
|
||||
if (_overflow_list == BUSY) {
|
||||
(void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
|
||||
Atomic::cmpxchg((oopDesc*)NULL, &_overflow_list, (oopDesc*)BUSY);
|
||||
}
|
||||
} else {
|
||||
// Chop off the suffix and return it to the global list.
|
||||
@ -7911,7 +7918,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num,
|
||||
bool attached = false;
|
||||
while (observed_overflow_list == BUSY || observed_overflow_list == NULL) {
|
||||
observed_overflow_list =
|
||||
(oop) Atomic::cmpxchg_ptr(suffix_head, &_overflow_list, cur_overflow_list);
|
||||
Atomic::cmpxchg((oopDesc*)suffix_head, &_overflow_list, (oopDesc*)cur_overflow_list);
|
||||
if (cur_overflow_list == observed_overflow_list) {
|
||||
attached = true;
|
||||
break;
|
||||
@ -7936,7 +7943,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num,
|
||||
}
|
||||
// ... and try to place spliced list back on overflow_list ...
|
||||
observed_overflow_list =
|
||||
(oop) Atomic::cmpxchg_ptr(suffix_head, &_overflow_list, cur_overflow_list);
|
||||
Atomic::cmpxchg((oopDesc*)suffix_head, &_overflow_list, (oopDesc*)cur_overflow_list);
|
||||
} while (cur_overflow_list != observed_overflow_list);
|
||||
// ... until we have succeeded in doing so.
|
||||
}
|
||||
@ -7957,7 +7964,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num,
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
assert(_num_par_pushes >= n, "Too many pops?");
|
||||
Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes);
|
||||
Atomic::sub(n, &_num_par_pushes);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@ -7986,7 +7993,7 @@ void CMSCollector::par_push_on_overflow_list(oop p) {
|
||||
p->set_mark(NULL);
|
||||
}
|
||||
observed_overflow_list =
|
||||
(oop) Atomic::cmpxchg_ptr(p, &_overflow_list, cur_overflow_list);
|
||||
Atomic::cmpxchg((oopDesc*)p, &_overflow_list, (oopDesc*)cur_overflow_list);
|
||||
} while (cur_overflow_list != observed_overflow_list);
|
||||
}
|
||||
#undef BUSY
|
||||
|
@ -25,13 +25,13 @@
|
||||
#ifndef SHARE_VM_GC_CMS_CONCURRENTMARKSWEEPGENERATION_INLINE_HPP
|
||||
#define SHARE_VM_GC_CMS_CONCURRENTMARKSWEEPGENERATION_INLINE_HPP
|
||||
|
||||
#include "gc/cms/cmsHeap.hpp"
|
||||
#include "gc/cms/cmsLockVerifier.hpp"
|
||||
#include "gc/cms/compactibleFreeListSpace.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepThread.hpp"
|
||||
#include "gc/cms/parNewGeneration.hpp"
|
||||
#include "gc/shared/gcUtil.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
|
||||
@ -256,7 +256,7 @@ inline bool CMSCollector::should_abort_preclean() const {
|
||||
// scavenge is done or foreground GC wants to take over collection
|
||||
return _collectorState == AbortablePreclean &&
|
||||
(_abort_preclean || _foregroundGCIsActive ||
|
||||
GenCollectedHeap::heap()->incremental_collection_will_fail(true /* consult_young */));
|
||||
CMSHeap::heap()->incremental_collection_will_fail(true /* consult_young */));
|
||||
}
|
||||
|
||||
inline size_t CMSCollector::get_eden_used() const {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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,10 +24,10 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "gc/cms/cmsHeap.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepThread.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
@ -225,7 +225,7 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) {
|
||||
// Wait time in millis or 0 value representing infinite wait for a scavenge
|
||||
assert(t_millis >= 0, "Wait time for scavenge should be 0 or positive");
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
double start_time_secs = os::elapsedTime();
|
||||
double end_time_secs = start_time_secs + (t_millis / ((double) MILLIUNITS));
|
||||
|
||||
@ -233,7 +233,7 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) {
|
||||
unsigned int before_count;
|
||||
{
|
||||
MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag);
|
||||
before_count = gch->total_collections();
|
||||
before_count = heap->total_collections();
|
||||
}
|
||||
|
||||
unsigned int loop_count = 0;
|
||||
@ -279,7 +279,7 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) {
|
||||
unsigned int after_count;
|
||||
{
|
||||
MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag);
|
||||
after_count = gch->total_collections();
|
||||
after_count = heap->total_collections();
|
||||
}
|
||||
|
||||
if(before_count != after_count) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,10 +23,10 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/cms/cmsHeap.hpp"
|
||||
#include "gc/shared/cardTableModRefBS.hpp"
|
||||
#include "gc/shared/cardTableRS.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "gc/shared/space.inline.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/virtualspace.hpp"
|
||||
@ -394,7 +394,7 @@ get_LNC_array_for_space(Space* sp,
|
||||
// Do a dirty read here. If we pass the conditional then take the rare
|
||||
// event lock and do the read again in case some other thread had already
|
||||
// succeeded and done the resize.
|
||||
int cur_collection = GenCollectedHeap::heap()->total_collections();
|
||||
int cur_collection = CMSHeap::heap()->total_collections();
|
||||
// Updated _last_LNC_resizing_collection[i] must not be visible before
|
||||
// _lowest_non_clean and friends are visible. Therefore use acquire/release
|
||||
// to guarantee this on non TSO architecures.
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/cms/cmsHeap.hpp"
|
||||
#include "gc/cms/compactibleFreeListSpace.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
|
||||
#include "gc/cms/parNewGeneration.inline.hpp"
|
||||
@ -45,6 +46,7 @@
|
||||
#include "gc/shared/spaceDecorator.hpp"
|
||||
#include "gc/shared/strongRootsScope.hpp"
|
||||
#include "gc/shared/taskqueue.inline.hpp"
|
||||
#include "gc/shared/weakProcessor.hpp"
|
||||
#include "gc/shared/workgroup.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
@ -124,7 +126,7 @@ bool ParScanThreadState::should_be_partially_scanned(oop new_obj, oop old_obj) c
|
||||
void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) {
|
||||
assert(old->is_objArray(), "must be obj array");
|
||||
assert(old->is_forwarded(), "must be forwarded");
|
||||
assert(GenCollectedHeap::heap()->is_in_reserved(old), "must be in heap.");
|
||||
assert(CMSHeap::heap()->is_in_reserved(old), "must be in heap.");
|
||||
assert(!old_gen()->is_in(old), "must be in young generation.");
|
||||
|
||||
objArrayOop obj = objArrayOop(old->forwardee());
|
||||
@ -205,9 +207,9 @@ bool ParScanThreadState::take_from_overflow_stack() {
|
||||
for (size_t i = 0; i != num_take_elems; i++) {
|
||||
oop cur = of_stack->pop();
|
||||
oop obj_to_push = cur->forwardee();
|
||||
assert(GenCollectedHeap::heap()->is_in_reserved(cur), "Should be in heap");
|
||||
assert(CMSHeap::heap()->is_in_reserved(cur), "Should be in heap");
|
||||
assert(!old_gen()->is_in_reserved(cur), "Should be in young gen");
|
||||
assert(GenCollectedHeap::heap()->is_in_reserved(obj_to_push), "Should be in heap");
|
||||
assert(CMSHeap::heap()->is_in_reserved(obj_to_push), "Should be in heap");
|
||||
if (should_be_partially_scanned(obj_to_push, cur)) {
|
||||
assert(arrayOop(cur)->length() == 0, "entire array remaining to be scanned");
|
||||
obj_to_push = cur;
|
||||
@ -590,7 +592,7 @@ ParNewGenTask::ParNewGenTask(ParNewGeneration* young_gen,
|
||||
{}
|
||||
|
||||
void ParNewGenTask::work(uint worker_id) {
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
// Since this is being done in a separate thread, need new resource
|
||||
// and handle marks.
|
||||
ResourceMark rm;
|
||||
@ -602,10 +604,10 @@ void ParNewGenTask::work(uint worker_id) {
|
||||
par_scan_state.set_young_old_boundary(_young_old_boundary);
|
||||
|
||||
CLDScanClosure cld_scan_closure(&par_scan_state.to_space_root_closure(),
|
||||
gch->rem_set()->cld_rem_set()->accumulate_modified_oops());
|
||||
heap->rem_set()->cld_rem_set()->accumulate_modified_oops());
|
||||
|
||||
par_scan_state.start_strong_roots();
|
||||
gch->young_process_roots(_strong_roots_scope,
|
||||
heap->young_process_roots(_strong_roots_scope,
|
||||
&par_scan_state.to_space_root_closure(),
|
||||
&par_scan_state.older_gen_closure(),
|
||||
&cld_scan_closure);
|
||||
@ -687,7 +689,7 @@ void /*ParNewGeneration::*/ParKeepAliveClosure::do_oop_work(T* p) {
|
||||
|
||||
_par_cl->do_oop_nv(p);
|
||||
|
||||
if (GenCollectedHeap::heap()->is_in_reserved(p)) {
|
||||
if (CMSHeap::heap()->is_in_reserved(p)) {
|
||||
oop obj = oopDesc::load_decode_heap_oop_not_null(p);
|
||||
_rs->write_ref_field_gc_par(p, obj);
|
||||
}
|
||||
@ -714,7 +716,7 @@ void /*ParNewGeneration::*/KeepAliveClosure::do_oop_work(T* p) {
|
||||
|
||||
_cl->do_oop_nv(p);
|
||||
|
||||
if (GenCollectedHeap::heap()->is_in_reserved(p)) {
|
||||
if (CMSHeap::heap()->is_in_reserved(p)) {
|
||||
oop obj = oopDesc::load_decode_heap_oop_not_null(p);
|
||||
_rs->write_ref_field_gc_par(p, obj);
|
||||
}
|
||||
@ -804,7 +806,7 @@ public:
|
||||
};
|
||||
|
||||
void ParNewRefProcTaskExecutor::execute(ProcessTask& task) {
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* gch = CMSHeap::heap();
|
||||
WorkGang* workers = gch->workers();
|
||||
assert(workers != NULL, "Need parallel worker threads.");
|
||||
_state_set.reset(workers->active_workers(), _young_gen.promotion_failed());
|
||||
@ -816,7 +818,7 @@ void ParNewRefProcTaskExecutor::execute(ProcessTask& task) {
|
||||
}
|
||||
|
||||
void ParNewRefProcTaskExecutor::execute(EnqueueTask& task) {
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* gch = CMSHeap::heap();
|
||||
WorkGang* workers = gch->workers();
|
||||
assert(workers != NULL, "Need parallel worker threads.");
|
||||
ParNewRefEnqueueTaskProxy enq_task(task);
|
||||
@ -825,8 +827,8 @@ void ParNewRefProcTaskExecutor::execute(EnqueueTask& task) {
|
||||
|
||||
void ParNewRefProcTaskExecutor::set_single_threaded_mode() {
|
||||
_state_set.flush();
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
gch->save_marks();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
heap->save_marks();
|
||||
}
|
||||
|
||||
ScanClosureWithParBarrier::
|
||||
@ -835,10 +837,10 @@ ScanClosureWithParBarrier(ParNewGeneration* g, bool gc_barrier) :
|
||||
{ }
|
||||
|
||||
EvacuateFollowersClosureGeneral::
|
||||
EvacuateFollowersClosureGeneral(GenCollectedHeap* gch,
|
||||
EvacuateFollowersClosureGeneral(CMSHeap* heap,
|
||||
OopsInGenClosure* cur,
|
||||
OopsInGenClosure* older) :
|
||||
_gch(gch),
|
||||
_heap(heap),
|
||||
_scan_cur_or_nonheap(cur), _scan_older(older)
|
||||
{ }
|
||||
|
||||
@ -846,15 +848,15 @@ void EvacuateFollowersClosureGeneral::do_void() {
|
||||
do {
|
||||
// Beware: this call will lead to closure applications via virtual
|
||||
// calls.
|
||||
_gch->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen,
|
||||
_scan_cur_or_nonheap,
|
||||
_scan_older);
|
||||
} while (!_gch->no_allocs_since_save_marks());
|
||||
_heap->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen,
|
||||
_scan_cur_or_nonheap,
|
||||
_scan_older);
|
||||
} while (!_heap->no_allocs_since_save_marks());
|
||||
}
|
||||
|
||||
// A Generation that does parallel young-gen collection.
|
||||
|
||||
void ParNewGeneration::handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set) {
|
||||
void ParNewGeneration::handle_promotion_failed(CMSHeap* gch, ParScanThreadStateSet& thread_state_set) {
|
||||
assert(_promo_failure_scan_stack.is_empty(), "post condition");
|
||||
_promo_failure_scan_stack.clear(true); // Clear cached segments.
|
||||
|
||||
@ -883,7 +885,7 @@ void ParNewGeneration::collect(bool full,
|
||||
bool is_tlab) {
|
||||
assert(full || size > 0, "otherwise we don't want to collect");
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* gch = CMSHeap::heap();
|
||||
|
||||
_gc_timer->register_gc_start();
|
||||
|
||||
@ -998,6 +1000,8 @@ void ParNewGeneration::collect(bool full,
|
||||
_gc_tracer.report_tenuring_threshold(tenuring_threshold());
|
||||
pt.print_all_references();
|
||||
|
||||
WeakProcessor::weak_oops_do(&is_alive, &keep_alive, &evacuate_followers);
|
||||
|
||||
if (!promotion_failed()) {
|
||||
// Swap the survivor spaces.
|
||||
eden()->clear(SpaceDecorator::Mangle);
|
||||
@ -1064,7 +1068,7 @@ void ParNewGeneration::collect(bool full,
|
||||
}
|
||||
|
||||
size_t ParNewGeneration::desired_plab_sz() {
|
||||
return _plab_stats.desired_plab_sz(GenCollectedHeap::heap()->workers()->active_workers());
|
||||
return _plab_stats.desired_plab_sz(CMSHeap::heap()->workers()->active_workers());
|
||||
}
|
||||
|
||||
static int sum;
|
||||
@ -1168,7 +1172,7 @@ oop ParNewGeneration::copy_to_survivor_space(ParScanThreadState* par_scan_state,
|
||||
} else {
|
||||
// Is in to-space; do copying ourselves.
|
||||
Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)new_obj, sz);
|
||||
assert(GenCollectedHeap::heap()->is_in_reserved(new_obj), "illegal forwarding pointer value.");
|
||||
assert(CMSHeap::heap()->is_in_reserved(new_obj), "illegal forwarding pointer value.");
|
||||
forward_ptr = old->forward_to_atomic(new_obj);
|
||||
// Restore the mark word copied above.
|
||||
new_obj->set_mark(m);
|
||||
@ -1296,7 +1300,7 @@ void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadSt
|
||||
from_space_obj->set_klass_to_list_ptr(NULL);
|
||||
}
|
||||
observed_overflow_list =
|
||||
(oop)Atomic::cmpxchg_ptr(from_space_obj, &_overflow_list, cur_overflow_list);
|
||||
Atomic::cmpxchg((oopDesc*)from_space_obj, &_overflow_list, (oopDesc*)cur_overflow_list);
|
||||
} while (cur_overflow_list != observed_overflow_list);
|
||||
}
|
||||
}
|
||||
@ -1339,7 +1343,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
|
||||
if (_overflow_list == NULL) return false;
|
||||
|
||||
// Otherwise, there was something there; try claiming the list.
|
||||
oop prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list));
|
||||
oop prefix = cast_to_oop(Atomic::xchg((oopDesc*)BUSY, &_overflow_list));
|
||||
// Trim off a prefix of at most objsFromOverflow items
|
||||
Thread* tid = Thread::current();
|
||||
size_t spin_count = ParallelGCThreads;
|
||||
@ -1353,7 +1357,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
|
||||
return false;
|
||||
} else if (_overflow_list != BUSY) {
|
||||
// try and grab the prefix
|
||||
prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list));
|
||||
prefix = cast_to_oop(Atomic::xchg((oopDesc*)BUSY, &_overflow_list));
|
||||
}
|
||||
}
|
||||
if (prefix == NULL || prefix == BUSY) {
|
||||
@ -1361,7 +1365,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
|
||||
if (prefix == NULL) {
|
||||
// Write back the NULL in case we overwrote it with BUSY above
|
||||
// and it is still the same value.
|
||||
(void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
|
||||
(void) Atomic::cmpxchg((oopDesc*)NULL, &_overflow_list, (oopDesc*)BUSY);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1380,7 +1384,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
|
||||
// Write back the NULL in lieu of the BUSY we wrote
|
||||
// above and it is still the same value.
|
||||
if (_overflow_list == BUSY) {
|
||||
(void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
|
||||
(void) Atomic::cmpxchg((oopDesc*)NULL, &_overflow_list, (oopDesc*)BUSY);
|
||||
}
|
||||
} else {
|
||||
assert(suffix != BUSY, "Error");
|
||||
@ -1394,7 +1398,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
|
||||
bool attached = false;
|
||||
while (observed_overflow_list == BUSY || observed_overflow_list == NULL) {
|
||||
observed_overflow_list =
|
||||
(oop) Atomic::cmpxchg_ptr(suffix, &_overflow_list, cur_overflow_list);
|
||||
Atomic::cmpxchg((oopDesc*)suffix, &_overflow_list, (oopDesc*)cur_overflow_list);
|
||||
if (cur_overflow_list == observed_overflow_list) {
|
||||
attached = true;
|
||||
break;
|
||||
@ -1420,7 +1424,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
|
||||
last->set_klass_to_list_ptr(NULL);
|
||||
}
|
||||
observed_overflow_list =
|
||||
(oop)Atomic::cmpxchg_ptr(suffix, &_overflow_list, cur_overflow_list);
|
||||
Atomic::cmpxchg((oopDesc*)suffix, &_overflow_list, (oopDesc*)cur_overflow_list);
|
||||
} while (cur_overflow_list != observed_overflow_list);
|
||||
}
|
||||
}
|
||||
@ -1452,7 +1456,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
|
||||
TASKQUEUE_STATS_ONLY(par_scan_state->note_overflow_refill(n));
|
||||
#ifndef PRODUCT
|
||||
assert(_num_par_pushes >= n, "Too many pops?");
|
||||
Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes);
|
||||
Atomic::sub(n, &_num_par_pushes);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@ -1475,3 +1479,9 @@ void ParNewGeneration::ref_processor_init() {
|
||||
const char* ParNewGeneration::name() const {
|
||||
return "par new generation";
|
||||
}
|
||||
|
||||
void ParNewGeneration::restore_preserved_marks() {
|
||||
SharedRestorePreservedMarksTaskExecutor task_executor(CMSHeap::heap()->workers());
|
||||
_preserved_marks_set.restore(&task_executor);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -35,6 +35,7 @@
|
||||
#include "memory/padded.hpp"
|
||||
|
||||
class ChunkArray;
|
||||
class CMSHeap;
|
||||
class ParScanWithoutBarrierClosure;
|
||||
class ParScanWithBarrierClosure;
|
||||
class ParRootScanWithoutBarrierClosure;
|
||||
@ -259,11 +260,11 @@ class KeepAliveClosure: public DefNewGeneration::KeepAliveClosure {
|
||||
|
||||
class EvacuateFollowersClosureGeneral: public VoidClosure {
|
||||
private:
|
||||
GenCollectedHeap* _gch;
|
||||
CMSHeap* _heap;
|
||||
OopsInGenClosure* _scan_cur_or_nonheap;
|
||||
OopsInGenClosure* _scan_older;
|
||||
public:
|
||||
EvacuateFollowersClosureGeneral(GenCollectedHeap* gch,
|
||||
EvacuateFollowersClosureGeneral(CMSHeap* heap,
|
||||
OopsInGenClosure* cur,
|
||||
OopsInGenClosure* older);
|
||||
virtual void do_void();
|
||||
@ -336,7 +337,7 @@ class ParNewGeneration: public DefNewGeneration {
|
||||
static oop real_forwardee_slow(oop obj);
|
||||
static void waste_some_time();
|
||||
|
||||
void handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set);
|
||||
void handle_promotion_failed(CMSHeap* gch, ParScanThreadStateSet& thread_state_set);
|
||||
|
||||
protected:
|
||||
|
||||
@ -345,6 +346,8 @@ class ParNewGeneration: public DefNewGeneration {
|
||||
bool survivor_overflow() { return _survivor_overflow; }
|
||||
void set_survivor_overflow(bool v) { _survivor_overflow = v; }
|
||||
|
||||
void restore_preserved_marks();
|
||||
|
||||
public:
|
||||
ParNewGeneration(ReservedSpace rs, size_t initial_byte_size);
|
||||
|
||||
|
@ -25,10 +25,10 @@
|
||||
#ifndef SHARE_VM_GC_CMS_PAROOPCLOSURES_INLINE_HPP
|
||||
#define SHARE_VM_GC_CMS_PAROOPCLOSURES_INLINE_HPP
|
||||
|
||||
#include "gc/cms/cmsHeap.hpp"
|
||||
#include "gc/cms/parNewGeneration.hpp"
|
||||
#include "gc/cms/parOopClosures.hpp"
|
||||
#include "gc/shared/cardTableRS.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
@ -72,9 +72,9 @@ template <class T>
|
||||
inline void ParScanClosure::do_oop_work(T* p,
|
||||
bool gc_barrier,
|
||||
bool root_scan) {
|
||||
assert((!GenCollectedHeap::heap()->is_in_reserved(p) ||
|
||||
assert((!CMSHeap::heap()->is_in_reserved(p) ||
|
||||
generation()->is_in_reserved(p))
|
||||
&& (GenCollectedHeap::heap()->is_young_gen(generation()) || gc_barrier),
|
||||
&& (CMSHeap::heap()->is_young_gen(generation()) || gc_barrier),
|
||||
"The gen must be right, and we must be doing the barrier "
|
||||
"in older generations.");
|
||||
T heap_oop = oopDesc::load_heap_oop(p);
|
||||
@ -85,8 +85,8 @@ inline void ParScanClosure::do_oop_work(T* p,
|
||||
if (_g->to()->is_in_reserved(obj)) {
|
||||
Log(gc) log;
|
||||
log.error("Scanning field (" PTR_FORMAT ") twice?", p2i(p));
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
Space* sp = gch->space_containing(p);
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
Space* sp = heap->space_containing(p);
|
||||
oop obj = oop(sp->block_start(p));
|
||||
assert((HeapWord*)obj < (HeapWord*)p, "Error");
|
||||
log.error("Object: " PTR_FORMAT, p2i((void *)obj));
|
||||
@ -96,7 +96,7 @@ inline void ParScanClosure::do_oop_work(T* p,
|
||||
log.error("-----");
|
||||
log.error("Heap:");
|
||||
log.error("-----");
|
||||
gch->print_on(&ls);
|
||||
heap->print_on(&ls);
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/cms/cmsHeap.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepThread.hpp"
|
||||
#include "gc/cms/vmCMSOperations.hpp"
|
||||
@ -39,19 +40,19 @@
|
||||
//////////////////////////////////////////////////////////
|
||||
void VM_CMS_Operation::verify_before_gc() {
|
||||
if (VerifyBeforeGC &&
|
||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
CMSHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
GCTraceTime(Info, gc, phases, verify) tm("Verify Before", _collector->_gc_timer_cm);
|
||||
HandleMark hm;
|
||||
FreelistLocker x(_collector);
|
||||
MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
|
||||
GenCollectedHeap::heap()->prepare_for_verify();
|
||||
CMSHeap::heap()->prepare_for_verify();
|
||||
Universe::verify();
|
||||
}
|
||||
}
|
||||
|
||||
void VM_CMS_Operation::verify_after_gc() {
|
||||
if (VerifyAfterGC &&
|
||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
CMSHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
GCTraceTime(Info, gc, phases, verify) tm("Verify After", _collector->_gc_timer_cm);
|
||||
HandleMark hm;
|
||||
FreelistLocker x(_collector);
|
||||
@ -112,13 +113,13 @@ void VM_CMS_Initial_Mark::doit() {
|
||||
|
||||
_collector->_gc_timer_cm->register_gc_pause_start("Initial Mark");
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
GCCauseSetter gccs(gch, GCCause::_cms_initial_mark);
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
GCCauseSetter gccs(heap, GCCause::_cms_initial_mark);
|
||||
|
||||
VM_CMS_Operation::verify_before_gc();
|
||||
|
||||
IsGCActiveMark x; // stop-world GC active
|
||||
_collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsInitial, gch->gc_cause());
|
||||
_collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsInitial, heap->gc_cause());
|
||||
|
||||
VM_CMS_Operation::verify_after_gc();
|
||||
|
||||
@ -140,13 +141,13 @@ void VM_CMS_Final_Remark::doit() {
|
||||
|
||||
_collector->_gc_timer_cm->register_gc_pause_start("Final Mark");
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
GCCauseSetter gccs(gch, GCCause::_cms_final_remark);
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
GCCauseSetter gccs(heap, GCCause::_cms_final_remark);
|
||||
|
||||
VM_CMS_Operation::verify_before_gc();
|
||||
|
||||
IsGCActiveMark x; // stop-world GC active
|
||||
_collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsFinal, gch->gc_cause());
|
||||
_collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsFinal, heap->gc_cause());
|
||||
|
||||
VM_CMS_Operation::verify_after_gc();
|
||||
|
||||
@ -162,8 +163,8 @@ void VM_GenCollectFullConcurrent::doit() {
|
||||
assert(Thread::current()->is_VM_thread(), "Should be VM thread");
|
||||
assert(GCLockerInvokesConcurrent || ExplicitGCInvokesConcurrent, "Unexpected");
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
if (_gc_count_before == gch->total_collections()) {
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
if (_gc_count_before == heap->total_collections()) {
|
||||
// The "full" of do_full_collection call below "forces"
|
||||
// a collection; the second arg, 0, below ensures that
|
||||
// only the young gen is collected. XXX In the future,
|
||||
@ -173,21 +174,21 @@ void VM_GenCollectFullConcurrent::doit() {
|
||||
// for the future.
|
||||
assert(SafepointSynchronize::is_at_safepoint(),
|
||||
"We can only be executing this arm of if at a safepoint");
|
||||
GCCauseSetter gccs(gch, _gc_cause);
|
||||
gch->do_full_collection(gch->must_clear_all_soft_refs(), GenCollectedHeap::YoungGen);
|
||||
GCCauseSetter gccs(heap, _gc_cause);
|
||||
heap->do_full_collection(heap->must_clear_all_soft_refs(), GenCollectedHeap::YoungGen);
|
||||
} // Else no need for a foreground young gc
|
||||
assert((_gc_count_before < gch->total_collections()) ||
|
||||
assert((_gc_count_before < heap->total_collections()) ||
|
||||
(GCLocker::is_active() /* gc may have been skipped */
|
||||
&& (_gc_count_before == gch->total_collections())),
|
||||
&& (_gc_count_before == heap->total_collections())),
|
||||
"total_collections() should be monotonically increasing");
|
||||
|
||||
MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag);
|
||||
assert(_full_gc_count_before <= gch->total_full_collections(), "Error");
|
||||
if (gch->total_full_collections() == _full_gc_count_before) {
|
||||
assert(_full_gc_count_before <= heap->total_full_collections(), "Error");
|
||||
if (heap->total_full_collections() == _full_gc_count_before) {
|
||||
// Nudge the CMS thread to start a concurrent collection.
|
||||
CMSCollector::request_full_gc(_full_gc_count_before, _gc_cause);
|
||||
} else {
|
||||
assert(_full_gc_count_before < gch->total_full_collections(), "Error");
|
||||
assert(_full_gc_count_before < heap->total_full_collections(), "Error");
|
||||
FullGCCount_lock->notify_all(); // Inform the Java thread its work is done
|
||||
}
|
||||
}
|
||||
@ -197,11 +198,11 @@ bool VM_GenCollectFullConcurrent::evaluate_at_safepoint() const {
|
||||
assert(thr != NULL, "Unexpected tid");
|
||||
if (!thr->is_Java_thread()) {
|
||||
assert(thr->is_VM_thread(), "Expected to be evaluated by VM thread");
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
if (_gc_count_before != gch->total_collections()) {
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
if (_gc_count_before != heap->total_collections()) {
|
||||
// No need to do a young gc, we'll just nudge the CMS thread
|
||||
// in the doit() method above, to be executed soon.
|
||||
assert(_gc_count_before < gch->total_collections(),
|
||||
assert(_gc_count_before < heap->total_collections(),
|
||||
"total_collections() should be monotonically increasing");
|
||||
return false; // no need for foreground young gc
|
||||
}
|
||||
@ -227,9 +228,9 @@ void VM_GenCollectFullConcurrent::doit_epilogue() {
|
||||
// count overflows and wraps around. XXX fix me !!!
|
||||
// e.g. at the rate of 1 full gc per ms, this could
|
||||
// overflow in about 1000 years.
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
CMSHeap* heap = CMSHeap::heap();
|
||||
if (_gc_cause != GCCause::_gc_locker &&
|
||||
gch->total_full_collections_completed() <= _full_gc_count_before) {
|
||||
heap->total_full_collections_completed() <= _full_gc_count_before) {
|
||||
// maybe we should change the condition to test _gc_cause ==
|
||||
// GCCause::_java_lang_system_gc or GCCause::_dcmd_gc_run,
|
||||
// instead of _gc_cause != GCCause::_gc_locker
|
||||
@ -245,7 +246,7 @@ void VM_GenCollectFullConcurrent::doit_epilogue() {
|
||||
MutexLockerEx ml(FullGCCount_lock, Mutex::_no_safepoint_check_flag);
|
||||
// Either a concurrent or a stop-world full gc is sufficient
|
||||
// witness to our request.
|
||||
while (gch->total_full_collections_completed() <= _full_gc_count_before) {
|
||||
while (heap->total_full_collections_completed() <= _full_gc_count_before) {
|
||||
FullGCCount_lock->wait(Mutex::_no_safepoint_check_flag);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,7 +27,7 @@
|
||||
#include "gc/g1/concurrentG1RefineThread.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1RemSet.hpp"
|
||||
#include "gc/g1/suspendibleThreadSet.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
|
@ -30,12 +30,12 @@
|
||||
#include "gc/g1/g1ConcurrentMark.inline.hpp"
|
||||
#include "gc/g1/g1MMUTracker.hpp"
|
||||
#include "gc/g1/g1Policy.hpp"
|
||||
#include "gc/g1/suspendibleThreadSet.hpp"
|
||||
#include "gc/g1/vm_operations_g1.hpp"
|
||||
#include "gc/shared/concurrentGCPhaseManager.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "gc/shared/gcTrace.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
|
@ -280,13 +280,13 @@ void DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(CardTableEntr
|
||||
BufferNode* nd = _cur_par_buffer_node;
|
||||
while (nd != NULL) {
|
||||
BufferNode* next = nd->next();
|
||||
void* actual = Atomic::cmpxchg_ptr(next, &_cur_par_buffer_node, nd);
|
||||
BufferNode* actual = Atomic::cmpxchg(next, &_cur_par_buffer_node, nd);
|
||||
if (actual == nd) {
|
||||
bool b = apply_closure_to_buffer(cl, nd, false);
|
||||
guarantee(b, "Should not stop early.");
|
||||
nd = next;
|
||||
} else {
|
||||
nd = static_cast<BufferNode*>(actual);
|
||||
nd = actual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1ConcurrentMark.inline.hpp"
|
||||
#include "gc/g1/g1CardLiveData.inline.hpp"
|
||||
#include "gc/g1/suspendibleThreadSet.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "gc/shared/workgroup.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -155,19 +155,19 @@ G1CodeRootSet::~G1CodeRootSet() {
|
||||
}
|
||||
|
||||
G1CodeRootSetTable* G1CodeRootSet::load_acquire_table() {
|
||||
return (G1CodeRootSetTable*) OrderAccess::load_ptr_acquire(&_table);
|
||||
return OrderAccess::load_acquire(&_table);
|
||||
}
|
||||
|
||||
void G1CodeRootSet::allocate_small_table() {
|
||||
G1CodeRootSetTable* temp = new G1CodeRootSetTable(SmallSize);
|
||||
|
||||
OrderAccess::release_store_ptr(&_table, temp);
|
||||
OrderAccess::release_store(&_table, temp);
|
||||
}
|
||||
|
||||
void G1CodeRootSetTable::purge_list_append(G1CodeRootSetTable* table) {
|
||||
for (;;) {
|
||||
table->_purge_next = _purge_list;
|
||||
G1CodeRootSetTable* old = (G1CodeRootSetTable*) Atomic::cmpxchg_ptr(table, &_purge_list, table->_purge_next);
|
||||
G1CodeRootSetTable* old = Atomic::cmpxchg(table, &_purge_list, table->_purge_next);
|
||||
if (old == table->_purge_next) {
|
||||
break;
|
||||
}
|
||||
@ -191,7 +191,7 @@ void G1CodeRootSet::move_to_large() {
|
||||
|
||||
G1CodeRootSetTable::purge_list_append(_table);
|
||||
|
||||
OrderAccess::release_store_ptr(&_table, temp);
|
||||
OrderAccess::release_store(&_table, temp);
|
||||
}
|
||||
|
||||
void G1CodeRootSet::purge() {
|
||||
|
@ -57,7 +57,6 @@
|
||||
#include "gc/g1/heapRegion.inline.hpp"
|
||||
#include "gc/g1/heapRegionRemSet.hpp"
|
||||
#include "gc/g1/heapRegionSet.inline.hpp"
|
||||
#include "gc/g1/suspendibleThreadSet.hpp"
|
||||
#include "gc/g1/vm_operations_g1.hpp"
|
||||
#include "gc/shared/gcHeapSummary.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
@ -68,8 +67,10 @@
|
||||
#include "gc/shared/generationSpec.hpp"
|
||||
#include "gc/shared/isGCActiveMark.hpp"
|
||||
#include "gc/shared/preservedMarks.inline.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "gc/shared/referenceProcessor.inline.hpp"
|
||||
#include "gc/shared/taskqueue.inline.hpp"
|
||||
#include "gc/shared/weakProcessor.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
@ -141,13 +142,6 @@ void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_region
|
||||
reset_from_card_cache(start_idx, num_regions);
|
||||
}
|
||||
|
||||
// Returns true if the reference points to an object that
|
||||
// can move in an incremental collection.
|
||||
bool G1CollectedHeap::is_scavengable(const void* p) {
|
||||
HeapRegion* hr = heap_region_containing(p);
|
||||
return !hr->is_pinned();
|
||||
}
|
||||
|
||||
// Private methods.
|
||||
|
||||
HeapRegion*
|
||||
@ -1849,6 +1843,14 @@ void G1CollectedHeap::stop() {
|
||||
}
|
||||
}
|
||||
|
||||
void G1CollectedHeap::safepoint_synchronize_begin() {
|
||||
SuspendibleThreadSet::synchronize();
|
||||
}
|
||||
|
||||
void G1CollectedHeap::safepoint_synchronize_end() {
|
||||
SuspendibleThreadSet::desynchronize();
|
||||
}
|
||||
|
||||
size_t G1CollectedHeap::conservative_max_heap_alignment() {
|
||||
return HeapRegion::max_region_size();
|
||||
}
|
||||
@ -3458,10 +3460,10 @@ private:
|
||||
|
||||
// Variables used to claim nmethods.
|
||||
CompiledMethod* _first_nmethod;
|
||||
volatile CompiledMethod* _claimed_nmethod;
|
||||
CompiledMethod* volatile _claimed_nmethod;
|
||||
|
||||
// The list of nmethods that need to be processed by the second pass.
|
||||
volatile CompiledMethod* _postponed_list;
|
||||
CompiledMethod* volatile _postponed_list;
|
||||
volatile uint _num_entered_barrier;
|
||||
|
||||
public:
|
||||
@ -3480,7 +3482,7 @@ private:
|
||||
if(iter.next_alive()) {
|
||||
_first_nmethod = iter.method();
|
||||
}
|
||||
_claimed_nmethod = (volatile CompiledMethod*)_first_nmethod;
|
||||
_claimed_nmethod = _first_nmethod;
|
||||
}
|
||||
|
||||
~G1CodeCacheUnloadingTask() {
|
||||
@ -3496,9 +3498,9 @@ private:
|
||||
void add_to_postponed_list(CompiledMethod* nm) {
|
||||
CompiledMethod* old;
|
||||
do {
|
||||
old = (CompiledMethod*)_postponed_list;
|
||||
old = _postponed_list;
|
||||
nm->set_unloading_next(old);
|
||||
} while ((CompiledMethod*)Atomic::cmpxchg_ptr(nm, &_postponed_list, old) != old);
|
||||
} while (Atomic::cmpxchg(nm, &_postponed_list, old) != old);
|
||||
}
|
||||
|
||||
void clean_nmethod(CompiledMethod* nm) {
|
||||
@ -3527,7 +3529,7 @@ private:
|
||||
do {
|
||||
*num_claimed_nmethods = 0;
|
||||
|
||||
first = (CompiledMethod*)_claimed_nmethod;
|
||||
first = _claimed_nmethod;
|
||||
last = CompiledMethodIterator(first);
|
||||
|
||||
if (first != NULL) {
|
||||
@ -3541,7 +3543,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
} while ((CompiledMethod*)Atomic::cmpxchg_ptr(last.method(), &_claimed_nmethod, first) != first);
|
||||
} while (Atomic::cmpxchg(last.method(), &_claimed_nmethod, first) != first);
|
||||
}
|
||||
|
||||
CompiledMethod* claim_postponed_nmethod() {
|
||||
@ -3549,14 +3551,14 @@ private:
|
||||
CompiledMethod* next;
|
||||
|
||||
do {
|
||||
claim = (CompiledMethod*)_postponed_list;
|
||||
claim = _postponed_list;
|
||||
if (claim == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
next = claim->unloading_next();
|
||||
|
||||
} while ((CompiledMethod*)Atomic::cmpxchg_ptr(next, &_postponed_list, claim) != claim);
|
||||
} while (Atomic::cmpxchg(next, &_postponed_list, claim) != claim);
|
||||
|
||||
return claim;
|
||||
}
|
||||
@ -4127,17 +4129,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void G1CollectedHeap::process_weak_jni_handles() {
|
||||
double ref_proc_start = os::elapsedTime();
|
||||
|
||||
G1STWIsAliveClosure is_alive(this);
|
||||
G1KeepAliveClosure keep_alive(this);
|
||||
JNIHandles::weak_oops_do(&is_alive, &keep_alive);
|
||||
|
||||
double ref_proc_time = os::elapsedTime() - ref_proc_start;
|
||||
g1_policy()->phase_times()->record_ref_proc_time(ref_proc_time * 1000.0);
|
||||
}
|
||||
|
||||
void G1CollectedHeap::preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states) {
|
||||
// Any reference objects, in the collection set, that were 'discovered'
|
||||
// by the CM ref processor should have already been copied (either by
|
||||
@ -4368,14 +4359,23 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in
|
||||
process_discovered_references(per_thread_states);
|
||||
} else {
|
||||
ref_processor_stw()->verify_no_references_recorded();
|
||||
process_weak_jni_handles();
|
||||
}
|
||||
|
||||
G1STWIsAliveClosure is_alive(this);
|
||||
G1KeepAliveClosure keep_alive(this);
|
||||
|
||||
{
|
||||
double start = os::elapsedTime();
|
||||
|
||||
WeakProcessor::weak_oops_do(&is_alive, &keep_alive);
|
||||
|
||||
double time_ms = (os::elapsedTime() - start) * 1000.0;
|
||||
g1_policy()->phase_times()->record_ref_proc_time(time_ms);
|
||||
}
|
||||
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
double fixup_start = os::elapsedTime();
|
||||
|
||||
G1STWIsAliveClosure is_alive(this);
|
||||
G1KeepAliveClosure keep_alive(this);
|
||||
G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive, true, g1_policy()->phase_times());
|
||||
|
||||
double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0;
|
||||
@ -5323,17 +5323,20 @@ public:
|
||||
void do_oop(narrowOop* p) { do_oop_work(p); }
|
||||
};
|
||||
|
||||
void G1CollectedHeap::register_nmethod(nmethod* nm) {
|
||||
CollectedHeap::register_nmethod(nm);
|
||||
// Returns true if the reference points to an object that
|
||||
// can move in an incremental collection.
|
||||
bool G1CollectedHeap::is_scavengable(oop obj) {
|
||||
HeapRegion* hr = heap_region_containing(obj);
|
||||
return !hr->is_pinned();
|
||||
}
|
||||
|
||||
void G1CollectedHeap::register_nmethod(nmethod* nm) {
|
||||
guarantee(nm != NULL, "sanity");
|
||||
RegisterNMethodOopClosure reg_cl(this, nm);
|
||||
nm->oops_do(®_cl);
|
||||
}
|
||||
|
||||
void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
|
||||
CollectedHeap::unregister_nmethod(nm);
|
||||
|
||||
guarantee(nm != NULL, "sanity");
|
||||
UnregisterNMethodOopClosure reg_cl(this, nm);
|
||||
nm->oops_do(®_cl, true);
|
||||
|
@ -303,8 +303,6 @@ private:
|
||||
|
||||
void trace_heap(GCWhen::Type when, const GCTracer* tracer);
|
||||
|
||||
void process_weak_jni_handles();
|
||||
|
||||
// These are macros so that, if the assert fires, we get the correct
|
||||
// line number, file, etc.
|
||||
|
||||
@ -968,6 +966,8 @@ public:
|
||||
jint initialize();
|
||||
|
||||
virtual void stop();
|
||||
virtual void safepoint_synchronize_begin();
|
||||
virtual void safepoint_synchronize_end();
|
||||
|
||||
// Return the (conservative) maximum heap alignment for any G1 heap
|
||||
static size_t conservative_max_heap_alignment();
|
||||
@ -1282,8 +1282,6 @@ public:
|
||||
|
||||
inline bool is_in_young(const oop obj);
|
||||
|
||||
virtual bool is_scavengable(const void* addr);
|
||||
|
||||
// We don't need barriers for initializing stores to objects
|
||||
// in the young gen: for the SATB pre-barrier, there is no
|
||||
// pre-value that needs to be remembered; for the remembered-set
|
||||
@ -1395,6 +1393,9 @@ public:
|
||||
|
||||
// Optimized nmethod scanning support routines
|
||||
|
||||
// Is an oop scavengeable
|
||||
virtual bool is_scavengable(oop obj);
|
||||
|
||||
// Register the given nmethod with the G1 heap.
|
||||
virtual void register_nmethod(nmethod* nm);
|
||||
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "gc/g1/heapRegion.inline.hpp"
|
||||
#include "gc/g1/heapRegionRemSet.hpp"
|
||||
#include "gc/g1/heapRegionSet.inline.hpp"
|
||||
#include "gc/g1/suspendibleThreadSet.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "gc/shared/gcTimer.hpp"
|
||||
#include "gc/shared/gcTrace.hpp"
|
||||
@ -46,8 +45,10 @@
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "gc/shared/referencePolicy.hpp"
|
||||
#include "gc/shared/strongRootsScope.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "gc/shared/taskqueue.inline.hpp"
|
||||
#include "gc/shared/vmGCOperations.hpp"
|
||||
#include "gc/shared/weakProcessor.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@ -1603,6 +1604,23 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
|
||||
// Is alive closure.
|
||||
G1CMIsAliveClosure g1_is_alive(g1h);
|
||||
|
||||
// Instances of the 'Keep Alive' and 'Complete GC' closures used
|
||||
// in serial reference processing. Note these closures are also
|
||||
// used for serially processing (by the the current thread) the
|
||||
// JNI references during parallel reference processing.
|
||||
//
|
||||
// These closures do not need to synchronize with the worker
|
||||
// threads involved in parallel reference processing as these
|
||||
// instances are executed serially by the current thread (e.g.
|
||||
// reference processing is not multi-threaded and is thus
|
||||
// performed by the current thread instead of a gang worker).
|
||||
//
|
||||
// The gang tasks involved in parallel reference processing create
|
||||
// their own instances of these closures, which do their own
|
||||
// synchronization among themselves.
|
||||
G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0), true /* is_serial */);
|
||||
G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), true /* is_serial */);
|
||||
|
||||
// Inner scope to exclude the cleaning of the string and symbol
|
||||
// tables from the displayed time.
|
||||
{
|
||||
@ -1617,23 +1635,6 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
|
||||
rp->setup_policy(clear_all_soft_refs);
|
||||
assert(_global_mark_stack.is_empty(), "mark stack should be empty");
|
||||
|
||||
// Instances of the 'Keep Alive' and 'Complete GC' closures used
|
||||
// in serial reference processing. Note these closures are also
|
||||
// used for serially processing (by the the current thread) the
|
||||
// JNI references during parallel reference processing.
|
||||
//
|
||||
// These closures do not need to synchronize with the worker
|
||||
// threads involved in parallel reference processing as these
|
||||
// instances are executed serially by the current thread (e.g.
|
||||
// reference processing is not multi-threaded and is thus
|
||||
// performed by the current thread instead of a gang worker).
|
||||
//
|
||||
// The gang tasks involved in parallel reference processing create
|
||||
// their own instances of these closures, which do their own
|
||||
// synchronization among themselves.
|
||||
G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0), true /* is_serial */);
|
||||
G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), true /* is_serial */);
|
||||
|
||||
// We need at least one active thread. If reference processing
|
||||
// is not multi-threaded we use the current (VMThread) thread,
|
||||
// otherwise we use the work gang from the G1CollectedHeap and
|
||||
@ -1687,6 +1688,11 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
|
||||
assert(!rp->discovery_enabled(), "Post condition");
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) debug("Weak Processing", _gc_timer_cm);
|
||||
WeakProcessor::weak_oops_do(&g1_is_alive, &g1_keep_alive, &g1_drain_mark_stack);
|
||||
}
|
||||
|
||||
if (has_overflown()) {
|
||||
// We can not trust g1_is_alive if the marking stack overflowed
|
||||
return;
|
||||
@ -1870,7 +1876,7 @@ G1ConcurrentMark::claim_region(uint worker_id) {
|
||||
HeapWord* end = curr_region != NULL ? curr_region->end() : finger + HeapRegion::GrainWords;
|
||||
|
||||
// Is the gap between reading the finger and doing the CAS too long?
|
||||
HeapWord* res = (HeapWord*) Atomic::cmpxchg_ptr(end, &_finger, finger);
|
||||
HeapWord* res = Atomic::cmpxchg(end, &_finger, finger);
|
||||
if (res == finger && curr_region != NULL) {
|
||||
// we succeeded
|
||||
HeapWord* bottom = curr_region->bottom();
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "gc/g1/g1ConcurrentMark.hpp"
|
||||
#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp"
|
||||
#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp"
|
||||
#include "gc/g1/suspendibleThreadSet.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "gc/shared/taskqueue.inline.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,17 +29,17 @@
|
||||
#include "runtime/atomic.hpp"
|
||||
|
||||
inline void G1EvacStats::add_direct_allocated(size_t value) {
|
||||
Atomic::add_ptr(value, &_direct_allocated);
|
||||
Atomic::add(value, &_direct_allocated);
|
||||
}
|
||||
|
||||
inline void G1EvacStats::add_region_end_waste(size_t value) {
|
||||
Atomic::add_ptr(value, &_region_end_waste);
|
||||
Atomic::add_ptr(1, &_regions_filled);
|
||||
Atomic::add(value, &_region_end_waste);
|
||||
Atomic::inc(&_regions_filled);
|
||||
}
|
||||
|
||||
inline void G1EvacStats::add_failure_used_and_waste(size_t used, size_t waste) {
|
||||
Atomic::add_ptr(used, &_failure_used);
|
||||
Atomic::add_ptr(waste, &_failure_waste);
|
||||
Atomic::add(used, &_failure_used);
|
||||
Atomic::add(waste, &_failure_waste);
|
||||
}
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1EVACSTATS_INLINE_HPP
|
||||
|
@ -74,9 +74,9 @@ jbyte* G1HotCardCache::insert(jbyte* card_ptr) {
|
||||
// card_ptr in favor of the other option, which would be starting over. This
|
||||
// should be OK since card_ptr will likely be the older card already when/if
|
||||
// this ever happens.
|
||||
jbyte* previous_ptr = (jbyte*)Atomic::cmpxchg_ptr(card_ptr,
|
||||
&_hot_cache[masked_index],
|
||||
current_ptr);
|
||||
jbyte* previous_ptr = Atomic::cmpxchg(card_ptr,
|
||||
&_hot_cache[masked_index],
|
||||
current_ptr);
|
||||
return (previous_ptr == current_ptr) ? previous_ptr : card_ptr;
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,6 @@
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
#define _DISABLE_MMU 0
|
||||
|
||||
// can't rely on comparing doubles with tolerating a small margin for error
|
||||
#define SMALL_MARGIN 0.0000001
|
||||
#define is_double_leq_0(_value) ( (_value) < SMALL_MARGIN )
|
||||
@ -119,9 +117,6 @@ void G1MMUTrackerQueue::add_pause(double start, double end) {
|
||||
// of other places (debugging)
|
||||
|
||||
double G1MMUTrackerQueue::when_sec(double current_time, double pause_time) {
|
||||
if (_DISABLE_MMU)
|
||||
return 0.0;
|
||||
|
||||
MutexLockerEx x(MMUTracker_lock, Mutex::_no_safepoint_check_flag);
|
||||
remove_expired_entries(current_time);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user