This commit is contained in:
Andrew Haley 2017-11-27 17:04:45 +00:00
commit 1b6f4c4ddc
467 changed files with 13945 additions and 12381 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(/^ +\*.*/, ""); \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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>, &amp;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-&gt;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">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"
/*

View File

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

View File

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

View File

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

View File

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

View File

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