Merge
This commit is contained in:
commit
1b6f4c4ddc
2
.hgtags
2
.hgtags
@ -456,3 +456,5 @@ b87d7b5d5dedc1185e5929470f945b7378cdb3ad jdk-10+27
|
||||
a6e591e12f122768f675428e1e5a838fd0e9c7ec jdk-10+29
|
||||
8fee80b92e65149f7414250fd5e34b6f35d417b4 jdk-10+30
|
||||
e6278add9ff28fab70fe1cc4c1d65f7363dc9445 jdk-10+31
|
||||
a2008587c13fa05fa2dbfcb09fe987576fbedfd1 jdk-10+32
|
||||
bbd692ad4fa300ecca7939ffbe3b1d5e52a28cc6 jdk-10+33
|
||||
|
@ -871,9 +871,9 @@ test-support/</code></pre>
|
||||
<p>When building for distribution, <code>zipped</code> is a good solution. Binaries built with <code>internal</code> is suitable for use by developers, since they facilitate debugging, but should be stripped before distributed to end users.</p>
|
||||
<h3 id="autoconf-details">Autoconf Details</h3>
|
||||
<p>The <code>configure</code> script is based on the autoconf framework, but in some details deviate from a normal autoconf <code>configure</code> script.</p>
|
||||
<p>The <code>configure</code> script in the top level directory of OpenJDK is just a thin wrapper that calls <code>common/autoconf/configure</code>. This in turn provides functionality that is not easily expressed in the normal Autoconf framework, and then calls into the core of the <code>configure</code> script, which is the <code>common/autoconf/generated-configure.sh</code> file.</p>
|
||||
<p>The <code>configure</code> script in the top level directory of OpenJDK is just a thin wrapper that calls <code>make/autoconf/configure</code>. This in turn provides functionality that is not easily expressed in the normal Autoconf framework, and then calls into the core of the <code>configure</code> script, which is the <code>make/autoconf/generated-configure.sh</code> file.</p>
|
||||
<p>As the name implies, this file is generated by Autoconf. It is checked in after regeneration, to alleviate the common user to have to install Autoconf.</p>
|
||||
<p>The build system will detect if the Autoconf source files have changed, and will trigger a regeneration of <code>common/autoconf/generated-configure.sh</code> if needed. You can also manually request such an update by <code>bash common/autoconf/autogen.sh</code>.</p>
|
||||
<p>The build system will detect if the Autoconf source files have changed, and will trigger a regeneration of <code>make/autoconf/generated-configure.sh</code> if needed. You can also manually request such an update by <code>bash make/autoconf/autogen.sh</code>.</p>
|
||||
<p>If you make changes to the build system that requires a re-generation, note the following:</p>
|
||||
<ul>
|
||||
<li><p>You must use <em>exactly</em> version 2.69 of autoconf for your patch to be accepted. This is to avoid spurious changes in the generated file. Note that Ubuntu 16.04 ships a patched version of autoconf which claims to be 2.69, but is not.</p></li>
|
||||
|
@ -1660,18 +1660,18 @@ The `configure` script is based on the autoconf framework, but in some details
|
||||
deviate from a normal autoconf `configure` script.
|
||||
|
||||
The `configure` script in the top level directory of OpenJDK is just a thin
|
||||
wrapper that calls `common/autoconf/configure`. This in turn provides
|
||||
wrapper that calls `make/autoconf/configure`. This in turn provides
|
||||
functionality that is not easily expressed in the normal Autoconf framework,
|
||||
and then calls into the core of the `configure` script, which is the
|
||||
`common/autoconf/generated-configure.sh` file.
|
||||
`make/autoconf/generated-configure.sh` file.
|
||||
|
||||
As the name implies, this file is generated by Autoconf. It is checked in after
|
||||
regeneration, to alleviate the common user to have to install Autoconf.
|
||||
|
||||
The build system will detect if the Autoconf source files have changed, and
|
||||
will trigger a regeneration of `common/autoconf/generated-configure.sh` if
|
||||
will trigger a regeneration of `make/autoconf/generated-configure.sh` if
|
||||
needed. You can also manually request such an update by `bash
|
||||
common/autoconf/autogen.sh`.
|
||||
make/autoconf/autogen.sh`.
|
||||
|
||||
If you make changes to the build system that requires a re-generation, note the
|
||||
following:
|
||||
|
@ -329,7 +329,7 @@ else # HAS_SPEC=true
|
||||
$(call PrintFailureReports)
|
||||
$(call PrintBuildLogFailures)
|
||||
$(call ReportProfileTimes)
|
||||
$(PRINTF) "Hint: See common/doc/building.html#troubleshooting for assistance.\n\n"
|
||||
$(PRINTF) "Hint: See doc/building.html#troubleshooting for assistance.\n\n"
|
||||
ifneq ($(COMPARE_BUILD), )
|
||||
$(call CleanupCompareBuild)
|
||||
endif
|
||||
|
@ -32,9 +32,6 @@ include FindTests.gmk
|
||||
# We will always run multiple tests serially
|
||||
.NOTPARALLEL:
|
||||
|
||||
# Directories to find jtreg tests relative to
|
||||
JTREG_TEST_TOPDIRS := $(TOPDIR) $(JTREG_TESTROOTS)
|
||||
|
||||
# Hook to include the corresponding custom file, if present.
|
||||
$(eval $(call IncludeCustomExtension, RunTests.gmk))
|
||||
|
||||
@ -119,12 +116,40 @@ define ParseGtestTestSelection
|
||||
)
|
||||
endef
|
||||
|
||||
# Take a partial Jtreg root path and return a full, absolute path to that Jtreg
|
||||
# root. Also support having "hotspot" as an alias for "hotspot/jtreg".
|
||||
ExpandJtregRoot = \
|
||||
$(strip $(wildcard $(patsubst %/, %, \
|
||||
$(if $(filter /%, $1), \
|
||||
$1 \
|
||||
, \
|
||||
$(filter $(addprefix %, $1), $(JTREG_TESTROOTS) $(addsuffix /, $(JTREG_TESTROOTS))) \
|
||||
$(filter $(addprefix %, $(strip $1)/jtreg), $(JTREG_TESTROOTS) $(addsuffix /, $(JTREG_TESTROOTS))) \
|
||||
) \
|
||||
)))
|
||||
|
||||
# Take a partial Jtreg test path and return a full, absolute path to that Jtreg
|
||||
# test. Also support having "hotspot" as an alias for "hotspot/jtreg".
|
||||
ExpandJtregPath = \
|
||||
$(if $(call ExpandJtregRoot, $1), \
|
||||
$(call ExpandJtregRoot, $1) \
|
||||
, \
|
||||
$(strip $(wildcard $(patsubst %/, %, \
|
||||
$(if $(filter /%, $1), \
|
||||
$1 \
|
||||
, \
|
||||
$(addsuffix /$(strip $1), $(JTREG_TESTROOTS) $(TEST_BASEDIRS)) \
|
||||
$(addsuffix $(strip $(patsubst hotspot/%, /hotspot/jtreg/%, $1)), $(JTREG_TESTROOTS) $(TEST_BASEDIRS)) \
|
||||
) \
|
||||
))) \
|
||||
)
|
||||
|
||||
# Helper function to determine if a test specification is a Jtreg test
|
||||
#
|
||||
# It is a Jtreg test if it optionally begins with jtreg:, and then is either
|
||||
# an unspecified group name (possibly prefixed by :), or a group in a
|
||||
# specified test/<component> directory, or a path to a test or test directory,
|
||||
# either absolute or relative to any of the JTREG_TEST_TOPDIRS.
|
||||
# specified test root, or a path to a test or test directory,
|
||||
# either absolute or relative to any of the TEST_BASEDIRS or test roots.
|
||||
define ParseJtregTestSelection
|
||||
$(eval TEST_NAME := $(strip $(patsubst jtreg:%, %, $1))) \
|
||||
$(if $(or $(findstring :, $(TEST_NAME)), $(findstring /, $(TEST_NAME))), , \
|
||||
@ -132,20 +157,16 @@ define ParseJtregTestSelection
|
||||
) \
|
||||
$(if $(findstring :, $(TEST_NAME)), \
|
||||
$(if $(filter :%, $(TEST_NAME)), \
|
||||
$(foreach root, $(JTREG_TESTROOTS), \
|
||||
$(if $(filter $(patsubst :%, %, $(TEST_NAME)), \
|
||||
$($(root)_JTREG_TEST_GROUPS)), \
|
||||
jtreg:$(root):$(patsubst :%,%,$(TEST_NAME)) \
|
||||
) \
|
||||
) \
|
||||
$(eval TEST_GROUP := $(patsubst :%, %, $(TEST_NAME))) \
|
||||
$(eval TEST_ROOTS := $(JTREG_TESTROOTS)) \
|
||||
, \
|
||||
$(eval ROOT_PART := $(word 1, $(subst :, $(SPACE), $(TEST_NAME)))) \
|
||||
$(eval ROOT := $(filter $(addprefix %, $(ROOT_PART)), $(JTREG_TESTROOTS))) \
|
||||
$(eval GROUP := $(word 2, $(subst :, $(SPACE), $(TEST_NAME)))) \
|
||||
$(foreach root, $(ROOT), \
|
||||
$(if $(filter $(GROUP), $($(root)_JTREG_TEST_GROUPS)), \
|
||||
jtreg:$(root):$(GROUP) \
|
||||
) \
|
||||
$(eval TEST_PATH := $(word 1, $(subst :, $(SPACE), $(TEST_NAME)))) \
|
||||
$(eval TEST_GROUP := $(word 2, $(subst :, $(SPACE), $(TEST_NAME)))) \
|
||||
$(eval TEST_ROOTS := $(call ExpandJtregRoot, $(TEST_PATH))) \
|
||||
) \
|
||||
$(foreach test_root, $(TEST_ROOTS), \
|
||||
$(if $(filter $(TEST_GROUP), $($(test_root)_JTREG_TEST_GROUPS)), \
|
||||
jtreg:$(test_root):$(TEST_GROUP) \
|
||||
) \
|
||||
) \
|
||||
, \
|
||||
@ -154,7 +175,10 @@ define ParseJtregTestSelection
|
||||
jtreg:$(TEST_NAME) \
|
||||
) \
|
||||
, \
|
||||
$(addprefix jtreg:, $(wildcard $(addsuffix /$(TEST_NAME), $(JTREG_TEST_TOPDIRS)))) \
|
||||
$(eval TEST_PATHS := $(call ExpandJtregPath, $(TEST_NAME))) \
|
||||
$(foreach test_path, $(TEST_PATHS), \
|
||||
jtreg:$(test_path) \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
endef
|
||||
@ -162,7 +186,7 @@ endef
|
||||
ifeq ($(TEST), )
|
||||
$(info No test selection given in TEST!)
|
||||
$(info Please use e.g. 'run-test TEST=tier1' or 'run-test-tier1')
|
||||
$(info See common/doc/testing.[md|html] for help)
|
||||
$(info See doc/testing.[md|html] for help)
|
||||
$(error Cannot continue)
|
||||
endif
|
||||
|
||||
@ -185,7 +209,7 @@ $(foreach test, $(TEST), \
|
||||
|
||||
ifneq ($(UNKNOWN_TEST), )
|
||||
$(info Unknown test selection: '$(UNKNOWN_TEST)')
|
||||
$(info See common/doc/testing.[md|html] for help)
|
||||
$(info See doc/testing.[md|html] for help)
|
||||
$(error Cannot continue)
|
||||
endif
|
||||
|
||||
@ -299,8 +323,17 @@ define SetupRunJtregTestBody
|
||||
$1_TEST_SUPPORT_DIR := $$(TEST_SUPPORT_DIR)/$1
|
||||
|
||||
$1_TEST_NAME := $$(strip $$(patsubst jtreg:%, %, $$($1_TEST)))
|
||||
$1_COMPONENT := $$(firstword $$(subst /, $$(SPACE), \
|
||||
$$(patsubst test/%, %, $$($1_TEST_NAME))))
|
||||
|
||||
$1_COMPONENT := \
|
||||
$$(strip $$(foreach root, $$(JTREG_TESTROOTS), \
|
||||
$$(if $$(filter $$(root)%, $$($1_TEST_NAME)), \
|
||||
$$(lastword $$(subst /, $$(SPACE), $$(root))) \
|
||||
) \
|
||||
))
|
||||
# This will work only as long as just hotspot has the additional "jtreg" directory
|
||||
ifeq ($$($1_COMPONENT), jtreg)
|
||||
$1_COMPONENT := hotspot
|
||||
endif
|
||||
|
||||
ifeq ($$(JT_HOME), )
|
||||
$$(info Error: jtreg framework is not found.)
|
||||
|
4
make/autoconf/configure
vendored
4
make/autoconf/configure
vendored
@ -90,13 +90,13 @@ check_autoconf_timestamps() {
|
||||
|
||||
check_hg_updates() {
|
||||
if test "x`which hg 2> /dev/null | grep -v '^no hg in'`" != x; then
|
||||
conf_updated_autoconf_files=`cd $conf_script_dir && hg status -mard 2> /dev/null | grep autoconf`
|
||||
conf_updated_autoconf_files=`cd $conf_script_dir && hg status -mard . 2> /dev/null`
|
||||
if test "x$conf_updated_autoconf_files" != x; then
|
||||
echo "Configure source code has been updated, checking time stamps"
|
||||
check_autoconf_timestamps
|
||||
elif test "x$CUSTOM_CONFIG_DIR" != x; then
|
||||
# If custom source configure is available, make sure it is up-to-date as well.
|
||||
conf_custom_updated_autoconf_files=`cd $CUSTOM_CONFIG_DIR && hg status -mard 2> /dev/null | grep autoconf`
|
||||
conf_custom_updated_autoconf_files=`cd $CUSTOM_CONFIG_DIR && hg status -mard . 2> /dev/null`
|
||||
if test "x$conf_custom_updated_autoconf_files" != x; then
|
||||
echo "Configure custom source code has been updated, checking time stamps"
|
||||
check_autoconf_timestamps
|
||||
|
@ -656,7 +656,6 @@ BUILD_FAILURE_HANDLER
|
||||
ENABLE_INTREE_EC
|
||||
VALID_JVM_FEATURES
|
||||
JVM_FEATURES_custom
|
||||
JVM_FEATURES_zeroshark
|
||||
JVM_FEATURES_zero
|
||||
JVM_FEATURES_minimal
|
||||
JVM_FEATURES_core
|
||||
@ -676,10 +675,6 @@ PNG_LIBS
|
||||
PNG_CFLAGS
|
||||
USE_EXTERNAL_LIBGIF
|
||||
USE_EXTERNAL_LIBJPEG
|
||||
LLVM_LIBS
|
||||
LLVM_LDFLAGS
|
||||
LLVM_CFLAGS
|
||||
LLVM_CONFIG
|
||||
LIBFFI_LIB_FILE
|
||||
ENABLE_LIBFFI_BUNDLING
|
||||
LIBFFI_LIBS
|
||||
@ -1993,6 +1988,7 @@ Optional Features:
|
||||
--enable-cds[=yes/no] enable class data sharing feature in non-minimal VM.
|
||||
Default is yes.
|
||||
--disable-hotspot-gtest Disables building of the Hotspot unit tests
|
||||
[enabled]
|
||||
--disable-freetype-bundling
|
||||
disable bundling of the freetype library with the
|
||||
build result [enabled on Windows or when using
|
||||
@ -2033,8 +2029,7 @@ Optional Packages:
|
||||
--with-debug-level set the debug level (release, fastdebug, slowdebug,
|
||||
optimized) [release]
|
||||
--with-jvm-variants JVM variants (separated by commas) to build
|
||||
(server,client,minimal,core,zero,zeroshark,custom)
|
||||
[server]
|
||||
(server,client,minimal,core,zero,custom) [server]
|
||||
--with-cpu-port specify sources to use for Hotspot 64-bit ARM port
|
||||
(arm64,aarch64) [aarch64]
|
||||
--with-devkit use this devkit for compilers, tools and resources
|
||||
@ -4272,12 +4267,12 @@ pkgadd_help() {
|
||||
#
|
||||
|
||||
# All valid JVM features, regardless of platform
|
||||
VALID_JVM_FEATURES="compiler1 compiler2 zero shark minimal dtrace jvmti jvmci \
|
||||
VALID_JVM_FEATURES="compiler1 compiler2 zero minimal dtrace jvmti jvmci \
|
||||
graal vm-structs jni-check services management all-gcs nmt cds \
|
||||
static-build link-time-opt aot"
|
||||
|
||||
# All valid JVM variants
|
||||
VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom"
|
||||
VALID_JVM_VARIANTS="server client minimal core zero custom"
|
||||
|
||||
###############################################################################
|
||||
# Check if the specified JVM variant should be built. To be used in shell if
|
||||
@ -4308,7 +4303,6 @@ VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom"
|
||||
# minimal: reduced form of client with optional features stripped out
|
||||
# core: normal interpreter only, no compiler
|
||||
# zero: C++ based interpreter only, no compiler
|
||||
# zeroshark: C++ based interpreter, and a llvm-based compiler
|
||||
# custom: baseline JVM with no default features
|
||||
#
|
||||
|
||||
@ -4808,11 +4802,6 @@ VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom"
|
||||
################################################################################
|
||||
|
||||
|
||||
################################################################################
|
||||
# Setup llvm (Low-Level VM)
|
||||
################################################################################
|
||||
|
||||
|
||||
################################################################################
|
||||
# Setup various libraries, typically small system libraries
|
||||
################################################################################
|
||||
@ -5166,7 +5155,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=1509128484
|
||||
DATE_WHEN_GENERATED=1511254554
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -17069,7 +17058,7 @@ $as_echo "$as_me: Unknown variant(s) specified: $INVALID_VARIANTS" >&6;}
|
||||
|
||||
|
||||
|
||||
if [[ " $JVM_VARIANTS " =~ " zero " ]] || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
|
||||
if [[ " $JVM_VARIANTS " =~ " zero " ]] ; then
|
||||
# zero behaves as a platform and rewrites these values. This is really weird. :(
|
||||
# We are guaranteed that we do not build any other variants when building zero.
|
||||
HOTSPOT_TARGET_CPU=zero
|
||||
@ -25114,7 +25103,7 @@ fi
|
||||
|
||||
# Should we build the serviceability agent (SA)?
|
||||
INCLUDE_SA=true
|
||||
if [[ " $JVM_VARIANTS " =~ " zero " ]] || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
|
||||
if [[ " $JVM_VARIANTS " =~ " zero " ]] ; then
|
||||
INCLUDE_SA=false
|
||||
fi
|
||||
if test "x$OPENJDK_TARGET_OS" = xaix ; then
|
||||
@ -51971,7 +51960,7 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA
|
||||
|
||||
|
||||
fi
|
||||
if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
|
||||
if ! [[ " $JVM_VARIANTS " =~ " zero " ]] ; then
|
||||
# Non-zero builds have stricter warnings
|
||||
JVM_CFLAGS="$JVM_CFLAGS -Wreturn-type -Wundef -Wformat=2"
|
||||
else
|
||||
@ -52852,7 +52841,7 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA
|
||||
|
||||
|
||||
fi
|
||||
if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
|
||||
if ! [[ " $JVM_VARIANTS " =~ " zero " ]] ; then
|
||||
# Non-zero builds have stricter warnings
|
||||
OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -Wreturn-type -Wundef -Wformat=2"
|
||||
else
|
||||
@ -54613,7 +54602,7 @@ $as_echo "yes" >&6; }
|
||||
fi
|
||||
|
||||
# Check if ffi is needed
|
||||
if [[ " $JVM_VARIANTS " =~ " zero " ]] || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
|
||||
if [[ " $JVM_VARIANTS " =~ " zero " ]] ; then
|
||||
NEEDS_LIB_FFI=true
|
||||
else
|
||||
NEEDS_LIB_FFI=false
|
||||
@ -54686,8 +54675,7 @@ $as_echo "$has_static_libstdcxx" >&6; }
|
||||
# If dynamic wasn't requested, go with static unless it isn't available.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libstdc++" >&5
|
||||
$as_echo_n "checking how to link with libstdc++... " >&6; }
|
||||
if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno \
|
||||
|| [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
|
||||
if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno ; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: dynamic" >&5
|
||||
$as_echo "dynamic" >&6; }
|
||||
else
|
||||
@ -65169,94 +65157,6 @@ $as_echo "${LIBFFI_LIB_FILE}" >&6; }
|
||||
|
||||
|
||||
|
||||
if [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
|
||||
# Extract the first word of "llvm-config", so it can be a program name with args.
|
||||
set dummy llvm-config; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_prog_LLVM_CONFIG+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$LLVM_CONFIG"; then
|
||||
ac_cv_prog_LLVM_CONFIG="$LLVM_CONFIG" # Let the user override the test.
|
||||
else
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_LLVM_CONFIG="llvm-config"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
fi
|
||||
fi
|
||||
LLVM_CONFIG=$ac_cv_prog_LLVM_CONFIG
|
||||
if test -n "$LLVM_CONFIG"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LLVM_CONFIG" >&5
|
||||
$as_echo "$LLVM_CONFIG" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test "x$LLVM_CONFIG" != xllvm-config; then
|
||||
as_fn_error $? "llvm-config not found in $PATH." "$LINENO" 5
|
||||
fi
|
||||
|
||||
llvm_components="jit mcjit engine nativecodegen native"
|
||||
unset LLVM_CFLAGS
|
||||
for flag in $("$LLVM_CONFIG" --cxxflags); do
|
||||
if echo "${flag}" | grep -q '^-[ID]'; then
|
||||
if test "${flag}" != "-D_DEBUG" ; then
|
||||
if test "${LLVM_CFLAGS}" != "" ; then
|
||||
LLVM_CFLAGS="${LLVM_CFLAGS} "
|
||||
fi
|
||||
LLVM_CFLAGS="${LLVM_CFLAGS}${flag}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
llvm_version=$("${LLVM_CONFIG}" --version | $SED 's/\.//; s/svn.*//')
|
||||
LLVM_CFLAGS="${LLVM_CFLAGS} -DSHARK_LLVM_VERSION=${llvm_version}"
|
||||
|
||||
unset LLVM_LDFLAGS
|
||||
for flag in $("${LLVM_CONFIG}" --ldflags); do
|
||||
if echo "${flag}" | grep -q '^-L'; then
|
||||
if test "${LLVM_LDFLAGS}" != ""; then
|
||||
LLVM_LDFLAGS="${LLVM_LDFLAGS} "
|
||||
fi
|
||||
LLVM_LDFLAGS="${LLVM_LDFLAGS}${flag}"
|
||||
fi
|
||||
done
|
||||
|
||||
unset LLVM_LIBS
|
||||
for flag in $("${LLVM_CONFIG}" --libs ${llvm_components}); do
|
||||
if echo "${flag}" | grep -q '^-l'; then
|
||||
if test "${LLVM_LIBS}" != ""; then
|
||||
LLVM_LIBS="${LLVM_LIBS} "
|
||||
fi
|
||||
LLVM_LIBS="${LLVM_LIBS}${flag}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Due to https://llvm.org/bugs/show_bug.cgi?id=16902, llvm does not
|
||||
# always properly detect -ltinfo
|
||||
LLVM_LIBS="${LLVM_LIBS} -ltinfo"
|
||||
|
||||
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Check whether --with-libjpeg was given.
|
||||
if test "${with_libjpeg+set}" = set; then :
|
||||
@ -66053,7 +65953,6 @@ $as_echo "no, not found at $STLPORT_LIB" >&6; }
|
||||
|
||||
|
||||
|
||||
|
||||
# Hotspot setup depends on lib checks.
|
||||
|
||||
|
||||
@ -66124,15 +66023,9 @@ $as_echo "$JVM_FEATURES" >&6; }
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! [[ " $JVM_VARIANTS " =~ " zero " ]] && ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
|
||||
if ! [[ " $JVM_VARIANTS " =~ " zero " ]] ; then
|
||||
if [[ " $JVM_FEATURES " =~ " zero " ]] ; then
|
||||
as_fn_error $? "To enable zero/zeroshark, you must use --with-jvm-variants=zero/zeroshark" "$LINENO" 5
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then
|
||||
if [[ " $JVM_FEATURES " =~ " shark " ]] ; then
|
||||
as_fn_error $? "To enable shark, you must use --with-jvm-variants=zeroshark" "$LINENO" 5
|
||||
as_fn_error $? "To enable zero, you must use --with-jvm-variants=zero" "$LINENO" 5
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -66216,7 +66109,6 @@ $as_echo "no" >&6; }
|
||||
JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES"
|
||||
JVM_FEATURES_minimal="compiler1 minimal $JVM_FEATURES $JVM_FEATURES_link_time_opt"
|
||||
JVM_FEATURES_zero="zero $NON_MINIMAL_FEATURES $JVM_FEATURES"
|
||||
JVM_FEATURES_zeroshark="zero shark $NON_MINIMAL_FEATURES $JVM_FEATURES"
|
||||
JVM_FEATURES_custom="$JVM_FEATURES"
|
||||
|
||||
|
||||
@ -66226,7 +66118,6 @@ $as_echo "no" >&6; }
|
||||
|
||||
|
||||
|
||||
|
||||
# Used for verification of Makefiles by check-jvm-feature
|
||||
|
||||
|
||||
@ -68104,7 +67995,6 @@ $as_echo "$OUTPUT_DIR_IS_LOCAL" >&6; }
|
||||
JVM_FEATURES_core="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_core | $SORT -u))"
|
||||
JVM_FEATURES_minimal="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_minimal | $SORT -u))"
|
||||
JVM_FEATURES_zero="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_zero | $SORT -u))"
|
||||
JVM_FEATURES_zeroshark="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_zeroshark | $SORT -u))"
|
||||
JVM_FEATURES_custom="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_custom | $SORT -u))"
|
||||
|
||||
# Validate features
|
||||
|
@ -393,7 +393,7 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti vm-structs jni-check services management all-gcs nmt"
|
||||
if test "x$ENABLE_CDS" = "xtrue"; then
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cds"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Enable features depending on variant.
|
||||
JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci $JVM_FEATURES_aot $JVM_FEATURES_graal"
|
||||
@ -476,7 +476,7 @@ AC_DEFUN([SETUP_HOTSPOT_TARGET_CPU_PORT],
|
||||
AC_DEFUN_ONCE([HOTSPOT_ENABLE_DISABLE_GTEST],
|
||||
[
|
||||
AC_ARG_ENABLE([hotspot-gtest], [AS_HELP_STRING([--disable-hotspot-gtest],
|
||||
[Disables building of the Hotspot unit tests])])
|
||||
[Disables building of the Hotspot unit tests @<:@enabled@:>@])])
|
||||
|
||||
if test -e "${TOPDIR}/test/hotspot/gtest"; then
|
||||
GTEST_DIR_EXISTS="true"
|
||||
|
@ -29,6 +29,9 @@ _FIND_TESTS_GMK := 1
|
||||
# Hook to include the corresponding custom file, if present.
|
||||
$(eval $(call IncludeCustomExtension, common/FindTests.gmk))
|
||||
|
||||
# TEST_BASEDIRS might have been set by a custom extension
|
||||
TEST_BASEDIRS += $(TOPDIR)/test $(TOPDIR)
|
||||
|
||||
# JTREG_TESTROOTS might have been set by a custom extension
|
||||
JTREG_TESTROOTS += $(addprefix $(TOPDIR)/test/, hotspot/jtreg jdk langtools nashorn jaxp)
|
||||
|
||||
|
@ -328,8 +328,9 @@ $(MODULE_DEPS_MAKEFILE): $(MODULE_INFOS) \
|
||||
$(NAWK) -v MODULE=$(call GetModuleNameFromModuleInfo, $m) '\
|
||||
BEGIN { if (MODULE != "java.base") printf(" java.base"); } \
|
||||
/^ *requires/ { sub(/;/, ""); \
|
||||
sub(/requires/, ""); \
|
||||
sub(/transitive/, ""); \
|
||||
sub(/requires /, " "); \
|
||||
sub(/ static /, " "); \
|
||||
sub(/ transitive /, " "); \
|
||||
sub(/\/\/.*/, ""); \
|
||||
sub(/\/\*.*\*\//, ""); \
|
||||
gsub(/^ +\*.*/, ""); \
|
||||
|
@ -203,7 +203,7 @@ var getJibProfiles = function (input) {
|
||||
data.src_bundle_excludes = "./build webrev* */webrev* */*/webrev* */*/*/webrev* .hg */.hg */*/.hg */*/*/.hg";
|
||||
// Include list to use when creating a minimal jib source bundle which
|
||||
// contains just the jib configuration files.
|
||||
data.conf_bundle_includes = "*/conf/jib-profiles.* common/autoconf/version-numbers"
|
||||
data.conf_bundle_includes = "*/conf/jib-profiles.* make/autoconf/version-numbers"
|
||||
|
||||
// Define some common values
|
||||
var common = getJibProfilesCommon(input, data);
|
||||
@ -1043,7 +1043,7 @@ var concatObjects = function (o1, o2) {
|
||||
|
||||
/**
|
||||
* Constructs the numeric version string from reading the
|
||||
* common/autoconf/version-numbers file and removing all trailing ".0".
|
||||
* make/autoconf/version-numbers file and removing all trailing ".0".
|
||||
*
|
||||
* @param major Override major version
|
||||
* @param minor Override minor version
|
||||
@ -1080,17 +1080,17 @@ var versionArgs = function(input, common) {
|
||||
return args;
|
||||
}
|
||||
|
||||
// Properties representation of the common/autoconf/version-numbers file. Lazily
|
||||
// Properties representation of the make/autoconf/version-numbers file. Lazily
|
||||
// initiated by the function below.
|
||||
var version_numbers;
|
||||
|
||||
/**
|
||||
* Read the common/autoconf/version-numbers file into a Properties object.
|
||||
* Read the make/autoconf/version-numbers file into a Properties object.
|
||||
*
|
||||
* @returns {java.utilProperties}
|
||||
*/
|
||||
var getVersionNumbers = function () {
|
||||
// Read version information from common/autoconf/version-numbers
|
||||
// Read version information from make/autoconf/version-numbers
|
||||
if (version_numbers == null) {
|
||||
version_numbers = new java.util.Properties();
|
||||
var stream = new java.io.FileInputStream(__DIR__ + "/../autoconf/version-numbers");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -114,7 +114,7 @@ JVM_LIBS += \
|
||||
#
|
||||
|
||||
# These files and directories are always excluded
|
||||
JVM_EXCLUDE_FILES += jsig.c args.cc
|
||||
JVM_EXCLUDE_FILES += args.cc
|
||||
JVM_EXCLUDES += adlc
|
||||
|
||||
# Needed by vm_version.cpp
|
||||
|
@ -81,7 +81,7 @@ ifneq ($(OPENJDK_TARGET_OS), windows)
|
||||
$(error Unknown target OS $(OPENJDK_TARGET_OS) in CompileLibjsig.gmk)
|
||||
endif
|
||||
|
||||
LIBJSIG_SRC_FILE := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjsig/jsig.c
|
||||
LIBJSIG_SRC_DIR := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjsig
|
||||
LIBJSIG_MAPFILE := $(wildcard $(TOPDIR)/make/mapfiles/libjsig/mapfile-vers-$(OPENJDK_TARGET_OS))
|
||||
LIBJSIG_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/libjsig
|
||||
|
||||
@ -91,7 +91,7 @@ ifneq ($(OPENJDK_TARGET_OS), windows)
|
||||
|
||||
$(eval $(call SetupNativeCompilation, BUILD_LIBJSIG, \
|
||||
LIBRARY := jsig, \
|
||||
EXTRA_FILES := $(LIBJSIG_SRC_FILE), \
|
||||
SRC := $(LIBJSIG_SRC_DIR), \
|
||||
OUTPUT_DIR := $(LIB_OUTPUTDIR), \
|
||||
LANG := C, \
|
||||
CFLAGS := $(LIBJSIG_CFLAGS) $(LIBJSIG_CPU_FLAGS), \
|
||||
|
@ -177,7 +177,6 @@ SUNWprivate_1.1 {
|
||||
Java_sun_java2d_xr_XRBackendNative_setGCMode;
|
||||
Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative;
|
||||
Java_sun_java2d_xr_XRUtils_initFormatPtrs;
|
||||
Java_sun_java2d_xr_XRBackendNative_renderCompositeTrapezoidsNative;
|
||||
XRT_DrawGlyphList;
|
||||
|
||||
Java_sun_java2d_opengl_OGLContext_getOGLIdString;
|
||||
|
@ -408,7 +408,6 @@ SUNWprivate_1.1 {
|
||||
Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative;
|
||||
Java_sun_java2d_xr_XRBackendNative_setGCMode;
|
||||
Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative;
|
||||
Java_sun_java2d_xr_XRBackendNative_renderCompositeTrapezoidsNative;
|
||||
|
||||
Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1arrow;
|
||||
Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1box;
|
||||
|
@ -278,7 +278,7 @@
|
||||
<arg value="${javadoc.option}"/>
|
||||
<fileset dir="${nashorn.module.src.dir}" includes="**/*.java"/>
|
||||
<fileset dir="${dynalink.module.src.dir}" includes="**/*.java"/>
|
||||
<link href="http://docs.oracle.com/javase/8/docs/api/"/>
|
||||
<link offline="true" href="${javadoc.base.url}" packagelistLoc="${javadoc.pkg.list}"/>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
@ -296,7 +296,7 @@
|
||||
<arg value="."/>
|
||||
<arg value="${javadoc.option}"/>
|
||||
<fileset dir="${nashorn.module.src.dir}" includes="jdk/nashorn/api/**/*.java"/>
|
||||
<link href="http://docs.oracle.com/javase/8/docs/api/"/>
|
||||
<link offline="true" href="${javadoc.base.url}" packagelistLoc="${javadoc.pkg.list}"/>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
@ -314,7 +314,7 @@
|
||||
<arg value="."/>
|
||||
<arg value="${javadoc.option}"/>
|
||||
<fileset dir="${dynalink.module.src.dir}" includes="**/*.java"/>
|
||||
<link href="http://docs.oracle.com/javase/8/docs/api/"/>
|
||||
<link offline="true" href="${javadoc.base.url}" packagelistLoc="${javadoc.pkg.list}"/>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
|
315
make/nashorn/package-list
Normal file
315
make/nashorn/package-list
Normal file
@ -0,0 +1,315 @@
|
||||
com.sun.jarsigner
|
||||
com.sun.java.accessibility.util
|
||||
com.sun.javadoc
|
||||
com.sun.jdi
|
||||
com.sun.jdi.connect
|
||||
com.sun.jdi.connect.spi
|
||||
com.sun.jdi.event
|
||||
com.sun.jdi.request
|
||||
com.sun.management
|
||||
com.sun.net.httpserver
|
||||
com.sun.net.httpserver.spi
|
||||
com.sun.nio.sctp
|
||||
com.sun.security.auth
|
||||
com.sun.security.auth.callback
|
||||
com.sun.security.auth.login
|
||||
com.sun.security.auth.module
|
||||
com.sun.security.jgss
|
||||
com.sun.source.doctree
|
||||
com.sun.source.tree
|
||||
com.sun.source.util
|
||||
com.sun.tools.attach
|
||||
com.sun.tools.attach.spi
|
||||
com.sun.tools.doclets
|
||||
com.sun.tools.doclets.standard
|
||||
com.sun.tools.javac
|
||||
com.sun.tools.javadoc
|
||||
com.sun.tools.jconsole
|
||||
java.applet
|
||||
java.awt
|
||||
java.awt.color
|
||||
java.awt.datatransfer
|
||||
java.awt.desktop
|
||||
java.awt.dnd
|
||||
java.awt.event
|
||||
java.awt.font
|
||||
java.awt.geom
|
||||
java.awt.im
|
||||
java.awt.im.spi
|
||||
java.awt.image
|
||||
java.awt.image.renderable
|
||||
java.awt.print
|
||||
java.beans
|
||||
java.beans.beancontext
|
||||
java.io
|
||||
java.lang
|
||||
java.lang.annotation
|
||||
java.lang.instrument
|
||||
java.lang.invoke
|
||||
java.lang.management
|
||||
java.lang.module
|
||||
java.lang.ref
|
||||
java.lang.reflect
|
||||
java.math
|
||||
java.net
|
||||
java.net.spi
|
||||
java.nio
|
||||
java.nio.channels
|
||||
java.nio.channels.spi
|
||||
java.nio.charset
|
||||
java.nio.charset.spi
|
||||
java.nio.file
|
||||
java.nio.file.attribute
|
||||
java.nio.file.spi
|
||||
java.rmi
|
||||
java.rmi.activation
|
||||
java.rmi.dgc
|
||||
java.rmi.registry
|
||||
java.rmi.server
|
||||
java.security
|
||||
java.security.acl
|
||||
java.security.cert
|
||||
java.security.interfaces
|
||||
java.security.spec
|
||||
java.sql
|
||||
java.text
|
||||
java.text.spi
|
||||
java.time
|
||||
java.time.chrono
|
||||
java.time.format
|
||||
java.time.temporal
|
||||
java.time.zone
|
||||
java.util
|
||||
java.util.concurrent
|
||||
java.util.concurrent.atomic
|
||||
java.util.concurrent.locks
|
||||
java.util.function
|
||||
java.util.jar
|
||||
java.util.logging
|
||||
java.util.prefs
|
||||
java.util.regex
|
||||
java.util.spi
|
||||
java.util.stream
|
||||
java.util.zip
|
||||
javafx.animation
|
||||
javafx.application
|
||||
javafx.beans
|
||||
javafx.beans.binding
|
||||
javafx.beans.property
|
||||
javafx.beans.property.adapter
|
||||
javafx.beans.value
|
||||
javafx.collections
|
||||
javafx.collections.transformation
|
||||
javafx.concurrent
|
||||
javafx.css
|
||||
javafx.css.converter
|
||||
javafx.embed.swing
|
||||
javafx.event
|
||||
javafx.fxml
|
||||
javafx.geometry
|
||||
javafx.print
|
||||
javafx.scene
|
||||
javafx.scene.canvas
|
||||
javafx.scene.chart
|
||||
javafx.scene.control
|
||||
javafx.scene.control.cell
|
||||
javafx.scene.control.skin
|
||||
javafx.scene.effect
|
||||
javafx.scene.image
|
||||
javafx.scene.input
|
||||
javafx.scene.layout
|
||||
javafx.scene.media
|
||||
javafx.scene.paint
|
||||
javafx.scene.shape
|
||||
javafx.scene.text
|
||||
javafx.scene.transform
|
||||
javafx.scene.web
|
||||
javafx.stage
|
||||
javafx.util
|
||||
javafx.util.converter
|
||||
javax.accessibility
|
||||
javax.activation
|
||||
javax.activity
|
||||
javax.annotation
|
||||
javax.annotation.processing
|
||||
javax.crypto
|
||||
javax.crypto.interfaces
|
||||
javax.crypto.spec
|
||||
javax.imageio
|
||||
javax.imageio.event
|
||||
javax.imageio.metadata
|
||||
javax.imageio.plugins.bmp
|
||||
javax.imageio.plugins.jpeg
|
||||
javax.imageio.plugins.tiff
|
||||
javax.imageio.spi
|
||||
javax.imageio.stream
|
||||
javax.jnlp
|
||||
javax.jws
|
||||
javax.jws.soap
|
||||
javax.lang.model
|
||||
javax.lang.model.element
|
||||
javax.lang.model.type
|
||||
javax.lang.model.util
|
||||
javax.management
|
||||
javax.management.loading
|
||||
javax.management.modelmbean
|
||||
javax.management.monitor
|
||||
javax.management.openmbean
|
||||
javax.management.relation
|
||||
javax.management.remote
|
||||
javax.management.remote.rmi
|
||||
javax.management.timer
|
||||
javax.naming
|
||||
javax.naming.directory
|
||||
javax.naming.event
|
||||
javax.naming.ldap
|
||||
javax.naming.spi
|
||||
javax.net
|
||||
javax.net.ssl
|
||||
javax.print
|
||||
javax.print.attribute
|
||||
javax.print.attribute.standard
|
||||
javax.print.event
|
||||
javax.rmi
|
||||
javax.rmi.CORBA
|
||||
javax.rmi.ssl
|
||||
javax.script
|
||||
javax.security.auth
|
||||
javax.security.auth.callback
|
||||
javax.security.auth.kerberos
|
||||
javax.security.auth.login
|
||||
javax.security.auth.spi
|
||||
javax.security.auth.x500
|
||||
javax.security.cert
|
||||
javax.security.sasl
|
||||
javax.smartcardio
|
||||
javax.sound.midi
|
||||
javax.sound.midi.spi
|
||||
javax.sound.sampled
|
||||
javax.sound.sampled.spi
|
||||
javax.sql
|
||||
javax.sql.rowset
|
||||
javax.sql.rowset.serial
|
||||
javax.sql.rowset.spi
|
||||
javax.swing
|
||||
javax.swing.border
|
||||
javax.swing.colorchooser
|
||||
javax.swing.event
|
||||
javax.swing.filechooser
|
||||
javax.swing.plaf
|
||||
javax.swing.plaf.basic
|
||||
javax.swing.plaf.metal
|
||||
javax.swing.plaf.multi
|
||||
javax.swing.plaf.nimbus
|
||||
javax.swing.plaf.synth
|
||||
javax.swing.table
|
||||
javax.swing.text
|
||||
javax.swing.text.html
|
||||
javax.swing.text.html.parser
|
||||
javax.swing.text.rtf
|
||||
javax.swing.tree
|
||||
javax.swing.undo
|
||||
javax.tools
|
||||
javax.transaction
|
||||
javax.transaction.xa
|
||||
javax.xml
|
||||
javax.xml.bind
|
||||
javax.xml.bind.annotation
|
||||
javax.xml.bind.annotation.adapters
|
||||
javax.xml.bind.attachment
|
||||
javax.xml.bind.helpers
|
||||
javax.xml.bind.util
|
||||
javax.xml.catalog
|
||||
javax.xml.crypto
|
||||
javax.xml.crypto.dom
|
||||
javax.xml.crypto.dsig
|
||||
javax.xml.crypto.dsig.dom
|
||||
javax.xml.crypto.dsig.keyinfo
|
||||
javax.xml.crypto.dsig.spec
|
||||
javax.xml.datatype
|
||||
javax.xml.namespace
|
||||
javax.xml.parsers
|
||||
javax.xml.soap
|
||||
javax.xml.stream
|
||||
javax.xml.stream.events
|
||||
javax.xml.stream.util
|
||||
javax.xml.transform
|
||||
javax.xml.transform.dom
|
||||
javax.xml.transform.sax
|
||||
javax.xml.transform.stax
|
||||
javax.xml.transform.stream
|
||||
javax.xml.validation
|
||||
javax.xml.ws
|
||||
javax.xml.ws.handler
|
||||
javax.xml.ws.handler.soap
|
||||
javax.xml.ws.http
|
||||
javax.xml.ws.soap
|
||||
javax.xml.ws.spi
|
||||
javax.xml.ws.spi.http
|
||||
javax.xml.ws.wsaddressing
|
||||
javax.xml.xpath
|
||||
jdk.dynalink
|
||||
jdk.dynalink.beans
|
||||
jdk.dynalink.linker
|
||||
jdk.dynalink.linker.support
|
||||
jdk.dynalink.support
|
||||
jdk.incubator.http
|
||||
jdk.javadoc.doclet
|
||||
jdk.jfr
|
||||
jdk.jfr.consumer
|
||||
jdk.jshell
|
||||
jdk.jshell.execution
|
||||
jdk.jshell.spi
|
||||
jdk.jshell.tool
|
||||
jdk.management.cmm
|
||||
jdk.management.jfr
|
||||
jdk.management.resource
|
||||
jdk.nashorn.api.scripting
|
||||
jdk.nashorn.api.tree
|
||||
jdk.net
|
||||
jdk.packager.services
|
||||
jdk.security.jarsigner
|
||||
netscape.javascript
|
||||
org.ietf.jgss
|
||||
org.omg.CORBA
|
||||
org.omg.CORBA_2_3
|
||||
org.omg.CORBA_2_3.portable
|
||||
org.omg.CORBA.DynAnyPackage
|
||||
org.omg.CORBA.ORBPackage
|
||||
org.omg.CORBA.portable
|
||||
org.omg.CORBA.TypeCodePackage
|
||||
org.omg.CosNaming
|
||||
org.omg.CosNaming.NamingContextExtPackage
|
||||
org.omg.CosNaming.NamingContextPackage
|
||||
org.omg.Dynamic
|
||||
org.omg.DynamicAny
|
||||
org.omg.DynamicAny.DynAnyFactoryPackage
|
||||
org.omg.DynamicAny.DynAnyPackage
|
||||
org.omg.IOP
|
||||
org.omg.IOP.CodecFactoryPackage
|
||||
org.omg.IOP.CodecPackage
|
||||
org.omg.Messaging
|
||||
org.omg.PortableInterceptor
|
||||
org.omg.PortableInterceptor.ORBInitInfoPackage
|
||||
org.omg.PortableServer
|
||||
org.omg.PortableServer.CurrentPackage
|
||||
org.omg.PortableServer.POAManagerPackage
|
||||
org.omg.PortableServer.POAPackage
|
||||
org.omg.PortableServer.portable
|
||||
org.omg.PortableServer.ServantLocatorPackage
|
||||
org.omg.SendingContext
|
||||
org.omg.stub.java.rmi
|
||||
org.w3c.dom
|
||||
org.w3c.dom.bootstrap
|
||||
org.w3c.dom.css
|
||||
org.w3c.dom.events
|
||||
org.w3c.dom.html
|
||||
org.w3c.dom.ls
|
||||
org.w3c.dom.ranges
|
||||
org.w3c.dom.stylesheets
|
||||
org.w3c.dom.traversal
|
||||
org.w3c.dom.views
|
||||
org.w3c.dom.xpath
|
||||
org.xml.sax
|
||||
org.xml.sax.ext
|
||||
org.xml.sax.helpers
|
@ -33,6 +33,12 @@ jdk.jline.src.dir=src/jdk.internal.le/share/classes
|
||||
# source and target levels
|
||||
build.compiler=modern
|
||||
|
||||
jdk.build.dir=build
|
||||
nashorn.make.dir=make/nashorn
|
||||
|
||||
javadoc.base.url=https://docs.oracle.com/javase/9/docs/api/
|
||||
javadoc.pkg.list=make/nashorn
|
||||
|
||||
javadoc.option=\
|
||||
-tag "implSpec:a:Implementation Requirements:" \
|
||||
-tag "implNote:a:Implementation Note:" \
|
||||
@ -43,9 +49,6 @@ nashorn.version=0.1
|
||||
nashorn.fullversion=0.1
|
||||
nashorn.product.name=Oracle Nashorn
|
||||
|
||||
jdk.build.dir=build
|
||||
nashorn.make.dir=make/nashorn
|
||||
|
||||
# This directory is removed when the project is cleaned:
|
||||
build.dir=${jdk.build.dir}/nashorn
|
||||
build.classes.dir=${build.dir}/classes
|
||||
|
@ -2968,7 +2968,9 @@ class StubGenerator: public StubCodeGenerator {
|
||||
CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(bs);
|
||||
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
|
||||
|
||||
Label L_cardtable_loop;
|
||||
Label L_cardtable_loop, L_done;
|
||||
|
||||
__ cbz_32(count, L_done); // zero count - nothing to do
|
||||
|
||||
__ add_ptr_scaled_int32(count, addr, count, LogBytesPerHeapOop);
|
||||
__ sub(count, count, BytesPerHeapOop); // last addr
|
||||
@ -2987,6 +2989,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ strb(zero, Address(addr, 1, post_indexed));
|
||||
__ subs(count, count, 1);
|
||||
__ b(L_cardtable_loop, ge);
|
||||
__ BIND(L_done);
|
||||
}
|
||||
break;
|
||||
case BarrierSet::ModRef:
|
||||
|
@ -582,7 +582,11 @@ class Assembler : public AbstractAssembler {
|
||||
#define LOC_ZOPC (unsigned long)(0xebL << 40 | 0xf2L) // z196
|
||||
#define LOCG_ZOPC (unsigned long)(0xebL << 40 | 0xe2L) // z196
|
||||
|
||||
#define LMG_ZOPC (unsigned long)(235L << 40 | 4L)
|
||||
|
||||
// LOAD multiple registers at once
|
||||
#define LM_ZOPC (unsigned int)(0x98 << 24)
|
||||
#define LMY_ZOPC (unsigned long)(0xebL << 40 | 0x98L)
|
||||
#define LMG_ZOPC (unsigned long)(0xebL << 40 | 0x04L)
|
||||
|
||||
#define LE_ZOPC (unsigned int)(0x78 << 24)
|
||||
#define LEY_ZOPC (unsigned long)(237L << 40 | 100L)
|
||||
@ -613,7 +617,10 @@ class Assembler : public AbstractAssembler {
|
||||
#define STOC_ZOPC (unsigned long)(0xebL << 40 | 0xf3L) // z196
|
||||
#define STOCG_ZOPC (unsigned long)(0xebL << 40 | 0xe3L) // z196
|
||||
|
||||
#define STMG_ZOPC (unsigned long)(235L << 40 | 36L)
|
||||
// STORE multiple registers at once
|
||||
#define STM_ZOPC (unsigned int)(0x90 << 24)
|
||||
#define STMY_ZOPC (unsigned long)(0xebL << 40 | 0x90L)
|
||||
#define STMG_ZOPC (unsigned long)(0xebL << 40 | 0x24L)
|
||||
|
||||
#define STE_ZOPC (unsigned int)(0x70 << 24)
|
||||
#define STEY_ZOPC (unsigned long)(237L << 40 | 102L)
|
||||
@ -874,15 +881,19 @@ class Assembler : public AbstractAssembler {
|
||||
|
||||
// Shift
|
||||
// arithmetic
|
||||
#define SLA_ZOPC (unsigned int)(139 << 24)
|
||||
#define SLAG_ZOPC (unsigned long)(235L << 40 | 11L)
|
||||
#define SRA_ZOPC (unsigned int)(138 << 24)
|
||||
#define SRAG_ZOPC (unsigned long)(235L << 40 | 10L)
|
||||
#define SLA_ZOPC (unsigned int)(0x8b << 24)
|
||||
#define SLAK_ZOPC (unsigned long)(0xebL << 40 | 0xddL)
|
||||
#define SLAG_ZOPC (unsigned long)(0xebL << 40 | 0x0bL)
|
||||
#define SRA_ZOPC (unsigned int)(0x8a << 24)
|
||||
#define SRAK_ZOPC (unsigned long)(0xebL << 40 | 0xdcL)
|
||||
#define SRAG_ZOPC (unsigned long)(0xebL << 40 | 0x0aL)
|
||||
// logical
|
||||
#define SLL_ZOPC (unsigned int)(137 << 24)
|
||||
#define SLLG_ZOPC (unsigned long)(235L << 40 | 13L)
|
||||
#define SRL_ZOPC (unsigned int)(136 << 24)
|
||||
#define SRLG_ZOPC (unsigned long)(235L << 40 | 12L)
|
||||
#define SLL_ZOPC (unsigned int)(0x89 << 24)
|
||||
#define SLLK_ZOPC (unsigned long)(0xebL << 40 | 0xdfL)
|
||||
#define SLLG_ZOPC (unsigned long)(0xebL << 40 | 0x0dL)
|
||||
#define SRL_ZOPC (unsigned int)(0x88 << 24)
|
||||
#define SRLK_ZOPC (unsigned long)(0xebL << 40 | 0xdeL)
|
||||
#define SRLG_ZOPC (unsigned long)(0xebL << 40 | 0x0cL)
|
||||
|
||||
// Rotate, then AND/XOR/OR/insert
|
||||
// rotate
|
||||
@ -2262,12 +2273,16 @@ class Assembler : public AbstractAssembler {
|
||||
|
||||
// shift
|
||||
inline void z_sla( Register r1, int64_t d2, Register b2=Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, only 31 bits shifted, sign preserved!
|
||||
inline void z_slak(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int32, only 31 bits shifted, sign preserved!
|
||||
inline void z_slag(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, only 63 bits shifted, sign preserved!
|
||||
inline void z_sra( Register r1, int64_t d2, Register b2=Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, sign extended
|
||||
inline void z_srak(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int32, sign extended
|
||||
inline void z_srag(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, sign extended
|
||||
inline void z_sll( Register r1, int64_t d2, Register b2=Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, zeros added
|
||||
inline void z_sllk(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int32, zeros added
|
||||
inline void z_sllg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, zeros added
|
||||
inline void z_srl( Register r1, int64_t d2, Register b2=Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, zero extended
|
||||
inline void z_srlk(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int32, zero extended
|
||||
inline void z_srlg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, zero extended
|
||||
|
||||
// rotate
|
||||
@ -3035,7 +3050,11 @@ class Assembler : public AbstractAssembler {
|
||||
|
||||
inline void z_tam();
|
||||
inline void z_stckf(int64_t d2, Register b2);
|
||||
inline void z_stm( Register r1, Register r3, int64_t d2, Register b2);
|
||||
inline void z_stmy(Register r1, Register r3, int64_t d2, Register b2);
|
||||
inline void z_stmg(Register r1, Register r3, int64_t d2, Register b2);
|
||||
inline void z_lm( Register r1, Register r3, int64_t d2, Register b2);
|
||||
inline void z_lmy(Register r1, Register r3, int64_t d2, Register b2);
|
||||
inline void z_lmg(Register r1, Register r3, int64_t d2, Register b2);
|
||||
|
||||
inline void z_cs( Register r1, Register r3, int64_t d2, Register b2);
|
||||
|
@ -334,12 +334,16 @@ inline void Assembler::z_stfle(int64_t d2, Register b2) { emit_32(STFLE_ZOPC | u
|
||||
// SHIFT/RORATE OPERATIONS
|
||||
//-----------------------------------
|
||||
inline void Assembler::z_sla( Register r1, int64_t d2, Register b2) { emit_32( SLA_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); }
|
||||
inline void Assembler::z_slak(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLAK_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
|
||||
inline void Assembler::z_slag(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLAG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
|
||||
inline void Assembler::z_sra( Register r1, int64_t d2, Register b2) { emit_32( SRA_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); }
|
||||
inline void Assembler::z_srak(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRAK_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
|
||||
inline void Assembler::z_srag(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRAG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
|
||||
inline void Assembler::z_sll( Register r1, int64_t d2, Register b2) { emit_32( SLL_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); }
|
||||
inline void Assembler::z_sllk(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLLK_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
|
||||
inline void Assembler::z_sllg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLLG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
|
||||
inline void Assembler::z_srl( Register r1, int64_t d2, Register b2) { emit_32( SRL_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); }
|
||||
inline void Assembler::z_srlk(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRLK_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
|
||||
inline void Assembler::z_srlg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRLG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
|
||||
|
||||
// rotate left
|
||||
@ -690,10 +694,14 @@ inline void Assembler::z_ahhlr(Register r1, Register r2, Register r3) { emit_32(
|
||||
|
||||
inline void Assembler::z_tam() { emit_16( TAM_ZOPC); }
|
||||
inline void Assembler::z_stckf(int64_t d2, Register b2) { emit_32( STCKF_ZOPC | uimm12(d2, 20, 32) | regz(b2, 16, 32)); }
|
||||
inline void Assembler::z_stmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( STMG_ZOPC | simm20(d2) | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) ); }
|
||||
inline void Assembler::z_lmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( LMG_ZOPC | simm20(d2) | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) ); }
|
||||
inline void Assembler::z_stm( Register r1, Register r3, int64_t d2, Register b2) { emit_32( STM_ZOPC | reg(r1, 8, 32) | reg(r3,12,32)| reg(b2,16,32) | uimm12(d2, 20,32)); }
|
||||
inline void Assembler::z_stmy(Register r1, Register r3, int64_t d2, Register b2) { emit_48( STMY_ZOPC | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) | simm20(d2) ); }
|
||||
inline void Assembler::z_stmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( STMG_ZOPC | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) | simm20(d2) ); }
|
||||
inline void Assembler::z_lm( Register r1, Register r3, int64_t d2, Register b2) { emit_32( LM_ZOPC | reg(r1, 8, 32) | reg(r3,12,32)| reg(b2,16,32) | uimm12(d2, 20,32)); }
|
||||
inline void Assembler::z_lmy( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LMY_ZOPC | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) | simm20(d2) ); }
|
||||
inline void Assembler::z_lmg( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LMG_ZOPC | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) | simm20(d2) ); }
|
||||
|
||||
inline void Assembler::z_cs(Register r1, Register r3, int64_t d2, Register b2) { emit_32( CS_ZOPC | regt(r1, 8, 32) | reg(r3, 12, 32) | reg(b2, 16, 32) | uimm12(d2, 20, 32)); }
|
||||
inline void Assembler::z_cs( Register r1, Register r3, int64_t d2, Register b2) { emit_32( CS_ZOPC | regt(r1, 8, 32) | reg(r3, 12, 32) | reg(b2, 16, 32) | uimm12(d2, 20, 32)); }
|
||||
inline void Assembler::z_csy(Register r1, Register r3, int64_t d2, Register b2) { emit_48( CSY_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | reg(b2, 16, 48) | simm20(d2)); }
|
||||
inline void Assembler::z_csg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( CSG_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | reg(b2, 16, 48) | simm20(d2)); }
|
||||
inline void Assembler::z_cs( Register r1, Register r3, const Address& a) { assert(!a.has_index(), "Cannot encode index"); z_cs( r1, r3, a.disp(), a.baseOrR0()); }
|
||||
|
@ -936,7 +936,7 @@ void MacroAssembler::load_long_pcrelative(Register Rdst, address dataLocation) {
|
||||
|
||||
// Some extra safety net.
|
||||
if (!RelAddr::is_in_range_of_RelAddr32(total_distance)) {
|
||||
guarantee(RelAddr::is_in_range_of_RelAddr32(total_distance), "too far away");
|
||||
guarantee(RelAddr::is_in_range_of_RelAddr32(total_distance), "load_long_pcrelative can't handle distance " INTPTR_FORMAT, total_distance);
|
||||
}
|
||||
|
||||
(this)->relocate(rspec, relocInfo::pcrel_addr_format);
|
||||
@ -956,7 +956,7 @@ void MacroAssembler::load_addr_pcrelative(Register Rdst, address addrLocation) {
|
||||
|
||||
// Some extra safety net.
|
||||
if (!RelAddr::is_in_range_of_RelAddr32(total_distance)) {
|
||||
guarantee(RelAddr::is_in_range_of_RelAddr32(total_distance), "too far away");
|
||||
guarantee(RelAddr::is_in_range_of_RelAddr32(total_distance), "load_long_pcrelative can't handle distance " INTPTR_FORMAT, total_distance);
|
||||
}
|
||||
|
||||
(this)->relocate(rspec, relocInfo::pcrel_addr_format);
|
||||
@ -1025,6 +1025,13 @@ void MacroAssembler::testbit(Register r, unsigned int bitPos) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::prefetch_read(Address a) {
|
||||
z_pfd(1, a.disp20(), a.indexOrR0(), a.base());
|
||||
}
|
||||
void MacroAssembler::prefetch_update(Address a) {
|
||||
z_pfd(2, a.disp20(), a.indexOrR0(), a.base());
|
||||
}
|
||||
|
||||
// Clear a register, i.e. load const zero into reg.
|
||||
// Return len (in bytes) of generated instruction(s).
|
||||
// whole_reg: Clear 64 bits if true, 32 bits otherwise.
|
||||
@ -4896,77 +4903,295 @@ unsigned int MacroAssembler::CopyRawMemory_AlignedDisjoint(Register src_reg, Reg
|
||||
|
||||
// Intrinsics for CompactStrings
|
||||
|
||||
// Compress char[] to byte[]. odd_reg contains cnt. Kills dst. Early clobber: result
|
||||
// Compress char[] to byte[].
|
||||
// Restores: src, dst
|
||||
// Uses: cnt
|
||||
// Kills: tmp, Z_R0, Z_R1.
|
||||
// Early clobber: result.
|
||||
// Note:
|
||||
// cnt is signed int. Do not rely on high word!
|
||||
// counts # characters, not bytes.
|
||||
// The result is the number of characters copied before the first incompatible character was found.
|
||||
// If tmp2 is provided and the compression fails, the compression stops exactly at this point and the result is precise.
|
||||
// If precise is true, the processing stops exactly at this point. Otherwise, the result may be off
|
||||
// by a few bytes. The result always indicates the number of copied characters.
|
||||
//
|
||||
// Note: Does not behave exactly like package private StringUTF16 compress java implementation in case of failure:
|
||||
// - Different number of characters may have been written to dead array (if tmp2 not provided).
|
||||
// - Different number of characters may have been written to dead array (if precise is false).
|
||||
// - Returns a number <cnt instead of 0. (Result gets compared with cnt.)
|
||||
unsigned int MacroAssembler::string_compress(Register result, Register src, Register dst, Register odd_reg,
|
||||
Register even_reg, Register tmp, Register tmp2) {
|
||||
int block_start = offset();
|
||||
Label Lloop1, Lloop2, Lslow, Ldone;
|
||||
const Register addr2 = dst, ind1 = result, mask = tmp;
|
||||
const bool precise = (tmp2 != noreg);
|
||||
unsigned int MacroAssembler::string_compress(Register result, Register src, Register dst, Register cnt,
|
||||
Register tmp, bool precise) {
|
||||
assert_different_registers(Z_R0, Z_R1, src, dst, cnt, tmp);
|
||||
|
||||
BLOCK_COMMENT("string_compress {");
|
||||
|
||||
z_sll(odd_reg, 1); // Number of bytes to read. (Must be a positive simm32.)
|
||||
clear_reg(ind1); // Index to read.
|
||||
z_llilf(mask, 0xFF00FF00);
|
||||
z_ahi(odd_reg, -16); // Last possible index for fast loop.
|
||||
z_brl(Lslow);
|
||||
|
||||
// ind1: index, even_reg: index increment, odd_reg: index limit
|
||||
z_iihf(mask, 0xFF00FF00);
|
||||
z_lhi(even_reg, 16);
|
||||
|
||||
bind(Lloop1); // 8 Characters per iteration.
|
||||
z_lg(Z_R0, Address(src, ind1));
|
||||
z_lg(Z_R1, Address(src, ind1, 8));
|
||||
if (precise) {
|
||||
BLOCK_COMMENT("encode_iso_array {");
|
||||
} else {
|
||||
BLOCK_COMMENT("string_compress {");
|
||||
}
|
||||
int block_start = offset();
|
||||
|
||||
Register Rsrc = src;
|
||||
Register Rdst = dst;
|
||||
Register Rix = tmp;
|
||||
Register Rcnt = cnt;
|
||||
Register Rmask = result; // holds incompatibility check mask until result value is stored.
|
||||
Label ScalarShortcut, AllDone;
|
||||
|
||||
z_iilf(Rmask, 0xFF00FF00);
|
||||
z_iihf(Rmask, 0xFF00FF00);
|
||||
|
||||
#if 0 // Sacrifice shortcuts for code compactness
|
||||
{
|
||||
//---< shortcuts for short strings (very frequent) >---
|
||||
// Strings with 4 and 8 characters were fond to occur very frequently.
|
||||
// Therefore, we handle them right away with minimal overhead.
|
||||
Label skipShortcut, skip4Shortcut, skip8Shortcut;
|
||||
Register Rout = Z_R0;
|
||||
z_chi(Rcnt, 4);
|
||||
z_brne(skip4Shortcut); // 4 characters are very frequent
|
||||
z_lg(Z_R0, 0, Rsrc); // Treat exactly 4 characters specially.
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
Rout = Z_R0;
|
||||
z_ngrk(Rix, Z_R0, Rmask);
|
||||
} else {
|
||||
Rout = Rix;
|
||||
z_lgr(Rix, Z_R0);
|
||||
z_ngr(Z_R0, Rmask);
|
||||
}
|
||||
z_brnz(skipShortcut);
|
||||
z_stcmh(Rout, 5, 0, Rdst);
|
||||
z_stcm(Rout, 5, 2, Rdst);
|
||||
z_lgfr(result, Rcnt);
|
||||
z_bru(AllDone);
|
||||
bind(skip4Shortcut);
|
||||
|
||||
z_chi(Rcnt, 8);
|
||||
z_brne(skip8Shortcut); // There's more to do...
|
||||
z_lmg(Z_R0, Z_R1, 0, Rsrc); // Treat exactly 8 characters specially.
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
Rout = Z_R0;
|
||||
z_ogrk(Rix, Z_R0, Z_R1);
|
||||
z_ngr(Rix, Rmask);
|
||||
} else {
|
||||
Rout = Rix;
|
||||
z_lgr(Rix, Z_R0);
|
||||
z_ogr(Z_R0, Z_R1);
|
||||
z_ngr(Z_R0, Rmask);
|
||||
}
|
||||
z_brnz(skipShortcut);
|
||||
z_stcmh(Rout, 5, 0, Rdst);
|
||||
z_stcm(Rout, 5, 2, Rdst);
|
||||
z_stcmh(Z_R1, 5, 4, Rdst);
|
||||
z_stcm(Z_R1, 5, 6, Rdst);
|
||||
z_lgfr(result, Rcnt);
|
||||
z_bru(AllDone);
|
||||
|
||||
bind(skip8Shortcut);
|
||||
clear_reg(Z_R0, true, false); // #characters already processed (none). Precond for scalar loop.
|
||||
z_brl(ScalarShortcut); // Just a few characters
|
||||
|
||||
bind(skipShortcut);
|
||||
}
|
||||
#endif
|
||||
clear_reg(Z_R0); // make sure register is properly initialized.
|
||||
|
||||
if (VM_Version::has_VectorFacility()) {
|
||||
const int min_vcnt = 32; // Minimum #characters required to use vector instructions.
|
||||
// Otherwise just do nothing in vector mode.
|
||||
// Must be multiple of 2*(vector register length in chars (8 HW = 128 bits)).
|
||||
const int log_min_vcnt = exact_log2(min_vcnt);
|
||||
Label VectorLoop, VectorDone, VectorBreak;
|
||||
|
||||
VectorRegister Vtmp1 = Z_V16;
|
||||
VectorRegister Vtmp2 = Z_V17;
|
||||
VectorRegister Vmask = Z_V18;
|
||||
VectorRegister Vzero = Z_V19;
|
||||
VectorRegister Vsrc_first = Z_V20;
|
||||
VectorRegister Vsrc_last = Z_V23;
|
||||
|
||||
assert((Vsrc_last->encoding() - Vsrc_first->encoding() + 1) == min_vcnt/8, "logic error");
|
||||
assert(VM_Version::has_DistinctOpnds(), "Assumption when has_VectorFacility()");
|
||||
z_srak(Rix, Rcnt, log_min_vcnt); // # vector loop iterations
|
||||
z_brz(VectorDone); // not enough data for vector loop
|
||||
|
||||
z_vzero(Vzero); // all zeroes
|
||||
z_vgmh(Vmask, 0, 7); // generate 0xff00 mask for all 2-byte elements
|
||||
z_sllg(Z_R0, Rix, log_min_vcnt); // remember #chars that will be processed by vector loop
|
||||
|
||||
bind(VectorLoop);
|
||||
z_vlm(Vsrc_first, Vsrc_last, 0, Rsrc);
|
||||
add2reg(Rsrc, min_vcnt*2);
|
||||
|
||||
//---< check for incompatible character >---
|
||||
z_vo(Vtmp1, Z_V20, Z_V21);
|
||||
z_vo(Vtmp2, Z_V22, Z_V23);
|
||||
z_vo(Vtmp1, Vtmp1, Vtmp2);
|
||||
z_vn(Vtmp1, Vtmp1, Vmask);
|
||||
z_vceqhs(Vtmp1, Vtmp1, Vzero); // high half of all chars must be zero for successful compress.
|
||||
z_brne(VectorBreak); // break vector loop, incompatible character found.
|
||||
// re-process data from current iteration in break handler.
|
||||
|
||||
//---< pack & store characters >---
|
||||
z_vpkh(Vtmp1, Z_V20, Z_V21); // pack (src1, src2) -> tmp1
|
||||
z_vpkh(Vtmp2, Z_V22, Z_V23); // pack (src3, src4) -> tmp2
|
||||
z_vstm(Vtmp1, Vtmp2, 0, Rdst); // store packed string
|
||||
add2reg(Rdst, min_vcnt);
|
||||
|
||||
z_brct(Rix, VectorLoop);
|
||||
|
||||
z_bru(VectorDone);
|
||||
|
||||
bind(VectorBreak);
|
||||
z_sll(Rix, log_min_vcnt); // # chars processed so far in VectorLoop, excl. current iteration.
|
||||
z_sr(Z_R0, Rix); // correct # chars processed in total.
|
||||
|
||||
bind(VectorDone);
|
||||
}
|
||||
|
||||
{
|
||||
const int min_cnt = 8; // Minimum #characters required to use unrolled loop.
|
||||
// Otherwise just do nothing in unrolled loop.
|
||||
// Must be multiple of 8.
|
||||
const int log_min_cnt = exact_log2(min_cnt);
|
||||
Label UnrolledLoop, UnrolledDone, UnrolledBreak;
|
||||
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
z_ogrk(tmp2, Z_R0, Z_R1);
|
||||
z_srk(Rix, Rcnt, Z_R0); // remaining # chars to compress in unrolled loop
|
||||
} else {
|
||||
z_lgr(tmp2, Z_R0);
|
||||
z_ogr(tmp2, Z_R1);
|
||||
z_lr(Rix, Rcnt);
|
||||
z_sr(Rix, Z_R0);
|
||||
}
|
||||
z_ngr(tmp2, mask);
|
||||
z_brne(Lslow); // Failed fast case, retry slowly.
|
||||
z_sra(Rix, log_min_cnt); // unrolled loop count
|
||||
z_brz(UnrolledDone);
|
||||
|
||||
bind(UnrolledLoop);
|
||||
z_lmg(Z_R0, Z_R1, 0, Rsrc);
|
||||
if (precise) {
|
||||
z_ogr(Z_R1, Z_R0); // check all 8 chars for incompatibility
|
||||
z_ngr(Z_R1, Rmask);
|
||||
z_brnz(UnrolledBreak);
|
||||
|
||||
z_lg(Z_R1, 8, Rsrc); // reload destroyed register
|
||||
z_stcmh(Z_R0, 5, 0, Rdst);
|
||||
z_stcm(Z_R0, 5, 2, Rdst);
|
||||
} else {
|
||||
z_stcmh(Z_R0, 5, 0, Rdst);
|
||||
z_stcm(Z_R0, 5, 2, Rdst);
|
||||
|
||||
z_ogr(Z_R0, Z_R1);
|
||||
z_ngr(Z_R0, Rmask);
|
||||
z_brnz(UnrolledBreak);
|
||||
}
|
||||
z_stcmh(Z_R1, 5, 4, Rdst);
|
||||
z_stcm(Z_R1, 5, 6, Rdst);
|
||||
|
||||
add2reg(Rsrc, min_cnt*2);
|
||||
add2reg(Rdst, min_cnt);
|
||||
z_brct(Rix, UnrolledLoop);
|
||||
|
||||
z_lgfr(Z_R0, Rcnt); // # chars processed in total after unrolled loop.
|
||||
z_nilf(Z_R0, ~(min_cnt-1));
|
||||
z_tmll(Rcnt, min_cnt-1);
|
||||
z_brnaz(ScalarShortcut); // if all bits zero, there is nothing left to do for scalar loop.
|
||||
// Rix == 0 in all cases.
|
||||
z_lgfr(result, Rcnt); // all characters processed.
|
||||
z_sgfr(Rdst, Rcnt); // restore ptr
|
||||
z_sgfr(Rsrc, Rcnt); // restore ptr, double the element count for Rsrc restore
|
||||
z_sgfr(Rsrc, Rcnt);
|
||||
z_bru(AllDone);
|
||||
|
||||
bind(UnrolledBreak);
|
||||
z_lgfr(Z_R0, Rcnt); // # chars processed in total after unrolled loop
|
||||
z_nilf(Z_R0, ~(min_cnt-1));
|
||||
z_sll(Rix, log_min_cnt); // # chars processed so far in UnrolledLoop, excl. current iteration.
|
||||
z_sr(Z_R0, Rix); // correct # chars processed in total.
|
||||
if (!precise) {
|
||||
z_lgfr(result, Z_R0);
|
||||
z_aghi(result, min_cnt/2); // min_cnt/2 characters have already been written
|
||||
// but ptrs were not updated yet.
|
||||
z_sgfr(Rdst, Z_R0); // restore ptr
|
||||
z_sgfr(Rsrc, Z_R0); // restore ptr, double the element count for Rsrc restore
|
||||
z_sgfr(Rsrc, Z_R0);
|
||||
z_bru(AllDone);
|
||||
}
|
||||
bind(UnrolledDone);
|
||||
}
|
||||
z_stcmh(Z_R0, 5, 0, addr2);
|
||||
z_stcm(Z_R0, 5, 2, addr2);
|
||||
if (!precise) { z_ogr(Z_R0, Z_R1); }
|
||||
z_stcmh(Z_R1, 5, 4, addr2);
|
||||
z_stcm(Z_R1, 5, 6, addr2);
|
||||
if (!precise) {
|
||||
z_ngr(Z_R0, mask);
|
||||
z_brne(Ldone); // Failed (more than needed was written).
|
||||
|
||||
{
|
||||
Label ScalarLoop, ScalarDone, ScalarBreak;
|
||||
|
||||
bind(ScalarShortcut);
|
||||
z_ltgfr(result, Rcnt);
|
||||
z_brz(AllDone);
|
||||
|
||||
#if 0 // Sacrifice shortcuts for code compactness
|
||||
{
|
||||
//---< Special treatment for very short strings (one or two characters) >---
|
||||
// For these strings, we are sure that the above code was skipped.
|
||||
// Thus, no registers were modified, register restore is not required.
|
||||
Label ScalarDoit, Scalar2Char;
|
||||
z_chi(Rcnt, 2);
|
||||
z_brh(ScalarDoit);
|
||||
z_llh(Z_R1, 0, Z_R0, Rsrc);
|
||||
z_bre(Scalar2Char);
|
||||
z_tmll(Z_R1, 0xff00);
|
||||
z_lghi(result, 0); // cnt == 1, first char invalid, no chars successfully processed
|
||||
z_brnaz(AllDone);
|
||||
z_stc(Z_R1, 0, Z_R0, Rdst);
|
||||
z_lghi(result, 1);
|
||||
z_bru(AllDone);
|
||||
|
||||
bind(Scalar2Char);
|
||||
z_llh(Z_R0, 2, Z_R0, Rsrc);
|
||||
z_tmll(Z_R1, 0xff00);
|
||||
z_lghi(result, 0); // cnt == 2, first char invalid, no chars successfully processed
|
||||
z_brnaz(AllDone);
|
||||
z_stc(Z_R1, 0, Z_R0, Rdst);
|
||||
z_tmll(Z_R0, 0xff00);
|
||||
z_lghi(result, 1); // cnt == 2, second char invalid, one char successfully processed
|
||||
z_brnaz(AllDone);
|
||||
z_stc(Z_R0, 1, Z_R0, Rdst);
|
||||
z_lghi(result, 2);
|
||||
z_bru(AllDone);
|
||||
|
||||
bind(ScalarDoit);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
z_srk(Rix, Rcnt, Z_R0); // remaining # chars to compress in unrolled loop
|
||||
} else {
|
||||
z_lr(Rix, Rcnt);
|
||||
z_sr(Rix, Z_R0);
|
||||
}
|
||||
z_lgfr(result, Rcnt); // # processed characters (if all runs ok).
|
||||
z_brz(ScalarDone);
|
||||
|
||||
bind(ScalarLoop);
|
||||
z_llh(Z_R1, 0, Z_R0, Rsrc);
|
||||
z_tmll(Z_R1, 0xff00);
|
||||
z_brnaz(ScalarBreak);
|
||||
z_stc(Z_R1, 0, Z_R0, Rdst);
|
||||
add2reg(Rsrc, 2);
|
||||
add2reg(Rdst, 1);
|
||||
z_brct(Rix, ScalarLoop);
|
||||
|
||||
z_bru(ScalarDone);
|
||||
|
||||
bind(ScalarBreak);
|
||||
z_sr(result, Rix);
|
||||
|
||||
bind(ScalarDone);
|
||||
z_sgfr(Rdst, result); // restore ptr
|
||||
z_sgfr(Rsrc, result); // restore ptr, double the element count for Rsrc restore
|
||||
z_sgfr(Rsrc, result);
|
||||
}
|
||||
z_aghi(addr2, 8);
|
||||
z_brxle(ind1, even_reg, Lloop1);
|
||||
|
||||
bind(Lslow);
|
||||
// Compute index limit and skip if negative.
|
||||
z_ahi(odd_reg, 16-2); // Last possible index for slow loop.
|
||||
z_lhi(even_reg, 2);
|
||||
z_cr(ind1, odd_reg);
|
||||
z_brh(Ldone);
|
||||
|
||||
bind(Lloop2); // 1 Character per iteration.
|
||||
z_llh(Z_R0, Address(src, ind1));
|
||||
z_tmll(Z_R0, 0xFF00);
|
||||
z_brnaz(Ldone); // Failed slow case: Return number of written characters.
|
||||
z_stc(Z_R0, Address(addr2));
|
||||
z_aghi(addr2, 1);
|
||||
z_brxle(ind1, even_reg, Lloop2);
|
||||
|
||||
bind(Ldone); // result = ind1 = 2*cnt
|
||||
z_srl(ind1, 1);
|
||||
|
||||
BLOCK_COMMENT("} string_compress");
|
||||
bind(AllDone);
|
||||
|
||||
if (precise) {
|
||||
BLOCK_COMMENT("} encode_iso_array");
|
||||
} else {
|
||||
BLOCK_COMMENT("} string_compress");
|
||||
}
|
||||
return offset() - block_start;
|
||||
}
|
||||
|
||||
@ -4997,53 +5222,432 @@ unsigned int MacroAssembler::string_inflate_trot(Register src, Register dst, Reg
|
||||
return offset() - block_start;
|
||||
}
|
||||
|
||||
// Inflate byte[] to char[]. odd_reg contains cnt. Kills src.
|
||||
unsigned int MacroAssembler::string_inflate(Register src, Register dst, Register odd_reg,
|
||||
Register even_reg, Register tmp) {
|
||||
int block_start = offset();
|
||||
// Inflate byte[] to char[].
|
||||
// Restores: src, dst
|
||||
// Uses: cnt
|
||||
// Kills: tmp, Z_R0, Z_R1.
|
||||
// Note:
|
||||
// cnt is signed int. Do not rely on high word!
|
||||
// counts # characters, not bytes.
|
||||
unsigned int MacroAssembler::string_inflate(Register src, Register dst, Register cnt, Register tmp) {
|
||||
assert_different_registers(Z_R0, Z_R1, src, dst, cnt, tmp);
|
||||
|
||||
BLOCK_COMMENT("string_inflate {");
|
||||
int block_start = offset();
|
||||
|
||||
Label Lloop1, Lloop2, Lslow, Ldone;
|
||||
const Register addr1 = src, ind2 = tmp;
|
||||
Register Rcnt = cnt; // # characters (src: bytes, dst: char (2-byte)), remaining after current loop.
|
||||
Register Rix = tmp; // loop index
|
||||
Register Rsrc = src; // addr(src array)
|
||||
Register Rdst = dst; // addr(dst array)
|
||||
Label ScalarShortcut, AllDone;
|
||||
|
||||
z_sll(odd_reg, 1); // Number of bytes to write. (Must be a positive simm32.)
|
||||
clear_reg(ind2); // Index to write.
|
||||
z_ahi(odd_reg, -16); // Last possible index for fast loop.
|
||||
z_brl(Lslow);
|
||||
#if 0 // Sacrifice shortcuts for code compactness
|
||||
{
|
||||
//---< shortcuts for short strings (very frequent) >---
|
||||
Label skipShortcut, skip4Shortcut;
|
||||
z_ltr(Rcnt, Rcnt); // absolutely nothing to do for strings of len == 0.
|
||||
z_brz(AllDone);
|
||||
clear_reg(Z_R0); // make sure registers are properly initialized.
|
||||
clear_reg(Z_R1);
|
||||
z_chi(Rcnt, 4);
|
||||
z_brne(skip4Shortcut); // 4 characters are very frequent
|
||||
z_icm(Z_R0, 5, 0, Rsrc); // Treat exactly 4 characters specially.
|
||||
z_icm(Z_R1, 5, 2, Rsrc);
|
||||
z_stm(Z_R0, Z_R1, 0, Rdst);
|
||||
z_bru(AllDone);
|
||||
bind(skip4Shortcut);
|
||||
|
||||
// ind2: index, even_reg: index increment, odd_reg: index limit
|
||||
clear_reg(Z_R0);
|
||||
clear_reg(Z_R1);
|
||||
z_lhi(even_reg, 16);
|
||||
z_chi(Rcnt, 8);
|
||||
z_brh(skipShortcut); // There's a lot to do...
|
||||
z_lgfr(Z_R0, Rcnt); // remaining #characters (<= 8). Precond for scalar loop.
|
||||
// This does not destroy the "register cleared" state of Z_R0.
|
||||
z_brl(ScalarShortcut); // Just a few characters
|
||||
z_icmh(Z_R0, 5, 0, Rsrc); // Treat exactly 8 characters specially.
|
||||
z_icmh(Z_R1, 5, 4, Rsrc);
|
||||
z_icm(Z_R0, 5, 2, Rsrc);
|
||||
z_icm(Z_R1, 5, 6, Rsrc);
|
||||
z_stmg(Z_R0, Z_R1, 0, Rdst);
|
||||
z_bru(AllDone);
|
||||
bind(skipShortcut);
|
||||
}
|
||||
#endif
|
||||
clear_reg(Z_R0); // make sure register is properly initialized.
|
||||
|
||||
bind(Lloop1); // 8 Characters per iteration.
|
||||
z_icmh(Z_R0, 5, 0, addr1);
|
||||
z_icmh(Z_R1, 5, 4, addr1);
|
||||
z_icm(Z_R0, 5, 2, addr1);
|
||||
z_icm(Z_R1, 5, 6, addr1);
|
||||
z_aghi(addr1, 8);
|
||||
z_stg(Z_R0, Address(dst, ind2));
|
||||
z_stg(Z_R1, Address(dst, ind2, 8));
|
||||
z_brxle(ind2, even_reg, Lloop1);
|
||||
if (VM_Version::has_VectorFacility()) {
|
||||
const int min_vcnt = 32; // Minimum #characters required to use vector instructions.
|
||||
// Otherwise just do nothing in vector mode.
|
||||
// Must be multiple of vector register length (16 bytes = 128 bits).
|
||||
const int log_min_vcnt = exact_log2(min_vcnt);
|
||||
Label VectorLoop, VectorDone;
|
||||
|
||||
bind(Lslow);
|
||||
// Compute index limit and skip if negative.
|
||||
z_ahi(odd_reg, 16-2); // Last possible index for slow loop.
|
||||
z_lhi(even_reg, 2);
|
||||
z_cr(ind2, odd_reg);
|
||||
z_brh(Ldone);
|
||||
assert(VM_Version::has_DistinctOpnds(), "Assumption when has_VectorFacility()");
|
||||
z_srak(Rix, Rcnt, log_min_vcnt); // calculate # vector loop iterations
|
||||
z_brz(VectorDone); // skip if none
|
||||
|
||||
bind(Lloop2); // 1 Character per iteration.
|
||||
z_llc(Z_R0, Address(addr1));
|
||||
z_sth(Z_R0, Address(dst, ind2));
|
||||
z_aghi(addr1, 1);
|
||||
z_brxle(ind2, even_reg, Lloop2);
|
||||
z_sllg(Z_R0, Rix, log_min_vcnt); // remember #chars that will be processed by vector loop
|
||||
|
||||
bind(Ldone);
|
||||
bind(VectorLoop);
|
||||
z_vlm(Z_V20, Z_V21, 0, Rsrc); // get next 32 characters (single-byte)
|
||||
add2reg(Rsrc, min_vcnt);
|
||||
|
||||
z_vuplhb(Z_V22, Z_V20); // V2 <- (expand) V0(high)
|
||||
z_vupllb(Z_V23, Z_V20); // V3 <- (expand) V0(low)
|
||||
z_vuplhb(Z_V24, Z_V21); // V4 <- (expand) V1(high)
|
||||
z_vupllb(Z_V25, Z_V21); // V5 <- (expand) V1(low)
|
||||
z_vstm(Z_V22, Z_V25, 0, Rdst); // store next 32 bytes
|
||||
add2reg(Rdst, min_vcnt*2);
|
||||
|
||||
z_brct(Rix, VectorLoop);
|
||||
|
||||
bind(VectorDone);
|
||||
}
|
||||
|
||||
const int min_cnt = 8; // Minimum #characters required to use unrolled scalar loop.
|
||||
// Otherwise just do nothing in unrolled scalar mode.
|
||||
// Must be multiple of 8.
|
||||
{
|
||||
const int log_min_cnt = exact_log2(min_cnt);
|
||||
Label UnrolledLoop, UnrolledDone;
|
||||
|
||||
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
z_srk(Rix, Rcnt, Z_R0); // remaining # chars to process in unrolled loop
|
||||
} else {
|
||||
z_lr(Rix, Rcnt);
|
||||
z_sr(Rix, Z_R0);
|
||||
}
|
||||
z_sra(Rix, log_min_cnt); // unrolled loop count
|
||||
z_brz(UnrolledDone);
|
||||
|
||||
clear_reg(Z_R0);
|
||||
clear_reg(Z_R1);
|
||||
|
||||
bind(UnrolledLoop);
|
||||
z_icmh(Z_R0, 5, 0, Rsrc);
|
||||
z_icmh(Z_R1, 5, 4, Rsrc);
|
||||
z_icm(Z_R0, 5, 2, Rsrc);
|
||||
z_icm(Z_R1, 5, 6, Rsrc);
|
||||
add2reg(Rsrc, min_cnt);
|
||||
|
||||
z_stmg(Z_R0, Z_R1, 0, Rdst);
|
||||
|
||||
add2reg(Rdst, min_cnt*2);
|
||||
z_brct(Rix, UnrolledLoop);
|
||||
|
||||
bind(UnrolledDone);
|
||||
z_lgfr(Z_R0, Rcnt); // # chars left over after unrolled loop.
|
||||
z_nilf(Z_R0, min_cnt-1);
|
||||
z_brnz(ScalarShortcut); // if zero, there is nothing left to do for scalar loop.
|
||||
// Rix == 0 in all cases.
|
||||
z_sgfr(Z_R0, Rcnt); // negative # characters the ptrs have been advanced previously.
|
||||
z_agr(Rdst, Z_R0); // restore ptr, double the element count for Rdst restore.
|
||||
z_agr(Rdst, Z_R0);
|
||||
z_agr(Rsrc, Z_R0); // restore ptr.
|
||||
z_bru(AllDone);
|
||||
}
|
||||
|
||||
{
|
||||
bind(ScalarShortcut);
|
||||
// Z_R0 must contain remaining # characters as 64-bit signed int here.
|
||||
// register contents is preserved over scalar processing (for register fixup).
|
||||
|
||||
#if 0 // Sacrifice shortcuts for code compactness
|
||||
{
|
||||
Label ScalarDefault;
|
||||
z_chi(Rcnt, 2);
|
||||
z_brh(ScalarDefault);
|
||||
z_llc(Z_R0, 0, Z_R0, Rsrc); // 6 bytes
|
||||
z_sth(Z_R0, 0, Z_R0, Rdst); // 4 bytes
|
||||
z_brl(AllDone);
|
||||
z_llc(Z_R0, 1, Z_R0, Rsrc); // 6 bytes
|
||||
z_sth(Z_R0, 2, Z_R0, Rdst); // 4 bytes
|
||||
z_bru(AllDone);
|
||||
bind(ScalarDefault);
|
||||
}
|
||||
#endif
|
||||
|
||||
Label CodeTable;
|
||||
// Some comments on Rix calculation:
|
||||
// - Rcnt is small, therefore no bits shifted out of low word (sll(g) instructions).
|
||||
// - high word of both Rix and Rcnt may contain garbage
|
||||
// - the final lngfr takes care of that garbage, extending the sign to high word
|
||||
z_sllg(Rix, Z_R0, 2); // calculate 10*Rix = (4*Rix + Rix)*2
|
||||
z_ar(Rix, Z_R0);
|
||||
z_larl(Z_R1, CodeTable);
|
||||
z_sll(Rix, 1);
|
||||
z_lngfr(Rix, Rix); // ix range: [0..7], after inversion & mult: [-(7*12)..(0*12)].
|
||||
z_bc(Assembler::bcondAlways, 0, Rix, Z_R1);
|
||||
|
||||
z_llc(Z_R1, 6, Z_R0, Rsrc); // 6 bytes
|
||||
z_sth(Z_R1, 12, Z_R0, Rdst); // 4 bytes
|
||||
|
||||
z_llc(Z_R1, 5, Z_R0, Rsrc);
|
||||
z_sth(Z_R1, 10, Z_R0, Rdst);
|
||||
|
||||
z_llc(Z_R1, 4, Z_R0, Rsrc);
|
||||
z_sth(Z_R1, 8, Z_R0, Rdst);
|
||||
|
||||
z_llc(Z_R1, 3, Z_R0, Rsrc);
|
||||
z_sth(Z_R1, 6, Z_R0, Rdst);
|
||||
|
||||
z_llc(Z_R1, 2, Z_R0, Rsrc);
|
||||
z_sth(Z_R1, 4, Z_R0, Rdst);
|
||||
|
||||
z_llc(Z_R1, 1, Z_R0, Rsrc);
|
||||
z_sth(Z_R1, 2, Z_R0, Rdst);
|
||||
|
||||
z_llc(Z_R1, 0, Z_R0, Rsrc);
|
||||
z_sth(Z_R1, 0, Z_R0, Rdst);
|
||||
bind(CodeTable);
|
||||
|
||||
z_chi(Rcnt, 8); // no fixup for small strings. Rdst, Rsrc were not modified.
|
||||
z_brl(AllDone);
|
||||
|
||||
z_sgfr(Z_R0, Rcnt); // # characters the ptrs have been advanced previously.
|
||||
z_agr(Rdst, Z_R0); // restore ptr, double the element count for Rdst restore.
|
||||
z_agr(Rdst, Z_R0);
|
||||
z_agr(Rsrc, Z_R0); // restore ptr.
|
||||
}
|
||||
bind(AllDone);
|
||||
|
||||
BLOCK_COMMENT("} string_inflate");
|
||||
return offset() - block_start;
|
||||
}
|
||||
|
||||
// Inflate byte[] to char[], length known at compile time.
|
||||
// Restores: src, dst
|
||||
// Kills: tmp, Z_R0, Z_R1.
|
||||
// Note:
|
||||
// len is signed int. Counts # characters, not bytes.
|
||||
unsigned int MacroAssembler::string_inflate_const(Register src, Register dst, Register tmp, int len) {
|
||||
assert_different_registers(Z_R0, Z_R1, src, dst, tmp);
|
||||
|
||||
BLOCK_COMMENT("string_inflate_const {");
|
||||
int block_start = offset();
|
||||
|
||||
Register Rix = tmp; // loop index
|
||||
Register Rsrc = src; // addr(src array)
|
||||
Register Rdst = dst; // addr(dst array)
|
||||
Label ScalarShortcut, AllDone;
|
||||
int nprocessed = 0;
|
||||
int src_off = 0; // compensate for saved (optimized away) ptr advancement.
|
||||
int dst_off = 0; // compensate for saved (optimized away) ptr advancement.
|
||||
bool restore_inputs = false;
|
||||
bool workreg_clear = false;
|
||||
|
||||
if ((len >= 32) && VM_Version::has_VectorFacility()) {
|
||||
const int min_vcnt = 32; // Minimum #characters required to use vector instructions.
|
||||
// Otherwise just do nothing in vector mode.
|
||||
// Must be multiple of vector register length (16 bytes = 128 bits).
|
||||
const int log_min_vcnt = exact_log2(min_vcnt);
|
||||
const int iterations = (len - nprocessed) >> log_min_vcnt;
|
||||
nprocessed += iterations << log_min_vcnt;
|
||||
Label VectorLoop;
|
||||
|
||||
if (iterations == 1) {
|
||||
z_vlm(Z_V20, Z_V21, 0+src_off, Rsrc); // get next 32 characters (single-byte)
|
||||
z_vuplhb(Z_V22, Z_V20); // V2 <- (expand) V0(high)
|
||||
z_vupllb(Z_V23, Z_V20); // V3 <- (expand) V0(low)
|
||||
z_vuplhb(Z_V24, Z_V21); // V4 <- (expand) V1(high)
|
||||
z_vupllb(Z_V25, Z_V21); // V5 <- (expand) V1(low)
|
||||
z_vstm(Z_V22, Z_V25, 0+dst_off, Rdst); // store next 32 bytes
|
||||
|
||||
src_off += min_vcnt;
|
||||
dst_off += min_vcnt*2;
|
||||
} else {
|
||||
restore_inputs = true;
|
||||
|
||||
z_lgfi(Rix, len>>log_min_vcnt);
|
||||
bind(VectorLoop);
|
||||
z_vlm(Z_V20, Z_V21, 0, Rsrc); // get next 32 characters (single-byte)
|
||||
add2reg(Rsrc, min_vcnt);
|
||||
|
||||
z_vuplhb(Z_V22, Z_V20); // V2 <- (expand) V0(high)
|
||||
z_vupllb(Z_V23, Z_V20); // V3 <- (expand) V0(low)
|
||||
z_vuplhb(Z_V24, Z_V21); // V4 <- (expand) V1(high)
|
||||
z_vupllb(Z_V25, Z_V21); // V5 <- (expand) V1(low)
|
||||
z_vstm(Z_V22, Z_V25, 0, Rdst); // store next 32 bytes
|
||||
add2reg(Rdst, min_vcnt*2);
|
||||
|
||||
z_brct(Rix, VectorLoop);
|
||||
}
|
||||
}
|
||||
|
||||
if (((len-nprocessed) >= 16) && VM_Version::has_VectorFacility()) {
|
||||
const int min_vcnt = 16; // Minimum #characters required to use vector instructions.
|
||||
// Otherwise just do nothing in vector mode.
|
||||
// Must be multiple of vector register length (16 bytes = 128 bits).
|
||||
const int log_min_vcnt = exact_log2(min_vcnt);
|
||||
const int iterations = (len - nprocessed) >> log_min_vcnt;
|
||||
nprocessed += iterations << log_min_vcnt;
|
||||
assert(iterations == 1, "must be!");
|
||||
|
||||
z_vl(Z_V20, 0+src_off, Z_R0, Rsrc); // get next 16 characters (single-byte)
|
||||
z_vuplhb(Z_V22, Z_V20); // V2 <- (expand) V0(high)
|
||||
z_vupllb(Z_V23, Z_V20); // V3 <- (expand) V0(low)
|
||||
z_vstm(Z_V22, Z_V23, 0+dst_off, Rdst); // store next 32 bytes
|
||||
|
||||
src_off += min_vcnt;
|
||||
dst_off += min_vcnt*2;
|
||||
}
|
||||
|
||||
if ((len-nprocessed) > 8) {
|
||||
const int min_cnt = 8; // Minimum #characters required to use unrolled scalar loop.
|
||||
// Otherwise just do nothing in unrolled scalar mode.
|
||||
// Must be multiple of 8.
|
||||
const int log_min_cnt = exact_log2(min_cnt);
|
||||
const int iterations = (len - nprocessed) >> log_min_cnt;
|
||||
nprocessed += iterations << log_min_cnt;
|
||||
|
||||
//---< avoid loop overhead/ptr increment for small # iterations >---
|
||||
if (iterations <= 2) {
|
||||
clear_reg(Z_R0);
|
||||
clear_reg(Z_R1);
|
||||
workreg_clear = true;
|
||||
|
||||
z_icmh(Z_R0, 5, 0+src_off, Rsrc);
|
||||
z_icmh(Z_R1, 5, 4+src_off, Rsrc);
|
||||
z_icm(Z_R0, 5, 2+src_off, Rsrc);
|
||||
z_icm(Z_R1, 5, 6+src_off, Rsrc);
|
||||
z_stmg(Z_R0, Z_R1, 0+dst_off, Rdst);
|
||||
|
||||
src_off += min_cnt;
|
||||
dst_off += min_cnt*2;
|
||||
}
|
||||
|
||||
if (iterations == 2) {
|
||||
z_icmh(Z_R0, 5, 0+src_off, Rsrc);
|
||||
z_icmh(Z_R1, 5, 4+src_off, Rsrc);
|
||||
z_icm(Z_R0, 5, 2+src_off, Rsrc);
|
||||
z_icm(Z_R1, 5, 6+src_off, Rsrc);
|
||||
z_stmg(Z_R0, Z_R1, 0+dst_off, Rdst);
|
||||
|
||||
src_off += min_cnt;
|
||||
dst_off += min_cnt*2;
|
||||
}
|
||||
|
||||
if (iterations > 2) {
|
||||
Label UnrolledLoop;
|
||||
restore_inputs = true;
|
||||
|
||||
clear_reg(Z_R0);
|
||||
clear_reg(Z_R1);
|
||||
workreg_clear = true;
|
||||
|
||||
z_lgfi(Rix, iterations);
|
||||
bind(UnrolledLoop);
|
||||
z_icmh(Z_R0, 5, 0, Rsrc);
|
||||
z_icmh(Z_R1, 5, 4, Rsrc);
|
||||
z_icm(Z_R0, 5, 2, Rsrc);
|
||||
z_icm(Z_R1, 5, 6, Rsrc);
|
||||
add2reg(Rsrc, min_cnt);
|
||||
|
||||
z_stmg(Z_R0, Z_R1, 0, Rdst);
|
||||
add2reg(Rdst, min_cnt*2);
|
||||
|
||||
z_brct(Rix, UnrolledLoop);
|
||||
}
|
||||
}
|
||||
|
||||
if ((len-nprocessed) > 0) {
|
||||
switch (len-nprocessed) {
|
||||
case 8:
|
||||
if (!workreg_clear) {
|
||||
clear_reg(Z_R0);
|
||||
clear_reg(Z_R1);
|
||||
}
|
||||
z_icmh(Z_R0, 5, 0+src_off, Rsrc);
|
||||
z_icmh(Z_R1, 5, 4+src_off, Rsrc);
|
||||
z_icm(Z_R0, 5, 2+src_off, Rsrc);
|
||||
z_icm(Z_R1, 5, 6+src_off, Rsrc);
|
||||
z_stmg(Z_R0, Z_R1, 0+dst_off, Rdst);
|
||||
break;
|
||||
case 7:
|
||||
if (!workreg_clear) {
|
||||
clear_reg(Z_R0);
|
||||
clear_reg(Z_R1);
|
||||
}
|
||||
clear_reg(Rix);
|
||||
z_icm(Z_R0, 5, 0+src_off, Rsrc);
|
||||
z_icm(Z_R1, 5, 2+src_off, Rsrc);
|
||||
z_icm(Rix, 5, 4+src_off, Rsrc);
|
||||
z_stm(Z_R0, Z_R1, 0+dst_off, Rdst);
|
||||
z_llc(Z_R0, 6+src_off, Z_R0, Rsrc);
|
||||
z_st(Rix, 8+dst_off, Z_R0, Rdst);
|
||||
z_sth(Z_R0, 12+dst_off, Z_R0, Rdst);
|
||||
break;
|
||||
case 6:
|
||||
if (!workreg_clear) {
|
||||
clear_reg(Z_R0);
|
||||
clear_reg(Z_R1);
|
||||
}
|
||||
clear_reg(Rix);
|
||||
z_icm(Z_R0, 5, 0+src_off, Rsrc);
|
||||
z_icm(Z_R1, 5, 2+src_off, Rsrc);
|
||||
z_icm(Rix, 5, 4+src_off, Rsrc);
|
||||
z_stm(Z_R0, Z_R1, 0+dst_off, Rdst);
|
||||
z_st(Rix, 8+dst_off, Z_R0, Rdst);
|
||||
break;
|
||||
case 5:
|
||||
if (!workreg_clear) {
|
||||
clear_reg(Z_R0);
|
||||
clear_reg(Z_R1);
|
||||
}
|
||||
z_icm(Z_R0, 5, 0+src_off, Rsrc);
|
||||
z_icm(Z_R1, 5, 2+src_off, Rsrc);
|
||||
z_llc(Rix, 4+src_off, Z_R0, Rsrc);
|
||||
z_stm(Z_R0, Z_R1, 0+dst_off, Rdst);
|
||||
z_sth(Rix, 8+dst_off, Z_R0, Rdst);
|
||||
break;
|
||||
case 4:
|
||||
if (!workreg_clear) {
|
||||
clear_reg(Z_R0);
|
||||
clear_reg(Z_R1);
|
||||
}
|
||||
z_icm(Z_R0, 5, 0+src_off, Rsrc);
|
||||
z_icm(Z_R1, 5, 2+src_off, Rsrc);
|
||||
z_stm(Z_R0, Z_R1, 0+dst_off, Rdst);
|
||||
break;
|
||||
case 3:
|
||||
if (!workreg_clear) {
|
||||
clear_reg(Z_R0);
|
||||
}
|
||||
z_llc(Z_R1, 2+src_off, Z_R0, Rsrc);
|
||||
z_icm(Z_R0, 5, 0+src_off, Rsrc);
|
||||
z_sth(Z_R1, 4+dst_off, Z_R0, Rdst);
|
||||
z_st(Z_R0, 0+dst_off, Rdst);
|
||||
break;
|
||||
case 2:
|
||||
z_llc(Z_R0, 0+src_off, Z_R0, Rsrc);
|
||||
z_llc(Z_R1, 1+src_off, Z_R0, Rsrc);
|
||||
z_sth(Z_R0, 0+dst_off, Z_R0, Rdst);
|
||||
z_sth(Z_R1, 2+dst_off, Z_R0, Rdst);
|
||||
break;
|
||||
case 1:
|
||||
z_llc(Z_R0, 0+src_off, Z_R0, Rsrc);
|
||||
z_sth(Z_R0, 0+dst_off, Z_R0, Rdst);
|
||||
break;
|
||||
default:
|
||||
guarantee(false, "Impossible");
|
||||
break;
|
||||
}
|
||||
src_off += len-nprocessed;
|
||||
dst_off += (len-nprocessed)*2;
|
||||
nprocessed = len;
|
||||
}
|
||||
|
||||
//---< restore modified input registers >---
|
||||
if ((nprocessed > 0) && restore_inputs) {
|
||||
z_agfi(Rsrc, -(nprocessed-src_off));
|
||||
if (nprocessed < 1000000000) { // avoid int overflow
|
||||
z_agfi(Rdst, -(nprocessed*2-dst_off));
|
||||
} else {
|
||||
z_agfi(Rdst, -(nprocessed-dst_off));
|
||||
z_agfi(Rdst, -nprocessed);
|
||||
}
|
||||
}
|
||||
|
||||
BLOCK_COMMENT("} string_inflate_const");
|
||||
return offset() - block_start;
|
||||
}
|
||||
|
||||
|
@ -198,6 +198,9 @@ class MacroAssembler: public Assembler {
|
||||
// Test a bit in a register. Result is reflected in CC.
|
||||
void testbit(Register r, unsigned int bitPos);
|
||||
|
||||
void prefetch_read(Address a);
|
||||
void prefetch_update(Address a);
|
||||
|
||||
// Clear a register, i.e. load const zero into reg. Return len (in bytes) of
|
||||
// generated instruction(s).
|
||||
// whole_reg: Clear 64 bits if true, 32 bits otherwise.
|
||||
@ -836,7 +839,7 @@ class MacroAssembler: public Assembler {
|
||||
void load_mirror(Register mirror, Register method);
|
||||
|
||||
//--------------------------
|
||||
//--- perations on arrays.
|
||||
//--- Operations on arrays.
|
||||
//--------------------------
|
||||
unsigned int Clear_Array(Register cnt_arg, Register base_pointer_arg, Register src_addr, Register src_len);
|
||||
unsigned int Clear_Array_Const(long cnt, Register base);
|
||||
@ -849,20 +852,34 @@ class MacroAssembler: public Assembler {
|
||||
// Special String Intrinsics Implementation.
|
||||
//-------------------------------------------
|
||||
// Intrinsics for CompactStrings
|
||||
// Compress char[] to byte[]. odd_reg contains cnt. tmp3 is only needed for precise behavior in failure case. Kills dst.
|
||||
unsigned int string_compress(Register result, Register src, Register dst, Register odd_reg,
|
||||
Register even_reg, Register tmp, Register tmp2 = noreg);
|
||||
// Restores: src, dst
|
||||
// Uses: cnt
|
||||
// Kills: tmp, Z_R0, Z_R1.
|
||||
// Early clobber: result.
|
||||
// Boolean precise controls accuracy of result value.
|
||||
unsigned int string_compress(Register result, Register src, Register dst, Register cnt,
|
||||
Register tmp, bool precise);
|
||||
|
||||
// Inflate byte[] to char[].
|
||||
unsigned int string_inflate_trot(Register src, Register dst, Register cnt, Register tmp);
|
||||
|
||||
// Inflate byte[] to char[].
|
||||
// Restores: src, dst
|
||||
// Uses: cnt
|
||||
// Kills: tmp, Z_R0, Z_R1.
|
||||
unsigned int string_inflate(Register src, Register dst, Register cnt, Register tmp);
|
||||
|
||||
// Inflate byte[] to char[], length known at compile time.
|
||||
// Restores: src, dst
|
||||
// Kills: tmp, Z_R0, Z_R1.
|
||||
// Note:
|
||||
// len is signed int. Counts # characters, not bytes.
|
||||
unsigned int string_inflate_const(Register src, Register dst, Register tmp, int len);
|
||||
|
||||
// Kills src.
|
||||
unsigned int has_negatives(Register result, Register src, Register cnt,
|
||||
Register odd_reg, Register even_reg, Register tmp);
|
||||
|
||||
// Inflate byte[] to char[].
|
||||
unsigned int string_inflate_trot(Register src, Register dst, Register cnt, Register tmp);
|
||||
// Odd_reg contains cnt. Kills src.
|
||||
unsigned int string_inflate(Register src, Register dst, Register odd_reg,
|
||||
Register even_reg, Register tmp);
|
||||
|
||||
unsigned int string_compare(Register str1, Register str2, Register cnt1, Register cnt2,
|
||||
Register odd_reg, Register even_reg, Register result, int ae);
|
||||
|
||||
|
@ -10267,14 +10267,14 @@ instruct indexOf_UL(iRegP haystack, rarg2RegI haycnt, iRegP needle, rarg5RegI ne
|
||||
%}
|
||||
|
||||
// char[] to byte[] compression
|
||||
instruct string_compress(iRegP src, rarg5RegP dst, iRegI result, roddRegI len, revenRegI evenReg, iRegI tmp, flagsReg cr) %{
|
||||
instruct string_compress(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tmp, flagsReg cr) %{
|
||||
match(Set result (StrCompressedCopy src (Binary dst len)));
|
||||
effect(TEMP_DEF result, USE_KILL dst, USE_KILL len, TEMP evenReg, TEMP tmp, KILL cr); // R0, R1 are killed, too.
|
||||
effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too.
|
||||
ins_cost(300);
|
||||
format %{ "String Compress $src->$dst($len) -> $result" %}
|
||||
ins_encode %{
|
||||
__ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register,
|
||||
$evenReg$$Register, $tmp$$Register);
|
||||
$tmp$$Register, false);
|
||||
%}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -10293,13 +10293,25 @@ instruct string_compress(iRegP src, rarg5RegP dst, iRegI result, roddRegI len, r
|
||||
//%}
|
||||
|
||||
// byte[] to char[] inflation
|
||||
instruct string_inflate(Universe dummy, rarg5RegP src, iRegP dst, roddRegI len, revenRegI evenReg, iRegI tmp, flagsReg cr) %{
|
||||
instruct string_inflate(Universe dummy, iRegP src, iRegP dst, iRegI len, iRegI tmp, flagsReg cr) %{
|
||||
match(Set dummy (StrInflatedCopy src (Binary dst len)));
|
||||
effect(USE_KILL src, USE_KILL len, TEMP evenReg, TEMP tmp, KILL cr); // R0, R1 are killed, too.
|
||||
effect(TEMP tmp, KILL cr); // R0, R1 are killed, too.
|
||||
ins_cost(300);
|
||||
format %{ "String Inflate $src->$dst($len)" %}
|
||||
ins_encode %{
|
||||
__ string_inflate($src$$Register, $dst$$Register, $len$$Register, $evenReg$$Register, $tmp$$Register);
|
||||
__ string_inflate($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
|
||||
// byte[] to char[] inflation
|
||||
instruct string_inflate_const(Universe dummy, iRegP src, iRegP dst, iRegI tmp, immI len, flagsReg cr) %{
|
||||
match(Set dummy (StrInflatedCopy src (Binary dst len)));
|
||||
effect(TEMP tmp, KILL cr); // R0, R1 are killed, too.
|
||||
ins_cost(300);
|
||||
format %{ "String Inflate (constLen) $src->$dst($len)" %}
|
||||
ins_encode %{
|
||||
__ string_inflate_const($src$$Register, $dst$$Register, $tmp$$Register, $len$$constant);
|
||||
%}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -10318,14 +10330,14 @@ instruct has_negatives(rarg5RegP ary1, iRegI len, iRegI result, roddRegI oddReg,
|
||||
%}
|
||||
|
||||
// encode char[] to byte[] in ISO_8859_1
|
||||
instruct encode_iso_array(rarg5RegP src, iRegP dst, iRegI result, roddRegI len, revenRegI evenReg, iRegI tmp, iRegI tmp2, flagsReg cr) %{
|
||||
instruct encode_iso_array(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tmp, flagsReg cr) %{
|
||||
match(Set result (EncodeISOArray src (Binary dst len)));
|
||||
effect(TEMP_DEF result, USE_KILL src, USE_KILL len, TEMP evenReg, TEMP tmp, TEMP tmp2, KILL cr); // R0, R1 are killed, too.
|
||||
effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too.
|
||||
ins_cost(300);
|
||||
format %{ "Encode array $src->$dst($len) -> $result" %}
|
||||
ins_encode %{
|
||||
__ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register,
|
||||
$evenReg$$Register, $tmp$$Register, $tmp2$$Register);
|
||||
$tmp$$Register, true);
|
||||
%}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
|
@ -398,8 +398,13 @@ void LIR_Assembler::jobject2reg(jobject o, Register reg) {
|
||||
if (o == NULL) {
|
||||
__ set(NULL_WORD, reg);
|
||||
} else {
|
||||
#ifdef ASSERT
|
||||
{
|
||||
ThreadInVMfromNative tiv(JavaThread::current());
|
||||
assert(Universe::heap()->is_in_reserved(JNIHandles::resolve(o)), "should be real oop");
|
||||
}
|
||||
#endif
|
||||
int oop_index = __ oop_recorder()->find_index(o);
|
||||
assert(Universe::heap()->is_in_reserved(JNIHandles::resolve(o)), "should be real oop");
|
||||
RelocationHolder rspec = oop_Relocation::spec(oop_index);
|
||||
__ set(NULL_WORD, reg, rspec); // Will be set when the nmethod is created
|
||||
}
|
||||
|
@ -898,7 +898,9 @@ class StubGenerator: public StubCodeGenerator {
|
||||
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
|
||||
assert_different_registers(addr, count, tmp);
|
||||
|
||||
Label L_loop;
|
||||
Label L_loop, L_done;
|
||||
|
||||
__ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_done); // zero count - nothing to do
|
||||
|
||||
__ sll_ptr(count, LogBytesPerHeapOop, count);
|
||||
__ sub(count, BytesPerHeapOop, count);
|
||||
@ -914,6 +916,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ subcc(count, 1, count);
|
||||
__ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
|
||||
__ delayed()->add(addr, 1, addr);
|
||||
__ BIND(L_done);
|
||||
}
|
||||
break;
|
||||
case BarrierSet::ModRef:
|
||||
|
@ -1264,9 +1264,12 @@ class StubGenerator: public StubCodeGenerator {
|
||||
CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(bs);
|
||||
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
|
||||
|
||||
Label L_loop;
|
||||
Label L_loop, L_done;
|
||||
const Register end = count;
|
||||
|
||||
__ testl(count, count);
|
||||
__ jcc(Assembler::zero, L_done); // zero count - nothing to do
|
||||
|
||||
__ leaq(end, Address(start, count, TIMES_OOP, 0)); // end == start+count*oop_size
|
||||
__ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive
|
||||
__ shrptr(start, CardTableModRefBS::card_shift);
|
||||
@ -1280,6 +1283,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ movb(Address(start, count, Address::times_1), 0);
|
||||
__ decrement(count);
|
||||
__ jcc(Assembler::greaterEqual, L_loop);
|
||||
__ BIND(L_done);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadCritical.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/timer.hpp"
|
||||
#include "semaphore_posix.hpp"
|
||||
#include "services/attachListener.hpp"
|
||||
@ -1646,7 +1647,10 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
||||
//
|
||||
// Dynamic loader will make all stacks executable after
|
||||
// this function returns, and will not do that again.
|
||||
assert(Threads::first() == NULL, "no Java threads should exist yet.");
|
||||
#ifdef ASSERT
|
||||
ThreadsListHandle tlh;
|
||||
assert(tlh.length() == 0, "no Java threads should exist yet.");
|
||||
#endif
|
||||
} else {
|
||||
warning("You have loaded library %s which might have disabled stack guard. "
|
||||
"The VM will try to fix the stack guard now.\n"
|
||||
@ -1874,16 +1878,13 @@ void * os::Linux::dll_load_in_vmthread(const char *filename, char *ebuf,
|
||||
// may have been queued at the same time.
|
||||
|
||||
if (!_stack_is_executable) {
|
||||
JavaThread *jt = Threads::first();
|
||||
|
||||
while (jt) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
|
||||
if (!jt->stack_guard_zone_unused() && // Stack not yet fully initialized
|
||||
jt->stack_guards_enabled()) { // No pending stack overflow exceptions
|
||||
if (!os::guard_memory((char *)jt->stack_end(), jt->stack_guard_zone_size())) {
|
||||
warning("Attempt to reguard stack yellow zone failed.");
|
||||
}
|
||||
}
|
||||
jt = jt->next();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4947,25 +4948,20 @@ jint os::init_2(void) {
|
||||
UseNUMA = false;
|
||||
}
|
||||
}
|
||||
// With SHM and HugeTLBFS large pages we cannot uncommit a page, so there's no way
|
||||
// we can make the adaptive lgrp chunk resizing work. If the user specified
|
||||
// both UseNUMA and UseLargePages (or UseSHM/UseHugeTLBFS) on the command line - warn and
|
||||
// disable adaptive resizing.
|
||||
if (UseNUMA && UseLargePages && !can_commit_large_page_memory()) {
|
||||
if (FLAG_IS_DEFAULT(UseNUMA)) {
|
||||
UseNUMA = false;
|
||||
} else {
|
||||
if (FLAG_IS_DEFAULT(UseLargePages) &&
|
||||
FLAG_IS_DEFAULT(UseSHM) &&
|
||||
FLAG_IS_DEFAULT(UseHugeTLBFS)) {
|
||||
UseLargePages = false;
|
||||
} else if (UseAdaptiveSizePolicy || UseAdaptiveNUMAChunkSizing) {
|
||||
warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing (-XX:-UseAdaptiveSizePolicy -XX:-UseAdaptiveNUMAChunkSizing)");
|
||||
UseAdaptiveSizePolicy = false;
|
||||
UseAdaptiveNUMAChunkSizing = false;
|
||||
}
|
||||
|
||||
if (UseParallelGC && UseNUMA && UseLargePages && !can_commit_large_page_memory()) {
|
||||
// With SHM and HugeTLBFS large pages we cannot uncommit a page, so there's no way
|
||||
// we can make the adaptive lgrp chunk resizing work. If the user specified both
|
||||
// UseNUMA and UseLargePages (or UseSHM/UseHugeTLBFS) on the command line - warn
|
||||
// and disable adaptive resizing.
|
||||
if (UseAdaptiveSizePolicy || UseAdaptiveNUMAChunkSizing) {
|
||||
warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, "
|
||||
"disabling adaptive resizing (-XX:-UseAdaptiveSizePolicy -XX:-UseAdaptiveNUMAChunkSizing)");
|
||||
UseAdaptiveSizePolicy = false;
|
||||
UseAdaptiveNUMAChunkSizing = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!UseNUMA && ForceNUMA) {
|
||||
UseNUMA = true;
|
||||
}
|
||||
|
@ -478,8 +478,7 @@ int os::sleep(Thread* thread, jlong millis, bool interruptible) {
|
||||
// interrupt support
|
||||
|
||||
void os::interrupt(Thread* thread) {
|
||||
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
|
||||
"possibility of dangling Thread pointer");
|
||||
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
|
||||
|
||||
OSThread* osthread = thread->osthread();
|
||||
|
||||
@ -499,12 +498,10 @@ void os::interrupt(Thread* thread) {
|
||||
|
||||
ParkEvent * ev = thread->_ParkEvent ;
|
||||
if (ev != NULL) ev->unpark() ;
|
||||
|
||||
}
|
||||
|
||||
bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
|
||||
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
|
||||
"possibility of dangling Thread pointer");
|
||||
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
|
||||
|
||||
OSThread* osthread = thread->osthread();
|
||||
|
||||
|
@ -3490,9 +3490,7 @@ OSReturn os::get_native_priority(const Thread* const thread,
|
||||
void os::hint_no_preempt() {}
|
||||
|
||||
void os::interrupt(Thread* thread) {
|
||||
assert(!thread->is_Java_thread() || Thread::current() == thread ||
|
||||
Threads_lock->owned_by_self(),
|
||||
"possibility of dangling Thread pointer");
|
||||
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
|
||||
|
||||
OSThread* osthread = thread->osthread();
|
||||
osthread->set_interrupted(true);
|
||||
@ -3513,8 +3511,7 @@ void os::interrupt(Thread* thread) {
|
||||
|
||||
|
||||
bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
|
||||
assert(!thread->is_Java_thread() || Thread::current() == thread || Threads_lock->owned_by_self(),
|
||||
"possibility of dangling Thread pointer");
|
||||
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
|
||||
|
||||
OSThread* osthread = thread->osthread();
|
||||
// There is no synchronization between the setting of the interrupt
|
||||
|
@ -30,74 +30,6 @@
|
||||
|
||||
// Implementation of class atomic
|
||||
|
||||
#ifdef M68K
|
||||
|
||||
/*
|
||||
* __m68k_cmpxchg
|
||||
*
|
||||
* Atomically store newval in *ptr if *ptr is equal to oldval for user space.
|
||||
* Returns newval on success and oldval if no exchange happened.
|
||||
* This implementation is processor specific and works on
|
||||
* 68020 68030 68040 and 68060.
|
||||
*
|
||||
* It will not work on ColdFire, 68000 and 68010 since they lack the CAS
|
||||
* instruction.
|
||||
* Using a kernelhelper would be better for arch complete implementation.
|
||||
*
|
||||
*/
|
||||
|
||||
static inline int __m68k_cmpxchg(int oldval, int newval, volatile int *ptr) {
|
||||
int ret;
|
||||
__asm __volatile ("cas%.l %0,%2,%1"
|
||||
: "=d" (ret), "+m" (*(ptr))
|
||||
: "d" (newval), "0" (oldval));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Perform an atomic compare and swap: if the current value of `*PTR'
|
||||
is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of
|
||||
`*PTR' before the operation.*/
|
||||
static inline int m68k_compare_and_swap(int newval,
|
||||
volatile int *ptr,
|
||||
int oldval) {
|
||||
for (;;) {
|
||||
int prev = *ptr;
|
||||
if (prev != oldval)
|
||||
return prev;
|
||||
|
||||
if (__m68k_cmpxchg (prev, newval, ptr) == newval)
|
||||
// Success.
|
||||
return prev;
|
||||
|
||||
// We failed even though prev == oldval. Try again.
|
||||
}
|
||||
}
|
||||
|
||||
/* Atomically add an int to memory. */
|
||||
static inline int m68k_add_and_fetch(int add_value, volatile int *ptr) {
|
||||
for (;;) {
|
||||
// Loop until success.
|
||||
|
||||
int prev = *ptr;
|
||||
|
||||
if (__m68k_cmpxchg (prev, prev + add_value, ptr) == prev + add_value)
|
||||
return prev + add_value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Atomically write VALUE into `*PTR' and returns the previous
|
||||
contents of `*PTR'. */
|
||||
static inline int m68k_lock_test_and_set(int newval, volatile int *ptr) {
|
||||
for (;;) {
|
||||
// Loop until success.
|
||||
int prev = *ptr;
|
||||
|
||||
if (__m68k_cmpxchg (prev, newval, ptr) == prev)
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
#endif // M68K
|
||||
|
||||
#ifdef ARM
|
||||
|
||||
/*
|
||||
@ -175,12 +107,8 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
|
||||
|
||||
#ifdef ARM
|
||||
return add_using_helper<int>(arm_add_and_fetch, add_value, dest);
|
||||
#else
|
||||
#ifdef M68K
|
||||
return add_using_helper<int>(m68k_add_and_fetch, add_value, dest);
|
||||
#else
|
||||
return __sync_add_and_fetch(dest, add_value);
|
||||
#endif // M68K
|
||||
#endif // ARM
|
||||
}
|
||||
|
||||
@ -200,9 +128,6 @@ inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
|
||||
STATIC_ASSERT(4 == sizeof(T));
|
||||
#ifdef ARM
|
||||
return xchg_using_helper<int>(arm_lock_test_and_set, exchange_value, dest);
|
||||
#else
|
||||
#ifdef M68K
|
||||
return xchg_using_helper<int>(m68k_lock_test_and_set, exchange_value, dest);
|
||||
#else
|
||||
// __sync_lock_test_and_set is a bizarrely named atomic exchange
|
||||
// operation. Note that some platforms only support this with the
|
||||
@ -215,7 +140,6 @@ inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
|
||||
// barrier.
|
||||
__sync_synchronize();
|
||||
return result;
|
||||
#endif // M68K
|
||||
#endif // ARM
|
||||
}
|
||||
|
||||
@ -242,12 +166,8 @@ inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
|
||||
STATIC_ASSERT(4 == sizeof(T));
|
||||
#ifdef ARM
|
||||
return cmpxchg_using_helper<int>(arm_compare_and_swap, exchange_value, dest, compare_value);
|
||||
#else
|
||||
#ifdef M68K
|
||||
return cmpxchg_using_helper<int>(m68k_compare_and_swap, exchange_value, dest, compare_value);
|
||||
#else
|
||||
return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
|
||||
#endif // M68K
|
||||
#endif // ARM
|
||||
}
|
||||
|
||||
|
@ -3441,6 +3441,7 @@ const char* GraphBuilder::check_can_parse(ciMethod* callee) const {
|
||||
if ( callee->is_native()) return "native method";
|
||||
if ( callee->is_abstract()) return "abstract method";
|
||||
if (!callee->can_be_compiled()) return "not compilable (disabled)";
|
||||
if (!callee->can_be_parsed()) return "cannot be parsed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,7 @@ ciMethod::ciMethod(const methodHandle& h_m, ciInstanceKlass* holder) :
|
||||
_balanced_monitors = !_uses_monitors || h_m()->access_flags().is_monitor_matching();
|
||||
_is_c1_compilable = !h_m()->is_not_c1_compilable();
|
||||
_is_c2_compilable = !h_m()->is_not_c2_compilable();
|
||||
_can_be_parsed = true;
|
||||
_has_reserved_stack_access = h_m()->has_reserved_stack_access();
|
||||
// Lazy fields, filled in on demand. Require allocation.
|
||||
_code = NULL;
|
||||
@ -99,12 +100,13 @@ ciMethod::ciMethod(const methodHandle& h_m, ciInstanceKlass* holder) :
|
||||
#endif // COMPILER2
|
||||
|
||||
ciEnv *env = CURRENT_ENV;
|
||||
if (env->jvmti_can_hotswap_or_post_breakpoint() && can_be_compiled()) {
|
||||
if (env->jvmti_can_hotswap_or_post_breakpoint()) {
|
||||
// 6328518 check hotswap conditions under the right lock.
|
||||
MutexLocker locker(Compile_lock);
|
||||
if (Dependencies::check_evol_method(h_m()) != NULL) {
|
||||
_is_c1_compilable = false;
|
||||
_is_c2_compilable = false;
|
||||
_can_be_parsed = false;
|
||||
}
|
||||
} else {
|
||||
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
|
||||
|
@ -87,6 +87,7 @@ class ciMethod : public ciMetadata {
|
||||
bool _balanced_monitors;
|
||||
bool _is_c1_compilable;
|
||||
bool _is_c2_compilable;
|
||||
bool _can_be_parsed;
|
||||
bool _can_be_statically_bound;
|
||||
bool _has_reserved_stack_access;
|
||||
|
||||
@ -291,6 +292,7 @@ class ciMethod : public ciMetadata {
|
||||
bool has_option(const char *option);
|
||||
bool has_option_value(const char* option, double& value);
|
||||
bool can_be_compiled();
|
||||
bool can_be_parsed() const { return _can_be_parsed; }
|
||||
bool can_be_osr_compiled(int entry_bci);
|
||||
void set_not_compilable(const char* reason = NULL);
|
||||
bool has_compiled_code();
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define SHARE_VM_CLASSFILE_CLASSLOADER_HPP
|
||||
|
||||
#include "jimage.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
@ -42,6 +43,7 @@
|
||||
class JImageFile;
|
||||
class ClassFileStream;
|
||||
class PackageEntry;
|
||||
template <typename T> class GrowableArray;
|
||||
|
||||
class ClassPathEntry : public CHeapObj<mtClass> {
|
||||
private:
|
||||
|
@ -259,12 +259,12 @@ void CodeCache::initialize_heaps() {
|
||||
}
|
||||
|
||||
// We do not need the profiled CodeHeap, use all space for the non-profiled CodeHeap
|
||||
if(!heap_available(CodeBlobType::MethodProfiled)) {
|
||||
if (!heap_available(CodeBlobType::MethodProfiled)) {
|
||||
non_profiled_size += profiled_size;
|
||||
profiled_size = 0;
|
||||
}
|
||||
// We do not need the non-profiled CodeHeap, use all space for the non-nmethod CodeHeap
|
||||
if(!heap_available(CodeBlobType::MethodNonProfiled)) {
|
||||
if (!heap_available(CodeBlobType::MethodNonProfiled)) {
|
||||
non_nmethod_size += non_profiled_size;
|
||||
non_profiled_size = 0;
|
||||
}
|
||||
@ -282,10 +282,11 @@ void CodeCache::initialize_heaps() {
|
||||
FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, profiled_size);
|
||||
FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, non_profiled_size);
|
||||
|
||||
// Align CodeHeaps
|
||||
size_t alignment = heap_alignment();
|
||||
// If large page support is enabled, align code heaps according to large
|
||||
// page size to make sure that code cache is covered by large pages.
|
||||
const size_t alignment = MAX2(page_size(false), (size_t) os::vm_allocation_granularity());
|
||||
non_nmethod_size = align_up(non_nmethod_size, alignment);
|
||||
profiled_size = align_down(profiled_size, alignment);
|
||||
profiled_size = align_down(profiled_size, alignment);
|
||||
|
||||
// Reserve one continuous chunk of memory for CodeHeaps and split it into
|
||||
// parts for the individual heaps. The memory layout looks like this:
|
||||
@ -308,37 +309,29 @@ void CodeCache::initialize_heaps() {
|
||||
add_heap(non_profiled_space, "CodeHeap 'non-profiled nmethods'", CodeBlobType::MethodNonProfiled);
|
||||
}
|
||||
|
||||
size_t CodeCache::heap_alignment() {
|
||||
// If large page support is enabled, align code heaps according to large
|
||||
// page size to make sure that code cache is covered by large pages.
|
||||
const size_t page_size = os::can_execute_large_page_memory() ?
|
||||
os::page_size_for_region_unaligned(ReservedCodeCacheSize, 8) :
|
||||
os::vm_page_size();
|
||||
return MAX2(page_size, (size_t) os::vm_allocation_granularity());
|
||||
size_t CodeCache::page_size(bool aligned) {
|
||||
if (os::can_execute_large_page_memory()) {
|
||||
return aligned ? os::page_size_for_region_aligned(ReservedCodeCacheSize, 8) :
|
||||
os::page_size_for_region_unaligned(ReservedCodeCacheSize, 8);
|
||||
} else {
|
||||
return os::vm_page_size();
|
||||
}
|
||||
}
|
||||
|
||||
ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size) {
|
||||
// Determine alignment
|
||||
const size_t page_size = os::can_execute_large_page_memory() ?
|
||||
MIN2(os::page_size_for_region_aligned(InitialCodeCacheSize, 8),
|
||||
os::page_size_for_region_aligned(size, 8)) :
|
||||
os::vm_page_size();
|
||||
const size_t granularity = os::vm_allocation_granularity();
|
||||
const size_t r_align = MAX2(page_size, granularity);
|
||||
const size_t r_size = align_up(size, r_align);
|
||||
const size_t rs_align = page_size == (size_t) os::vm_page_size() ? 0 :
|
||||
MAX2(page_size, granularity);
|
||||
|
||||
ReservedCodeSpace rs(r_size, rs_align, rs_align > 0);
|
||||
|
||||
// Align and reserve space for code cache
|
||||
const size_t rs_ps = page_size();
|
||||
const size_t rs_align = MAX2(rs_ps, (size_t) os::vm_allocation_granularity());
|
||||
const size_t rs_size = align_up(size, rs_align);
|
||||
ReservedCodeSpace rs(rs_size, rs_align, rs_ps > (size_t) os::vm_page_size());
|
||||
if (!rs.is_reserved()) {
|
||||
vm_exit_during_initialization("Could not reserve enough space for code cache");
|
||||
vm_exit_during_initialization(err_msg("Could not reserve enough space for code cache (" SIZE_FORMAT "K)",
|
||||
rs_size/K));
|
||||
}
|
||||
|
||||
// Initialize bounds
|
||||
_low_bound = (address)rs.base();
|
||||
_high_bound = _low_bound + rs.size();
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
@ -415,7 +408,8 @@ void CodeCache::add_heap(ReservedSpace rs, const char* name, int code_blob_type)
|
||||
size_t size_initial = MIN2(InitialCodeCacheSize, rs.size());
|
||||
size_initial = align_up(size_initial, os::vm_page_size());
|
||||
if (!heap->reserve(rs, size_initial, CodeCacheSegmentSize)) {
|
||||
vm_exit_during_initialization("Could not reserve enough space for code cache");
|
||||
vm_exit_during_initialization(err_msg("Could not reserve enough space in %s (" SIZE_FORMAT "K)",
|
||||
heap->name(), size_initial/K));
|
||||
}
|
||||
|
||||
// Register the CodeHeap
|
||||
|
@ -107,7 +107,7 @@ class CodeCache : AllStatic {
|
||||
static CodeHeap* get_code_heap(int code_blob_type); // Returns the CodeHeap for the given CodeBlobType
|
||||
// Returns the name of the VM option to set the size of the corresponding CodeHeap
|
||||
static const char* get_code_heap_flag_name(int code_blob_type);
|
||||
static size_t heap_alignment(); // Returns the alignment of the CodeHeaps in bytes
|
||||
static size_t page_size(bool aligned = true); // Returns the page size used by the CodeCache
|
||||
static ReservedCodeSpace reserve_heap_memory(size_t size); // Reserves one continuous chunk of memory for the CodeHeaps
|
||||
|
||||
// Iteration
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "code/nmethod.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
|
||||
// Constructors
|
||||
|
||||
@ -209,14 +211,24 @@ void ConstantDoubleValue::print_on(outputStream* st) const {
|
||||
// ConstantOopWriteValue
|
||||
|
||||
void ConstantOopWriteValue::write_on(DebugInfoWriteStream* stream) {
|
||||
assert(JNIHandles::resolve(value()) == NULL ||
|
||||
Universe::heap()->is_in_reserved(JNIHandles::resolve(value())),
|
||||
"Should be in heap");
|
||||
#ifdef ASSERT
|
||||
{
|
||||
// cannot use ThreadInVMfromNative here since in case of JVMCI compiler,
|
||||
// thread is already in VM state.
|
||||
ThreadInVMfromUnknown tiv;
|
||||
assert(JNIHandles::resolve(value()) == NULL ||
|
||||
Universe::heap()->is_in_reserved(JNIHandles::resolve(value())),
|
||||
"Should be in heap");
|
||||
}
|
||||
#endif
|
||||
stream->write_int(CONSTANT_OOP_CODE);
|
||||
stream->write_handle(value());
|
||||
}
|
||||
|
||||
void ConstantOopWriteValue::print_on(outputStream* st) const {
|
||||
// using ThreadInVMfromUnknown here since in case of JVMCI compiler,
|
||||
// thread is already in VM state.
|
||||
ThreadInVMfromUnknown tiv;
|
||||
JNIHandles::resolve(value())->print_value_on(st);
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,6 @@ StubQueue::StubQueue(StubInterface* stub_interface, int buffer_size,
|
||||
_queue_begin = 0;
|
||||
_queue_end = 0;
|
||||
_number_of_stubs = 0;
|
||||
register_queue(this);
|
||||
}
|
||||
|
||||
|
||||
@ -205,36 +204,6 @@ void StubQueue::remove_all(){
|
||||
}
|
||||
|
||||
|
||||
enum { StubQueueLimit = 10 }; // there are only a few in the world
|
||||
static StubQueue* registered_stub_queues[StubQueueLimit];
|
||||
|
||||
void StubQueue::register_queue(StubQueue* sq) {
|
||||
for (int i = 0; i < StubQueueLimit; i++) {
|
||||
if (registered_stub_queues[i] == NULL) {
|
||||
registered_stub_queues[i] = sq;
|
||||
return;
|
||||
}
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
|
||||
void StubQueue::queues_do(void f(StubQueue* sq)) {
|
||||
for (int i = 0; i < StubQueueLimit; i++) {
|
||||
if (registered_stub_queues[i] != NULL) {
|
||||
f(registered_stub_queues[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void StubQueue::stubs_do(void f(Stub* s)) {
|
||||
debug_only(verify();)
|
||||
MutexLockerEx lock(_mutex);
|
||||
for (Stub* s = first(); s != NULL; s = next(s)) f(s);
|
||||
}
|
||||
|
||||
|
||||
void StubQueue::verify() {
|
||||
// verify only if initialized
|
||||
if (_stub_buffer == NULL) return;
|
||||
|
@ -172,8 +172,6 @@ class StubQueue: public CHeapObj<mtCode> {
|
||||
void stub_verify(Stub* s) { _stub_interface->verify(s); }
|
||||
void stub_print(Stub* s) { _stub_interface->print(s); }
|
||||
|
||||
static void register_queue(StubQueue*);
|
||||
|
||||
public:
|
||||
StubQueue(StubInterface* stub_interface, int buffer_size, Mutex* lock,
|
||||
const char* name);
|
||||
@ -204,8 +202,6 @@ class StubQueue: public CHeapObj<mtCode> {
|
||||
void deallocate_unused_tail(); // deallocate the unused tail of the underlying CodeBlob
|
||||
// only used from TemplateInterpreter::initialize()
|
||||
// Iteration
|
||||
static void queues_do(void f(StubQueue* s)); // call f with each StubQueue
|
||||
void stubs_do(void f(Stub* s)); // call f with all stubs
|
||||
Stub* first() const { return number_of_stubs() > 0 ? stub_at(_queue_begin) : NULL; }
|
||||
Stub* next(Stub* s) const { int i = index_of(s) + stub_size(s);
|
||||
// Only wrap around in the non-contiguous case (see stubss.cpp)
|
||||
@ -213,9 +209,6 @@ class StubQueue: public CHeapObj<mtCode> {
|
||||
return (i == _queue_end) ? NULL : stub_at(i);
|
||||
}
|
||||
|
||||
address stub_code_begin(Stub* s) const { return _stub_interface->code_begin(s); }
|
||||
address stub_code_end(Stub* s) const { return _stub_interface->code_end(s); }
|
||||
|
||||
// Debugging/printing
|
||||
void verify(); // verifies the stub queue
|
||||
void print(); // prints information about the stub queue
|
||||
|
@ -71,6 +71,6 @@ void ConcurrentMarkSweepPolicy::initialize_size_policy(size_t init_eden_size,
|
||||
}
|
||||
|
||||
void ConcurrentMarkSweepPolicy::initialize_gc_policy_counters() {
|
||||
// initialize the policy counters - 2 collectors, 3 generations
|
||||
_gc_policy_counters = new GCPolicyCounters("ParNew:CMS", 2, 3);
|
||||
// initialize the policy counters - 2 collectors, 2 generations
|
||||
_gc_policy_counters = new GCPolicyCounters("ParNew:CMS", 2, 2);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
|
||||
// Closure used for updating remembered sets and recording references that
|
||||
// point into the collection set while the mutator is running.
|
||||
@ -319,7 +320,7 @@ void DirtyCardQueueSet::abandon_logs() {
|
||||
clear();
|
||||
// Since abandon is done only at safepoints, we can safely manipulate
|
||||
// these queues.
|
||||
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
|
||||
t->dirty_card_queue().reset();
|
||||
}
|
||||
shared_dirty_card_queue()->reset();
|
||||
@ -338,7 +339,7 @@ void DirtyCardQueueSet::concatenate_logs() {
|
||||
int save_max_completed_queue = _max_completed_queue;
|
||||
_max_completed_queue = max_jint;
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
|
||||
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
|
||||
concatenate_log(t->dirty_card_queue());
|
||||
}
|
||||
concatenate_log(_shared_dirty_card_queue);
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include "gc/g1/g1ConcurrentRefineThread.hpp"
|
||||
#include "gc/g1/g1EvacStats.inline.hpp"
|
||||
#include "gc/g1/g1FullCollector.hpp"
|
||||
#include "gc/g1/g1FullGCScope.hpp"
|
||||
#include "gc/g1/g1GCPhaseTimes.hpp"
|
||||
#include "gc/g1/g1HeapSizingPolicy.hpp"
|
||||
#include "gc/g1/g1HeapTransition.hpp"
|
||||
@ -81,6 +80,7 @@
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/orderAccess.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
@ -1217,34 +1217,6 @@ void G1CollectedHeap::print_heap_after_full_collection(G1HeapTransition* heap_tr
|
||||
#endif
|
||||
}
|
||||
|
||||
void G1CollectedHeap::do_full_collection_inner(G1FullGCScope* scope) {
|
||||
GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true);
|
||||
g1_policy()->record_full_collection_start();
|
||||
|
||||
print_heap_before_gc();
|
||||
print_heap_regions();
|
||||
|
||||
abort_concurrent_cycle();
|
||||
verify_before_full_collection(scope->is_explicit_gc());
|
||||
|
||||
gc_prologue(true);
|
||||
prepare_heap_for_full_collection();
|
||||
|
||||
G1FullCollector collector(scope, ref_processor_stw(), concurrent_mark()->next_mark_bitmap(), workers()->active_workers());
|
||||
collector.prepare_collection();
|
||||
collector.collect();
|
||||
collector.complete_collection();
|
||||
|
||||
prepare_heap_for_mutators();
|
||||
|
||||
g1_policy()->record_full_collection_end();
|
||||
gc_epilogue(true);
|
||||
|
||||
verify_after_full_collection();
|
||||
|
||||
print_heap_after_full_collection(scope->heap_transition());
|
||||
}
|
||||
|
||||
bool G1CollectedHeap::do_full_collection(bool explicit_gc,
|
||||
bool clear_all_soft_refs) {
|
||||
assert_at_safepoint(true /* should_be_vm_thread */);
|
||||
@ -1257,8 +1229,12 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc,
|
||||
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
|
||||
collector_policy()->should_clear_all_soft_refs();
|
||||
|
||||
G1FullGCScope scope(explicit_gc, do_clear_all_soft_refs);
|
||||
do_full_collection_inner(&scope);
|
||||
G1FullCollector collector(this, explicit_gc, do_clear_all_soft_refs);
|
||||
GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true);
|
||||
|
||||
collector.prepare_collection();
|
||||
collector.collect();
|
||||
collector.complete_collection();
|
||||
|
||||
// Full collection was successfully completed.
|
||||
return true;
|
||||
@ -2653,11 +2629,9 @@ G1CollectedHeap::doConcurrentMark() {
|
||||
|
||||
size_t G1CollectedHeap::pending_card_num() {
|
||||
size_t extra_cards = 0;
|
||||
JavaThread *curr = Threads::first();
|
||||
while (curr != NULL) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *curr = jtiwh.next(); ) {
|
||||
DirtyCardQueue& dcq = curr->dirty_card_queue();
|
||||
extra_cards += dcq.size();
|
||||
curr = curr->next();
|
||||
}
|
||||
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
|
||||
size_t buffer_size = dcqs.buffer_size();
|
||||
|
@ -42,11 +42,11 @@
|
||||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
||||
#include "gc/g1/g1SurvivorRegions.hpp"
|
||||
#include "gc/g1/g1YCTypes.hpp"
|
||||
#include "gc/g1/hSpaceCounters.hpp"
|
||||
#include "gc/g1/heapRegionManager.hpp"
|
||||
#include "gc/g1/heapRegionSet.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/gcHeapSummary.hpp"
|
||||
#include "gc/shared/plab.hpp"
|
||||
#include "gc/shared/preservedMarks.hpp"
|
||||
#include "memory/memRegion.hpp"
|
||||
@ -126,6 +126,7 @@ class G1CollectedHeap : public CollectedHeap {
|
||||
friend class VM_G1IncCollectionPause;
|
||||
friend class VMStructs;
|
||||
friend class MutatorAllocRegion;
|
||||
friend class G1FullCollector;
|
||||
friend class G1GCAllocRegion;
|
||||
friend class G1HeapVerifier;
|
||||
|
||||
@ -517,7 +518,6 @@ protected:
|
||||
private:
|
||||
// Internal helpers used during full GC to split it up to
|
||||
// increase readability.
|
||||
void do_full_collection_inner(G1FullGCScope* scope);
|
||||
void abort_concurrent_cycle();
|
||||
void verify_before_full_collection(bool explicit_gc);
|
||||
void prepare_heap_for_full_collection();
|
||||
|
@ -1756,28 +1756,24 @@ private:
|
||||
G1ConcurrentMark* _cm;
|
||||
public:
|
||||
void work(uint worker_id) {
|
||||
// Since all available tasks are actually started, we should
|
||||
// only proceed if we're supposed to be active.
|
||||
if (worker_id < _cm->active_tasks()) {
|
||||
G1CMTask* task = _cm->task(worker_id);
|
||||
task->record_start_time();
|
||||
{
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
G1CMTask* task = _cm->task(worker_id);
|
||||
task->record_start_time();
|
||||
{
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
|
||||
G1RemarkThreadsClosure threads_f(G1CollectedHeap::heap(), task);
|
||||
Threads::threads_do(&threads_f);
|
||||
}
|
||||
|
||||
do {
|
||||
task->do_marking_step(1000000000.0 /* something very large */,
|
||||
true /* do_termination */,
|
||||
false /* is_serial */);
|
||||
} while (task->has_aborted() && !_cm->has_overflown());
|
||||
// If we overflow, then we do not want to restart. We instead
|
||||
// want to abort remark and do concurrent marking again.
|
||||
task->record_end_time();
|
||||
G1RemarkThreadsClosure threads_f(G1CollectedHeap::heap(), task);
|
||||
Threads::threads_do(&threads_f);
|
||||
}
|
||||
|
||||
do {
|
||||
task->do_marking_step(1000000000.0 /* something very large */,
|
||||
true /* do_termination */,
|
||||
false /* is_serial */);
|
||||
} while (task->has_aborted() && !_cm->has_overflown());
|
||||
// If we overflow, then we do not want to restart. We instead
|
||||
// want to abort remark and do concurrent marking again.
|
||||
task->record_end_time();
|
||||
}
|
||||
|
||||
G1CMRemarkTask(G1ConcurrentMark* cm, uint active_workers) :
|
||||
|
@ -33,6 +33,107 @@
|
||||
#include "utilities/pair.hpp"
|
||||
#include <math.h>
|
||||
|
||||
G1ConcurrentRefineThread* G1ConcurrentRefineThreadControl::create_refinement_thread(uint worker_id, bool initializing) {
|
||||
G1ConcurrentRefineThread* result = NULL;
|
||||
if (initializing || !InjectGCWorkerCreationFailure) {
|
||||
result = new G1ConcurrentRefineThread(_cr, worker_id);
|
||||
}
|
||||
if (result == NULL || result->osthread() == NULL) {
|
||||
log_warning(gc)("Failed to create refinement thread %u, no more %s",
|
||||
worker_id,
|
||||
result == NULL ? "memory" : "OS threads");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
G1ConcurrentRefineThreadControl::G1ConcurrentRefineThreadControl() :
|
||||
_cr(NULL),
|
||||
_threads(NULL),
|
||||
_num_max_threads(0)
|
||||
{
|
||||
}
|
||||
|
||||
G1ConcurrentRefineThreadControl::~G1ConcurrentRefineThreadControl() {
|
||||
for (uint i = 0; i < _num_max_threads; i++) {
|
||||
G1ConcurrentRefineThread* t = _threads[i];
|
||||
if (t != NULL) {
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(G1ConcurrentRefineThread*, _threads);
|
||||
}
|
||||
|
||||
jint G1ConcurrentRefineThreadControl::initialize(G1ConcurrentRefine* cr, uint num_max_threads) {
|
||||
assert(cr != NULL, "G1ConcurrentRefine must not be NULL");
|
||||
_cr = cr;
|
||||
_num_max_threads = num_max_threads;
|
||||
|
||||
_threads = NEW_C_HEAP_ARRAY_RETURN_NULL(G1ConcurrentRefineThread*, num_max_threads, mtGC);
|
||||
if (_threads == NULL) {
|
||||
vm_shutdown_during_initialization("Could not allocate thread holder array.");
|
||||
return JNI_ENOMEM;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < num_max_threads; i++) {
|
||||
if (UseDynamicNumberOfGCThreads && i != 0 /* Always start first thread. */) {
|
||||
_threads[i] = NULL;
|
||||
} else {
|
||||
_threads[i] = create_refinement_thread(i, true);
|
||||
if (_threads[i] == NULL) {
|
||||
vm_shutdown_during_initialization("Could not allocate refinement threads.");
|
||||
return JNI_ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
void G1ConcurrentRefineThreadControl::maybe_activate_next(uint cur_worker_id) {
|
||||
assert(cur_worker_id < _num_max_threads,
|
||||
"Activating another thread from %u not allowed since there can be at most %u",
|
||||
cur_worker_id, _num_max_threads);
|
||||
if (cur_worker_id == (_num_max_threads - 1)) {
|
||||
// Already the last thread, there is no more thread to activate.
|
||||
return;
|
||||
}
|
||||
|
||||
uint worker_id = cur_worker_id + 1;
|
||||
G1ConcurrentRefineThread* thread_to_activate = _threads[worker_id];
|
||||
if (thread_to_activate == NULL) {
|
||||
// Still need to create the thread...
|
||||
_threads[worker_id] = create_refinement_thread(worker_id, false);
|
||||
thread_to_activate = _threads[worker_id];
|
||||
}
|
||||
if (thread_to_activate != NULL && !thread_to_activate->is_active()) {
|
||||
thread_to_activate->activate();
|
||||
}
|
||||
}
|
||||
|
||||
void G1ConcurrentRefineThreadControl::print_on(outputStream* st) const {
|
||||
for (uint i = 0; i < _num_max_threads; ++i) {
|
||||
if (_threads[i] != NULL) {
|
||||
_threads[i]->print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void G1ConcurrentRefineThreadControl::worker_threads_do(ThreadClosure* tc) {
|
||||
for (uint i = 0; i < _num_max_threads; i++) {
|
||||
if (_threads[i] != NULL) {
|
||||
tc->do_thread(_threads[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void G1ConcurrentRefineThreadControl::stop() {
|
||||
for (uint i = 0; i < _num_max_threads; i++) {
|
||||
if (_threads[i] != NULL) {
|
||||
_threads[i]->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Arbitrary but large limits, to simplify some of the zone calculations.
|
||||
// The general idea is to allow expressions like
|
||||
// MIN2(x OP y, max_XXX_zone)
|
||||
@ -96,7 +197,7 @@ static Thresholds calc_thresholds(size_t green_zone,
|
||||
size_t yellow_zone,
|
||||
uint worker_i) {
|
||||
double yellow_size = yellow_zone - green_zone;
|
||||
double step = yellow_size / G1ConcurrentRefine::thread_num();
|
||||
double step = yellow_size / G1ConcurrentRefine::max_num_threads();
|
||||
if (worker_i == 0) {
|
||||
// Potentially activate worker 0 more aggressively, to keep
|
||||
// available buffers near green_zone value. When yellow_size is
|
||||
@ -115,8 +216,7 @@ G1ConcurrentRefine::G1ConcurrentRefine(size_t green_zone,
|
||||
size_t yellow_zone,
|
||||
size_t red_zone,
|
||||
size_t min_yellow_zone_size) :
|
||||
_threads(NULL),
|
||||
_n_worker_threads(thread_num()),
|
||||
_thread_control(),
|
||||
_green_zone(green_zone),
|
||||
_yellow_zone(yellow_zone),
|
||||
_red_zone(red_zone),
|
||||
@ -125,9 +225,13 @@ G1ConcurrentRefine::G1ConcurrentRefine(size_t green_zone,
|
||||
assert_zone_constraints_gyr(green_zone, yellow_zone, red_zone);
|
||||
}
|
||||
|
||||
jint G1ConcurrentRefine::initialize() {
|
||||
return _thread_control.initialize(this, max_num_threads());
|
||||
}
|
||||
|
||||
static size_t calc_min_yellow_zone_size() {
|
||||
size_t step = G1ConcRefinementThresholdStep;
|
||||
uint n_workers = G1ConcurrentRefine::thread_num();
|
||||
uint n_workers = G1ConcurrentRefine::max_num_threads();
|
||||
if ((max_yellow_zone / step) < n_workers) {
|
||||
return max_yellow_zone;
|
||||
} else {
|
||||
@ -191,77 +295,27 @@ G1ConcurrentRefine* G1ConcurrentRefine::create(jint* ecode) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cr->_threads = NEW_C_HEAP_ARRAY_RETURN_NULL(G1ConcurrentRefineThread*, cr->_n_worker_threads, mtGC);
|
||||
if (cr->_threads == NULL) {
|
||||
*ecode = JNI_ENOMEM;
|
||||
vm_shutdown_during_initialization("Could not allocate an array for G1ConcurrentRefineThread");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint worker_id_offset = DirtyCardQueueSet::num_par_ids();
|
||||
|
||||
G1ConcurrentRefineThread *next = NULL;
|
||||
for (uint i = cr->_n_worker_threads - 1; i != UINT_MAX; i--) {
|
||||
Thresholds thresholds = calc_thresholds(green_zone, yellow_zone, i);
|
||||
G1ConcurrentRefineThread* t =
|
||||
new G1ConcurrentRefineThread(cr,
|
||||
next,
|
||||
worker_id_offset,
|
||||
i,
|
||||
activation_level(thresholds),
|
||||
deactivation_level(thresholds));
|
||||
assert(t != NULL, "Conc refine should have been created");
|
||||
if (t->osthread() == NULL) {
|
||||
*ecode = JNI_ENOMEM;
|
||||
vm_shutdown_during_initialization("Could not create G1ConcurrentRefineThread");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(t->cr() == cr, "Conc refine thread should refer to this");
|
||||
cr->_threads[i] = t;
|
||||
next = t;
|
||||
}
|
||||
|
||||
*ecode = JNI_OK;
|
||||
*ecode = cr->initialize();
|
||||
return cr;
|
||||
}
|
||||
|
||||
void G1ConcurrentRefine::stop() {
|
||||
for (uint i = 0; i < _n_worker_threads; i++) {
|
||||
_threads[i]->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void G1ConcurrentRefine::update_thread_thresholds() {
|
||||
for (uint i = 0; i < _n_worker_threads; i++) {
|
||||
Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, i);
|
||||
_threads[i]->update_thresholds(activation_level(thresholds),
|
||||
deactivation_level(thresholds));
|
||||
}
|
||||
_thread_control.stop();
|
||||
}
|
||||
|
||||
G1ConcurrentRefine::~G1ConcurrentRefine() {
|
||||
for (uint i = 0; i < _n_worker_threads; i++) {
|
||||
delete _threads[i];
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(G1ConcurrentRefineThread*, _threads);
|
||||
}
|
||||
|
||||
void G1ConcurrentRefine::threads_do(ThreadClosure *tc) {
|
||||
for (uint i = 0; i < _n_worker_threads; i++) {
|
||||
tc->do_thread(_threads[i]);
|
||||
}
|
||||
_thread_control.worker_threads_do(tc);
|
||||
}
|
||||
|
||||
uint G1ConcurrentRefine::thread_num() {
|
||||
uint G1ConcurrentRefine::max_num_threads() {
|
||||
return G1ConcRefinementThreads;
|
||||
}
|
||||
|
||||
void G1ConcurrentRefine::print_threads_on(outputStream* st) const {
|
||||
for (uint i = 0; i < _n_worker_threads; ++i) {
|
||||
_threads[i]->print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
_thread_control.print_on(st);
|
||||
}
|
||||
|
||||
static size_t calc_new_green_zone(size_t green,
|
||||
@ -326,16 +380,15 @@ void G1ConcurrentRefine::adjust(double update_rs_time,
|
||||
|
||||
if (G1UseAdaptiveConcRefinement) {
|
||||
update_zones(update_rs_time, update_rs_processed_buffers, goal_ms);
|
||||
update_thread_thresholds();
|
||||
|
||||
// Change the barrier params
|
||||
if (_n_worker_threads == 0) {
|
||||
if (max_num_threads() == 0) {
|
||||
// Disable dcqs notification when there are no threads to notify.
|
||||
dcqs.set_process_completed_threshold(INT_MAX);
|
||||
} else {
|
||||
// Worker 0 is the primary; wakeup is via dcqs notification.
|
||||
STATIC_ASSERT(max_yellow_zone <= INT_MAX);
|
||||
size_t activate = _threads[0]->activation_threshold();
|
||||
size_t activate = activation_threshold(0);
|
||||
dcqs.set_process_completed_threshold((int)activate);
|
||||
}
|
||||
dcqs.set_max_completed_queue((int)red_zone());
|
||||
@ -349,3 +402,42 @@ void G1ConcurrentRefine::adjust(double update_rs_time,
|
||||
}
|
||||
dcqs.notify_if_necessary();
|
||||
}
|
||||
|
||||
size_t G1ConcurrentRefine::activation_threshold(uint worker_id) const {
|
||||
Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
|
||||
return activation_level(thresholds);
|
||||
}
|
||||
|
||||
size_t G1ConcurrentRefine::deactivation_threshold(uint worker_id) const {
|
||||
Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
|
||||
return deactivation_level(thresholds);
|
||||
}
|
||||
|
||||
uint G1ConcurrentRefine::worker_id_offset() {
|
||||
return DirtyCardQueueSet::num_par_ids();
|
||||
}
|
||||
|
||||
void G1ConcurrentRefine::maybe_activate_more_threads(uint worker_id, size_t num_cur_buffers) {
|
||||
if (num_cur_buffers > activation_threshold(worker_id + 1)) {
|
||||
_thread_control.maybe_activate_next(worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
bool G1ConcurrentRefine::do_refinement_step(uint worker_id) {
|
||||
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
|
||||
|
||||
size_t curr_buffer_num = dcqs.completed_buffers_num();
|
||||
// If the number of the buffers falls down into the yellow zone,
|
||||
// that means that the transition period after the evacuation pause has ended.
|
||||
// Since the value written to the DCQS is the same for all threads, there is no
|
||||
// need to synchronize.
|
||||
if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= yellow_zone()) {
|
||||
dcqs.set_completed_queue_padding(0);
|
||||
}
|
||||
|
||||
maybe_activate_more_threads(worker_id, curr_buffer_num);
|
||||
|
||||
// Process the next buffer, if there are enough left.
|
||||
return dcqs.refine_completed_buffer_concurrently(worker_id + worker_id_offset(),
|
||||
deactivation_threshold(worker_id));
|
||||
}
|
||||
|
@ -30,30 +30,63 @@
|
||||
|
||||
// Forward decl
|
||||
class CardTableEntryClosure;
|
||||
class G1ConcurrentRefine;
|
||||
class G1ConcurrentRefineThread;
|
||||
class outputStream;
|
||||
class ThreadClosure;
|
||||
|
||||
class G1ConcurrentRefine : public CHeapObj<mtGC> {
|
||||
// Helper class for refinement thread management. Used to start, stop and
|
||||
// iterate over them.
|
||||
class G1ConcurrentRefineThreadControl VALUE_OBJ_CLASS_SPEC {
|
||||
G1ConcurrentRefine* _cr;
|
||||
|
||||
G1ConcurrentRefineThread** _threads;
|
||||
uint _n_worker_threads;
|
||||
/*
|
||||
* The value of the update buffer queue length falls into one of 3 zones:
|
||||
* green, yellow, red. If the value is in [0, green) nothing is
|
||||
* done, the buffers are left unprocessed to enable the caching effect of the
|
||||
* dirtied cards. In the yellow zone [green, yellow) the concurrent refinement
|
||||
* threads are gradually activated. In [yellow, red) all threads are
|
||||
* running. If the length becomes red (max queue length) the mutators start
|
||||
* processing the buffers.
|
||||
*
|
||||
* There are some interesting cases (when G1UseAdaptiveConcRefinement
|
||||
* is turned off):
|
||||
* 1) green = yellow = red = 0. In this case the mutator will process all
|
||||
* buffers. Except for those that are created by the deferred updates
|
||||
* machinery during a collection.
|
||||
* 2) green = 0. Means no caching. Can be a good way to minimize the
|
||||
* amount of time spent updating rsets during a collection.
|
||||
*/
|
||||
uint _num_max_threads;
|
||||
|
||||
// Create the refinement thread for the given worker id.
|
||||
// If initializing is true, ignore InjectGCWorkerCreationFailure.
|
||||
G1ConcurrentRefineThread* create_refinement_thread(uint worker_id, bool initializing);
|
||||
public:
|
||||
G1ConcurrentRefineThreadControl();
|
||||
~G1ConcurrentRefineThreadControl();
|
||||
|
||||
jint initialize(G1ConcurrentRefine* cr, uint num_max_threads);
|
||||
|
||||
// If there is a "successor" thread that can be activated given the current id,
|
||||
// activate it.
|
||||
void maybe_activate_next(uint cur_worker_id);
|
||||
|
||||
void print_on(outputStream* st) const;
|
||||
void worker_threads_do(ThreadClosure* tc);
|
||||
void stop();
|
||||
};
|
||||
|
||||
// Controls refinement threads and their activation based on the number of completed
|
||||
// buffers currently available in the global dirty card queue.
|
||||
// Refinement threads pick work from the queue based on these thresholds. They are activated
|
||||
// gradually based on the amount of work to do.
|
||||
// Refinement thread n activates thread n+1 if the instance of this class determines there
|
||||
// is enough work available. Threads deactivate themselves if the current amount of
|
||||
// completed buffers falls below their individual threshold.
|
||||
class G1ConcurrentRefine : public CHeapObj<mtGC> {
|
||||
G1ConcurrentRefineThreadControl _thread_control;
|
||||
/*
|
||||
* The value of the completed dirty card queue length falls into one of 3 zones:
|
||||
* green, yellow, red. If the value is in [0, green) nothing is
|
||||
* done, the buffers are left unprocessed to enable the caching effect of the
|
||||
* dirtied cards. In the yellow zone [green, yellow) the concurrent refinement
|
||||
* threads are gradually activated. In [yellow, red) all threads are
|
||||
* running. If the length becomes red (max queue length) the mutators start
|
||||
* processing the buffers.
|
||||
*
|
||||
* There are some interesting cases (when G1UseAdaptiveConcRefinement
|
||||
* is turned off):
|
||||
* 1) green = yellow = red = 0. In this case the mutator will process all
|
||||
* buffers. Except for those that are created by the deferred updates
|
||||
* machinery during a collection.
|
||||
* 2) green = 0. Means no caching. Can be a good way to minimize the
|
||||
* amount of time spent updating remembered sets during a collection.
|
||||
*/
|
||||
size_t _green_zone;
|
||||
size_t _yellow_zone;
|
||||
size_t _red_zone;
|
||||
@ -69,24 +102,32 @@ class G1ConcurrentRefine : public CHeapObj<mtGC> {
|
||||
size_t update_rs_processed_buffers,
|
||||
double goal_ms);
|
||||
|
||||
// Update thread thresholds to account for updated zone values.
|
||||
void update_thread_thresholds();
|
||||
static uint worker_id_offset();
|
||||
void maybe_activate_more_threads(uint worker_id, size_t num_cur_buffers);
|
||||
|
||||
public:
|
||||
jint initialize();
|
||||
public:
|
||||
~G1ConcurrentRefine();
|
||||
|
||||
// Returns a G1ConcurrentRefine instance if succeeded to create/initialize G1ConcurrentRefine and G1ConcurrentRefineThreads.
|
||||
// Otherwise, returns NULL with error code.
|
||||
// Returns a G1ConcurrentRefine instance if succeeded to create/initialize the
|
||||
// G1ConcurrentRefine instance. Otherwise, returns NULL with error code.
|
||||
static G1ConcurrentRefine* create(jint* ecode);
|
||||
|
||||
void stop();
|
||||
|
||||
// Adjust refinement thresholds based on work done during the pause and the goal time.
|
||||
void adjust(double update_rs_time, size_t update_rs_processed_buffers, double goal_ms);
|
||||
|
||||
size_t activation_threshold(uint worker_id) const;
|
||||
size_t deactivation_threshold(uint worker_id) const;
|
||||
// Perform a single refinement step. Called by the refinement threads when woken up.
|
||||
bool do_refinement_step(uint worker_id);
|
||||
|
||||
// Iterate over all concurrent refinement threads applying the given closure.
|
||||
void threads_do(ThreadClosure *tc);
|
||||
|
||||
static uint thread_num();
|
||||
// Maximum number of refinement threads.
|
||||
static uint max_num_threads();
|
||||
|
||||
void print_threads_on(outputStream* st) const;
|
||||
|
||||
|
@ -25,32 +25,20 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1ConcurrentRefine.hpp"
|
||||
#include "gc/g1/g1ConcurrentRefineThread.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1RemSet.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
|
||||
G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr,
|
||||
G1ConcurrentRefineThread *next,
|
||||
uint worker_id_offset,
|
||||
uint worker_id,
|
||||
size_t activate,
|
||||
size_t deactivate) :
|
||||
G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id) :
|
||||
ConcurrentGCThread(),
|
||||
_worker_id_offset(worker_id_offset),
|
||||
_worker_id(worker_id),
|
||||
_active(false),
|
||||
_next(next),
|
||||
_monitor(NULL),
|
||||
_cr(cr),
|
||||
_vtime_accum(0.0),
|
||||
_activation_threshold(activate),
|
||||
_deactivation_threshold(deactivate)
|
||||
_vtime_accum(0.0)
|
||||
{
|
||||
|
||||
// Each thread has its own monitor. The i-th thread is responsible for signaling
|
||||
// to thread i+1 if the number of buffers in the queue exceeds a threshold for this
|
||||
// thread. Monitors are also used to wake up the threads during termination.
|
||||
@ -67,13 +55,6 @@ G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr,
|
||||
create_and_start();
|
||||
}
|
||||
|
||||
void G1ConcurrentRefineThread::update_thresholds(size_t activate,
|
||||
size_t deactivate) {
|
||||
assert(deactivate < activate, "precondition");
|
||||
_activation_threshold = activate;
|
||||
_deactivation_threshold = deactivate;
|
||||
}
|
||||
|
||||
void G1ConcurrentRefineThread::wait_for_completed_buffers() {
|
||||
MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
|
||||
while (!should_terminate() && !is_active()) {
|
||||
@ -118,9 +99,9 @@ void G1ConcurrentRefineThread::run_service() {
|
||||
}
|
||||
|
||||
size_t buffers_processed = 0;
|
||||
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
|
||||
log_debug(gc, refine)("Activated %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT,
|
||||
_worker_id, _activation_threshold, dcqs.completed_buffers_num());
|
||||
log_debug(gc, refine)("Activated worker %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT,
|
||||
_worker_id, _cr->activation_threshold(_worker_id),
|
||||
JavaThread::dirty_card_queue_set().completed_buffers_num());
|
||||
|
||||
{
|
||||
SuspendibleThreadSetJoiner sts_join;
|
||||
@ -131,33 +112,18 @@ void G1ConcurrentRefineThread::run_service() {
|
||||
continue; // Re-check for termination after yield delay.
|
||||
}
|
||||
|
||||
size_t curr_buffer_num = dcqs.completed_buffers_num();
|
||||
// If the number of the buffers falls down into the yellow zone,
|
||||
// that means that the transition period after the evacuation pause has ended.
|
||||
if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cr()->yellow_zone()) {
|
||||
dcqs.set_completed_queue_padding(0);
|
||||
}
|
||||
|
||||
// Check if we need to activate the next thread.
|
||||
if ((_next != NULL) &&
|
||||
!_next->is_active() &&
|
||||
(curr_buffer_num > _next->_activation_threshold)) {
|
||||
_next->activate();
|
||||
}
|
||||
|
||||
// Process the next buffer, if there are enough left.
|
||||
if (!dcqs.refine_completed_buffer_concurrently(_worker_id + _worker_id_offset, _deactivation_threshold)) {
|
||||
break; // Deactivate, number of buffers fell below threshold.
|
||||
if (!_cr->do_refinement_step(_worker_id)) {
|
||||
break;
|
||||
}
|
||||
++buffers_processed;
|
||||
}
|
||||
}
|
||||
|
||||
deactivate();
|
||||
log_debug(gc, refine)("Deactivated %d, off threshold: " SIZE_FORMAT
|
||||
log_debug(gc, refine)("Deactivated worker %d, off threshold: " SIZE_FORMAT
|
||||
", current: " SIZE_FORMAT ", processed: " SIZE_FORMAT,
|
||||
_worker_id, _deactivation_threshold,
|
||||
dcqs.completed_buffers_num(),
|
||||
_worker_id, _cr->deactivation_threshold(_worker_id),
|
||||
JavaThread::dirty_card_queue_set().completed_buffers_num(),
|
||||
buffers_processed);
|
||||
|
||||
if (os::supports_vtime()) {
|
||||
|
@ -43,43 +43,29 @@ class G1ConcurrentRefineThread: public ConcurrentGCThread {
|
||||
uint _worker_id;
|
||||
uint _worker_id_offset;
|
||||
|
||||
// The refinement threads collection is linked list. A predecessor can activate a successor
|
||||
// when the number of the rset update buffer crosses a certain threshold. A successor
|
||||
// would self-deactivate when the number of the buffers falls below the threshold.
|
||||
bool _active;
|
||||
G1ConcurrentRefineThread* _next;
|
||||
Monitor* _monitor;
|
||||
G1ConcurrentRefine* _cr;
|
||||
|
||||
// This thread's activation/deactivation thresholds
|
||||
size_t _activation_threshold;
|
||||
size_t _deactivation_threshold;
|
||||
|
||||
void wait_for_completed_buffers();
|
||||
|
||||
void set_active(bool x) { _active = x; }
|
||||
bool is_active();
|
||||
void activate();
|
||||
// Deactivate this thread.
|
||||
void deactivate();
|
||||
|
||||
bool is_primary() { return (_worker_id == 0); }
|
||||
|
||||
void run_service();
|
||||
void stop_service();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
G1ConcurrentRefineThread(G1ConcurrentRefine* cr, G1ConcurrentRefineThread* next,
|
||||
uint worker_id_offset, uint worker_id,
|
||||
size_t activate, size_t deactivate);
|
||||
G1ConcurrentRefineThread(G1ConcurrentRefine* cg1r, uint worker_id);
|
||||
|
||||
void update_thresholds(size_t activate, size_t deactivate);
|
||||
size_t activation_threshold() const { return _activation_threshold; }
|
||||
bool is_active();
|
||||
// Activate this thread.
|
||||
void activate();
|
||||
|
||||
// Total virtual time so far.
|
||||
double vtime_accum() { return _vtime_accum; }
|
||||
|
||||
G1ConcurrentRefine* cr() { return _cr; }
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1CONCURRENTREFINETHREAD_HPP
|
||||
|
@ -52,7 +52,7 @@ G1DefaultPolicy::G1DefaultPolicy(STWGCTimer* gc_timer) :
|
||||
_analytics(new G1Analytics(&_predictor)),
|
||||
_mmu_tracker(new G1MMUTrackerQueue(GCPauseIntervalMillis / 1000.0, MaxGCPauseMillis / 1000.0)),
|
||||
_ihop_control(create_ihop_control(&_predictor)),
|
||||
_policy_counters(new GCPolicyCounters("GarbageFirst", 1, 3)),
|
||||
_policy_counters(new GCPolicyCounters("GarbageFirst", 1, 2)),
|
||||
_young_list_fixed_length(0),
|
||||
_short_lived_surv_rate_group(new SurvRateGroup()),
|
||||
_survivor_surv_rate_group(new SurvRateGroup()),
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "gc/g1/g1FullGCReferenceProcessorExecutor.hpp"
|
||||
#include "gc/g1/g1FullGCScope.hpp"
|
||||
#include "gc/g1/g1OopClosures.hpp"
|
||||
#include "gc/g1/g1Policy.hpp"
|
||||
#include "gc/g1/g1StringDedup.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/preservedMarks.hpp"
|
||||
@ -62,20 +63,24 @@ static void update_derived_pointers() {
|
||||
#endif
|
||||
}
|
||||
|
||||
G1FullCollector::G1FullCollector(G1FullGCScope* scope,
|
||||
ReferenceProcessor* reference_processor,
|
||||
G1CMBitMap* bitmap,
|
||||
uint workers) :
|
||||
_scope(scope),
|
||||
_num_workers(workers),
|
||||
_mark_bitmap(bitmap),
|
||||
G1CMBitMap* G1FullCollector::mark_bitmap() {
|
||||
return _heap->concurrent_mark()->next_mark_bitmap();
|
||||
}
|
||||
|
||||
ReferenceProcessor* G1FullCollector::reference_processor() {
|
||||
return _heap->ref_processor_stw();
|
||||
}
|
||||
|
||||
G1FullCollector::G1FullCollector(G1CollectedHeap* heap, bool explicit_gc, bool clear_soft_refs) :
|
||||
_heap(heap),
|
||||
_scope(explicit_gc, clear_soft_refs),
|
||||
_num_workers(heap->workers()->active_workers()),
|
||||
_oop_queue_set(_num_workers),
|
||||
_array_queue_set(_num_workers),
|
||||
_preserved_marks_set(true),
|
||||
_reference_processor(reference_processor),
|
||||
_serial_compaction_point(),
|
||||
_is_alive(_mark_bitmap),
|
||||
_is_alive_mutator(_reference_processor, &_is_alive) {
|
||||
_is_alive(heap->concurrent_mark()->next_mark_bitmap()),
|
||||
_is_alive_mutator(heap->ref_processor_stw(), &_is_alive) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
|
||||
|
||||
_preserved_marks_set.init(_num_workers);
|
||||
@ -99,8 +104,19 @@ G1FullCollector::~G1FullCollector() {
|
||||
}
|
||||
|
||||
void G1FullCollector::prepare_collection() {
|
||||
_reference_processor->enable_discovery();
|
||||
_reference_processor->setup_policy(scope()->should_clear_soft_refs());
|
||||
_heap->g1_policy()->record_full_collection_start();
|
||||
|
||||
_heap->print_heap_before_gc();
|
||||
_heap->print_heap_regions();
|
||||
|
||||
_heap->abort_concurrent_cycle();
|
||||
_heap->verify_before_full_collection(scope()->is_explicit_gc());
|
||||
|
||||
_heap->gc_prologue(true);
|
||||
_heap->prepare_heap_for_full_collection();
|
||||
|
||||
reference_processor()->enable_discovery();
|
||||
reference_processor()->setup_policy(scope()->should_clear_soft_refs());
|
||||
|
||||
// When collecting the permanent generation Method*s may be moving,
|
||||
// so we either have to flush all bcp data or convert it into bci.
|
||||
@ -139,6 +155,15 @@ void G1FullCollector::complete_collection() {
|
||||
BiasedLocking::restore_marks();
|
||||
CodeCache::gc_epilogue();
|
||||
JvmtiExport::gc_epilogue();
|
||||
|
||||
_heap->prepare_heap_for_mutators();
|
||||
|
||||
_heap->g1_policy()->record_full_collection_end();
|
||||
_heap->gc_epilogue(true);
|
||||
|
||||
_heap->verify_after_full_collection();
|
||||
|
||||
_heap->print_heap_after_full_collection(scope()->heap_transition());
|
||||
}
|
||||
|
||||
void G1FullCollector::phase1_mark_live_objects() {
|
||||
@ -164,11 +189,11 @@ void G1FullCollector::phase1_mark_live_objects() {
|
||||
GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer());
|
||||
// Unload classes and purge the SystemDictionary.
|
||||
bool purged_class = SystemDictionary::do_unloading(&_is_alive, scope()->timer());
|
||||
G1CollectedHeap::heap()->complete_cleaning(&_is_alive, purged_class);
|
||||
_heap->complete_cleaning(&_is_alive, purged_class);
|
||||
} else {
|
||||
GCTraceTime(Debug, gc, phases) debug("Phase 1: String and Symbol Tables Cleanup", scope()->timer());
|
||||
// If no class unloading just clean out strings and symbols.
|
||||
G1CollectedHeap::heap()->partial_cleaning(&_is_alive, true, true, G1StringDedup::is_enabled());
|
||||
_heap->partial_cleaning(&_is_alive, true, true, G1StringDedup::is_enabled());
|
||||
}
|
||||
|
||||
scope()->tracer()->report_object_count_after_gc(&_is_alive);
|
||||
@ -210,13 +235,13 @@ void G1FullCollector::phase4_do_compaction() {
|
||||
}
|
||||
|
||||
void G1FullCollector::restore_marks() {
|
||||
SharedRestorePreservedMarksTaskExecutor task_executor(G1CollectedHeap::heap()->workers());
|
||||
SharedRestorePreservedMarksTaskExecutor task_executor(_heap->workers());
|
||||
_preserved_marks_set.restore(&task_executor);
|
||||
_preserved_marks_set.reclaim();
|
||||
}
|
||||
|
||||
void G1FullCollector::run_task(AbstractGangTask* task) {
|
||||
G1CollectedHeap::heap()->workers()->run_task(task, _num_workers);
|
||||
_heap->workers()->run_task(task, _num_workers);
|
||||
}
|
||||
|
||||
void G1FullCollector::verify_after_marking() {
|
||||
@ -229,7 +254,7 @@ void G1FullCollector::verify_after_marking() {
|
||||
#if COMPILER2_OR_JVMCI
|
||||
DerivedPointerTableDeactivate dpt_deact;
|
||||
#endif
|
||||
G1CollectedHeap::heap()->prepare_for_verify();
|
||||
_heap->prepare_for_verify();
|
||||
// Note: we can verify only the heap here. When an object is
|
||||
// marked, the previous value of the mark word (including
|
||||
// identity hash values, ages, etc) is preserved, and the mark
|
||||
@ -241,5 +266,5 @@ void G1FullCollector::verify_after_marking() {
|
||||
// (including hash values) are restored to the appropriate
|
||||
// objects.
|
||||
GCTraceTime(Info, gc, verify)("During GC (full)");
|
||||
G1CollectedHeap::heap()->verify(VerifyOption_G1UseFullMarking);
|
||||
_heap->verify(VerifyOption_G1UseFullMarking);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "gc/g1/g1FullGCCompactionPoint.hpp"
|
||||
#include "gc/g1/g1FullGCMarker.hpp"
|
||||
#include "gc/g1/g1FullGCOopClosures.hpp"
|
||||
#include "gc/g1/g1FullGCScope.hpp"
|
||||
#include "gc/shared/preservedMarks.hpp"
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "gc/shared/taskqueue.hpp"
|
||||
@ -42,41 +43,36 @@ class ReferenceProcessor;
|
||||
|
||||
// The G1FullCollector holds data associated with the current Full GC.
|
||||
class G1FullCollector : StackObj {
|
||||
G1FullGCScope* _scope;
|
||||
G1CollectedHeap* _heap;
|
||||
G1FullGCScope _scope;
|
||||
uint _num_workers;
|
||||
G1FullGCMarker** _markers;
|
||||
G1FullGCCompactionPoint** _compaction_points;
|
||||
G1CMBitMap* _mark_bitmap;
|
||||
OopQueueSet _oop_queue_set;
|
||||
ObjArrayTaskQueueSet _array_queue_set;
|
||||
PreservedMarksSet _preserved_marks_set;
|
||||
ReferenceProcessor* _reference_processor;
|
||||
G1FullGCCompactionPoint _serial_compaction_point;
|
||||
|
||||
G1IsAliveClosure _is_alive;
|
||||
ReferenceProcessorIsAliveMutator _is_alive_mutator;
|
||||
|
||||
public:
|
||||
G1FullCollector(G1FullGCScope* scope,
|
||||
ReferenceProcessor* reference_processor,
|
||||
G1CMBitMap* mark_bitmap,
|
||||
uint workers);
|
||||
G1FullCollector(G1CollectedHeap* heap, bool explicit_gc, bool clear_soft_refs);
|
||||
~G1FullCollector();
|
||||
|
||||
void prepare_collection();
|
||||
void collect();
|
||||
void complete_collection();
|
||||
|
||||
G1FullGCScope* scope() { return _scope; }
|
||||
G1FullGCScope* scope() { return &_scope; }
|
||||
uint workers() { return _num_workers; }
|
||||
G1FullGCMarker* marker(uint id) { return _markers[id]; }
|
||||
G1FullGCCompactionPoint* compaction_point(uint id) { return _compaction_points[id]; }
|
||||
G1CMBitMap* mark_bitmap() { return _mark_bitmap; }
|
||||
OopQueueSet* oop_queue_set() { return &_oop_queue_set; }
|
||||
ObjArrayTaskQueueSet* array_queue_set() { return &_array_queue_set; }
|
||||
PreservedMarksSet* preserved_mark_set() { return &_preserved_marks_set; }
|
||||
ReferenceProcessor* reference_processor() { return _reference_processor; }
|
||||
G1FullGCCompactionPoint* serial_compaction_point() { return &_serial_compaction_point; }
|
||||
G1CMBitMap* mark_bitmap();
|
||||
ReferenceProcessor* reference_processor();
|
||||
|
||||
private:
|
||||
void phase1_mark_live_objects();
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1MonitoringSupport.hpp"
|
||||
#include "gc/g1/g1Policy.hpp"
|
||||
#include "gc/shared/hSpaceCounters.hpp"
|
||||
|
||||
G1GenerationCounters::G1GenerationCounters(G1MonitoringSupport* g1mm,
|
||||
const char* name,
|
||||
@ -128,10 +129,10 @@ G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h) :
|
||||
// name "generation.1.space.0"
|
||||
// Counters are created from maxCapacity, capacity, initCapacity,
|
||||
// and used.
|
||||
_old_space_counters = new HSpaceCounters("space", 0 /* ordinal */,
|
||||
_old_space_counters = new HSpaceCounters(_old_collection_counters->name_space(),
|
||||
"space", 0 /* ordinal */,
|
||||
pad_capacity(overall_reserved()) /* max_capacity */,
|
||||
pad_capacity(old_space_committed()) /* init_capacity */,
|
||||
_old_collection_counters);
|
||||
pad_capacity(old_space_committed()) /* init_capacity */);
|
||||
|
||||
// Young collection set
|
||||
// name "generation.0". This is logically the young generation.
|
||||
@ -139,27 +140,29 @@ G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h) :
|
||||
// See _old_collection_counters for additional counters
|
||||
_young_collection_counters = new G1YoungGenerationCounters(this, "young");
|
||||
|
||||
const char* young_collection_name_space = _young_collection_counters->name_space();
|
||||
|
||||
// name "generation.0.space.0"
|
||||
// See _old_space_counters for additional counters
|
||||
_eden_counters = new HSpaceCounters("eden", 0 /* ordinal */,
|
||||
_eden_counters = new HSpaceCounters(young_collection_name_space,
|
||||
"eden", 0 /* ordinal */,
|
||||
pad_capacity(overall_reserved()) /* max_capacity */,
|
||||
pad_capacity(eden_space_committed()) /* init_capacity */,
|
||||
_young_collection_counters);
|
||||
pad_capacity(eden_space_committed()) /* init_capacity */);
|
||||
|
||||
// name "generation.0.space.1"
|
||||
// See _old_space_counters for additional counters
|
||||
// Set the arguments to indicate that this survivor space is not used.
|
||||
_from_counters = new HSpaceCounters("s0", 1 /* ordinal */,
|
||||
_from_counters = new HSpaceCounters(young_collection_name_space,
|
||||
"s0", 1 /* ordinal */,
|
||||
pad_capacity(0) /* max_capacity */,
|
||||
pad_capacity(0) /* init_capacity */,
|
||||
_young_collection_counters);
|
||||
pad_capacity(0) /* init_capacity */);
|
||||
|
||||
// name "generation.0.space.2"
|
||||
// See _old_space_counters for additional counters
|
||||
_to_counters = new HSpaceCounters("s1", 2 /* ordinal */,
|
||||
_to_counters = new HSpaceCounters(young_collection_name_space,
|
||||
"s1", 2 /* ordinal */,
|
||||
pad_capacity(overall_reserved()) /* max_capacity */,
|
||||
pad_capacity(survivor_space_committed()) /* init_capacity */,
|
||||
_young_collection_counters);
|
||||
pad_capacity(survivor_space_committed()) /* init_capacity */);
|
||||
|
||||
if (UsePerfData) {
|
||||
// Given that this survivor space is not used, we update it here
|
||||
|
@ -25,9 +25,11 @@
|
||||
#ifndef SHARE_VM_GC_G1_G1MONITORINGSUPPORT_HPP
|
||||
#define SHARE_VM_GC_G1_G1MONITORINGSUPPORT_HPP
|
||||
|
||||
#include "gc/g1/hSpaceCounters.hpp"
|
||||
#include "gc/shared/generationCounters.hpp"
|
||||
|
||||
class CollectorCounters;
|
||||
class G1CollectedHeap;
|
||||
class HSpaceCounters;
|
||||
|
||||
// Class for monitoring logical spaces in G1. It provides data for
|
||||
// both G1's jstat counters as well as G1's memory pools.
|
||||
|
@ -298,7 +298,7 @@ G1RemSet::~G1RemSet() {
|
||||
}
|
||||
|
||||
uint G1RemSet::num_par_rem_sets() {
|
||||
return MAX2(DirtyCardQueueSet::num_par_ids() + G1ConcurrentRefine::thread_num(), ParallelGCThreads);
|
||||
return MAX2(DirtyCardQueueSet::num_par_ids() + G1ConcurrentRefine::max_num_threads(), ParallelGCThreads);
|
||||
}
|
||||
|
||||
void G1RemSet::initialize(size_t capacity, uint max_regions) {
|
||||
|
@ -86,7 +86,7 @@ G1RemSetSummary::G1RemSetSummary() :
|
||||
_num_processed_buf_mutator(0),
|
||||
_num_processed_buf_rs_threads(0),
|
||||
_num_coarsenings(0),
|
||||
_num_vtimes(G1ConcurrentRefine::thread_num()),
|
||||
_num_vtimes(G1ConcurrentRefine::max_num_threads()),
|
||||
_rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)),
|
||||
_sampling_thread_vtime(0.0f) {
|
||||
|
||||
@ -99,7 +99,7 @@ G1RemSetSummary::G1RemSetSummary(G1RemSet* rem_set) :
|
||||
_num_processed_buf_mutator(0),
|
||||
_num_processed_buf_rs_threads(0),
|
||||
_num_coarsenings(0),
|
||||
_num_vtimes(G1ConcurrentRefine::thread_num()),
|
||||
_num_vtimes(G1ConcurrentRefine::max_num_threads()),
|
||||
_rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)),
|
||||
_sampling_thread_vtime(0.0f) {
|
||||
update();
|
||||
|
@ -175,6 +175,9 @@ void G1SATBCardTableLoggingModRefBS::write_ref_field_post_slow(volatile jbyte* b
|
||||
|
||||
void
|
||||
G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr) {
|
||||
if (mr.is_empty()) {
|
||||
return;
|
||||
}
|
||||
volatile jbyte* byte = byte_for(mr.start());
|
||||
jbyte* last_byte = byte_for(mr.last());
|
||||
Thread* thr = Thread::current();
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
|
||||
SATBMarkQueue::SATBMarkQueue(SATBMarkQueueSet* qset, bool permanent) :
|
||||
@ -214,7 +215,7 @@ void SATBMarkQueueSet::dump_active_states(bool expected_active) {
|
||||
log_error(gc, verify)("Expected SATB active state: %s", expected_active ? "ACTIVE" : "INACTIVE");
|
||||
log_error(gc, verify)("Actual SATB active states:");
|
||||
log_error(gc, verify)(" Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE");
|
||||
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
|
||||
log_error(gc, verify)(" Thread \"%s\" queue: %s", t->name(), t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE");
|
||||
}
|
||||
log_error(gc, verify)(" Shared queue: %s", shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE");
|
||||
@ -228,7 +229,7 @@ void SATBMarkQueueSet::verify_active_states(bool expected_active) {
|
||||
}
|
||||
|
||||
// Verify thread queue states
|
||||
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
|
||||
if (t->satb_mark_queue().is_active() != expected_active) {
|
||||
dump_active_states(expected_active);
|
||||
guarantee(false, "Thread SATB queue has an unexpected active state");
|
||||
@ -249,14 +250,14 @@ void SATBMarkQueueSet::set_active_all_threads(bool active, bool expected_active)
|
||||
verify_active_states(expected_active);
|
||||
#endif // ASSERT
|
||||
_all_active = active;
|
||||
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
|
||||
t->satb_mark_queue().set_active(active);
|
||||
}
|
||||
shared_satb_queue()->set_active(active);
|
||||
}
|
||||
|
||||
void SATBMarkQueueSet::filter_thread_buffers() {
|
||||
for(JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
|
||||
t->satb_mark_queue().filter();
|
||||
}
|
||||
shared_satb_queue()->filter();
|
||||
@ -309,7 +310,7 @@ void SATBMarkQueueSet::print_all(const char* msg) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
|
||||
jio_snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name());
|
||||
t->satb_mark_queue().print(buffer);
|
||||
}
|
||||
@ -341,8 +342,8 @@ void SATBMarkQueueSet::abandon_partial_marking() {
|
||||
}
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
|
||||
// So we can safely manipulate these queues.
|
||||
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
|
||||
t->satb_mark_queue().reset();
|
||||
}
|
||||
shared_satb_queue()->reset();
|
||||
shared_satb_queue()->reset();
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
MutableNUMASpace::MutableNUMASpace(size_t alignment) : MutableSpace(alignment), _must_use_large_pages(false) {
|
||||
@ -287,7 +288,7 @@ bool MutableNUMASpace::update_layout(bool force) {
|
||||
FREE_C_HEAP_ARRAY(int, lgrp_ids);
|
||||
|
||||
if (changed) {
|
||||
for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
|
||||
thread->set_lgrp_id(-1);
|
||||
}
|
||||
}
|
||||
|
@ -105,9 +105,9 @@ jint ParallelScavengeHeap::initialize() {
|
||||
(old_gen()->virtual_space()->high_boundary() ==
|
||||
young_gen()->virtual_space()->low_boundary()),
|
||||
"Boundaries must meet");
|
||||
// initialize the policy counters - 2 collectors, 3 generations
|
||||
// initialize the policy counters - 2 collectors, 2 generations
|
||||
_gc_policy_counters =
|
||||
new PSGCAdaptivePolicyCounters("ParScav:MSC", 2, 3, _size_policy);
|
||||
new PSGCAdaptivePolicyCounters("ParScav:MSC", 2, 2, _size_policy);
|
||||
|
||||
// Set up the GCTaskManager
|
||||
_gc_task_manager = GCTaskManager::create(ParallelGCThreads);
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "services/heapDumper.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
@ -540,10 +541,11 @@ void CollectedHeap::ensure_parsability(bool retire_tlabs) {
|
||||
const bool deferred = _defer_initial_card_mark;
|
||||
// The main thread starts allocating via a TLAB even before it
|
||||
// has added itself to the threads list at vm boot-up.
|
||||
assert(!use_tlab || Threads::first() != NULL,
|
||||
JavaThreadIteratorWithHandle jtiwh;
|
||||
assert(!use_tlab || jtiwh.length() > 0,
|
||||
"Attempt to fill tlabs before main thread has been added"
|
||||
" to threads list is doomed to failure!");
|
||||
for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
|
||||
for (; JavaThread *thread = jtiwh.next(); ) {
|
||||
if (use_tlab) thread->tlab().make_parsable(retire_tlabs);
|
||||
#if COMPILER2_OR_JVMCI
|
||||
// The deferred store barriers must all have been flushed to the
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/collectorCounters.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
|
||||
CollectorCounters::CollectorCounters(const char* name, int ordinal) {
|
||||
|
||||
@ -59,3 +60,24 @@ CollectorCounters::CollectorCounters(const char* name, int ordinal) {
|
||||
CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
CollectorCounters::~CollectorCounters() {
|
||||
if (_name_space != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, _name_space);
|
||||
}
|
||||
}
|
||||
|
||||
TraceCollectorStats::TraceCollectorStats(CollectorCounters* c) :
|
||||
PerfTraceTimedEvent(c->time_counter(), c->invocation_counter()),
|
||||
_c(c) {
|
||||
|
||||
if (UsePerfData) {
|
||||
_c->last_entry_counter()->set_value(os::elapsed_counter());
|
||||
}
|
||||
}
|
||||
|
||||
TraceCollectorStats::~TraceCollectorStats() {
|
||||
if (UsePerfData) {
|
||||
_c->last_exit_counter()->set_value(os::elapsed_counter());
|
||||
}
|
||||
}
|
||||
|
@ -49,9 +49,7 @@ class CollectorCounters: public CHeapObj<mtGC> {
|
||||
|
||||
CollectorCounters(const char* name, int ordinal);
|
||||
|
||||
~CollectorCounters() {
|
||||
if (_name_space != NULL) FREE_C_HEAP_ARRAY(char, _name_space);
|
||||
}
|
||||
~CollectorCounters();
|
||||
|
||||
inline PerfCounter* invocation_counter() const { return _invocations; }
|
||||
|
||||
@ -70,18 +68,9 @@ class TraceCollectorStats: public PerfTraceTimedEvent {
|
||||
CollectorCounters* _c;
|
||||
|
||||
public:
|
||||
inline TraceCollectorStats(CollectorCounters* c) :
|
||||
PerfTraceTimedEvent(c->time_counter(), c->invocation_counter()),
|
||||
_c(c) {
|
||||
TraceCollectorStats(CollectorCounters* c);
|
||||
|
||||
if (UsePerfData) {
|
||||
_c->last_entry_counter()->set_value(os::elapsed_counter());
|
||||
}
|
||||
}
|
||||
|
||||
inline ~TraceCollectorStats() {
|
||||
if (UsePerfData) _c->last_exit_counter()->set_value(os::elapsed_counter());
|
||||
}
|
||||
~TraceCollectorStats();
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_SHARED_COLLECTORCOUNTERS_HPP
|
||||
|
@ -911,7 +911,7 @@ void MarkSweepPolicy::initialize_generations() {
|
||||
}
|
||||
|
||||
void MarkSweepPolicy::initialize_gc_policy_counters() {
|
||||
// Initialize the policy counters - 2 collectors, 3 generations.
|
||||
_gc_policy_counters = new GCPolicyCounters("Copy:MSC", 2, 3);
|
||||
// Initialize the policy counters - 2 collectors, 2 generations.
|
||||
_gc_policy_counters = new GCPolicyCounters("Copy:MSC", 2, 2);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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,6 +29,7 @@
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
|
||||
volatile jint GCLocker::_jni_lock_count = 0;
|
||||
volatile bool GCLocker::_needs_gc = false;
|
||||
@ -45,14 +46,16 @@ void GCLocker::verify_critical_count() {
|
||||
assert(!needs_gc() || _debug_jni_lock_count == _jni_lock_count, "must agree");
|
||||
int count = 0;
|
||||
// Count the number of threads with critical operations in progress
|
||||
for (JavaThread* thr = Threads::first(); thr; thr = thr->next()) {
|
||||
JavaThreadIteratorWithHandle jtiwh;
|
||||
for (; JavaThread *thr = jtiwh.next(); ) {
|
||||
if (thr->in_critical()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (_jni_lock_count != count) {
|
||||
log_error(gc, verify)("critical counts don't match: %d != %d", _jni_lock_count, count);
|
||||
for (JavaThread* thr = Threads::first(); thr; thr = thr->next()) {
|
||||
jtiwh.rewind();
|
||||
for (; JavaThread *thr = jtiwh.next(); ) {
|
||||
if (thr->in_critical()) {
|
||||
log_error(gc, verify)(INTPTR_FORMAT " in_critical %d", p2i(thr), thr->in_critical());
|
||||
}
|
||||
|
@ -78,6 +78,12 @@ GenerationCounters::GenerationCounters(const char* name,
|
||||
initialize(name, ordinal, spaces, min_capacity, max_capacity, curr_capacity);
|
||||
}
|
||||
|
||||
GenerationCounters::~GenerationCounters() {
|
||||
if (_name_space != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, _name_space);
|
||||
}
|
||||
}
|
||||
|
||||
void GenerationCounters::update_all() {
|
||||
assert(_virtual_space != NULL, "otherwise, override this method");
|
||||
_current_size->set_value(_virtual_space->committed_size());
|
||||
|
@ -68,9 +68,7 @@ private:
|
||||
GenerationCounters(const char* name, int ordinal, int spaces,
|
||||
size_t min_capacity, size_t max_capacity, VirtualSpace* v);
|
||||
|
||||
~GenerationCounters() {
|
||||
if (_name_space != NULL) FREE_C_HEAP_ARRAY(char, _name_space);
|
||||
}
|
||||
~GenerationCounters();
|
||||
|
||||
virtual void update_all();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 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,22 +23,23 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/hSpaceCounters.hpp"
|
||||
#include "gc/shared/generation.hpp"
|
||||
#include "gc/shared/hSpaceCounters.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
|
||||
HSpaceCounters::HSpaceCounters(const char* name,
|
||||
HSpaceCounters::HSpaceCounters(const char* name_space,
|
||||
const char* name,
|
||||
int ordinal,
|
||||
size_t max_size,
|
||||
size_t initial_capacity,
|
||||
GenerationCounters* gc) {
|
||||
size_t initial_capacity) {
|
||||
|
||||
if (UsePerfData) {
|
||||
EXCEPTION_MARK;
|
||||
ResourceMark rm;
|
||||
|
||||
const char* cns =
|
||||
PerfDataManager::name_space(gc->name_space(), "space", ordinal);
|
||||
PerfDataManager::name_space(name_space, "space", ordinal);
|
||||
|
||||
_name_space = NEW_C_HEAP_ARRAY(char, strlen(cns)+1, mtGC);
|
||||
strcpy(_name_space, cns);
|
||||
@ -64,3 +65,33 @@ HSpaceCounters::HSpaceCounters(const char* name,
|
||||
initial_capacity, CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
HSpaceCounters::~HSpaceCounters() {
|
||||
if (_name_space != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, _name_space);
|
||||
}
|
||||
}
|
||||
|
||||
void HSpaceCounters::update_capacity(size_t v) {
|
||||
_capacity->set_value(v);
|
||||
}
|
||||
|
||||
void HSpaceCounters::update_used(size_t v) {
|
||||
_used->set_value(v);
|
||||
}
|
||||
|
||||
void HSpaceCounters::update_all(size_t capacity, size_t used) {
|
||||
update_capacity(capacity);
|
||||
update_used(used);
|
||||
}
|
||||
|
||||
debug_only(
|
||||
// for security reasons, we do not allow arbitrary reads from
|
||||
// the counters as they may live in shared memory.
|
||||
jlong HSpaceCounters::used() {
|
||||
return _used->get_value();
|
||||
}
|
||||
jlong HSpaceCounters::capacity() {
|
||||
return _used->get_value();
|
||||
}
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 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,65 +22,47 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_GC_G1_HSPACECOUNTERS_HPP
|
||||
#define SHARE_VM_GC_G1_HSPACECOUNTERS_HPP
|
||||
#ifndef SHARE_VM_GC_SHARED_HSPACECOUNTERS_HPP
|
||||
#define SHARE_VM_GC_SHARED_HSPACECOUNTERS_HPP
|
||||
|
||||
#include "gc/shared/generation.hpp"
|
||||
#include "gc/shared/generationCounters.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// A HSpaceCounter is a holder class for performance counters
|
||||
// that track a collections (logical spaces) in a heap;
|
||||
|
||||
class HeapSpaceUsedHelper;
|
||||
class G1SpaceMonitoringSupport;
|
||||
|
||||
class HSpaceCounters: public CHeapObj<mtGC> {
|
||||
friend class VMStructs;
|
||||
|
||||
private:
|
||||
PerfVariable* _capacity;
|
||||
PerfVariable* _used;
|
||||
PerfVariable* _capacity;
|
||||
PerfVariable* _used;
|
||||
|
||||
// Constant PerfData types don't need to retain a reference.
|
||||
// However, it's a good idea to document them here.
|
||||
|
||||
char* _name_space;
|
||||
char* _name_space;
|
||||
|
||||
public:
|
||||
|
||||
HSpaceCounters(const char* name, int ordinal, size_t max_size,
|
||||
size_t initial_capacity, GenerationCounters* gc);
|
||||
HSpaceCounters(const char* name_space, const char* name, int ordinal,
|
||||
size_t max_size, size_t initial_capacity);
|
||||
|
||||
~HSpaceCounters() {
|
||||
if (_name_space != NULL) FREE_C_HEAP_ARRAY(char, _name_space);
|
||||
}
|
||||
~HSpaceCounters();
|
||||
|
||||
inline void update_capacity(size_t v) {
|
||||
_capacity->set_value(v);
|
||||
}
|
||||
void update_capacity(size_t v);
|
||||
void update_used(size_t v);
|
||||
|
||||
inline void update_used(size_t v) {
|
||||
_used->set_value(v);
|
||||
}
|
||||
void update_all(size_t capacity, size_t used);
|
||||
|
||||
debug_only(
|
||||
// for security reasons, we do not allow arbitrary reads from
|
||||
// the counters as they may live in shared memory.
|
||||
jlong used() {
|
||||
return _used->get_value();
|
||||
}
|
||||
jlong capacity() {
|
||||
return _used->get_value();
|
||||
}
|
||||
jlong used();
|
||||
jlong capacity();
|
||||
)
|
||||
|
||||
inline void update_all(size_t capacity, size_t used) {
|
||||
update_capacity(capacity);
|
||||
update_used(used);
|
||||
}
|
||||
|
||||
const char* name_space() const { return _name_space; }
|
||||
};
|
||||
#endif // SHARE_VM_GC_G1_HSPACECOUNTERS_HPP
|
||||
#endif // SHARE_VM_GC_SHARED_HSPACECOUNTERS_HPP
|
@ -30,6 +30,7 @@
|
||||
#include "memory/universe.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "utilities/copy.hpp"
|
||||
|
||||
// Thread-Local Edens support
|
||||
@ -48,7 +49,7 @@ void ThreadLocalAllocBuffer::clear_before_allocation() {
|
||||
void ThreadLocalAllocBuffer::accumulate_statistics_before_gc() {
|
||||
global_stats()->initialize();
|
||||
|
||||
for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
|
||||
thread->tlab().accumulate_statistics();
|
||||
thread->tlab().initialize_statistics();
|
||||
}
|
||||
@ -130,7 +131,7 @@ void ThreadLocalAllocBuffer::make_parsable(bool retire, bool zap) {
|
||||
|
||||
void ThreadLocalAllocBuffer::resize_all_tlabs() {
|
||||
if (ResizeTLAB) {
|
||||
for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
|
||||
thread->tlab().resize();
|
||||
}
|
||||
}
|
||||
|
@ -261,6 +261,10 @@ WorkGang::WorkGang(const char* name,
|
||||
_dispatcher(create_dispatcher())
|
||||
{ }
|
||||
|
||||
WorkGang::~WorkGang() {
|
||||
delete _dispatcher;
|
||||
}
|
||||
|
||||
AbstractGangWorker* WorkGang::allocate_worker(uint worker_id) {
|
||||
return new GangWorker(this, worker_id);
|
||||
}
|
||||
|
@ -122,6 +122,8 @@ class AbstractWorkGang : public CHeapObj<mtInternal> {
|
||||
// Printing support.
|
||||
const char* _name;
|
||||
|
||||
~AbstractWorkGang() {}
|
||||
|
||||
private:
|
||||
// Initialize only instance data.
|
||||
const bool _are_GC_task_threads;
|
||||
@ -206,9 +208,6 @@ class WorkGang: public AbstractWorkGang {
|
||||
// To get access to the GangTaskDispatcher instance.
|
||||
friend class GangWorker;
|
||||
|
||||
// Never deleted.
|
||||
~WorkGang();
|
||||
|
||||
GangTaskDispatcher* const _dispatcher;
|
||||
GangTaskDispatcher* dispatcher() const {
|
||||
return _dispatcher;
|
||||
@ -220,6 +219,8 @@ public:
|
||||
bool are_GC_task_threads,
|
||||
bool are_ConcurrentGC_threads);
|
||||
|
||||
~WorkGang();
|
||||
|
||||
// Run a task using the current active number of workers, returns when the task is done.
|
||||
virtual void run_task(AbstractGangTask* task);
|
||||
// Run a task with the given number of workers, returns
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/reflection.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
@ -598,12 +599,13 @@ JRT_ENTRY(jint, JVMCIRuntime::identity_hash_code(JavaThread* thread, oopDesc* ob
|
||||
JRT_END
|
||||
|
||||
JRT_ENTRY(jboolean, JVMCIRuntime::thread_is_interrupted(JavaThread* thread, oopDesc* receiver, jboolean clear_interrupted))
|
||||
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate.
|
||||
// This locking requires thread_in_vm which is why this method cannot be JRT_LEAF.
|
||||
Handle receiverHandle(thread, receiver);
|
||||
MutexLockerEx ml(thread->threadObj() == (void*)receiver ? NULL : Threads_lock);
|
||||
// A nested ThreadsListHandle may require the Threads_lock which
|
||||
// requires thread_in_vm which is why this method cannot be JRT_LEAF.
|
||||
ThreadsListHandle tlh;
|
||||
|
||||
JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle());
|
||||
if (receiverThread == NULL) {
|
||||
if (receiverThread == NULL || (EnableThreadSMRExtraValidityChecks && !tlh.includes(receiverThread))) {
|
||||
// The other thread may exit during this process, which is ok so return false.
|
||||
return JNI_FALSE;
|
||||
} else {
|
||||
|
@ -121,6 +121,7 @@
|
||||
LOG_TAG(safepoint) \
|
||||
LOG_TAG(scavenge) \
|
||||
LOG_TAG(scrub) \
|
||||
LOG_TAG(smr) \
|
||||
LOG_TAG(stacktrace) \
|
||||
LOG_TAG(stackwalk) \
|
||||
LOG_TAG(start) \
|
||||
|
@ -687,6 +687,10 @@ jint universe_init() {
|
||||
|
||||
Metaspace::global_initialize();
|
||||
|
||||
// Initialize performance counters for metaspaces
|
||||
MetaspaceCounters::initialize_performance_counters();
|
||||
CompressedClassSpaceCounters::initialize_performance_counters();
|
||||
|
||||
AOTLoader::universe_init();
|
||||
|
||||
// Checks 'AfterMemoryInit' constraints.
|
||||
@ -1085,10 +1089,6 @@ bool universe_post_init() {
|
||||
// ("weak") refs processing infrastructure initialization
|
||||
Universe::heap()->post_initialize();
|
||||
|
||||
// Initialize performance counters for metaspaces
|
||||
MetaspaceCounters::initialize_performance_counters();
|
||||
CompressedClassSpaceCounters::initialize_performance_counters();
|
||||
|
||||
MemoryService::add_metaspace_memory_pools();
|
||||
|
||||
MemoryService::set_universe_heap(Universe::heap());
|
||||
|
@ -71,10 +71,15 @@ void InstanceMirrorKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
|
||||
Devirtualizer<nv>::do_klass(closure, klass);
|
||||
}
|
||||
} else {
|
||||
// If klass is NULL then this a mirror for a primitive type.
|
||||
// We don't have to follow them, since they are handled as strong
|
||||
// roots in Universe::oops_do.
|
||||
assert(java_lang_Class::is_primitive(obj), "Sanity check");
|
||||
// We would like to assert here (as below) that if klass has been NULL, then
|
||||
// this has been a mirror for a primitive type that we do not need to follow
|
||||
// as they are always strong roots.
|
||||
// However, we might get across a klass that just changed during CMS concurrent
|
||||
// marking if allocation occurred in the old generation.
|
||||
// This is benign here, as we keep alive all CLDs that were loaded during the
|
||||
// CMS concurrent phase in the class loading, i.e. they will be iterated over
|
||||
// and kept alive during remark.
|
||||
// assert(java_lang_Class::is_primitive(obj), "Sanity check");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, 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
|
||||
@ -480,6 +480,7 @@ const char* InlineTree::check_can_parse(ciMethod* callee) {
|
||||
if ( callee->is_abstract()) return "abstract method";
|
||||
if (!callee->has_balanced_monitors()) return "not compilable (unbalanced monitors)";
|
||||
if ( callee->get_flow_analysis()->failing()) return "not compilable (flow analysis failed)";
|
||||
if (!callee->can_be_parsed()) return "cannot be parsed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2016, 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
|
||||
@ -29,6 +29,7 @@
|
||||
#include "opto/machnode.hpp"
|
||||
#include "opto/parse.hpp"
|
||||
#include "runtime/threadCritical.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
@ -91,8 +92,7 @@ IdealGraphPrinter *IdealGraphPrinter::printer() {
|
||||
}
|
||||
|
||||
void IdealGraphPrinter::clean_up() {
|
||||
JavaThread *p;
|
||||
for (p = Threads::first(); p; p = p->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *p = jtiwh.next(); ) {
|
||||
if (p->is_Compiler_thread()) {
|
||||
CompilerThread *c = (CompilerThread *)p;
|
||||
IdealGraphPrinter *printer = c->ideal_graph_printer();
|
||||
|
@ -4119,7 +4119,7 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae
|
||||
thread->initialize_thread_current();
|
||||
|
||||
if (!os::create_attached_thread(thread)) {
|
||||
delete thread;
|
||||
thread->smr_delete();
|
||||
return JNI_ERR;
|
||||
}
|
||||
// Enable stack overflow checks
|
||||
@ -4250,7 +4250,7 @@ jint JNICALL jni_DetachCurrentThread(JavaVM *vm) {
|
||||
// (platform-dependent) methods where we do alternate stack
|
||||
// maintenance work?)
|
||||
thread->exit(false, JavaThread::jni_detach);
|
||||
delete thread;
|
||||
thread->smr_delete();
|
||||
|
||||
HOTSPOT_JNI_DETACHCURRENTTHREAD_RETURN(JNI_OK);
|
||||
return JNI_OK;
|
||||
|
@ -66,6 +66,7 @@
|
||||
#include "runtime/perfData.hpp"
|
||||
#include "runtime/reflection.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "runtime/vm_operations.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
@ -2737,16 +2738,12 @@ void jio_print(const char* s) {
|
||||
|
||||
// java.lang.Thread //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// In most of the JVM Thread support functions we need to be sure to lock the Threads_lock
|
||||
// to prevent the target thread from exiting after we have a pointer to the C++ Thread or
|
||||
// OSThread objects. The exception to this rule is when the target object is the thread
|
||||
// doing the operation, in which case we know that the thread won't exit until the
|
||||
// operation is done (all exits being voluntary). There are a few cases where it is
|
||||
// rather silly to do operations on yourself, like resuming yourself or asking whether
|
||||
// you are alive. While these can still happen, they are not subject to deadlocks if
|
||||
// the lock is held while the operation occurs (this is not the case for suspend, for
|
||||
// instance), and are very unlikely. Because IsAlive needs to be fast and its
|
||||
// implementation is local to this file, we always lock Threads_lock for that one.
|
||||
// In most of the JVM thread support functions we need to access the
|
||||
// thread through a ThreadsListHandle to prevent it from exiting and
|
||||
// being reclaimed while we try to operate on it. The exceptions to this
|
||||
// rule are when operating on the current thread, or if the monitor of
|
||||
// the target java.lang.Thread is locked at the Java level - in both
|
||||
// cases the target cannot exit.
|
||||
|
||||
static void thread_entry(JavaThread* thread, TRAPS) {
|
||||
HandleMark hm(THREAD);
|
||||
@ -2821,7 +2818,7 @@ JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
|
||||
|
||||
if (native_thread->osthread() == NULL) {
|
||||
// No one should hold a reference to the 'native_thread'.
|
||||
delete native_thread;
|
||||
native_thread->smr_delete();
|
||||
if (JvmtiExport::should_post_resource_exhausted()) {
|
||||
JvmtiExport::post_resource_exhausted(
|
||||
JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,
|
||||
@ -2835,41 +2832,45 @@ JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
|
||||
|
||||
JVM_END
|
||||
|
||||
|
||||
// JVM_Stop is implemented using a VM_Operation, so threads are forced to safepoints
|
||||
// before the quasi-asynchronous exception is delivered. This is a little obtrusive,
|
||||
// but is thought to be reliable and simple. In the case, where the receiver is the
|
||||
// same thread as the sender, no safepoint is needed.
|
||||
// same thread as the sender, no VM_Operation is needed.
|
||||
JVM_ENTRY(void, JVM_StopThread(JNIEnv* env, jobject jthread, jobject throwable))
|
||||
JVMWrapper("JVM_StopThread");
|
||||
|
||||
// A nested ThreadsListHandle will grab the Threads_lock so create
|
||||
// tlh before we resolve throwable.
|
||||
ThreadsListHandle tlh(thread);
|
||||
oop java_throwable = JNIHandles::resolve(throwable);
|
||||
if (java_throwable == NULL) {
|
||||
THROW(vmSymbols::java_lang_NullPointerException());
|
||||
}
|
||||
oop java_thread = JNIHandles::resolve_non_null(jthread);
|
||||
JavaThread* receiver = java_lang_Thread::thread(java_thread);
|
||||
Events::log_exception(JavaThread::current(),
|
||||
oop java_thread = NULL;
|
||||
JavaThread* receiver = NULL;
|
||||
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, &java_thread);
|
||||
Events::log_exception(thread,
|
||||
"JVM_StopThread thread JavaThread " INTPTR_FORMAT " as oop " INTPTR_FORMAT " [exception " INTPTR_FORMAT "]",
|
||||
p2i(receiver), p2i((address)java_thread), p2i(throwable));
|
||||
// First check if thread is alive
|
||||
if (receiver != NULL) {
|
||||
// Check if exception is getting thrown at self (use oop equality, since the
|
||||
// target object might exit)
|
||||
if (java_thread == thread->threadObj()) {
|
||||
|
||||
if (is_alive) {
|
||||
// jthread refers to a live JavaThread.
|
||||
if (thread == receiver) {
|
||||
// Exception is getting thrown at self so no VM_Operation needed.
|
||||
THROW_OOP(java_throwable);
|
||||
} else {
|
||||
// Enques a VM_Operation to stop all threads and then deliver the exception...
|
||||
Thread::send_async_exception(java_thread, JNIHandles::resolve(throwable));
|
||||
// Use a VM_Operation to throw the exception.
|
||||
Thread::send_async_exception(java_thread, java_throwable);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Either:
|
||||
// - target thread has not been started before being stopped, or
|
||||
// - target thread already terminated
|
||||
// We could read the threadStatus to determine which case it is
|
||||
// but that is overkill as it doesn't matter. We must set the
|
||||
// stillborn flag for the first case, and if the thread has already
|
||||
// exited setting this flag has no affect
|
||||
// exited setting this flag has no effect.
|
||||
java_lang_Thread::set_stillborn(java_thread);
|
||||
}
|
||||
JVM_END
|
||||
@ -2885,12 +2886,12 @@ JVM_END
|
||||
|
||||
JVM_ENTRY(void, JVM_SuspendThread(JNIEnv* env, jobject jthread))
|
||||
JVMWrapper("JVM_SuspendThread");
|
||||
oop java_thread = JNIHandles::resolve_non_null(jthread);
|
||||
JavaThread* receiver = java_lang_Thread::thread(java_thread);
|
||||
|
||||
if (receiver != NULL) {
|
||||
// thread has run and has not exited (still on threads list)
|
||||
|
||||
ThreadsListHandle tlh(thread);
|
||||
JavaThread* receiver = NULL;
|
||||
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
|
||||
if (is_alive) {
|
||||
// jthread refers to a live JavaThread.
|
||||
{
|
||||
MutexLockerEx ml(receiver->SR_lock(), Mutex::_no_safepoint_check_flag);
|
||||
if (receiver->is_external_suspend()) {
|
||||
@ -2922,30 +2923,49 @@ JVM_END
|
||||
|
||||
JVM_ENTRY(void, JVM_ResumeThread(JNIEnv* env, jobject jthread))
|
||||
JVMWrapper("JVM_ResumeThread");
|
||||
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate.
|
||||
// We need to *always* get the threads lock here, since this operation cannot be allowed during
|
||||
// a safepoint. The safepoint code relies on suspending a thread to examine its state. If other
|
||||
// threads randomly resumes threads, then a thread might not be suspended when the safepoint code
|
||||
// looks at it.
|
||||
MutexLocker ml(Threads_lock);
|
||||
JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
|
||||
if (thr != NULL) {
|
||||
// the thread has run and is not in the process of exiting
|
||||
thr->java_resume();
|
||||
|
||||
ThreadsListHandle tlh(thread);
|
||||
JavaThread* receiver = NULL;
|
||||
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
|
||||
if (is_alive) {
|
||||
// jthread refers to a live JavaThread.
|
||||
|
||||
// This is the original comment for this Threads_lock grab:
|
||||
// We need to *always* get the threads lock here, since this operation cannot be allowed during
|
||||
// a safepoint. The safepoint code relies on suspending a thread to examine its state. If other
|
||||
// threads randomly resumes threads, then a thread might not be suspended when the safepoint code
|
||||
// looks at it.
|
||||
//
|
||||
// The above comment dates back to when we had both internal and
|
||||
// external suspend APIs that shared a common underlying mechanism.
|
||||
// External suspend is now entirely cooperative and doesn't share
|
||||
// anything with internal suspend. That said, there are some
|
||||
// assumptions in the VM that an external resume grabs the
|
||||
// Threads_lock. We can't drop the Threads_lock grab here until we
|
||||
// resolve the assumptions that exist elsewhere.
|
||||
//
|
||||
MutexLocker ml(Threads_lock);
|
||||
receiver->java_resume();
|
||||
}
|
||||
JVM_END
|
||||
|
||||
|
||||
JVM_ENTRY(void, JVM_SetThreadPriority(JNIEnv* env, jobject jthread, jint prio))
|
||||
JVMWrapper("JVM_SetThreadPriority");
|
||||
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
|
||||
MutexLocker ml(Threads_lock);
|
||||
oop java_thread = JNIHandles::resolve_non_null(jthread);
|
||||
|
||||
ThreadsListHandle tlh(thread);
|
||||
oop java_thread = NULL;
|
||||
JavaThread* receiver = NULL;
|
||||
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, &java_thread);
|
||||
java_lang_Thread::set_priority(java_thread, (ThreadPriority)prio);
|
||||
JavaThread* thr = java_lang_Thread::thread(java_thread);
|
||||
if (thr != NULL) { // Thread not yet started; priority pushed down when it is
|
||||
Thread::set_priority(thr, (ThreadPriority)prio);
|
||||
|
||||
if (is_alive) {
|
||||
// jthread refers to a live JavaThread.
|
||||
Thread::set_priority(receiver, (ThreadPriority)prio);
|
||||
}
|
||||
// Implied else: If the JavaThread hasn't started yet, then the
|
||||
// priority set in the java.lang.Thread object above will be pushed
|
||||
// down when it does start.
|
||||
JVM_END
|
||||
|
||||
|
||||
@ -3016,67 +3036,39 @@ JVM_END
|
||||
JVM_ENTRY(jint, JVM_CountStackFrames(JNIEnv* env, jobject jthread))
|
||||
JVMWrapper("JVM_CountStackFrames");
|
||||
|
||||
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
|
||||
oop java_thread = JNIHandles::resolve_non_null(jthread);
|
||||
bool throw_illegal_thread_state = false;
|
||||
uint32_t debug_bits = 0;
|
||||
ThreadsListHandle tlh(thread);
|
||||
JavaThread* receiver = NULL;
|
||||
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
|
||||
int count = 0;
|
||||
|
||||
{
|
||||
MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
|
||||
// We need to re-resolve the java_thread, since a GC might have happened during the
|
||||
// acquire of the lock
|
||||
JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
|
||||
|
||||
if (thr == NULL) {
|
||||
// do nothing
|
||||
} else if(! thr->is_external_suspend() || ! thr->frame_anchor()->walkable()) {
|
||||
// Check whether this java thread has been suspended already. If not, throws
|
||||
// IllegalThreadStateException. We defer to throw that exception until
|
||||
// Threads_lock is released since loading exception class has to leave VM.
|
||||
// The correct way to test a thread is actually suspended is
|
||||
// wait_for_ext_suspend_completion(), but we can't call that while holding
|
||||
// the Threads_lock. The above tests are sufficient for our purposes
|
||||
// provided the walkability of the stack is stable - which it isn't
|
||||
// 100% but close enough for most practical purposes.
|
||||
throw_illegal_thread_state = true;
|
||||
} else {
|
||||
// Count all java activation, i.e., number of vframes
|
||||
for(vframeStream vfst(thr); !vfst.at_end(); vfst.next()) {
|
||||
// Native frames are not counted
|
||||
if (is_alive) {
|
||||
// jthread refers to a live JavaThread.
|
||||
if (receiver->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
|
||||
// Count all java activation, i.e., number of vframes.
|
||||
for (vframeStream vfst(receiver); !vfst.at_end(); vfst.next()) {
|
||||
// Native frames are not counted.
|
||||
if (!vfst.method()->is_native()) count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
THROW_MSG_0(vmSymbols::java_lang_IllegalThreadStateException(),
|
||||
"this thread is not suspended");
|
||||
}
|
||||
}
|
||||
// Implied else: if JavaThread is not alive simply return a count of 0.
|
||||
|
||||
if (throw_illegal_thread_state) {
|
||||
THROW_MSG_0(vmSymbols::java_lang_IllegalThreadStateException(),
|
||||
"this thread is not suspended");
|
||||
}
|
||||
return count;
|
||||
JVM_END
|
||||
|
||||
// Consider: A better way to implement JVM_Interrupt() is to acquire
|
||||
// Threads_lock to resolve the jthread into a Thread pointer, fetch
|
||||
// Thread->platformevent, Thread->native_thr, Thread->parker, etc.,
|
||||
// drop Threads_lock, and the perform the unpark() and thr_kill() operations
|
||||
// outside the critical section. Threads_lock is hot so we want to minimize
|
||||
// the hold-time. A cleaner interface would be to decompose interrupt into
|
||||
// two steps. The 1st phase, performed under Threads_lock, would return
|
||||
// a closure that'd be invoked after Threads_lock was dropped.
|
||||
// This tactic is safe as PlatformEvent and Parkers are type-stable (TSM) and
|
||||
// admit spurious wakeups.
|
||||
|
||||
JVM_ENTRY(void, JVM_Interrupt(JNIEnv* env, jobject jthread))
|
||||
JVMWrapper("JVM_Interrupt");
|
||||
|
||||
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
|
||||
oop java_thread = JNIHandles::resolve_non_null(jthread);
|
||||
MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
|
||||
// We need to re-resolve the java_thread, since a GC might have happened during the
|
||||
// acquire of the lock
|
||||
JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
|
||||
if (thr != NULL) {
|
||||
Thread::interrupt(thr);
|
||||
ThreadsListHandle tlh(thread);
|
||||
JavaThread* receiver = NULL;
|
||||
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
|
||||
if (is_alive) {
|
||||
// jthread refers to a live JavaThread.
|
||||
Thread::interrupt(receiver);
|
||||
}
|
||||
JVM_END
|
||||
|
||||
@ -3084,16 +3076,14 @@ JVM_END
|
||||
JVM_QUICK_ENTRY(jboolean, JVM_IsInterrupted(JNIEnv* env, jobject jthread, jboolean clear_interrupted))
|
||||
JVMWrapper("JVM_IsInterrupted");
|
||||
|
||||
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
|
||||
oop java_thread = JNIHandles::resolve_non_null(jthread);
|
||||
MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
|
||||
// We need to re-resolve the java_thread, since a GC might have happened during the
|
||||
// acquire of the lock
|
||||
JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
|
||||
if (thr == NULL) {
|
||||
return JNI_FALSE;
|
||||
ThreadsListHandle tlh(thread);
|
||||
JavaThread* receiver = NULL;
|
||||
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
|
||||
if (is_alive) {
|
||||
// jthread refers to a live JavaThread.
|
||||
return (jboolean) Thread::is_interrupted(receiver, clear_interrupted != 0);
|
||||
} else {
|
||||
return (jboolean) Thread::is_interrupted(thr, clear_interrupted != 0);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
JVM_END
|
||||
|
||||
@ -3122,14 +3112,16 @@ JVM_END
|
||||
|
||||
JVM_ENTRY(void, JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring name))
|
||||
JVMWrapper("JVM_SetNativeThreadName");
|
||||
ResourceMark rm(THREAD);
|
||||
|
||||
// We don't use a ThreadsListHandle here because the current thread
|
||||
// must be alive.
|
||||
oop java_thread = JNIHandles::resolve_non_null(jthread);
|
||||
JavaThread* thr = java_lang_Thread::thread(java_thread);
|
||||
// Thread naming only supported for the current thread, doesn't work for
|
||||
// target threads.
|
||||
if (Thread::current() == thr && !thr->has_attached_via_jni()) {
|
||||
if (thread == thr && !thr->has_attached_via_jni()) {
|
||||
// Thread naming is only supported for the current thread and
|
||||
// we don't set the name of an attached thread to avoid stepping
|
||||
// on other programs
|
||||
// on other programs.
|
||||
ResourceMark rm(thread);
|
||||
const char *thread_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(name));
|
||||
os::set_native_thread_name(thread_name);
|
||||
}
|
||||
@ -3671,6 +3663,8 @@ JVM_ENTRY(jobjectArray, JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobject
|
||||
thread_handle_array->append(h);
|
||||
}
|
||||
|
||||
// The JavaThread references in thread_handle_array are validated
|
||||
// in VM_ThreadDump::doit().
|
||||
Handle stacktraces = ThreadService::dump_stack_traces(thread_handle_array, num_threads, CHECK_NULL);
|
||||
return (jobjectArray)JNIHandles::make_local(env, stacktraces());
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
# include "prims/jvmtiEnter.hpp"
|
||||
# include "prims/jvmtiRawMonitor.hpp"
|
||||
# include "prims/jvmtiUtil.hpp"
|
||||
# include "runtime/threadSMR.hpp"
|
||||
|
||||
</xsl:text>
|
||||
|
||||
@ -769,47 +770,27 @@ static jvmtiError JNICALL
|
||||
|
||||
<xsl:template match="jthread" mode="dochecksbody">
|
||||
<xsl:param name="name"/>
|
||||
<xsl:text> oop thread_oop = JNIHandles::resolve_external_guard(</xsl:text>
|
||||
<xsl:text> err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), </xsl:text>
|
||||
<xsl:value-of select="$name"/>
|
||||
<xsl:text>);
|
||||
if (thread_oop == NULL) {
|
||||
<xsl:text>, &java_thread, NULL);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
</xsl:text>
|
||||
<xsl:apply-templates select=".." mode="traceError">
|
||||
<xsl:with-param name="err">JVMTI_ERROR_INVALID_THREAD</xsl:with-param>
|
||||
<xsl:with-param name="comment"> - jthread resolved to NULL - jthread = " PTR_FORMAT "</xsl:with-param>
|
||||
<xsl:with-param name="err">err</xsl:with-param>
|
||||
<xsl:with-param name="comment"> - jthread did not convert to a JavaThread - jthread = " PTR_FORMAT "</xsl:with-param>
|
||||
<xsl:with-param name="extraValue">, p2i(<xsl:value-of select="$name"/>)</xsl:with-param>
|
||||
</xsl:apply-templates>
|
||||
<xsl:text>
|
||||
}
|
||||
if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
</xsl:text>
|
||||
<xsl:apply-templates select=".." mode="traceError">
|
||||
<xsl:with-param name="err">JVMTI_ERROR_INVALID_THREAD</xsl:with-param>
|
||||
<xsl:with-param name="comment"> - oop is not a thread - jthread = " PTR_FORMAT "</xsl:with-param>
|
||||
<xsl:with-param name="extraValue">, p2i(<xsl:value-of select="$name"/>)</xsl:with-param>
|
||||
</xsl:apply-templates>
|
||||
<xsl:text>
|
||||
}
|
||||
java_thread = java_lang_Thread::thread(thread_oop);
|
||||
if (java_thread == NULL) {
|
||||
</xsl:text>
|
||||
<xsl:apply-templates select=".." mode="traceError">
|
||||
<xsl:with-param name="err">
|
||||
<xsl:text>JVMTI_ERROR_THREAD_NOT_ALIVE</xsl:text>
|
||||
</xsl:with-param>
|
||||
<xsl:with-param name="comment"> - not a Java thread - jthread = " PTR_FORMAT "</xsl:with-param>
|
||||
<xsl:with-param name="extraValue">, p2i(<xsl:value-of select="$name"/>)</xsl:with-param>
|
||||
</xsl:apply-templates>
|
||||
<xsl:text>
|
||||
}
|
||||
</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="jthread" mode="dochecks">
|
||||
<xsl:param name="name"/>
|
||||
<!-- If we convert and test threads -->
|
||||
<xsl:if test="count(@impl)=0 or not(contains(@impl,'noconvert'))">
|
||||
<xsl:text> JavaThread* java_thread;
|
||||
<xsl:text> JavaThread* java_thread = NULL;
|
||||
ThreadsListHandle tlh(this_thread);
|
||||
</xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="count(@null)=0">
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "runtime/reflectionUtils.hpp"
|
||||
#include "runtime/signature.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/timerTrace.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
@ -162,7 +163,6 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) {
|
||||
*data_ptr = (state == NULL) ? NULL :
|
||||
state->env_thread_state(this)->get_agent_thread_local_storage_data();
|
||||
} else {
|
||||
|
||||
// jvmti_GetThreadLocalStorage is "in native" and doesn't transition
|
||||
// the thread to _thread_in_vm. However, when the TLS for a thread
|
||||
// other than the current thread is required we need to transition
|
||||
@ -172,17 +172,13 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) {
|
||||
VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread)
|
||||
debug_only(VMNativeEntryWrapper __vew;)
|
||||
|
||||
oop thread_oop = JNIHandles::resolve_external_guard(thread);
|
||||
if (thread_oop == NULL) {
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
}
|
||||
if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
}
|
||||
JavaThread* java_thread = java_lang_Thread::thread(thread_oop);
|
||||
if (java_thread == NULL) {
|
||||
return JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
JavaThread* java_thread = NULL;
|
||||
ThreadsListHandle tlh(current_thread);
|
||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
return err;
|
||||
}
|
||||
|
||||
JvmtiThreadState* state = java_thread->jvmti_thread_state();
|
||||
*data_ptr = (state == NULL) ? NULL :
|
||||
state->env_thread_state(this)->get_agent_thread_local_storage_data();
|
||||
@ -518,42 +514,60 @@ JvmtiEnv::SetEventCallbacks(const jvmtiEventCallbacks* callbacks, jint size_of_c
|
||||
// event_thread - NULL is a valid value, must be checked
|
||||
jvmtiError
|
||||
JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread, ...) {
|
||||
JavaThread* java_thread = NULL;
|
||||
if (event_thread != NULL) {
|
||||
oop thread_oop = JNIHandles::resolve_external_guard(event_thread);
|
||||
if (thread_oop == NULL) {
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
if (event_thread == NULL) {
|
||||
// Can be called at Agent_OnLoad() time with event_thread == NULL
|
||||
// when Thread::current() does not work yet so we cannot create a
|
||||
// ThreadsListHandle that is common to both thread-specific and
|
||||
// global code paths.
|
||||
|
||||
// event_type must be valid
|
||||
if (!JvmtiEventController::is_valid_event_type(event_type)) {
|
||||
return JVMTI_ERROR_INVALID_EVENT_TYPE;
|
||||
}
|
||||
if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
|
||||
bool enabled = (mode == JVMTI_ENABLE);
|
||||
|
||||
// assure that needed capabilities are present
|
||||
if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
|
||||
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
|
||||
}
|
||||
java_thread = java_lang_Thread::thread(thread_oop);
|
||||
if (java_thread == NULL) {
|
||||
return JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
|
||||
if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
|
||||
record_class_file_load_hook_enabled();
|
||||
}
|
||||
}
|
||||
JvmtiEventController::set_user_enabled(this, (JavaThread*) NULL, event_type, enabled);
|
||||
} else {
|
||||
// We have a specified event_thread.
|
||||
|
||||
// event_type must be valid
|
||||
if (!JvmtiEventController::is_valid_event_type(event_type)) {
|
||||
return JVMTI_ERROR_INVALID_EVENT_TYPE;
|
||||
}
|
||||
JavaThread* java_thread = NULL;
|
||||
ThreadsListHandle tlh;
|
||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), event_thread, &java_thread, NULL);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// global events cannot be controlled at thread level.
|
||||
if (java_thread != NULL && JvmtiEventController::is_global_event(event_type)) {
|
||||
return JVMTI_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
// event_type must be valid
|
||||
if (!JvmtiEventController::is_valid_event_type(event_type)) {
|
||||
return JVMTI_ERROR_INVALID_EVENT_TYPE;
|
||||
}
|
||||
|
||||
bool enabled = (mode == JVMTI_ENABLE);
|
||||
// global events cannot be controlled at thread level.
|
||||
if (JvmtiEventController::is_global_event(event_type)) {
|
||||
return JVMTI_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
// assure that needed capabilities are present
|
||||
if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
|
||||
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
|
||||
}
|
||||
bool enabled = (mode == JVMTI_ENABLE);
|
||||
|
||||
if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
|
||||
record_class_file_load_hook_enabled();
|
||||
// assure that needed capabilities are present
|
||||
if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
|
||||
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
|
||||
}
|
||||
|
||||
if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
|
||||
record_class_file_load_hook_enabled();
|
||||
}
|
||||
JvmtiEventController::set_user_enabled(this, java_thread, event_type, enabled);
|
||||
}
|
||||
JvmtiEventController::set_user_enabled(this, java_thread, event_type, enabled);
|
||||
|
||||
return JVMTI_ERROR_NONE;
|
||||
} /* end SetEventNotificationMode */
|
||||
@ -817,35 +831,45 @@ JvmtiEnv::GetJLocationFormat(jvmtiJlocationFormat* format_ptr) {
|
||||
// thread_state_ptr - pre-checked for NULL
|
||||
jvmtiError
|
||||
JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) {
|
||||
jint state;
|
||||
oop thread_oop;
|
||||
JavaThread* thr;
|
||||
JavaThread* current_thread = JavaThread::current();
|
||||
JavaThread* java_thread = NULL;
|
||||
oop thread_oop = NULL;
|
||||
ThreadsListHandle tlh(current_thread);
|
||||
|
||||
if (thread == NULL) {
|
||||
thread_oop = JavaThread::current()->threadObj();
|
||||
} else {
|
||||
thread_oop = JNIHandles::resolve_external_guard(thread);
|
||||
}
|
||||
java_thread = current_thread;
|
||||
thread_oop = java_thread->threadObj();
|
||||
|
||||
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
}
|
||||
} else {
|
||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
// We got an error code so we don't have a JavaThread *, but
|
||||
// only return an error from here if we didn't get a valid
|
||||
// thread_oop.
|
||||
if (thread_oop == NULL) {
|
||||
return err;
|
||||
}
|
||||
// We have a valid thread_oop so we can return some thread state.
|
||||
}
|
||||
}
|
||||
|
||||
// get most state bits
|
||||
state = (jint)java_lang_Thread::get_thread_status(thread_oop);
|
||||
jint state = (jint)java_lang_Thread::get_thread_status(thread_oop);
|
||||
|
||||
// add more state bits
|
||||
thr = java_lang_Thread::thread(thread_oop);
|
||||
if (thr != NULL) {
|
||||
JavaThreadState jts = thr->thread_state();
|
||||
if (java_thread != NULL) {
|
||||
// We have a JavaThread* so add more state bits.
|
||||
JavaThreadState jts = java_thread->thread_state();
|
||||
|
||||
if (thr->is_being_ext_suspended()) {
|
||||
if (java_thread->is_being_ext_suspended()) {
|
||||
state |= JVMTI_THREAD_STATE_SUSPENDED;
|
||||
}
|
||||
if (jts == _thread_in_native) {
|
||||
state |= JVMTI_THREAD_STATE_IN_NATIVE;
|
||||
}
|
||||
OSThread* osThread = thr->osthread();
|
||||
OSThread* osThread = java_thread->osthread();
|
||||
if (osThread != NULL && osThread->interrupted()) {
|
||||
state |= JVMTI_THREAD_STATE_INTERRUPTED;
|
||||
}
|
||||
@ -891,7 +915,6 @@ JvmtiEnv::GetAllThreads(jint* threads_count_ptr, jthread** threads_ptr) {
|
||||
thread_objs[i] = Handle(tle.get_threadObj(i));
|
||||
}
|
||||
|
||||
// have to make global handles outside of Threads_lock
|
||||
jthread *jthreads = new_jthreadArray(nthreads, thread_objs);
|
||||
NULL_CHECK(jthreads, JVMTI_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
@ -935,19 +958,12 @@ JvmtiEnv::SuspendThread(JavaThread* java_thread) {
|
||||
jvmtiError
|
||||
JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
|
||||
int needSafepoint = 0; // > 0 if we need a safepoint
|
||||
ThreadsListHandle tlh;
|
||||
for (int i = 0; i < request_count; i++) {
|
||||
JavaThread *java_thread = get_JavaThread(request_list[i]);
|
||||
if (java_thread == NULL) {
|
||||
results[i] = JVMTI_ERROR_INVALID_THREAD;
|
||||
continue;
|
||||
}
|
||||
// the thread has not yet run or has exited (not on threads list)
|
||||
if (java_thread->threadObj() == NULL) {
|
||||
results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
continue;
|
||||
}
|
||||
if (java_lang_Thread::thread(java_thread->threadObj()) == NULL) {
|
||||
results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
JavaThread *java_thread = NULL;
|
||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
results[i] = err;
|
||||
continue;
|
||||
}
|
||||
// don't allow hidden thread suspend request.
|
||||
@ -1018,10 +1034,12 @@ JvmtiEnv::ResumeThread(JavaThread* java_thread) {
|
||||
// results - pre-checked for NULL
|
||||
jvmtiError
|
||||
JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
|
||||
ThreadsListHandle tlh;
|
||||
for (int i = 0; i < request_count; i++) {
|
||||
JavaThread *java_thread = get_JavaThread(request_list[i]);
|
||||
if (java_thread == NULL) {
|
||||
results[i] = JVMTI_ERROR_INVALID_THREAD;
|
||||
JavaThread* java_thread = NULL;
|
||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
results[i] = err;
|
||||
continue;
|
||||
}
|
||||
// don't allow hidden thread resume request.
|
||||
@ -1039,7 +1057,7 @@ JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmt
|
||||
continue;
|
||||
}
|
||||
|
||||
results[i] = JVMTI_ERROR_NONE; // indicate successful suspend
|
||||
results[i] = JVMTI_ERROR_NONE; // indicate successful resume
|
||||
}
|
||||
// per-thread resume results returned via results parameter
|
||||
return JVMTI_ERROR_NONE;
|
||||
@ -1064,20 +1082,14 @@ JvmtiEnv::StopThread(JavaThread* java_thread, jobject exception) {
|
||||
// thread - NOT pre-checked
|
||||
jvmtiError
|
||||
JvmtiEnv::InterruptThread(jthread thread) {
|
||||
oop thread_oop = JNIHandles::resolve_external_guard(thread);
|
||||
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass()))
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
|
||||
// TODO: this is very similar to JVM_Interrupt(); share code in future
|
||||
JavaThread* current_thread = JavaThread::current();
|
||||
|
||||
// Todo: this is a duplicate of JVM_Interrupt; share code in future
|
||||
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
|
||||
MutexLockerEx ml(current_thread->threadObj() == thread_oop ? NULL : Threads_lock);
|
||||
// We need to re-resolve the java_thread, since a GC might have happened during the
|
||||
// acquire of the lock
|
||||
|
||||
JavaThread* java_thread = java_lang_Thread::thread(JNIHandles::resolve_external_guard(thread));
|
||||
NULL_CHECK(java_thread, JVMTI_ERROR_THREAD_NOT_ALIVE);
|
||||
JavaThread* java_thread = NULL;
|
||||
ThreadsListHandle tlh(current_thread);
|
||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
return err;
|
||||
}
|
||||
|
||||
Thread::interrupt(java_thread);
|
||||
|
||||
@ -1094,16 +1106,28 @@ JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) {
|
||||
HandleMark hm;
|
||||
|
||||
JavaThread* current_thread = JavaThread::current();
|
||||
ThreadsListHandle tlh(current_thread);
|
||||
|
||||
// if thread is NULL the current thread is used
|
||||
oop thread_oop;
|
||||
oop thread_oop = NULL;
|
||||
if (thread == NULL) {
|
||||
thread_oop = current_thread->threadObj();
|
||||
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
}
|
||||
} else {
|
||||
thread_oop = JNIHandles::resolve_external_guard(thread);
|
||||
JavaThread* java_thread = NULL;
|
||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
// We got an error code so we don't have a JavaThread *, but
|
||||
// only return an error from here if we didn't get a valid
|
||||
// thread_oop.
|
||||
if (thread_oop == NULL) {
|
||||
return err;
|
||||
}
|
||||
// We have a valid thread_oop so we can return some thread info.
|
||||
}
|
||||
}
|
||||
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass()))
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
|
||||
Handle thread_obj(current_thread, thread_oop);
|
||||
Handle name;
|
||||
@ -1272,17 +1296,31 @@ JvmtiEnv::GetCurrentContendedMonitor(JavaThread* java_thread, jobject* monitor_p
|
||||
// arg - NULL is a valid value, must be checked
|
||||
jvmtiError
|
||||
JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, const void* arg, jint priority) {
|
||||
oop thread_oop = JNIHandles::resolve_external_guard(thread);
|
||||
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
JavaThread* current_thread = JavaThread::current();
|
||||
|
||||
JavaThread* java_thread = NULL;
|
||||
oop thread_oop = NULL;
|
||||
ThreadsListHandle tlh(current_thread);
|
||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
// We got an error code so we don't have a JavaThread *, but
|
||||
// only return an error from here if we didn't get a valid
|
||||
// thread_oop.
|
||||
if (thread_oop == NULL) {
|
||||
return err;
|
||||
}
|
||||
// We have a valid thread_oop.
|
||||
}
|
||||
|
||||
if (java_thread != NULL) {
|
||||
// 'thread' refers to an existing JavaThread.
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
}
|
||||
|
||||
if (priority < JVMTI_THREAD_MIN_PRIORITY || priority > JVMTI_THREAD_MAX_PRIORITY) {
|
||||
return JVMTI_ERROR_INVALID_PRIORITY;
|
||||
}
|
||||
|
||||
//Thread-self
|
||||
JavaThread* current_thread = JavaThread::current();
|
||||
|
||||
Handle thread_hndl(current_thread, thread_oop);
|
||||
{
|
||||
MutexLocker mu(Threads_lock); // grab Threads_lock
|
||||
@ -1292,7 +1330,9 @@ JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, const void* ar
|
||||
// At this point it may be possible that no osthread was created for the
|
||||
// JavaThread due to lack of memory.
|
||||
if (new_thread == NULL || new_thread->osthread() == NULL) {
|
||||
if (new_thread) delete new_thread;
|
||||
if (new_thread != NULL) {
|
||||
new_thread->smr_delete();
|
||||
}
|
||||
return JVMTI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
@ -1394,36 +1434,53 @@ JvmtiEnv::GetThreadGroupChildren(jthreadGroup group, jint* thread_count_ptr, jth
|
||||
int ngroups = 0;
|
||||
int hidden_threads = 0;
|
||||
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
ResourceMark rm(current_thread);
|
||||
HandleMark hm(current_thread);
|
||||
|
||||
Handle group_hdl(current_thread, group_obj);
|
||||
|
||||
{ MutexLocker mu(Threads_lock);
|
||||
{ // Cannot allow thread or group counts to change.
|
||||
MutexLocker mu(Threads_lock);
|
||||
|
||||
nthreads = java_lang_ThreadGroup::nthreads(group_hdl());
|
||||
ngroups = java_lang_ThreadGroup::ngroups(group_hdl());
|
||||
|
||||
if (nthreads > 0) {
|
||||
ThreadsListHandle tlh(current_thread);
|
||||
objArrayOop threads = java_lang_ThreadGroup::threads(group_hdl());
|
||||
assert(nthreads <= threads->length(), "too many threads");
|
||||
thread_objs = NEW_RESOURCE_ARRAY(Handle,nthreads);
|
||||
for (int i=0, j=0; i<nthreads; i++) {
|
||||
oop thread_obj = threads->obj_at(i);
|
||||
assert(thread_obj != NULL, "thread_obj is NULL");
|
||||
JavaThread *javathread = java_lang_Thread::thread(thread_obj);
|
||||
// Filter out hidden java threads.
|
||||
if (javathread != NULL && javathread->is_hidden_from_external_view()) {
|
||||
hidden_threads++;
|
||||
continue;
|
||||
JavaThread *java_thread = NULL;
|
||||
jvmtiError err = JvmtiExport::cv_oop_to_JavaThread(tlh.list(), thread_obj, &java_thread);
|
||||
if (err == JVMTI_ERROR_NONE) {
|
||||
// Have a valid JavaThread*.
|
||||
if (java_thread->is_hidden_from_external_view()) {
|
||||
// Filter out hidden java threads.
|
||||
hidden_threads++;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// We couldn't convert thread_obj into a JavaThread*.
|
||||
if (err == JVMTI_ERROR_INVALID_THREAD) {
|
||||
// The thread_obj does not refer to a java.lang.Thread object
|
||||
// so skip it.
|
||||
hidden_threads++;
|
||||
continue;
|
||||
}
|
||||
// We have a valid thread_obj, but no JavaThread*; the caller
|
||||
// can still have limited use for the thread_obj.
|
||||
}
|
||||
thread_objs[j++] = Handle(current_thread, thread_obj);
|
||||
}
|
||||
nthreads -= hidden_threads;
|
||||
}
|
||||
} // ThreadsListHandle is destroyed here.
|
||||
|
||||
if (ngroups > 0) {
|
||||
objArrayOop groups = java_lang_ThreadGroup::groups(group_hdl());
|
||||
assert(ngroups <= groups->length(), "too many threads");
|
||||
assert(ngroups <= groups->length(), "too many groups");
|
||||
group_objs = NEW_RESOURCE_ARRAY(Handle,ngroups);
|
||||
for (int i=0; i<ngroups; i++) {
|
||||
oop group_obj = groups->obj_at(i);
|
||||
@ -1556,7 +1613,7 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) {
|
||||
}
|
||||
|
||||
// Check if java_thread is fully suspended
|
||||
if (!is_thread_fully_suspended(java_thread, true /* wait for suspend completion */, &debug_bits)) {
|
||||
if (!java_thread->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
|
||||
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||
}
|
||||
// Check to see if a PopFrame was already in progress
|
||||
@ -1686,8 +1743,8 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
|
||||
return JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
|
||||
if (!JvmtiEnv::is_thread_fully_suspended(java_thread, true, &debug_bits)) {
|
||||
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||
if (!java_thread->is_thread_fully_suspended(true, &debug_bits)) {
|
||||
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||
}
|
||||
|
||||
if (TraceJVMTICalls) {
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "runtime/objectMonitor.inline.hpp"
|
||||
#include "runtime/signature.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "runtime/vframe_hp.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
@ -487,37 +488,6 @@ JvmtiEnvBase::set_event_callbacks(const jvmtiEventCallbacks* callbacks,
|
||||
}
|
||||
}
|
||||
|
||||
// Called from JVMTI entry points which perform stack walking. If the
|
||||
// associated JavaThread is the current thread, then wait_for_suspend
|
||||
// is not used. Otherwise, it determines if we should wait for the
|
||||
// "other" thread to complete external suspension. (NOTE: in future
|
||||
// releases the suspension mechanism should be reimplemented so this
|
||||
// is not necessary.)
|
||||
//
|
||||
bool
|
||||
JvmtiEnvBase::is_thread_fully_suspended(JavaThread* thr, bool wait_for_suspend, uint32_t *bits) {
|
||||
// "other" threads require special handling
|
||||
if (thr != JavaThread::current()) {
|
||||
if (wait_for_suspend) {
|
||||
// We are allowed to wait for the external suspend to complete
|
||||
// so give the other thread a chance to get suspended.
|
||||
if (!thr->wait_for_ext_suspend_completion(SuspendRetryCount,
|
||||
SuspendRetryDelay, bits)) {
|
||||
// didn't make it so let the caller know
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// We aren't allowed to wait for the external suspend to complete
|
||||
// so if the other thread isn't externally suspended we need to
|
||||
// let the caller know.
|
||||
else if (!thr->is_ext_suspend_completed_with_lock(bits)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// In the fullness of time, all users of the method should instead
|
||||
// directly use allocate, besides being cleaner and faster, this will
|
||||
@ -560,19 +530,6 @@ JvmtiEnvBase::new_jthreadGroupArray(int length, Handle *handles) {
|
||||
return (jthreadGroup *) new_jobjectArray(length,handles);
|
||||
}
|
||||
|
||||
|
||||
JavaThread *
|
||||
JvmtiEnvBase::get_JavaThread(jthread jni_thread) {
|
||||
oop t = JNIHandles::resolve_external_guard(jni_thread);
|
||||
if (t == NULL || !t->is_a(SystemDictionary::Thread_klass())) {
|
||||
return NULL;
|
||||
}
|
||||
// The following returns NULL if the thread has not yet run or is in
|
||||
// process of exiting
|
||||
return java_lang_Thread::thread(t);
|
||||
}
|
||||
|
||||
|
||||
// return the vframe on the specified thread and depth, NULL if no such frame
|
||||
vframe*
|
||||
JvmtiEnvBase::vframeFor(JavaThread* java_thread, jint depth) {
|
||||
@ -670,7 +627,7 @@ JvmtiEnvBase::get_current_contended_monitor(JavaThread *calling_thread, JavaThre
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert((SafepointSynchronize::is_at_safepoint() ||
|
||||
is_thread_fully_suspended(java_thread, false, &debug_bits)),
|
||||
java_thread->is_thread_fully_suspended(false, &debug_bits)),
|
||||
"at safepoint or target thread is suspended");
|
||||
oop obj = NULL;
|
||||
ObjectMonitor *mon = java_thread->current_waiting_monitor();
|
||||
@ -709,7 +666,7 @@ JvmtiEnvBase::get_owned_monitors(JavaThread *calling_thread, JavaThread* java_th
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert((SafepointSynchronize::is_at_safepoint() ||
|
||||
is_thread_fully_suspended(java_thread, false, &debug_bits)),
|
||||
java_thread->is_thread_fully_suspended(false, &debug_bits)),
|
||||
"at safepoint or target thread is suspended");
|
||||
|
||||
if (java_thread->has_last_Java_frame()) {
|
||||
@ -831,7 +788,7 @@ JvmtiEnvBase::get_stack_trace(JavaThread *java_thread,
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert((SafepointSynchronize::is_at_safepoint() ||
|
||||
is_thread_fully_suspended(java_thread, false, &debug_bits)),
|
||||
java_thread->is_thread_fully_suspended(false, &debug_bits)),
|
||||
"at safepoint or target thread is suspended");
|
||||
int count = 0;
|
||||
if (java_thread->has_last_Java_frame()) {
|
||||
@ -914,7 +871,7 @@ JvmtiEnvBase::get_frame_location(JavaThread *java_thread, jint depth,
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert((SafepointSynchronize::is_at_safepoint() ||
|
||||
is_thread_fully_suspended(java_thread, false, &debug_bits)),
|
||||
java_thread->is_thread_fully_suspended(false, &debug_bits)),
|
||||
"at safepoint or target thread is suspended");
|
||||
Thread* current_thread = Thread::current();
|
||||
ResourceMark rm(current_thread);
|
||||
@ -976,7 +933,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
|
||||
// first derive the object's owner and entry_count (if any)
|
||||
{
|
||||
// Revoke any biases before querying the mark word
|
||||
if (SafepointSynchronize::is_at_safepoint()) {
|
||||
if (at_safepoint) {
|
||||
BiasedLocking::revoke_at_safepoint(hobj);
|
||||
} else {
|
||||
BiasedLocking::revoke_and_rebias(hobj, false, calling_thread);
|
||||
@ -1008,11 +965,11 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
|
||||
}
|
||||
|
||||
if (owner != NULL) {
|
||||
// Use current thread since function can be called from a
|
||||
// JavaThread or the VMThread.
|
||||
ThreadsListHandle tlh;
|
||||
// This monitor is owned so we have to find the owning JavaThread.
|
||||
// Since owning_thread_from_monitor_owner() grabs a lock, GC can
|
||||
// move our object at this point. However, our owner value is safe
|
||||
// since it is either the Lock word on a stack or a JavaThread *.
|
||||
owning_thread = Threads::owning_thread_from_monitor_owner(owner, !at_safepoint);
|
||||
owning_thread = Threads::owning_thread_from_monitor_owner(tlh.list(), owner);
|
||||
// Cannot assume (owning_thread != NULL) here because this function
|
||||
// may not have been called at a safepoint and the owning_thread
|
||||
// might not be suspended.
|
||||
@ -1021,7 +978,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
|
||||
// or it has to be suspended. Any of these conditions will prevent both
|
||||
// contending and waiting threads from modifying the state of
|
||||
// the monitor.
|
||||
if (!at_safepoint && !JvmtiEnv::is_thread_fully_suspended(owning_thread, true, &debug_bits)) {
|
||||
if (!at_safepoint && !owning_thread->is_thread_fully_suspended(true, &debug_bits)) {
|
||||
// Don't worry! This return of JVMTI_ERROR_THREAD_NOT_SUSPENDED
|
||||
// will not make it back to the JVM/TI agent. The error code will
|
||||
// get intercepted in JvmtiEnv::GetObjectMonitorUsage() which
|
||||
@ -1033,7 +990,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
|
||||
ret.owner = (jthread)jni_reference(calling_thread, th);
|
||||
}
|
||||
// implied else: no owner
|
||||
}
|
||||
} // ThreadsListHandle is destroyed here.
|
||||
|
||||
if (owning_thread != NULL) { // monitor is owned
|
||||
// The recursions field of a monitor does not reflect recursions
|
||||
@ -1084,13 +1041,15 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
|
||||
if (ret.waiter_count > 0) {
|
||||
// we have contending and/or waiting threads
|
||||
HandleMark hm;
|
||||
// Use current thread since function can be called from a
|
||||
// JavaThread or the VMThread.
|
||||
ThreadsListHandle tlh;
|
||||
if (nWant > 0) {
|
||||
// we have contending threads
|
||||
ResourceMark rm;
|
||||
// get_pending_threads returns only java thread so we do not need to
|
||||
// check for non java threads.
|
||||
GrowableArray<JavaThread*>* wantList = Threads::get_pending_threads(
|
||||
nWant, (address)mon, !at_safepoint);
|
||||
// check for non java threads.
|
||||
GrowableArray<JavaThread*>* wantList = Threads::get_pending_threads(tlh.list(), nWant, (address)mon);
|
||||
if (wantList->length() < nWant) {
|
||||
// robustness: the pending list has gotten smaller
|
||||
nWant = wantList->length();
|
||||
@ -1101,7 +1060,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
|
||||
// thread could potentially change the state of the monitor by
|
||||
// entering it. The JVM/TI spec doesn't allow this.
|
||||
if (owning_thread == NULL && !at_safepoint &
|
||||
!JvmtiEnv::is_thread_fully_suspended(pending_thread, true, &debug_bits)) {
|
||||
!pending_thread->is_thread_fully_suspended(true, &debug_bits)) {
|
||||
if (ret.owner != NULL) {
|
||||
destroy_jni_reference(calling_thread, ret.owner);
|
||||
}
|
||||
@ -1139,7 +1098,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
|
||||
waiter = mon->next_waiter(waiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // ThreadsListHandle is destroyed here.
|
||||
|
||||
// Adjust count. nWant and nWait count values may be less than original.
|
||||
ret.waiter_count = nWant + nWait;
|
||||
@ -1291,14 +1250,23 @@ VM_GetThreadListStackTraces::doit() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||
|
||||
ResourceMark rm;
|
||||
ThreadsListHandle tlh;
|
||||
for (int i = 0; i < _thread_count; ++i) {
|
||||
jthread jt = _thread_list[i];
|
||||
oop thread_oop = JNIHandles::resolve_external_guard(jt);
|
||||
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
set_result(JVMTI_ERROR_INVALID_THREAD);
|
||||
return;
|
||||
JavaThread* java_thread = NULL;
|
||||
oop thread_oop = NULL;
|
||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), jt, &java_thread, &thread_oop);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
// We got an error code so we don't have a JavaThread *, but
|
||||
// only return an error from here if we didn't get a valid
|
||||
// thread_oop.
|
||||
if (thread_oop == NULL) {
|
||||
set_result(err);
|
||||
return;
|
||||
}
|
||||
// We have a valid thread_oop.
|
||||
}
|
||||
fill_frames(jt, java_lang_Thread::thread(thread_oop), thread_oop);
|
||||
fill_frames(jt, java_thread, thread_oop);
|
||||
}
|
||||
allocate_and_fill_stacks(_thread_count);
|
||||
}
|
||||
@ -1309,7 +1277,7 @@ VM_GetAllStackTraces::doit() {
|
||||
|
||||
ResourceMark rm;
|
||||
_final_thread_count = 0;
|
||||
for (JavaThread *jt = Threads::first(); jt != NULL; jt = jt->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
|
||||
oop thread_oop = jt->threadObj();
|
||||
if (thread_oop != NULL &&
|
||||
!jt->is_exiting() &&
|
||||
@ -1404,9 +1372,7 @@ JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState
|
||||
}
|
||||
|
||||
// Check if java_thread is fully suspended
|
||||
if (!is_thread_fully_suspended(java_thread,
|
||||
true /* wait for suspend completion */,
|
||||
&debug_bits)) {
|
||||
if (!java_thread->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
|
||||
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||
}
|
||||
|
||||
@ -1521,3 +1487,79 @@ JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobje
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
VM_UpdateForPopTopFrame::doit() {
|
||||
JavaThread* jt = _state->get_thread();
|
||||
ThreadsListHandle tlh;
|
||||
if (jt != NULL && tlh.includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
|
||||
_state->update_for_pop_top_frame();
|
||||
} else {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VM_SetFramePop::doit() {
|
||||
JavaThread* jt = _state->get_thread();
|
||||
ThreadsListHandle tlh;
|
||||
if (jt != NULL && tlh.includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
|
||||
int frame_number = _state->count_frames() - _depth;
|
||||
_state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number);
|
||||
} else {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VM_GetOwnedMonitorInfo::doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
ThreadsListHandle tlh;
|
||||
if (_java_thread != NULL && tlh.includes(_java_thread)
|
||||
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread, _java_thread,
|
||||
_owned_monitors_list);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VM_GetCurrentContendedMonitor::doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
ThreadsListHandle tlh;
|
||||
if (_java_thread != NULL && tlh.includes(_java_thread)
|
||||
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread,_java_thread,_owned_monitor_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VM_GetStackTrace::doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
ThreadsListHandle tlh;
|
||||
if (_java_thread != NULL && tlh.includes(_java_thread)
|
||||
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase *)_env)->get_stack_trace(_java_thread,
|
||||
_start_depth, _max_count,
|
||||
_frame_buffer, _count_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VM_GetFrameCount::doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
JavaThread* jt = _state->get_thread();
|
||||
ThreadsListHandle tlh;
|
||||
if (jt != NULL && tlh.includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase*)_env)->get_frame_count(_state, _count_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VM_GetFrameLocation::doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
ThreadsListHandle tlh;
|
||||
if (_java_thread != NULL && tlh.includes(_java_thread)
|
||||
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase*)_env)->get_frame_location(_java_thread, _depth,
|
||||
_method_ptr, _location_ptr);
|
||||
}
|
||||
}
|
||||
|
@ -280,9 +280,6 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
|
||||
jthread * new_jthreadArray(int length, Handle *handles);
|
||||
jthreadGroup * new_jthreadGroupArray(int length, Handle *handles);
|
||||
|
||||
// convert from JNIHandle to JavaThread *
|
||||
JavaThread * get_JavaThread(jthread jni_thread);
|
||||
|
||||
// convert to a jni jclass from a non-null Klass*
|
||||
jclass get_jni_class_non_null(Klass* k);
|
||||
|
||||
@ -297,11 +294,6 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
|
||||
public:
|
||||
// get a field descriptor for the specified class and field
|
||||
static bool get_field_descriptor(Klass* k, jfieldID field, fieldDescriptor* fd);
|
||||
// test for suspend - most (all?) of these should go away
|
||||
static bool is_thread_fully_suspended(JavaThread *thread,
|
||||
bool wait_for_suspend,
|
||||
uint32_t *bits);
|
||||
|
||||
|
||||
// JVMTI API helper functions which are called at safepoint or thread is suspended.
|
||||
jvmtiError get_frame_count(JvmtiThreadState *state, jint *count_ptr);
|
||||
@ -360,14 +352,7 @@ public:
|
||||
}
|
||||
VMOp_Type type() const { return VMOp_UpdateForPopTopFrame; }
|
||||
jvmtiError result() { return _result; }
|
||||
void doit() {
|
||||
JavaThread* jt = _state->get_thread();
|
||||
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
|
||||
_state->update_for_pop_top_frame();
|
||||
} else {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
}
|
||||
void doit();
|
||||
};
|
||||
|
||||
// VM operation to set frame pop.
|
||||
@ -390,15 +375,7 @@ public:
|
||||
bool allow_nested_vm_operations() const { return true; }
|
||||
VMOp_Type type() const { return VMOp_SetFramePop; }
|
||||
jvmtiError result() { return _result; }
|
||||
void doit() {
|
||||
JavaThread* jt = _state->get_thread();
|
||||
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
|
||||
int frame_number = _state->count_frames() - _depth;
|
||||
_state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number);
|
||||
} else {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
}
|
||||
void doit();
|
||||
};
|
||||
|
||||
|
||||
@ -422,14 +399,7 @@ public:
|
||||
_result = JVMTI_ERROR_NONE;
|
||||
}
|
||||
VMOp_Type type() const { return VMOp_GetOwnedMonitorInfo; }
|
||||
void doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
if (Threads::includes(_java_thread) && !_java_thread->is_exiting()
|
||||
&& _java_thread->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread, _java_thread,
|
||||
_owned_monitors_list);
|
||||
}
|
||||
}
|
||||
void doit();
|
||||
jvmtiError result() { return _result; }
|
||||
};
|
||||
|
||||
@ -476,13 +446,7 @@ public:
|
||||
}
|
||||
VMOp_Type type() const { return VMOp_GetCurrentContendedMonitor; }
|
||||
jvmtiError result() { return _result; }
|
||||
void doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
if (Threads::includes(_java_thread) && !_java_thread->is_exiting() &&
|
||||
_java_thread->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread,_java_thread,_owned_monitor_ptr);
|
||||
}
|
||||
}
|
||||
void doit();
|
||||
};
|
||||
|
||||
// VM operation to get stack trace at safepoint.
|
||||
@ -509,15 +473,7 @@ public:
|
||||
}
|
||||
jvmtiError result() { return _result; }
|
||||
VMOp_Type type() const { return VMOp_GetStackTrace; }
|
||||
void doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
if (Threads::includes(_java_thread) && !_java_thread->is_exiting()
|
||||
&& _java_thread->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase *)_env)->get_stack_trace(_java_thread,
|
||||
_start_depth, _max_count,
|
||||
_frame_buffer, _count_ptr);
|
||||
}
|
||||
}
|
||||
void doit();
|
||||
};
|
||||
|
||||
// forward declaration
|
||||
@ -607,13 +563,7 @@ public:
|
||||
}
|
||||
VMOp_Type type() const { return VMOp_GetFrameCount; }
|
||||
jvmtiError result() { return _result; }
|
||||
void doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
JavaThread* jt = _state->get_thread();
|
||||
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase*)_env)->get_frame_count(_state, _count_ptr);
|
||||
}
|
||||
}
|
||||
void doit();
|
||||
};
|
||||
|
||||
// VM operation to frame location at safepoint.
|
||||
@ -637,14 +587,7 @@ public:
|
||||
}
|
||||
VMOp_Type type() const { return VMOp_GetFrameLocation; }
|
||||
jvmtiError result() { return _result; }
|
||||
void doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
if (Threads::includes(_java_thread) && !_java_thread->is_exiting() &&
|
||||
_java_thread->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase*)_env)->get_frame_location(_java_thread, _depth,
|
||||
_method_ptr, _location_ptr);
|
||||
}
|
||||
}
|
||||
void doit();
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2014, 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
|
||||
@ -35,6 +35,7 @@
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/signature.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "runtime/vm_operations.hpp"
|
||||
|
||||
|
@ -33,7 +33,8 @@
|
||||
#include "prims/jvmtiImpl.hpp"
|
||||
#include "prims/jvmtiThreadState.inline.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "runtime/vframe_hp.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
@ -580,13 +581,10 @@ JvmtiEventControllerPrivate::recompute_enabled() {
|
||||
// filtered events and there weren't last time
|
||||
if ( (any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) != 0 &&
|
||||
(was_any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) == 0) {
|
||||
{
|
||||
MutexLocker mu(Threads_lock); //hold the Threads_lock for the iteration
|
||||
for (JavaThread *tp = Threads::first(); tp != NULL; tp = tp->next()) {
|
||||
// state_for_while_locked() makes tp->is_exiting() check
|
||||
JvmtiThreadState::state_for_while_locked(tp); // create the thread state if missing
|
||||
}
|
||||
}// release Threads_lock
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *tp = jtiwh.next(); ) {
|
||||
// state_for_while_locked() makes tp->is_exiting() check
|
||||
JvmtiThreadState::state_for_while_locked(tp); // create the thread state if missing
|
||||
}
|
||||
}
|
||||
|
||||
// compute and set thread-filtered events
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "runtime/objectMonitor.inline.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "services/serviceUtil.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
@ -721,6 +722,108 @@ JvmtiExport::get_all_native_method_prefixes(int* count_ptr) {
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an external thread reference to a JavaThread found on the
|
||||
// specified ThreadsList. The ThreadsListHandle in the caller "protects"
|
||||
// the returned JavaThread *.
|
||||
//
|
||||
// If thread_oop_p is not NULL, then the caller wants to use the oop
|
||||
// after this call so the oop is returned. On success, *jt_pp is set
|
||||
// to the converted JavaThread * and JVMTI_ERROR_NONE is returned.
|
||||
// On error, returns various JVMTI_ERROR_* values.
|
||||
//
|
||||
jvmtiError
|
||||
JvmtiExport::cv_external_thread_to_JavaThread(ThreadsList * t_list,
|
||||
jthread thread,
|
||||
JavaThread ** jt_pp,
|
||||
oop * thread_oop_p) {
|
||||
assert(t_list != NULL, "must have a ThreadsList");
|
||||
assert(jt_pp != NULL, "must have a return JavaThread pointer");
|
||||
// thread_oop_p is optional so no assert()
|
||||
|
||||
oop thread_oop = JNIHandles::resolve_external_guard(thread);
|
||||
if (thread_oop == NULL) {
|
||||
// NULL jthread, GC'ed jthread or a bad JNI handle.
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
}
|
||||
// Looks like an oop at this point.
|
||||
|
||||
if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
// The oop is not a java.lang.Thread.
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
}
|
||||
// Looks like a java.lang.Thread oop at this point.
|
||||
|
||||
if (thread_oop_p != NULL) {
|
||||
// Return the oop to the caller; the caller may still want
|
||||
// the oop even if this function returns an error.
|
||||
*thread_oop_p = thread_oop;
|
||||
}
|
||||
|
||||
JavaThread * java_thread = java_lang_Thread::thread(thread_oop);
|
||||
if (java_thread == NULL) {
|
||||
// The java.lang.Thread does not contain a JavaThread * so it has
|
||||
// not yet run or it has died.
|
||||
return JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
// Looks like a live JavaThread at this point.
|
||||
|
||||
// We do not check the EnableThreadSMRExtraValidityChecks option
|
||||
// for this includes() call because JVM/TI's spec is tighter.
|
||||
if (!t_list->includes(java_thread)) {
|
||||
// Not on the JavaThreads list so it is not alive.
|
||||
return JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
|
||||
// Return a live JavaThread that is "protected" by the
|
||||
// ThreadsListHandle in the caller.
|
||||
*jt_pp = java_thread;
|
||||
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
|
||||
// Convert an oop to a JavaThread found on the specified ThreadsList.
|
||||
// The ThreadsListHandle in the caller "protects" the returned
|
||||
// JavaThread *.
|
||||
//
|
||||
// On success, *jt_pp is set to the converted JavaThread * and
|
||||
// JVMTI_ERROR_NONE is returned. On error, returns various
|
||||
// JVMTI_ERROR_* values.
|
||||
//
|
||||
jvmtiError
|
||||
JvmtiExport::cv_oop_to_JavaThread(ThreadsList * t_list, oop thread_oop,
|
||||
JavaThread ** jt_pp) {
|
||||
assert(t_list != NULL, "must have a ThreadsList");
|
||||
assert(thread_oop != NULL, "must have an oop");
|
||||
assert(jt_pp != NULL, "must have a return JavaThread pointer");
|
||||
|
||||
if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
|
||||
// The oop is not a java.lang.Thread.
|
||||
return JVMTI_ERROR_INVALID_THREAD;
|
||||
}
|
||||
// Looks like a java.lang.Thread oop at this point.
|
||||
|
||||
JavaThread * java_thread = java_lang_Thread::thread(thread_oop);
|
||||
if (java_thread == NULL) {
|
||||
// The java.lang.Thread does not contain a JavaThread * so it has
|
||||
// not yet run or it has died.
|
||||
return JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
// Looks like a live JavaThread at this point.
|
||||
|
||||
// We do not check the EnableThreadSMRExtraValidityChecks option
|
||||
// for this includes() call because JVM/TI's spec is tighter.
|
||||
if (!t_list->includes(java_thread)) {
|
||||
// Not on the JavaThreads list so it is not alive.
|
||||
return JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
|
||||
// Return a live JavaThread that is "protected" by the
|
||||
// ThreadsListHandle in the caller.
|
||||
*jt_pp = java_thread;
|
||||
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
|
||||
class JvmtiClassFileLoadHookPoster : public StackObj {
|
||||
private:
|
||||
Symbol* _h_name;
|
||||
@ -2685,8 +2788,7 @@ void JvmtiVMObjectAllocEventCollector::oops_do_for_all_threads(OopClosure* f) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Runs at safepoint. So no need to acquire Threads_lock.
|
||||
for (JavaThread *jthr = Threads::first(); jthr != NULL; jthr = jthr->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jthr = jtiwh.next(); ) {
|
||||
JvmtiThreadState *state = jthr->jvmti_thread_state();
|
||||
if (state != NULL) {
|
||||
JvmtiVMObjectAllocEventCollector *collector;
|
||||
|
@ -399,6 +399,14 @@ class JvmtiExport : public AllStatic {
|
||||
|
||||
// SetNativeMethodPrefix support
|
||||
static char** get_all_native_method_prefixes(int* count_ptr) NOT_JVMTI_RETURN_(NULL);
|
||||
|
||||
// JavaThread lifecycle support:
|
||||
static jvmtiError cv_external_thread_to_JavaThread(ThreadsList * t_list,
|
||||
jthread thread,
|
||||
JavaThread ** jt_pp,
|
||||
oop * thread_oop_p);
|
||||
static jvmtiError cv_oop_to_JavaThread(ThreadsList * t_list, oop thread_oop,
|
||||
JavaThread ** jt_pp);
|
||||
};
|
||||
|
||||
// Support class used by JvmtiDynamicCodeEventCollector and others. It
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "runtime/serviceThread.hpp"
|
||||
#include "runtime/signature.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "runtime/vframe_hp.hpp"
|
||||
#include "runtime/vm_operations.hpp"
|
||||
@ -878,10 +879,9 @@ bool JvmtiSuspendControl::resume(JavaThread *java_thread) {
|
||||
|
||||
void JvmtiSuspendControl::print() {
|
||||
#ifndef PRODUCT
|
||||
MutexLocker mu(Threads_lock);
|
||||
LogStreamHandle(Trace, jvmti) log_stream;
|
||||
log_stream.print("Suspended Threads: [");
|
||||
for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
|
||||
#ifdef JVMTI_TRACE
|
||||
const char *name = JvmtiTrace::safe_get_thread_name(thread);
|
||||
#else
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/jvmtiImpl.hpp"
|
||||
#include "prims/jvmtiRedefineClasses.hpp"
|
||||
#include "prims/jvmtiThreadState.inline.hpp"
|
||||
#include "prims/resolvedMethodTable.hpp"
|
||||
#include "prims/methodComparator.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
|
@ -45,6 +45,8 @@
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/reflectionUtils.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "runtime/vm_operations.hpp"
|
||||
@ -3174,7 +3176,7 @@ inline bool VM_HeapWalkOperation::collect_stack_roots(JavaThread* java_thread,
|
||||
// stack to find all references and local JNI refs.
|
||||
inline bool VM_HeapWalkOperation::collect_stack_roots() {
|
||||
JNILocalRootsClosure blk;
|
||||
for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
|
||||
oop threadObj = thread->threadObj();
|
||||
if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) {
|
||||
// Collect the simple root for this thread before we
|
||||
|
@ -336,34 +336,10 @@ class JvmtiThreadState : public CHeapObj<mtInternal> {
|
||||
|
||||
// already holding JvmtiThreadState_lock - retrieve or create JvmtiThreadState
|
||||
// Can return NULL if JavaThread is exiting.
|
||||
inline static JvmtiThreadState *state_for_while_locked(JavaThread *thread) {
|
||||
assert(JvmtiThreadState_lock->is_locked(), "sanity check");
|
||||
|
||||
JvmtiThreadState *state = thread->jvmti_thread_state();
|
||||
if (state == NULL) {
|
||||
if (thread->is_exiting()) {
|
||||
// don't add a JvmtiThreadState to a thread that is exiting
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = new JvmtiThreadState(thread);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
static JvmtiThreadState *state_for_while_locked(JavaThread *thread);
|
||||
// retrieve or create JvmtiThreadState
|
||||
// Can return NULL if JavaThread is exiting.
|
||||
inline static JvmtiThreadState *state_for(JavaThread *thread) {
|
||||
JvmtiThreadState *state = thread->jvmti_thread_state();
|
||||
if (state == NULL) {
|
||||
MutexLocker mu(JvmtiThreadState_lock);
|
||||
// check again with the lock held
|
||||
state = state_for_while_locked(thread);
|
||||
} else {
|
||||
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
|
||||
}
|
||||
return state;
|
||||
}
|
||||
static JvmtiThreadState *state_for(JavaThread *thread);
|
||||
|
||||
// JVMTI ForceEarlyReturn support
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 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
|
||||
@ -68,4 +68,31 @@ void JvmtiThreadState::set_head_env_thread_state(JvmtiEnvThreadState* ets) {
|
||||
_head_env_thread_state = ets;
|
||||
}
|
||||
|
||||
inline JvmtiThreadState* JvmtiThreadState::state_for_while_locked(JavaThread *thread) {
|
||||
assert(JvmtiThreadState_lock->is_locked(), "sanity check");
|
||||
|
||||
JvmtiThreadState *state = thread->jvmti_thread_state();
|
||||
if (state == NULL) {
|
||||
if (thread->is_exiting()) {
|
||||
// don't add a JvmtiThreadState to a thread that is exiting
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = new JvmtiThreadState(thread);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
inline JvmtiThreadState* JvmtiThreadState::state_for(JavaThread *thread) {
|
||||
JvmtiThreadState *state = thread->jvmti_thread_state();
|
||||
if (state == NULL) {
|
||||
MutexLocker mu(JvmtiThreadState_lock);
|
||||
// check again with the lock held
|
||||
state = state_for_while_locked(thread);
|
||||
} else {
|
||||
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
#endif // SHARE_VM_PRIMS_JVMTITHREADSTATE_INLINE_HPP
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
#include "runtime/perfData.inline.hpp"
|
||||
#include "runtime/perfMemory.hpp"
|
||||
|
||||
/*
|
||||
|
@ -39,6 +39,8 @@
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/orderAccess.inline.hpp"
|
||||
#include "runtime/reflection.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "services/threadService.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
@ -937,8 +939,12 @@ UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread))
|
||||
Parker* p = NULL;
|
||||
|
||||
if (jthread != NULL) {
|
||||
oop java_thread = JNIHandles::resolve_non_null(jthread);
|
||||
ThreadsListHandle tlh;
|
||||
JavaThread* thr = NULL;
|
||||
oop java_thread = NULL;
|
||||
(void) tlh.cv_internal_thread_to_JavaThread(jthread, &thr, &java_thread);
|
||||
if (java_thread != NULL) {
|
||||
// This is a valid oop.
|
||||
jlong lp = java_lang_Thread::park_event(java_thread);
|
||||
if (lp != 0) {
|
||||
// This cast is OK even though the jlong might have been read
|
||||
@ -946,22 +952,19 @@ UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread))
|
||||
// always be zero anyway and the value set is always the same
|
||||
p = (Parker*)addr_from_java(lp);
|
||||
} else {
|
||||
// Grab lock if apparently null or using older version of library
|
||||
MutexLocker mu(Threads_lock);
|
||||
java_thread = JNIHandles::resolve_non_null(jthread);
|
||||
|
||||
if (java_thread != NULL) {
|
||||
JavaThread* thr = java_lang_Thread::thread(java_thread);
|
||||
if (thr != NULL) {
|
||||
p = thr->parker();
|
||||
if (p != NULL) { // Bind to Java thread for next time.
|
||||
java_lang_Thread::set_park_event(java_thread, addr_to_java(p));
|
||||
}
|
||||
// Not cached in the java.lang.Thread oop yet (could be an
|
||||
// older version of library).
|
||||
if (thr != NULL) {
|
||||
// The JavaThread is alive.
|
||||
p = thr->parker();
|
||||
if (p != NULL) {
|
||||
// Cache the Parker in the java.lang.Thread oop for next time.
|
||||
java_lang_Thread::set_park_event(java_thread, addr_to_java(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // ThreadsListHandle is destroyed here.
|
||||
|
||||
if (p != NULL) {
|
||||
HOTSPOT_THREAD_UNPARK((uintptr_t) p);
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/sweeper.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
@ -665,7 +666,7 @@ class VM_WhiteBoxDeoptimizeFrames : public VM_WhiteBoxOperation {
|
||||
int result() const { return _result; }
|
||||
|
||||
void doit() {
|
||||
for (JavaThread* t = Threads::first(); t != NULL; t = t->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
|
||||
if (t->has_last_Java_frame()) {
|
||||
for (StackFrameStream fst(t, UseBiasedLocking); !fst.is_done(); fst.next()) {
|
||||
frame* f = fst.current();
|
||||
|
@ -497,7 +497,7 @@ bool Arguments::is_obsolete_flag(const char *flag_name, JDK_Version* version) {
|
||||
SpecialFlag flag;
|
||||
if (lookup_special_flag(flag_name, flag)) {
|
||||
if (!flag.obsolete_in.is_undefined()) {
|
||||
if (version_less_than(JDK_Version::current(), flag.expired_in)) {
|
||||
if (!version_less_than(JDK_Version::current(), flag.obsolete_in)) {
|
||||
*version = flag.obsolete_in;
|
||||
return true;
|
||||
}
|
||||
@ -2152,12 +2152,7 @@ bool Arguments::check_vm_args_consistency() {
|
||||
// Check lower bounds of the code cache
|
||||
// Template Interpreter code is approximately 3X larger in debug builds.
|
||||
uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3);
|
||||
if (InitialCodeCacheSize < (uintx)os::vm_page_size()) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Invalid InitialCodeCacheSize=%dK. Must be at least %dK.\n", InitialCodeCacheSize/K,
|
||||
os::vm_page_size()/K);
|
||||
status = false;
|
||||
} else if (ReservedCodeCacheSize < InitialCodeCacheSize) {
|
||||
if (ReservedCodeCacheSize < InitialCodeCacheSize) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Invalid ReservedCodeCacheSize: %dK. Must be at least InitialCodeCacheSize=%dK.\n",
|
||||
ReservedCodeCacheSize/K, InitialCodeCacheSize/K);
|
||||
@ -2770,18 +2765,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m
|
||||
if (FLAG_SET_CMDLINE(intx, ThreadStackSize, value) != Flag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
} else if (match_option(option, "-XX:CodeCacheExpansionSize=", &tail)) {
|
||||
julong long_CodeCacheExpansionSize = 0;
|
||||
ArgsRange errcode = parse_memory_size(tail, &long_CodeCacheExpansionSize, os::vm_page_size());
|
||||
if (errcode != arg_in_range) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Invalid argument: %s. Must be at least %luK.\n", option->optionString,
|
||||
os::vm_page_size()/K);
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
if (FLAG_SET_CMDLINE(uintx, CodeCacheExpansionSize, (uintx)long_CodeCacheExpansionSize) != Flag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
} else if (match_option(option, "-Xmaxjitcodesize", &tail) ||
|
||||
match_option(option, "-XX:ReservedCodeCacheSize=", &tail)) {
|
||||
julong long_ReservedCodeCacheSize = 0;
|
||||
@ -2795,45 +2778,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m
|
||||
if (FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != Flag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
// -XX:NonNMethodCodeHeapSize=
|
||||
} else if (match_option(option, "-XX:NonNMethodCodeHeapSize=", &tail)) {
|
||||
julong long_NonNMethodCodeHeapSize = 0;
|
||||
|
||||
ArgsRange errcode = parse_memory_size(tail, &long_NonNMethodCodeHeapSize, 1);
|
||||
if (errcode != arg_in_range) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Invalid maximum non-nmethod code heap size: %s.\n", option->optionString);
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
if (FLAG_SET_CMDLINE(uintx, NonNMethodCodeHeapSize, (uintx)long_NonNMethodCodeHeapSize) != Flag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
// -XX:ProfiledCodeHeapSize=
|
||||
} else if (match_option(option, "-XX:ProfiledCodeHeapSize=", &tail)) {
|
||||
julong long_ProfiledCodeHeapSize = 0;
|
||||
|
||||
ArgsRange errcode = parse_memory_size(tail, &long_ProfiledCodeHeapSize, 1);
|
||||
if (errcode != arg_in_range) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Invalid maximum profiled code heap size: %s.\n", option->optionString);
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
if (FLAG_SET_CMDLINE(uintx, ProfiledCodeHeapSize, (uintx)long_ProfiledCodeHeapSize) != Flag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
// -XX:NonProfiledCodeHeapSizee=
|
||||
} else if (match_option(option, "-XX:NonProfiledCodeHeapSize=", &tail)) {
|
||||
julong long_NonProfiledCodeHeapSize = 0;
|
||||
|
||||
ArgsRange errcode = parse_memory_size(tail, &long_NonProfiledCodeHeapSize, 1);
|
||||
if (errcode != arg_in_range) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Invalid maximum non-profiled code heap size: %s.\n", option->optionString);
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
if (FLAG_SET_CMDLINE(uintx, NonProfiledCodeHeapSize, (uintx)long_NonProfiledCodeHeapSize) != Flag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
// -green
|
||||
} else if (match_option(option, "-green")) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "runtime/basicLock.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/task.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "runtime/vm_operations.hpp"
|
||||
@ -214,12 +215,8 @@ static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_
|
||||
if (requesting_thread == biased_thread) {
|
||||
thread_is_alive = true;
|
||||
} else {
|
||||
for (JavaThread* cur_thread = Threads::first(); cur_thread != NULL; cur_thread = cur_thread->next()) {
|
||||
if (cur_thread == biased_thread) {
|
||||
thread_is_alive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ThreadsListHandle tlh;
|
||||
thread_is_alive = tlh.includes(biased_thread);
|
||||
}
|
||||
if (!thread_is_alive) {
|
||||
if (allow_rebias) {
|
||||
@ -390,72 +387,76 @@ static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o,
|
||||
Klass* k_o = o->klass();
|
||||
Klass* klass = k_o;
|
||||
|
||||
if (bulk_rebias) {
|
||||
// Use the epoch in the klass of the object to implicitly revoke
|
||||
// all biases of objects of this data type and force them to be
|
||||
// reacquired. However, we also need to walk the stacks of all
|
||||
// threads and update the headers of lightweight locked objects
|
||||
// with biases to have the current epoch.
|
||||
{
|
||||
JavaThreadIteratorWithHandle jtiwh;
|
||||
|
||||
// If the prototype header doesn't have the bias pattern, don't
|
||||
// try to update the epoch -- assume another VM operation came in
|
||||
// and reset the header to the unbiased state, which will
|
||||
// implicitly cause all existing biases to be revoked
|
||||
if (klass->prototype_header()->has_bias_pattern()) {
|
||||
int prev_epoch = klass->prototype_header()->bias_epoch();
|
||||
klass->set_prototype_header(klass->prototype_header()->incr_bias_epoch());
|
||||
int cur_epoch = klass->prototype_header()->bias_epoch();
|
||||
if (bulk_rebias) {
|
||||
// Use the epoch in the klass of the object to implicitly revoke
|
||||
// all biases of objects of this data type and force them to be
|
||||
// reacquired. However, we also need to walk the stacks of all
|
||||
// threads and update the headers of lightweight locked objects
|
||||
// with biases to have the current epoch.
|
||||
|
||||
// Now walk all threads' stacks and adjust epochs of any biased
|
||||
// and locked objects of this data type we encounter
|
||||
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
|
||||
// If the prototype header doesn't have the bias pattern, don't
|
||||
// try to update the epoch -- assume another VM operation came in
|
||||
// and reset the header to the unbiased state, which will
|
||||
// implicitly cause all existing biases to be revoked
|
||||
if (klass->prototype_header()->has_bias_pattern()) {
|
||||
int prev_epoch = klass->prototype_header()->bias_epoch();
|
||||
klass->set_prototype_header(klass->prototype_header()->incr_bias_epoch());
|
||||
int cur_epoch = klass->prototype_header()->bias_epoch();
|
||||
|
||||
// Now walk all threads' stacks and adjust epochs of any biased
|
||||
// and locked objects of this data type we encounter
|
||||
for (; JavaThread *thr = jtiwh.next(); ) {
|
||||
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);
|
||||
for (int i = 0; i < cached_monitor_info->length(); i++) {
|
||||
MonitorInfo* mon_info = cached_monitor_info->at(i);
|
||||
oop owner = mon_info->owner();
|
||||
markOop mark = owner->mark();
|
||||
if ((owner->klass() == k_o) && mark->has_bias_pattern()) {
|
||||
// We might have encountered this object already in the case of recursive locking
|
||||
assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment");
|
||||
owner->set_mark(mark->set_bias_epoch(cur_epoch));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At this point we're done. All we have to do is potentially
|
||||
// adjust the header of the given object to revoke its bias.
|
||||
revoke_bias(o, attempt_rebias_of_object && klass->prototype_header()->has_bias_pattern(), true, requesting_thread, NULL);
|
||||
} else {
|
||||
if (log_is_enabled(Info, biasedlocking)) {
|
||||
ResourceMark rm;
|
||||
log_info(biasedlocking)("* Disabling biased locking for type %s", klass->external_name());
|
||||
}
|
||||
|
||||
// Disable biased locking for this data type. Not only will this
|
||||
// cause future instances to not be biased, but existing biased
|
||||
// instances will notice that this implicitly caused their biases
|
||||
// to be revoked.
|
||||
klass->set_prototype_header(markOopDesc::prototype());
|
||||
|
||||
// Now walk all threads' stacks and forcibly revoke the biases of
|
||||
// any locked and biased objects of this data type we encounter.
|
||||
for (; JavaThread *thr = jtiwh.next(); ) {
|
||||
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);
|
||||
for (int i = 0; i < cached_monitor_info->length(); i++) {
|
||||
MonitorInfo* mon_info = cached_monitor_info->at(i);
|
||||
oop owner = mon_info->owner();
|
||||
markOop mark = owner->mark();
|
||||
if ((owner->klass() == k_o) && mark->has_bias_pattern()) {
|
||||
// We might have encountered this object already in the case of recursive locking
|
||||
assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment");
|
||||
owner->set_mark(mark->set_bias_epoch(cur_epoch));
|
||||
revoke_bias(owner, false, true, requesting_thread, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must force the bias of the passed object to be forcibly revoked
|
||||
// as well to ensure guarantees to callers
|
||||
revoke_bias(o, false, true, requesting_thread, NULL);
|
||||
}
|
||||
|
||||
// At this point we're done. All we have to do is potentially
|
||||
// adjust the header of the given object to revoke its bias.
|
||||
revoke_bias(o, attempt_rebias_of_object && klass->prototype_header()->has_bias_pattern(), true, requesting_thread, NULL);
|
||||
} else {
|
||||
if (log_is_enabled(Info, biasedlocking)) {
|
||||
ResourceMark rm;
|
||||
log_info(biasedlocking)("* Disabling biased locking for type %s", klass->external_name());
|
||||
}
|
||||
|
||||
// Disable biased locking for this data type. Not only will this
|
||||
// cause future instances to not be biased, but existing biased
|
||||
// instances will notice that this implicitly caused their biases
|
||||
// to be revoked.
|
||||
klass->set_prototype_header(markOopDesc::prototype());
|
||||
|
||||
// Now walk all threads' stacks and forcibly revoke the biases of
|
||||
// any locked and biased objects of this data type we encounter.
|
||||
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
|
||||
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);
|
||||
for (int i = 0; i < cached_monitor_info->length(); i++) {
|
||||
MonitorInfo* mon_info = cached_monitor_info->at(i);
|
||||
oop owner = mon_info->owner();
|
||||
markOop mark = owner->mark();
|
||||
if ((owner->klass() == k_o) && mark->has_bias_pattern()) {
|
||||
revoke_bias(owner, false, true, requesting_thread, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must force the bias of the passed object to be forcibly revoked
|
||||
// as well to ensure guarantees to callers
|
||||
revoke_bias(o, false, true, requesting_thread, NULL);
|
||||
}
|
||||
} // ThreadsListHandle is destroyed here.
|
||||
|
||||
log_info(biasedlocking)("* Ending bulk revocation");
|
||||
|
||||
@ -481,7 +482,7 @@ static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o,
|
||||
|
||||
static void clean_up_cached_monitor_info() {
|
||||
// Walk the thread list clearing out the cached monitors
|
||||
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thr = jtiwh.next(); ) {
|
||||
thr->set_cached_monitor_info(NULL);
|
||||
}
|
||||
}
|
||||
@ -768,7 +769,7 @@ void BiasedLocking::preserve_marks() {
|
||||
|
||||
ResourceMark rm;
|
||||
Thread* cur = Thread::current();
|
||||
for (JavaThread* thread = Threads::first(); thread != NULL; thread = thread->next()) {
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
|
||||
if (thread->has_last_Java_frame()) {
|
||||
RegisterMap rm(thread);
|
||||
for (javaVFrame* vf = thread->last_java_vframe(&rm); vf != NULL; vf = vf->java_sender()) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user