Merge
This commit is contained in:
commit
11bb82baca
3
.hgtags
3
.hgtags
@ -543,3 +543,6 @@ b5f05fe4a6f8b3996a000c20078b356d991ca8ec jdk-13+6
|
||||
021917019cda1c0c5853255322274f37693a2431 jdk-13+7
|
||||
b5f7bb57de2f797be34f6c75d45c3245ad37ab97 jdk-12+31
|
||||
a535ba736cabc6886acdff36de3a096c46e5ddc5 jdk-13+8
|
||||
4ce47bc1fb92cf94c6e3d1f49d582f02dcb851ab jdk-12+32
|
||||
c081f3ea6b9300265a4a34e38f970b1e3ddaae9f jdk-13+9
|
||||
b67884871b5fff79c5ef3eb8ac74dd48d71ea9b1 jdk-12+33
|
||||
|
@ -112,6 +112,9 @@ GTEST_LAUNCHER_DIRS := $(patsubst %/gtestLauncher, %, \
|
||||
GTEST_VARIANTS := $(strip $(patsubst $(TEST_IMAGE_DIR)/hotspot/gtest/%, %, \
|
||||
$(GTEST_LAUNCHER_DIRS)))
|
||||
|
||||
COV_ENVIRONMENT :=
|
||||
JTREG_COV_OPTIONS :=
|
||||
|
||||
ifeq ($(TEST_OPTS_JCOV), true)
|
||||
JCOV_OUTPUT_DIR := $(TEST_RESULTS_DIR)/jcov-output
|
||||
JCOV_GRABBER_LOG := $(JCOV_OUTPUT_DIR)/grabber.log
|
||||
@ -122,12 +125,18 @@ ifeq ($(TEST_OPTS_JCOV), true)
|
||||
# Replace our normal test JDK with the JCov image.
|
||||
JDK_UNDER_TEST := $(JCOV_IMAGE_DIR)
|
||||
|
||||
JCOV_ENVIRONMENT := JAVA_TOOL_OPTIONS="$(JCOV_MEM_OPTIONS)" \
|
||||
COV_ENVIRONMENT += JAVA_TOOL_OPTIONS="$(JCOV_MEM_OPTIONS)" \
|
||||
_JAVA_OPTIONS="$(JCOV_MEM_OPTIONS)"
|
||||
JTREG_JCOV_OPTIONS := -e:JAVA_TOOL_OPTIONS='$(JCOV_MEM_OPTIONS)' \
|
||||
JTREG_COV_OPTIONS += -e:JAVA_TOOL_OPTIONS='$(JCOV_MEM_OPTIONS)' \
|
||||
-e:_JAVA_OPTIONS='$(JCOV_MEM_OPTIONS)'
|
||||
endif
|
||||
|
||||
ifeq ($(GCOV_ENABLED), true)
|
||||
GCOV_OUTPUT_DIR := $(TEST_RESULTS_DIR)/gcov-output
|
||||
COV_ENVIRONMENT += GCOV_PREFIX="$(GCOV_OUTPUT_DIR)"
|
||||
JTREG_COV_OPTIONS += -e:GCOV_PREFIX="$(GCOV_OUTPUT_DIR)"
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Optionally create AOT libraries for specified modules before running tests.
|
||||
# Note, this could not be done during JDK build time.
|
||||
@ -170,6 +179,7 @@ define SetupAotModuleBody
|
||||
$$(call LogWarn, Generating $$(patsubst $$(OUTPUTDIR)/%, %, $$@))
|
||||
$$(call MakeTargetDir)
|
||||
$$(call ExecuteWithLog, $$@, \
|
||||
$((COV_ENVIRONMENT) \
|
||||
$$(FIXPATH) $$(JDK_UNDER_TEST)/bin/jaotc \
|
||||
$$($1_JAOTC_OPTS) --output $$@ --module $$($1_MODULE) \
|
||||
)
|
||||
@ -658,6 +668,8 @@ define SetupRunMicroTestBody
|
||||
|
||||
# Current tests needs to open java.io
|
||||
$1_MICRO_JAVA_OPTIONS += --add-opens=java.base/java.io=ALL-UNNAMED
|
||||
# Set library path for native dependencies
|
||||
$1_MICRO_JAVA_OPTIONS += -Djava.library.path=$$(TEST_IMAGE_DIR)/micro/native
|
||||
|
||||
# Save output as JSON or CSV file
|
||||
ifneq ($$(MICRO_RESULTS_FORMAT), )
|
||||
@ -690,7 +702,8 @@ define SetupRunMicroTestBody
|
||||
$$(call LogWarn, Running test '$$($1_TEST)')
|
||||
$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR))
|
||||
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, \
|
||||
$$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) -jar $$($1_MICRO_BENCHMARKS_JAR) \
|
||||
$$(FIXPATH) $$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) \
|
||||
-jar $$($1_MICRO_BENCHMARKS_JAR) \
|
||||
$$($1_MICRO_ITER) $$($1_MICRO_FORK) $$($1_MICRO_TIME) \
|
||||
$$($1_MICRO_WARMUP_ITER) $$($1_MICRO_WARMUP_TIME) \
|
||||
$$($1_MICRO_VM_OPTIONS) $$($1_MICRO_BASIC_OPTIONS) $$(MICRO_OPTIONS) \
|
||||
@ -904,7 +917,7 @@ define SetupRunJtregTestBody
|
||||
$$(call LogWarn, Running test '$$($1_TEST)')
|
||||
$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR))
|
||||
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \
|
||||
$$(JCOV_ENVIRONMENT) \
|
||||
$$(COV_ENVIRONMENT) \
|
||||
$$(JAVA) $$($1_JTREG_LAUNCHER_OPTIONS) \
|
||||
-Dprogram=jtreg -jar $$(JT_HOME)/lib/jtreg.jar \
|
||||
$$($1_JTREG_BASIC_OPTIONS) \
|
||||
@ -914,7 +927,7 @@ define SetupRunJtregTestBody
|
||||
-workDir:$$($1_TEST_SUPPORT_DIR) \
|
||||
$$(JTREG_OPTIONS) \
|
||||
$$(JTREG_FAILURE_HANDLER_OPTIONS) \
|
||||
$$(JTREG_JCOV_OPTIONS) \
|
||||
$$(JTREG_COV_OPTIONS) \
|
||||
$$($1_TEST_NAME) \
|
||||
&& $$(ECHO) $$$$? > $$($1_EXITCODE) \
|
||||
|| $$(ECHO) $$$$? > $$($1_EXITCODE) \
|
||||
|
@ -618,14 +618,6 @@ AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS],
|
||||
BASIC_PATH_PROGS(CPIO, [cpio bsdcpio])
|
||||
BASIC_PATH_PROGS(NICE, nice)
|
||||
|
||||
BASIC_PATH_PROGS(PANDOC, pandoc)
|
||||
if test -n "$PANDOC"; then
|
||||
ENABLE_PANDOC="true"
|
||||
else
|
||||
ENABLE_PANDOC="false"
|
||||
fi
|
||||
AC_SUBST(ENABLE_PANDOC)
|
||||
|
||||
BASIC_PATH_PROGS(LSB_RELEASE, lsb_release)
|
||||
BASIC_PATH_PROGS(CMD, [cmd.exe /mnt/c/Windows/System32/cmd.exe])
|
||||
])
|
||||
@ -1193,6 +1185,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
|
||||
BASIC_CHECK_FIND_DELETE
|
||||
BASIC_CHECK_TAR
|
||||
BASIC_CHECK_GREP
|
||||
BASIC_SETUP_PANDOC
|
||||
|
||||
# These tools might not be installed by default,
|
||||
# need hint on how to install them.
|
||||
@ -1377,6 +1370,34 @@ AC_DEFUN_ONCE([BASIC_CHECK_BASH_OPTIONS],
|
||||
AC_SUBST(BASH_ARGS)
|
||||
])
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Setup Pandoc
|
||||
#
|
||||
AC_DEFUN_ONCE([BASIC_SETUP_PANDOC],
|
||||
[
|
||||
BASIC_PATH_PROGS(PANDOC, pandoc)
|
||||
|
||||
PANDOC_MARKDOWN_FLAG="markdown"
|
||||
if test -n "$PANDOC"; then
|
||||
AC_MSG_CHECKING(if the pandoc smart extension needs to be disabled for markdown)
|
||||
if $PANDOC --list-extensions | $GREP -q '\+smart'; then
|
||||
AC_MSG_RESULT([yes])
|
||||
PANDOC_MARKDOWN_FLAG="markdown-smart"
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$PANDOC"; then
|
||||
ENABLE_PANDOC="true"
|
||||
else
|
||||
ENABLE_PANDOC="false"
|
||||
fi
|
||||
AC_SUBST(ENABLE_PANDOC)
|
||||
AC_SUBST(PANDOC_MARKDOWN_FLAG)
|
||||
])
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Default make target
|
||||
|
@ -121,7 +121,11 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS],
|
||||
# -g0 enables debug symbols without disabling inlining.
|
||||
CFLAGS_DEBUG_SYMBOLS="-g0 -xs"
|
||||
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
|
||||
CFLAGS_DEBUG_SYMBOLS="-g"
|
||||
if test "x$XLC_USES_CLANG" = xtrue; then
|
||||
CFLAGS_DEBUG_SYMBOLS="-g1"
|
||||
else
|
||||
CFLAGS_DEBUG_SYMBOLS="-g"
|
||||
fi
|
||||
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
CFLAGS_DEBUG_SYMBOLS="-Z7 -d2Zi+"
|
||||
fi
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2019, 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
|
||||
@ -364,7 +364,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Gcov coverage data for hotspot
|
||||
# Native and Java code coverage
|
||||
#
|
||||
AC_DEFUN_ONCE([JDKOPT_SETUP_CODE_COVERAGE],
|
||||
[
|
||||
@ -372,23 +372,26 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_CODE_COVERAGE],
|
||||
[enable native compilation with code coverage data@<:@disabled@:>@])])
|
||||
GCOV_ENABLED="false"
|
||||
if test "x$enable_native_coverage" = "xyes"; then
|
||||
if test "x$TOOLCHAIN_TYPE" = "xgcc"; then
|
||||
AC_MSG_CHECKING([if native coverage is enabled])
|
||||
AC_MSG_RESULT([yes])
|
||||
GCOV_CFLAGS="-fprofile-arcs -ftest-coverage -fno-inline"
|
||||
GCOV_LDFLAGS="-fprofile-arcs"
|
||||
JVM_CFLAGS="$JVM_CFLAGS $GCOV_CFLAGS"
|
||||
JVM_LDFLAGS="$JVM_LDFLAGS $GCOV_LDFLAGS"
|
||||
CFLAGS_JDKLIB="$CFLAGS_JDKLIB $GCOV_CFLAGS"
|
||||
CFLAGS_JDKEXE="$CFLAGS_JDKEXE $GCOV_CFLAGS"
|
||||
CXXFLAGS_JDKLIB="$CXXFLAGS_JDKLIB $GCOV_CFLAGS"
|
||||
CXXFLAGS_JDKEXE="$CXXFLAGS_JDKEXE $GCOV_CFLAGS"
|
||||
LDFLAGS_JDKLIB="$LDFLAGS_JDKLIB $GCOV_LDFLAGS"
|
||||
LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE $GCOV_LDFLAGS"
|
||||
GCOV_ENABLED="true"
|
||||
else
|
||||
AC_MSG_ERROR([--enable-native-coverage only works with toolchain type gcc])
|
||||
fi
|
||||
case $TOOLCHAIN_TYPE in
|
||||
gcc | clang)
|
||||
AC_MSG_CHECKING([if native coverage is enabled])
|
||||
AC_MSG_RESULT([yes])
|
||||
GCOV_CFLAGS="-fprofile-arcs -ftest-coverage -fno-inline"
|
||||
GCOV_LDFLAGS="-fprofile-arcs"
|
||||
JVM_CFLAGS="$JVM_CFLAGS $GCOV_CFLAGS"
|
||||
JVM_LDFLAGS="$JVM_LDFLAGS $GCOV_LDFLAGS"
|
||||
CFLAGS_JDKLIB="$CFLAGS_JDKLIB $GCOV_CFLAGS"
|
||||
CFLAGS_JDKEXE="$CFLAGS_JDKEXE $GCOV_CFLAGS"
|
||||
CXXFLAGS_JDKLIB="$CXXFLAGS_JDKLIB $GCOV_CFLAGS"
|
||||
CXXFLAGS_JDKEXE="$CXXFLAGS_JDKEXE $GCOV_CFLAGS"
|
||||
LDFLAGS_JDKLIB="$LDFLAGS_JDKLIB $GCOV_LDFLAGS"
|
||||
LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE $GCOV_LDFLAGS"
|
||||
GCOV_ENABLED="true"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([--enable-native-coverage only works with toolchain type gcc or clang])
|
||||
;;
|
||||
esac
|
||||
elif test "x$enable_native_coverage" = "xno"; then
|
||||
AC_MSG_CHECKING([if native coverage is enabled])
|
||||
AC_MSG_RESULT([no])
|
||||
|
@ -774,6 +774,7 @@ MSVCP_DLL:=@MSVCP_DLL@
|
||||
UCRT_DLL_DIR:=@UCRT_DLL_DIR@
|
||||
STLPORT_LIB:=@STLPORT_LIB@
|
||||
ENABLE_PANDOC:=@ENABLE_PANDOC@
|
||||
PANDOC_MARKDOWN_FLAG:=@PANDOC_MARKDOWN_FLAG@
|
||||
|
||||
####################################################
|
||||
#
|
||||
|
@ -276,6 +276,20 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE],
|
||||
fi
|
||||
AC_SUBST(TOOLCHAIN_TYPE)
|
||||
|
||||
# on AIX, check for xlclang++ on the PATH and TOOLCHAIN_PATH and use it if it is available
|
||||
if test "x$OPENJDK_TARGET_OS" = xaix; then
|
||||
if test "x$TOOLCHAIN_PATH" != x; then
|
||||
XLC_TEST_PATH=${TOOLCHAIN_PATH}/
|
||||
fi
|
||||
|
||||
XLCLANG_VERSION_OUTPUT=`${XLC_TEST_PATH}xlclang++ -qversion 2>&1 | $HEAD -n 1`
|
||||
$ECHO "$XLCLANG_VERSION_OUTPUT" | $GREP "IBM XL C/C++ for AIX" > /dev/null
|
||||
if test $? -eq 0; then
|
||||
AC_MSG_NOTICE([xlclang++ output: $XLCLANG_VERSION_OUTPUT])
|
||||
XLC_USES_CLANG=true
|
||||
fi
|
||||
fi
|
||||
|
||||
TOOLCHAIN_CC_BINARY_clang="clang"
|
||||
TOOLCHAIN_CC_BINARY_gcc="gcc"
|
||||
TOOLCHAIN_CC_BINARY_microsoft="cl$EXE_SUFFIX"
|
||||
@ -288,6 +302,14 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE],
|
||||
TOOLCHAIN_CXX_BINARY_solstudio="CC"
|
||||
TOOLCHAIN_CXX_BINARY_xlc="xlC_r"
|
||||
|
||||
if test "x$OPENJDK_TARGET_OS" = xaix; then
|
||||
if test "x$XLC_USES_CLANG" = xtrue; then
|
||||
AC_MSG_NOTICE([xlclang++ detected, using it])
|
||||
TOOLCHAIN_CC_BINARY_xlc="xlclang"
|
||||
TOOLCHAIN_CXX_BINARY_xlc="xlclang++"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Use indirect variable referencing
|
||||
toolchain_var_name=TOOLCHAIN_DESCRIPTION_$TOOLCHAIN_TYPE
|
||||
TOOLCHAIN_DESCRIPTION=${!toolchain_var_name}
|
||||
|
@ -392,9 +392,10 @@ ifneq ($(DISABLE_CACHE_FIND), true)
|
||||
#
|
||||
# Param 1 - Dirs to find in
|
||||
# Param 2 - (optional) specialization. Normally "-a \( ... \)" expression.
|
||||
# Param 3 - (optional) options to find.
|
||||
define CacheFind
|
||||
$(if $(filter-out $(addsuffix /%,- $(FIND_CACHE_DIRS)) $(FIND_CACHE_DIRS),$1), \
|
||||
$(if $(wildcard $1), $(shell $(FIND) $(wildcard $1) \( -type f -o -type l \) $2 \
|
||||
$(if $(wildcard $1), $(shell $(FIND) $3 $(wildcard $1) \( -type f -o -type l \) $2 \
|
||||
| $(TR) ' ' '?')), \
|
||||
$(filter $(addsuffix /%,$(patsubst %/,%,$1)) $1,$(FIND_CACHE)))
|
||||
endef
|
||||
|
@ -80,7 +80,8 @@ define ProcessMarkdown
|
||||
$$(call LogInfo, Converting $2 to $$($1_FORMAT))
|
||||
$$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$(dir $$($1_$2_PANDOC_OUTPUT)))
|
||||
$$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER), \
|
||||
$$(PANDOC) $$($1_OPTIONS) -f markdown-smart -t $$($1_FORMAT) --standalone \
|
||||
$$(PANDOC) $$($1_OPTIONS) -f $$(PANDOC_MARKDOWN_FLAG) \
|
||||
-t $$($1_FORMAT) --standalone \
|
||||
$$($1_$2_CSS_OPTION) $$($1_$2_OPTIONS) '$$($1_$2_PANDOC_INPUT)' \
|
||||
-o '$$($1_$2_PANDOC_OUTPUT)')
|
||||
ifneq ($$(findstring $$(LOG_LEVEL), debug trace),)
|
||||
|
@ -62,8 +62,9 @@ define SetupZipArchiveBody
|
||||
$1_FIND_LIST := $$($1_SRC)
|
||||
endif
|
||||
|
||||
# Find all files in the source tree.
|
||||
$1_ALL_SRCS := $$(call not-containing,_the.,$$(call CacheFind,$$($1_FIND_LIST)))
|
||||
# Find all files in the source tree. Follow symlinks in this find since that is
|
||||
# what zip does.
|
||||
$1_ALL_SRCS := $$(call not-containing,_the.,$$(call CacheFind,$$($1_FIND_LIST), , -L))
|
||||
|
||||
# Filter on suffixes if set
|
||||
ifneq ($$($1_SUFFIXES),)
|
||||
@ -126,10 +127,14 @@ define SetupZipArchiveBody
|
||||
$$($1_ZIP) : $$($1_ALL_SRCS) $$($1_EXTRA_DEPS)
|
||||
$$(call LogWarn, Updating $$($1_NAME))
|
||||
$$(call MakeTargetDir)
|
||||
$$(foreach s,$$($1_SRC),(cd $$s && $(ZIPEXE) -qru $$($1_ZIP_OPTIONS) $$@ . \
|
||||
$$($1_ZIP_INCLUDES) $$($1_ZIP_EXCLUDES) -x \*_the.\* \
|
||||
$$($1_ZIP_EXCLUDES_$$s) \
|
||||
|| test "$$$$?" = "12" )$$(NEWLINE)) true
|
||||
$$(foreach s,$$($1_SRC), $$(call ExecuteWithLog, \
|
||||
$$(SUPPORT_OUTPUTDIR)/zip/$$(patsubst $$(OUTPUTDIR)/%,%, $$@), \
|
||||
(cd $$s && $(ZIPEXE) -qru $$($1_ZIP_OPTIONS) $$@ . \
|
||||
$$($1_ZIP_INCLUDES) $$($1_ZIP_EXCLUDES) -x \*_the.\* \
|
||||
$$($1_ZIP_EXCLUDES_$$s) \
|
||||
|| test "$$$$?" = "12" \
|
||||
))$$(NEWLINE) \
|
||||
) true \
|
||||
$(TOUCH) $$@
|
||||
|
||||
# Add zip to target list
|
||||
|
@ -241,7 +241,7 @@ var getJibProfilesCommon = function (input, data) {
|
||||
common.main_profile_names = [
|
||||
"linux-x64", "linux-x86", "macosx-x64", "solaris-x64",
|
||||
"solaris-sparcv9", "windows-x64", "windows-x86",
|
||||
"linux-aarch64", "linux-arm32"
|
||||
"linux-aarch64", "linux-arm32", "linux-ppc64le", "linux-s390x"
|
||||
];
|
||||
|
||||
// These are the base setttings for all the main build profiles.
|
||||
@ -464,6 +464,28 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
"--with-abi-profile=arm-vfp-hflt", "--disable-warnings-as-errors"
|
||||
],
|
||||
},
|
||||
|
||||
"linux-ppc64le": {
|
||||
target_os: "linux",
|
||||
target_cpu: "ppc64le",
|
||||
build_cpu: "x64",
|
||||
dependencies: ["devkit", "build_devkit", "cups"],
|
||||
configure_args: [
|
||||
"--openjdk-target=ppc64le-linux-gnu", "--with-freetype=bundled",
|
||||
"--disable-warnings-as-errors"
|
||||
],
|
||||
},
|
||||
|
||||
"linux-s390x": {
|
||||
target_os: "linux",
|
||||
target_cpu: "s390x",
|
||||
build_cpu: "x64",
|
||||
dependencies: ["devkit", "build_devkit", "cups"],
|
||||
configure_args: [
|
||||
"--openjdk-target=s390x-linux-gnu", "--with-freetype=bundled",
|
||||
"--disable-warnings-as-errors"
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
// Add the base settings to all the main profiles
|
||||
@ -499,6 +521,15 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
profiles[maketestName].default_make_targets = [ "test-make" ];
|
||||
});
|
||||
|
||||
// Generate -gcov profiles
|
||||
[ "linux-x64", "macosx-x64" ].forEach(function (name) {
|
||||
var gcovName = name + "-gcov";
|
||||
profiles[gcovName] = clone(profiles[name]);
|
||||
profiles[gcovName].default_make_targets = ["product-bundles", "test-bundles"];
|
||||
profiles[gcovName].configure_args = concat(profiles[gcovName].configure_args,
|
||||
["--enable-native-coverage", "--disable-warnings-as-errors"]);
|
||||
});
|
||||
|
||||
// Profiles for building the zero jvm variant. These are used for verification.
|
||||
var zeroProfiles = {
|
||||
"linux-x64-zero": {
|
||||
@ -626,6 +657,12 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
},
|
||||
"linux-arm32": {
|
||||
platform: "linux-arm32",
|
||||
},
|
||||
"linux-ppc64le": {
|
||||
platform: "linux-ppc64le",
|
||||
},
|
||||
"linux-s390x": {
|
||||
platform: "linux-s390x",
|
||||
}
|
||||
}
|
||||
// Generate common artifacts for all main profiles
|
||||
@ -744,6 +781,40 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
};
|
||||
});
|
||||
|
||||
// Artifacts of gcov (native-code-coverage) profiles
|
||||
[ "linux-x64", "macosx-x64" ].forEach(function (name) {
|
||||
var o = artifactData[name]
|
||||
var pf = o.platform
|
||||
var jdk_subdir = (o.jdk_subdir != null ? o.jdk_subdir : "jdk-" + data.version);
|
||||
var jdk_suffix = (o.jdk_suffix != null ? o.jdk_suffix : "tar.gz");
|
||||
var gcovName = name + "-gcov";
|
||||
profiles[gcovName].artifacts = {
|
||||
jdk: {
|
||||
local: "bundles/\\(jdk.*bin." + jdk_suffix + "\\)",
|
||||
remote: [
|
||||
"bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-gcov." + jdk_suffix,
|
||||
],
|
||||
subdir: jdk_subdir,
|
||||
exploded: "images/jdk",
|
||||
},
|
||||
test: {
|
||||
local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-gcov-tests.tar.gz",
|
||||
],
|
||||
exploded: "images/test"
|
||||
},
|
||||
jdk_symbols: {
|
||||
local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-gcov-symbols.tar.gz",
|
||||
],
|
||||
subdir: jdk_subdir,
|
||||
exploded: "images/jdk"
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// Profiles used to run tests.
|
||||
var testOnlyProfiles = {
|
||||
"run-test": {
|
||||
@ -770,6 +841,10 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
} else {
|
||||
testedProfileTest = testedProfile + ".test";
|
||||
}
|
||||
var testOnlyMake = [ "run-test-prebuilt", "LOG_CMDLINES=true", "JTREG_VERBOSE=fail,error,time" ];
|
||||
if (testedProfile.endsWith("-gcov")) {
|
||||
testOnlyMake = concat(testOnlyMake, "GCOV_ENABLED=true")
|
||||
}
|
||||
var testOnlyProfilesPrebuilt = {
|
||||
"run-test-prebuilt": {
|
||||
target_os: input.build_os,
|
||||
@ -779,7 +854,7 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
testedProfileTest
|
||||
],
|
||||
src: "src.conf",
|
||||
make_args: [ "run-test-prebuilt", "LOG_CMDLINES=true", "JTREG_VERBOSE=fail,error,time" ],
|
||||
make_args: testOnlyMake,
|
||||
environment: {
|
||||
"BOOT_JDK": common.boot_jdk_home,
|
||||
"JDK_IMAGE_DIR": input.get(testedProfileJDK, "home_path"),
|
||||
@ -870,7 +945,9 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
solaris_sparcv9: "SS12u6-Solaris11u3+1.0",
|
||||
windows_x64: "VS2017-15.5.5+1.0",
|
||||
linux_aarch64: "gcc7.3.0-Fedora27+1.2",
|
||||
linux_arm: "gcc7.3.0-Fedora27+1.2"
|
||||
linux_arm: "gcc7.3.0-Fedora27+1.2",
|
||||
linux_ppc64le: "gcc7.3.0-Fedora27+1.0",
|
||||
linux_s390x: "gcc7.3.0-Fedora27+1.0"
|
||||
};
|
||||
|
||||
var devkit_platform = (input.target_cpu == "x86"
|
||||
@ -930,7 +1007,7 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
jtreg: {
|
||||
server: "javare",
|
||||
revision: "4.2",
|
||||
build_number: "b13",
|
||||
build_number: "b14",
|
||||
checksum_file: "MD5_VALUES",
|
||||
file: "jtreg_bin-4.2.zip",
|
||||
environment_name: "JT_HOME",
|
||||
|
@ -66,6 +66,8 @@ endif
|
||||
# Setup make rules for copying legal files. This is only needed if the files
|
||||
# need to be filtered due to optional components being enabled/disabled.
|
||||
# Otherwise CreateJmods.gmk will find the legal files in the original src dirs.
|
||||
# If multiple license files with the same name are found, only the first one
|
||||
# found will get copied.
|
||||
#
|
||||
# Parameter 1 is the name of the rule.
|
||||
#
|
||||
@ -75,10 +77,12 @@ SetupCopyLegalFiles = $(NamedParamsMacroTemplate)
|
||||
define SetupCopyLegalFilesBody
|
||||
$$(foreach f, $$(filter-out $$(addprefix %/, $$($1_EXCLUDES)), \
|
||||
$$(wildcard $$(addsuffix /*, $$(call FindModuleLegalSrcDirs, $$(MODULE))))), \
|
||||
$$(eval $$(call SetupCopyFiles, $1_$$(notdir $$f), \
|
||||
DEST := $$(LEGAL_DST_DIR), \
|
||||
FILES := $$f, \
|
||||
)) \
|
||||
$$(eval $1 += $$($1_$$(notdir $$f))) \
|
||||
$$(if $$(filter $$($1_$$(notdir $$f)), $$($1)), , \
|
||||
$$(eval $$(call SetupCopyFiles, $1_$$(notdir $$f), \
|
||||
DEST := $$(LEGAL_DST_DIR), \
|
||||
FILES := $$f, \
|
||||
)) \
|
||||
$$(eval $1 += $$($1_$$(notdir $$f))) \
|
||||
) \
|
||||
)
|
||||
endef
|
||||
|
@ -613,7 +613,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER, \
|
||||
type-limits missing-field-initializers implicit-fallthrough \
|
||||
strict-aliasing undef unused-function, \
|
||||
DISABLED_WARNINGS_CXX_gcc := reorder delete-non-virtual-dtor strict-overflow \
|
||||
maybe-uninitialized, \
|
||||
maybe-uninitialized \
|
||||
missing-attributes class-memaccess, \
|
||||
DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \
|
||||
tautological-constant-out-of-range-compare int-to-pointer-cast \
|
||||
sign-compare undef missing-field-initializers, \
|
||||
|
@ -30,6 +30,7 @@ include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
include JavaCompilation.gmk
|
||||
include SetupJavaCompilers.gmk
|
||||
include TestFilesCompilation.gmk
|
||||
|
||||
ifeq ($(JMH_CORE_JAR), )
|
||||
$(info Error: JMH is missing. Please use configure --with-jmh.)
|
||||
@ -39,7 +40,8 @@ endif
|
||||
#### Variables
|
||||
|
||||
MICROBENCHMARK_SRC := $(TOPDIR)/test/micro
|
||||
MICROBENCHMARK_JAR := $(IMAGES_OUTPUTDIR)/test/micro/benchmarks.jar
|
||||
MICROBENCHMARK_IMAGE_DIR := $(TEST_IMAGE_DIR)/micro
|
||||
MICROBENCHMARK_JAR := $(MICROBENCHMARK_IMAGE_DIR)/benchmarks.jar
|
||||
|
||||
MICROBENCHMARK_OUTPUT := $(SUPPORT_OUTPUTDIR)/test/micro
|
||||
MICROBENCHMARK_CLASSES := $(MICROBENCHMARK_OUTPUT)/classes
|
||||
@ -54,6 +56,11 @@ JMH_RUNTIME_JARS := $(JMH_CORE_JAR) $(JMH_COMMONS_MATH_JAR) $(JMH_JOPT_SIMPLE_JA
|
||||
|
||||
MICROBENCHMARK_CLASSPATH := $(call PathList, $(JMH_COMPILE_JARS))
|
||||
|
||||
# Native dependencies
|
||||
MICROBENCHMARK_NATIVE_SRC_DIRS := $(MICROBENCHMARK_SRC)
|
||||
MICROBENCHMARK_NATIVE_OUTPUT := $(MICROBENCHMARK_OUTPUT)/native
|
||||
MICROBENCHMARK_NATIVE_EXCLUDE :=
|
||||
|
||||
###
|
||||
|
||||
# Need double \n to get new lines and no trailing spaces
|
||||
@ -108,6 +115,22 @@ $(eval $(call SetupJarArchive, BUILD_JDK_JAR, \
|
||||
JAR := $(MICROBENCHMARK_JAR), \
|
||||
))
|
||||
|
||||
all: $(MICROBENCHMARK_JAR)
|
||||
# Setup compilation of native library dependencies
|
||||
$(eval $(call SetupTestFilesCompilation, BUILD_MICROBENCHMARK_LIBRARIES, \
|
||||
TYPE := LIBRARY, \
|
||||
SOURCE_DIRS := $(MICROBENCHMARK_NATIVE_SRC_DIRS), \
|
||||
OUTPUT_DIR := $(MICROBENCHMARK_NATIVE_OUTPUT), \
|
||||
EXCLUDE := $(MICROBENCHMARK_NATIVE_EXCLUDE), \
|
||||
))
|
||||
|
||||
# Setup copy of native dependencies to image output dir
|
||||
$(eval $(call SetupCopyFiles, COPY_MICROBENCHMARK_NATIVE, \
|
||||
SRC := $(MICROBENCHMARK_NATIVE_OUTPUT), \
|
||||
DEST := $(MICROBENCHMARK_IMAGE_DIR)/native, \
|
||||
FILES := $(BUILD_MICROBENCHMARK_LIBRARIES), \
|
||||
FLATTEN := true, \
|
||||
))
|
||||
|
||||
all: $(MICROBENCHMARK_JAR) $(BUILD_MICROBENCHMARK_LIBRARIES) $(COPY_MICROBENCHMARK_NATIVE)
|
||||
|
||||
.PHONY: all
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -362,8 +362,8 @@ void NativeJump::verify() {
|
||||
|
||||
void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
|
||||
CodeBuffer cb(code_pos, BytesPerInstWord + 1);
|
||||
MacroAssembler* a = new MacroAssembler(&cb);
|
||||
a->b(entry);
|
||||
MacroAssembler a(&cb);
|
||||
a.b(entry);
|
||||
ICache::ppc64_flush_icache_bytes(code_pos, NativeGeneralJump::instruction_size);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2019, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -479,6 +479,7 @@ void frame::back_trace(outputStream* st, intptr_t* start_sp, intptr_t* top_pc, u
|
||||
// name
|
||||
Method* method = *(Method**)((address)current_fp + _z_ijava_state_neg(method));
|
||||
if (method) {
|
||||
ResourceMark rm;
|
||||
if (method->is_synchronized()) st->print("synchronized ");
|
||||
if (method->is_static()) st->print("static ");
|
||||
if (method->is_native()) st->print("native ");
|
||||
@ -543,6 +544,7 @@ void frame::back_trace(outputStream* st, intptr_t* start_sp, intptr_t* top_pc, u
|
||||
// name
|
||||
Method* method = ((nmethod *)blob)->method();
|
||||
if (method) {
|
||||
ResourceMark rm;
|
||||
method->name_and_sig_as_C_string(buf, sizeof(buf));
|
||||
st->print("%s ", buf);
|
||||
}
|
||||
|
@ -29,6 +29,8 @@
|
||||
|
||||
// processor dependent initialization for i486
|
||||
|
||||
LP64_ONLY(extern void reg_mask_init();)
|
||||
|
||||
void Compile::pd_compiler2_init() {
|
||||
guarantee(CodeEntryAlignment >= InteriorEntryAlignment, "" );
|
||||
// QQQ presumably all 64bit cpu's support this. Seems like the ifdef could
|
||||
@ -58,4 +60,5 @@ void Compile::pd_compiler2_init() {
|
||||
OptoReg::invalidate(i);
|
||||
}
|
||||
}
|
||||
LP64_ONLY(reg_mask_init();)
|
||||
}
|
||||
|
@ -359,7 +359,7 @@ void ZBarrierSetAssembler::generate_c1_load_barrier_runtime_stub(StubAssembler*
|
||||
// ZBarrierSetRuntime::load_barrier_on_weak_oop_field_preloaded().
|
||||
static address generate_load_barrier_stub(StubCodeGenerator* cgen, Register raddr, DecoratorSet decorators) {
|
||||
// Don't generate stub for invalid registers
|
||||
if (raddr == rsp || raddr == r12 || raddr == r15) {
|
||||
if (raddr == rsp || raddr == r15) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,8 @@ source %{
|
||||
#include "gc/z/zBarrierSetAssembler.hpp"
|
||||
|
||||
static void z_load_barrier_slow_reg(MacroAssembler& _masm, Register dst, Address src, bool weak) {
|
||||
assert(dst != r12, "Invalid register");
|
||||
assert(dst != r15, "Invalid register");
|
||||
assert(dst != rsp, "Invalid register");
|
||||
assert(dst != r15, "Invalid register");
|
||||
|
||||
const address stub = weak ? ZBarrierSet::assembler()->load_barrier_weak_slow_stub(dst)
|
||||
: ZBarrierSet::assembler()->load_barrier_slow_stub(dst);
|
||||
|
@ -336,7 +336,7 @@ protected:
|
||||
#define CPU_AVX512_VPOPCNTDQ ((uint64_t)UCONST64(0x2000000000)) // Vector popcount
|
||||
#define CPU_VPCLMULQDQ ((uint64_t)UCONST64(0x4000000000)) //Vector carryless multiplication
|
||||
#define CPU_VAES ((uint64_t)UCONST64(0x8000000000)) // Vector AES instructions
|
||||
#define CPU_VNNI ((uint64_t)UCONST64(0x16000000000)) // Vector Neural Network Instructions
|
||||
#define CPU_VNNI ((uint64_t)UCONST64(0x10000000000)) // Vector Neural Network Instructions
|
||||
|
||||
enum Extended_Family {
|
||||
// AMD
|
||||
|
@ -169,135 +169,94 @@ alloc_class chunk0(R10, R10_H,
|
||||
// Empty register class.
|
||||
reg_class no_reg();
|
||||
|
||||
// Class for all pointer registers (including RSP and RBP)
|
||||
reg_class any_reg_with_rbp(RAX, RAX_H,
|
||||
RDX, RDX_H,
|
||||
RBP, RBP_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
RSP, RSP_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R12, R12_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H,
|
||||
R15, R15_H);
|
||||
// Class for all pointer/long registers
|
||||
reg_class all_reg(RAX, RAX_H,
|
||||
RDX, RDX_H,
|
||||
RBP, RBP_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
RSP, RSP_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R12, R12_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H,
|
||||
R15, R15_H);
|
||||
|
||||
// Class for all pointer registers (including RSP, but excluding RBP)
|
||||
reg_class any_reg_no_rbp(RAX, RAX_H,
|
||||
RDX, RDX_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
RSP, RSP_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R12, R12_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H,
|
||||
R15, R15_H);
|
||||
// Class for all int registers
|
||||
reg_class all_int_reg(RAX
|
||||
RDX,
|
||||
RBP,
|
||||
RDI,
|
||||
RSI,
|
||||
RCX,
|
||||
RBX,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
R14);
|
||||
|
||||
// Dynamic register class that selects at runtime between register classes
|
||||
// any_reg_no_rbp and any_reg_with_rbp (depending on the value of the flag PreserveFramePointer).
|
||||
// Equivalent to: return PreserveFramePointer ? any_reg_no_rbp : any_reg_with_rbp;
|
||||
reg_class_dynamic any_reg(any_reg_no_rbp, any_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
// Class for all pointer registers
|
||||
reg_class any_reg %{
|
||||
return _ANY_REG_mask;
|
||||
%}
|
||||
|
||||
// Class for all pointer registers (excluding RSP)
|
||||
reg_class ptr_reg_with_rbp(RAX, RAX_H,
|
||||
RDX, RDX_H,
|
||||
RBP, RBP_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
reg_class ptr_reg %{
|
||||
return _PTR_REG_mask;
|
||||
%}
|
||||
|
||||
// Class for all pointer registers (excluding RSP and RBP)
|
||||
reg_class ptr_reg_no_rbp(RAX, RAX_H,
|
||||
RDX, RDX_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
|
||||
// Dynamic register class that selects between ptr_reg_no_rbp and ptr_reg_with_rbp.
|
||||
reg_class_dynamic ptr_reg(ptr_reg_no_rbp, ptr_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
reg_class ptr_reg_no_rbp %{
|
||||
return _PTR_REG_NO_RBP_mask;
|
||||
%}
|
||||
|
||||
// Class for all pointer registers (excluding RAX and RSP)
|
||||
reg_class ptr_no_rax_reg_with_rbp(RDX, RDX_H,
|
||||
RBP, RBP_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
|
||||
// Class for all pointer registers (excluding RAX, RSP, and RBP)
|
||||
reg_class ptr_no_rax_reg_no_rbp(RDX, RDX_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
|
||||
// Dynamic register class that selects between ptr_no_rax_reg_no_rbp and ptr_no_rax_reg_with_rbp.
|
||||
reg_class_dynamic ptr_no_rax_reg(ptr_no_rax_reg_no_rbp, ptr_no_rax_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
reg_class ptr_no_rax_reg %{
|
||||
return _PTR_NO_RAX_REG_mask;
|
||||
%}
|
||||
|
||||
// Class for all pointer registers (excluding RAX, RBX, and RSP)
|
||||
reg_class ptr_no_rax_rbx_reg_with_rbp(RDX, RDX_H,
|
||||
RBP, RBP_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
reg_class ptr_no_rax_rbx_reg %{
|
||||
return _PTR_NO_RAX_RBX_REG_mask;
|
||||
%}
|
||||
|
||||
// Class for all pointer registers (excluding RAX, RBX, RSP, and RBP)
|
||||
reg_class ptr_no_rax_rbx_reg_no_rbp(RDX, RDX_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
// Class for all long registers (excluding RSP)
|
||||
reg_class long_reg %{
|
||||
return _LONG_REG_mask;
|
||||
%}
|
||||
|
||||
// Dynamic register class that selects between ptr_no_rax_rbx_reg_no_rbp and ptr_no_rax_rbx_reg_with_rbp.
|
||||
reg_class_dynamic ptr_no_rax_rbx_reg(ptr_no_rax_rbx_reg_no_rbp, ptr_no_rax_rbx_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
// Class for all long registers (excluding RAX, RDX and RSP)
|
||||
reg_class long_no_rax_rdx_reg %{
|
||||
return _LONG_NO_RAX_RDX_REG_mask;
|
||||
%}
|
||||
|
||||
// Class for all long registers (excluding RCX and RSP)
|
||||
reg_class long_no_rcx_reg %{
|
||||
return _LONG_NO_RCX_REG_mask;
|
||||
%}
|
||||
|
||||
// Class for all int registers (excluding RSP)
|
||||
reg_class int_reg %{
|
||||
return _INT_REG_mask;
|
||||
%}
|
||||
|
||||
// Class for all int registers (excluding RAX, RDX, and RSP)
|
||||
reg_class int_no_rax_rdx_reg %{
|
||||
return _INT_NO_RAX_RDX_REG_mask;
|
||||
%}
|
||||
|
||||
// Class for all int registers (excluding RCX and RSP)
|
||||
reg_class int_no_rcx_reg %{
|
||||
return _INT_NO_RCX_REG_mask;
|
||||
%}
|
||||
|
||||
// Singleton class for RAX pointer register
|
||||
reg_class ptr_rax_reg(RAX, RAX_H);
|
||||
@ -317,96 +276,6 @@ reg_class ptr_rsp_reg(RSP, RSP_H);
|
||||
// Singleton class for TLS pointer
|
||||
reg_class ptr_r15_reg(R15, R15_H);
|
||||
|
||||
// Class for all long registers (excluding RSP)
|
||||
reg_class long_reg_with_rbp(RAX, RAX_H,
|
||||
RDX, RDX_H,
|
||||
RBP, RBP_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
|
||||
// Class for all long registers (excluding RSP and RBP)
|
||||
reg_class long_reg_no_rbp(RAX, RAX_H,
|
||||
RDX, RDX_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
|
||||
// Dynamic register class that selects between long_reg_no_rbp and long_reg_with_rbp.
|
||||
reg_class_dynamic long_reg(long_reg_no_rbp, long_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
|
||||
// Class for all long registers (excluding RAX, RDX and RSP)
|
||||
reg_class long_no_rax_rdx_reg_with_rbp(RBP, RBP_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
|
||||
// Class for all long registers (excluding RAX, RDX, RSP, and RBP)
|
||||
reg_class long_no_rax_rdx_reg_no_rbp(RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RCX, RCX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
|
||||
// Dynamic register class that selects between long_no_rax_rdx_reg_no_rbp and long_no_rax_rdx_reg_with_rbp.
|
||||
reg_class_dynamic long_no_rax_rdx_reg(long_no_rax_rdx_reg_no_rbp, long_no_rax_rdx_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
|
||||
// Class for all long registers (excluding RCX and RSP)
|
||||
reg_class long_no_rcx_reg_with_rbp(RBP, RBP_H,
|
||||
RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RAX, RAX_H,
|
||||
RDX, RDX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
|
||||
// Class for all long registers (excluding RCX, RSP, and RBP)
|
||||
reg_class long_no_rcx_reg_no_rbp(RDI, RDI_H,
|
||||
RSI, RSI_H,
|
||||
RAX, RAX_H,
|
||||
RDX, RDX_H,
|
||||
RBX, RBX_H,
|
||||
R8, R8_H,
|
||||
R9, R9_H,
|
||||
R10, R10_H,
|
||||
R11, R11_H,
|
||||
R13, R13_H,
|
||||
R14, R14_H);
|
||||
|
||||
// Dynamic register class that selects between long_no_rcx_reg_no_rbp and long_no_rcx_reg_with_rbp.
|
||||
reg_class_dynamic long_no_rcx_reg(long_no_rcx_reg_no_rbp, long_no_rcx_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
|
||||
// Singleton class for RAX long register
|
||||
reg_class long_rax_reg(RAX, RAX_H);
|
||||
|
||||
@ -416,96 +285,6 @@ reg_class long_rcx_reg(RCX, RCX_H);
|
||||
// Singleton class for RDX long register
|
||||
reg_class long_rdx_reg(RDX, RDX_H);
|
||||
|
||||
// Class for all int registers (excluding RSP)
|
||||
reg_class int_reg_with_rbp(RAX,
|
||||
RDX,
|
||||
RBP,
|
||||
RDI,
|
||||
RSI,
|
||||
RCX,
|
||||
RBX,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R13,
|
||||
R14);
|
||||
|
||||
// Class for all int registers (excluding RSP and RBP)
|
||||
reg_class int_reg_no_rbp(RAX,
|
||||
RDX,
|
||||
RDI,
|
||||
RSI,
|
||||
RCX,
|
||||
RBX,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R13,
|
||||
R14);
|
||||
|
||||
// Dynamic register class that selects between int_reg_no_rbp and int_reg_with_rbp.
|
||||
reg_class_dynamic int_reg(int_reg_no_rbp, int_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
|
||||
// Class for all int registers (excluding RCX and RSP)
|
||||
reg_class int_no_rcx_reg_with_rbp(RAX,
|
||||
RDX,
|
||||
RBP,
|
||||
RDI,
|
||||
RSI,
|
||||
RBX,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R13,
|
||||
R14);
|
||||
|
||||
// Class for all int registers (excluding RCX, RSP, and RBP)
|
||||
reg_class int_no_rcx_reg_no_rbp(RAX,
|
||||
RDX,
|
||||
RDI,
|
||||
RSI,
|
||||
RBX,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R13,
|
||||
R14);
|
||||
|
||||
// Dynamic register class that selects between int_no_rcx_reg_no_rbp and int_no_rcx_reg_with_rbp.
|
||||
reg_class_dynamic int_no_rcx_reg(int_no_rcx_reg_no_rbp, int_no_rcx_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
|
||||
// Class for all int registers (excluding RAX, RDX, and RSP)
|
||||
reg_class int_no_rax_rdx_reg_with_rbp(RBP,
|
||||
RDI,
|
||||
RSI,
|
||||
RCX,
|
||||
RBX,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R13,
|
||||
R14);
|
||||
|
||||
// Class for all int registers (excluding RAX, RDX, RSP, and RBP)
|
||||
reg_class int_no_rax_rdx_reg_no_rbp(RDI,
|
||||
RSI,
|
||||
RCX,
|
||||
RBX,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R13,
|
||||
R14);
|
||||
|
||||
// Dynamic register class that selects between int_no_rax_rdx_reg_no_rbp and int_no_rax_rdx_reg_with_rbp.
|
||||
reg_class_dynamic int_no_rax_rdx_reg(int_no_rax_rdx_reg_no_rbp, int_no_rax_rdx_reg_with_rbp, %{ PreserveFramePointer %});
|
||||
|
||||
// Singleton class for RAX int register
|
||||
reg_class int_rax_reg(RAX);
|
||||
|
||||
@ -529,12 +308,123 @@ reg_class int_rdi_reg(RDI);
|
||||
//----------SOURCE BLOCK-------------------------------------------------------
|
||||
// This is a block of C++ code which provides values, functions, and
|
||||
// definitions necessary in the rest of the architecture description
|
||||
source_hpp %{
|
||||
|
||||
extern RegMask _ANY_REG_mask;
|
||||
extern RegMask _PTR_REG_mask;
|
||||
extern RegMask _PTR_REG_NO_RBP_mask;
|
||||
extern RegMask _PTR_NO_RAX_REG_mask;
|
||||
extern RegMask _PTR_NO_RAX_RBX_REG_mask;
|
||||
extern RegMask _LONG_REG_mask;
|
||||
extern RegMask _LONG_NO_RAX_RDX_REG_mask;
|
||||
extern RegMask _LONG_NO_RCX_REG_mask;
|
||||
extern RegMask _INT_REG_mask;
|
||||
extern RegMask _INT_NO_RAX_RDX_REG_mask;
|
||||
extern RegMask _INT_NO_RCX_REG_mask;
|
||||
|
||||
extern RegMask _STACK_OR_PTR_REG_mask;
|
||||
extern RegMask _STACK_OR_LONG_REG_mask;
|
||||
extern RegMask _STACK_OR_INT_REG_mask;
|
||||
|
||||
inline const RegMask& STACK_OR_PTR_REG_mask() { return _STACK_OR_PTR_REG_mask; }
|
||||
inline const RegMask& STACK_OR_LONG_REG_mask() { return _STACK_OR_LONG_REG_mask; }
|
||||
inline const RegMask& STACK_OR_INT_REG_mask() { return _STACK_OR_INT_REG_mask; }
|
||||
|
||||
%}
|
||||
|
||||
source %{
|
||||
#define RELOC_IMM64 Assembler::imm_operand
|
||||
#define RELOC_DISP32 Assembler::disp32_operand
|
||||
|
||||
#define __ _masm.
|
||||
|
||||
RegMask _ANY_REG_mask;
|
||||
RegMask _PTR_REG_mask;
|
||||
RegMask _PTR_REG_NO_RBP_mask;
|
||||
RegMask _PTR_NO_RAX_REG_mask;
|
||||
RegMask _PTR_NO_RAX_RBX_REG_mask;
|
||||
RegMask _LONG_REG_mask;
|
||||
RegMask _LONG_NO_RAX_RDX_REG_mask;
|
||||
RegMask _LONG_NO_RCX_REG_mask;
|
||||
RegMask _INT_REG_mask;
|
||||
RegMask _INT_NO_RAX_RDX_REG_mask;
|
||||
RegMask _INT_NO_RCX_REG_mask;
|
||||
RegMask _STACK_OR_PTR_REG_mask;
|
||||
RegMask _STACK_OR_LONG_REG_mask;
|
||||
RegMask _STACK_OR_INT_REG_mask;
|
||||
|
||||
static bool need_r12_heapbase() {
|
||||
return UseCompressedOops || UseCompressedClassPointers;
|
||||
}
|
||||
|
||||
void reg_mask_init() {
|
||||
// _ALL_REG_mask is generated by adlc from the all_reg register class below.
|
||||
// We derive a number of subsets from it.
|
||||
_ANY_REG_mask = _ALL_REG_mask;
|
||||
|
||||
if (PreserveFramePointer) {
|
||||
_ANY_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
|
||||
_ANY_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
|
||||
}
|
||||
if (need_r12_heapbase()) {
|
||||
_ANY_REG_mask.Remove(OptoReg::as_OptoReg(r12->as_VMReg()));
|
||||
_ANY_REG_mask.Remove(OptoReg::as_OptoReg(r12->as_VMReg()->next()));
|
||||
}
|
||||
|
||||
_PTR_REG_mask = _ANY_REG_mask;
|
||||
_PTR_REG_mask.Remove(OptoReg::as_OptoReg(rsp->as_VMReg()));
|
||||
_PTR_REG_mask.Remove(OptoReg::as_OptoReg(rsp->as_VMReg()->next()));
|
||||
_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r15->as_VMReg()));
|
||||
_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r15->as_VMReg()->next()));
|
||||
|
||||
_STACK_OR_PTR_REG_mask = _PTR_REG_mask;
|
||||
_STACK_OR_PTR_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());
|
||||
|
||||
_PTR_REG_NO_RBP_mask = _PTR_REG_mask;
|
||||
_PTR_REG_NO_RBP_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
|
||||
_PTR_REG_NO_RBP_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
|
||||
|
||||
_PTR_NO_RAX_REG_mask = _PTR_REG_mask;
|
||||
_PTR_NO_RAX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()));
|
||||
_PTR_NO_RAX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()->next()));
|
||||
|
||||
_PTR_NO_RAX_RBX_REG_mask = _PTR_NO_RAX_REG_mask;
|
||||
_PTR_NO_RAX_RBX_REG_mask.Remove(OptoReg::as_OptoReg(rbx->as_VMReg()));
|
||||
_PTR_NO_RAX_RBX_REG_mask.Remove(OptoReg::as_OptoReg(rbx->as_VMReg()->next()));
|
||||
|
||||
_LONG_REG_mask = _PTR_REG_mask;
|
||||
_STACK_OR_LONG_REG_mask = _LONG_REG_mask;
|
||||
_STACK_OR_LONG_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());
|
||||
|
||||
_LONG_NO_RAX_RDX_REG_mask = _LONG_REG_mask;
|
||||
_LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()));
|
||||
_LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()->next()));
|
||||
_LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rdx->as_VMReg()));
|
||||
_LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rdx->as_VMReg()->next()));
|
||||
|
||||
_LONG_NO_RCX_REG_mask = _LONG_REG_mask;
|
||||
_LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()));
|
||||
_LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()->next()));
|
||||
|
||||
_INT_REG_mask = _ALL_INT_REG_mask;
|
||||
if (PreserveFramePointer) {
|
||||
_INT_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
|
||||
}
|
||||
if (need_r12_heapbase()) {
|
||||
_INT_REG_mask.Remove(OptoReg::as_OptoReg(r12->as_VMReg()));
|
||||
}
|
||||
|
||||
_STACK_OR_INT_REG_mask = _INT_REG_mask;
|
||||
_STACK_OR_INT_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());
|
||||
|
||||
_INT_NO_RAX_RDX_REG_mask = _INT_REG_mask;
|
||||
_INT_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()));
|
||||
_INT_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rdx->as_VMReg()));
|
||||
|
||||
_INT_NO_RCX_REG_mask = _INT_REG_mask;
|
||||
_INT_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()));
|
||||
}
|
||||
|
||||
static bool generate_vzeroupper(Compile* C) {
|
||||
return (VM_Version::supports_vzeroupper() && (C->max_vector_size() > 16 || C->clear_upper_avx() == true)) ? true: false; // Generate vzeroupper
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define OS_AIX_OS_AIX_INLINE_HPP
|
||||
|
||||
#include "runtime/os.hpp"
|
||||
#include "os_posix.inline.hpp"
|
||||
|
||||
// System includes
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019, 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
|
||||
@ -859,11 +859,7 @@ char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {
|
||||
|
||||
char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
|
||||
if (str != NULL) {
|
||||
size_t len = strlen(str);
|
||||
char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
|
||||
strncpy(tmp, str, len);
|
||||
tmp[len] = '\0';
|
||||
return tmp;
|
||||
return os::strdup_check_oom(str, mtInternal);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "memory/filemap.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "os_bsd.inline.hpp"
|
||||
#include "os_posix.inline.hpp"
|
||||
#include "os_share_bsd.hpp"
|
||||
#include "prims/jniFastGetField.hpp"
|
||||
#include "prims/jvm_misc.hpp"
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define OS_BSD_OS_BSD_INLINE_HPP
|
||||
|
||||
#include "runtime/os.hpp"
|
||||
#include "os_posix.inline.hpp"
|
||||
|
||||
// System includes
|
||||
|
||||
|
@ -70,7 +70,12 @@
|
||||
diagnostic(bool, DumpPrivateMappingsInCore, true, \
|
||||
"If true, sets bit 2 of /proc/PID/coredump_filter, thus " \
|
||||
"resulting in file-backed private mappings of the process to "\
|
||||
"be dumped into the corefile, if UseSharedSpaces is true.") \
|
||||
"be dumped into the corefile.") \
|
||||
\
|
||||
diagnostic(bool, DumpSharedMappingsInCore, true, \
|
||||
"If true, sets bit 3 of /proc/PID/coredump_filter, thus " \
|
||||
"resulting in file-backed shared mappings of the process to " \
|
||||
"be dumped into the corefile.") \
|
||||
\
|
||||
diagnostic(bool, UseCpuAllocPath, false, \
|
||||
"Use CPU_ALLOC code path in os::active_processor_count ")
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "memory/filemap.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "os_linux.inline.hpp"
|
||||
#include "os_posix.inline.hpp"
|
||||
#include "os_share_linux.hpp"
|
||||
#include "osContainer_linux.hpp"
|
||||
#include "prims/jniFastGetField.hpp"
|
||||
@ -131,6 +132,7 @@
|
||||
|
||||
enum CoredumpFilterBit {
|
||||
FILE_BACKED_PVT_BIT = 1 << 2,
|
||||
FILE_BACKED_SHARED_BIT = 1 << 3,
|
||||
LARGEPAGES_BIT = 1 << 6,
|
||||
DAX_SHARED_BIT = 1 << 8
|
||||
};
|
||||
@ -1357,11 +1359,9 @@ void os::shutdown() {
|
||||
void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
os::shutdown();
|
||||
if (dump_core) {
|
||||
#if INCLUDE_CDS
|
||||
if (UseSharedSpaces && DumpPrivateMappingsInCore) {
|
||||
if (DumpPrivateMappingsInCore) {
|
||||
ClassLoader::close_jrt_image();
|
||||
}
|
||||
#endif
|
||||
#ifndef PRODUCT
|
||||
fdStream out(defaultStream::output_fd());
|
||||
out.print_raw("Current thread is ");
|
||||
@ -3432,8 +3432,6 @@ bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Set the coredump_filter bits to include largepages in core dump (bit 6)
|
||||
//
|
||||
// From the coredump_filter documentation:
|
||||
//
|
||||
// - (bit 0) anonymous private memory
|
||||
@ -5131,11 +5129,13 @@ jint os::init_2(void) {
|
||||
set_coredump_filter(DAX_SHARED_BIT);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
if (UseSharedSpaces && DumpPrivateMappingsInCore) {
|
||||
if (DumpPrivateMappingsInCore) {
|
||||
set_coredump_filter(FILE_BACKED_PVT_BIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (DumpSharedMappingsInCore) {
|
||||
set_coredump_filter(FILE_BACKED_SHARED_BIT);
|
||||
}
|
||||
|
||||
return JNI_OK;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019, 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
|
||||
@ -861,11 +861,7 @@ char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {
|
||||
|
||||
char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
|
||||
if (str != NULL) {
|
||||
size_t len = strlen(str);
|
||||
char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
|
||||
strncpy(tmp, str, len);
|
||||
tmp[len] = '\0';
|
||||
return tmp;
|
||||
return os::strdup_check_oom(str, mtInternal);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -1066,7 +1062,7 @@ int64_t NetworkPerformanceInterface::NetworkPerformance::read_counter(const char
|
||||
|
||||
snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter);
|
||||
|
||||
int fd = open(buf, O_RDONLY);
|
||||
int fd = os::open(buf, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2019, 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
|
||||
@ -97,8 +97,8 @@ static void save_memory_to_file(char* addr, size_t size) {
|
||||
|
||||
int result;
|
||||
|
||||
RESTARTABLE(::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE),
|
||||
result);;
|
||||
RESTARTABLE(os::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR),
|
||||
result);
|
||||
if (result == OS_ERR) {
|
||||
if (PrintMiscellaneous && Verbose) {
|
||||
warning("Could not create Perfdata save file: %s: %s\n",
|
||||
@ -871,7 +871,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename,
|
||||
// Cannot use O_TRUNC here; truncation of an existing file has to happen
|
||||
// after the is_file_secure() check below.
|
||||
int result;
|
||||
RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result);
|
||||
RESTARTABLE(os::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR), result);
|
||||
if (result == OS_ERR) {
|
||||
if (PrintMiscellaneous && Verbose) {
|
||||
if (errno == ELOOP) {
|
||||
@ -949,7 +949,7 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) {
|
||||
|
||||
// open the file
|
||||
int result;
|
||||
RESTARTABLE(::open(filename, oflags), result);
|
||||
RESTARTABLE(os::open(filename, oflags, 0), result);
|
||||
if (result == OS_ERR) {
|
||||
if (errno == ENOENT) {
|
||||
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
|
@ -180,20 +180,17 @@ int os::create_file_for_heap(const char* dir) {
|
||||
|
||||
const char name_template[] = "/jvmheap.XXXXXX";
|
||||
|
||||
char *fullname = (char*)os::malloc((strlen(dir) + strlen(name_template) + 1), mtInternal);
|
||||
size_t fullname_len = strlen(dir) + strlen(name_template);
|
||||
char *fullname = (char*)os::malloc(fullname_len + 1, mtInternal);
|
||||
if (fullname == NULL) {
|
||||
vm_exit_during_initialization(err_msg("Malloc failed during creation of backing file for heap (%s)", os::strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
(void)strncpy(fullname, dir, strlen(dir)+1);
|
||||
(void)strncat(fullname, name_template, strlen(name_template));
|
||||
int n = snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template);
|
||||
assert((size_t)n == fullname_len, "Unexpected number of characters in string");
|
||||
|
||||
os::native_path(fullname);
|
||||
|
||||
sigset_t set, oldset;
|
||||
int ret = sigfillset(&set);
|
||||
assert_with_errno(ret == 0, "sigfillset returned error");
|
||||
|
||||
// set the file creation mask.
|
||||
mode_t file_mode = S_IRUSR | S_IWUSR;
|
||||
|
||||
@ -207,7 +204,7 @@ int os::create_file_for_heap(const char* dir) {
|
||||
}
|
||||
|
||||
// delete the name from the filesystem. When 'fd' is closed, the file (and space) will be deleted.
|
||||
ret = unlink(fullname);
|
||||
int ret = unlink(fullname);
|
||||
assert_with_errno(ret == 0, "unlink returned error");
|
||||
|
||||
os::free(fullname);
|
||||
@ -2218,22 +2215,6 @@ os::PlatformMonitor::~PlatformMonitor() {
|
||||
assert_status(status == 0, status, "mutex_destroy");
|
||||
}
|
||||
|
||||
void os::PlatformMonitor::lock() {
|
||||
int status = pthread_mutex_lock(&_mutex);
|
||||
assert_status(status == 0, status, "mutex_lock");
|
||||
}
|
||||
|
||||
void os::PlatformMonitor::unlock() {
|
||||
int status = pthread_mutex_unlock(&_mutex);
|
||||
assert_status(status == 0, status, "mutex_unlock");
|
||||
}
|
||||
|
||||
bool os::PlatformMonitor::try_lock() {
|
||||
int status = pthread_mutex_trylock(&_mutex);
|
||||
assert_status(status == 0 || status == EBUSY, status, "mutex_trylock");
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
// Must already be locked
|
||||
int os::PlatformMonitor::wait(jlong millis) {
|
||||
assert(millis >= 0, "negative timeout");
|
||||
@ -2262,14 +2243,4 @@ int os::PlatformMonitor::wait(jlong millis) {
|
||||
}
|
||||
}
|
||||
|
||||
void os::PlatformMonitor::notify() {
|
||||
int status = pthread_cond_signal(&_cond);
|
||||
assert_status(status == 0, status, "cond_signal");
|
||||
}
|
||||
|
||||
void os::PlatformMonitor::notify_all() {
|
||||
int status = pthread_cond_broadcast(&_cond);
|
||||
assert_status(status == 0, status, "cond_broadcast");
|
||||
}
|
||||
|
||||
#endif // !SOLARIS
|
||||
|
@ -177,7 +177,7 @@ private:
|
||||
* These event objects are type-stable and immortal - we never delete them.
|
||||
* Events are associated with a thread for the lifetime of the thread.
|
||||
*/
|
||||
class PlatformEvent : public CHeapObj<mtInternal> {
|
||||
class PlatformEvent : public CHeapObj<mtSynchronizer> {
|
||||
private:
|
||||
double cachePad[4]; // Increase odds that _mutex is sole occupant of cache line
|
||||
volatile int _event; // Event count/permit: -1, 0 or 1
|
||||
@ -212,7 +212,7 @@ class PlatformEvent : public CHeapObj<mtInternal> {
|
||||
// API updates of course). But Parker methods use fastpaths that break that
|
||||
// level of encapsulation - so combining the two remains a future project.
|
||||
|
||||
class PlatformParker : public CHeapObj<mtInternal> {
|
||||
class PlatformParker : public CHeapObj<mtSynchronizer> {
|
||||
protected:
|
||||
enum {
|
||||
REL_INDEX = 0,
|
||||
@ -230,7 +230,7 @@ class PlatformParker : public CHeapObj<mtInternal> {
|
||||
};
|
||||
|
||||
// Platform specific implementation that underpins VM Monitor/Mutex class
|
||||
class PlatformMonitor : public CHeapObj<mtInternal> {
|
||||
class PlatformMonitor : public CHeapObj<mtSynchronizer> {
|
||||
private:
|
||||
pthread_mutex_t _mutex; // Native mutex for locking
|
||||
pthread_cond_t _cond; // Native condition variable for blocking
|
||||
|
@ -42,6 +42,39 @@ inline int os::Posix::clock_gettime(clockid_t clock_id, struct timespec *tp) {
|
||||
inline int os::Posix::clock_getres(clockid_t clock_id, struct timespec *tp) {
|
||||
return _clock_getres != NULL ? _clock_getres(clock_id, tp) : -1;
|
||||
}
|
||||
|
||||
#endif // SUPPORTS_CLOCK_MONOTONIC
|
||||
|
||||
#ifndef SOLARIS
|
||||
|
||||
// Platform Monitor implementation
|
||||
|
||||
inline void os::PlatformMonitor::lock() {
|
||||
int status = pthread_mutex_lock(&_mutex);
|
||||
assert_status(status == 0, status, "mutex_lock");
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::unlock() {
|
||||
int status = pthread_mutex_unlock(&_mutex);
|
||||
assert_status(status == 0, status, "mutex_unlock");
|
||||
}
|
||||
|
||||
inline bool os::PlatformMonitor::try_lock() {
|
||||
int status = pthread_mutex_trylock(&_mutex);
|
||||
assert_status(status == 0 || status == EBUSY, status, "mutex_trylock");
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::notify() {
|
||||
int status = pthread_cond_signal(&_cond);
|
||||
assert_status(status == 0, status, "cond_signal");
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::notify_all() {
|
||||
int status = pthread_cond_broadcast(&_cond);
|
||||
assert_status(status == 0, status, "cond_broadcast");
|
||||
}
|
||||
|
||||
#endif // !SOLARIS
|
||||
|
||||
#endif // OS_POSIX_OS_POSIX_INLINE_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019, 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
|
||||
@ -74,7 +74,7 @@ static int get_info(const char* path, void* info, size_t s, off_t o) {
|
||||
|
||||
int fd = -1;
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) < 0) {
|
||||
if ((fd = os::open(path, O_RDONLY, 0)) < 0) {
|
||||
return OS_ERR;
|
||||
}
|
||||
if (pread(fd, info, s, o) != s) {
|
||||
@ -544,11 +544,7 @@ bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(st
|
||||
|
||||
char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
|
||||
if (str != NULL) {
|
||||
size_t len = strlen(str);
|
||||
char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
|
||||
strncpy(tmp, str, len);
|
||||
tmp[len] = '\0';
|
||||
return tmp;
|
||||
return os::strdup_check_oom(str, mtInternal);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ class Solaris {
|
||||
|
||||
};
|
||||
|
||||
class PlatformEvent : public CHeapObj<mtInternal> {
|
||||
class PlatformEvent : public CHeapObj<mtSynchronizer> {
|
||||
private:
|
||||
double CachePad[4]; // increase odds that _mutex is sole occupant of cache line
|
||||
volatile int _Event;
|
||||
@ -317,7 +317,7 @@ class PlatformEvent : public CHeapObj<mtInternal> {
|
||||
void unpark();
|
||||
};
|
||||
|
||||
class PlatformParker : public CHeapObj<mtInternal> {
|
||||
class PlatformParker : public CHeapObj<mtSynchronizer> {
|
||||
protected:
|
||||
mutex_t _mutex[1];
|
||||
cond_t _cond[1];
|
||||
@ -336,7 +336,7 @@ class PlatformParker : public CHeapObj<mtInternal> {
|
||||
};
|
||||
|
||||
// Platform specific implementation that underpins VM Monitor/Mutex class
|
||||
class PlatformMonitor : public CHeapObj<mtInternal> {
|
||||
class PlatformMonitor : public CHeapObj<mtSynchronizer> {
|
||||
private:
|
||||
mutex_t _mutex; // Native mutex for locking
|
||||
cond_t _cond; // Native condition variable for blocking
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019, 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
|
||||
@ -1253,14 +1253,7 @@ int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProc
|
||||
|
||||
char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
|
||||
if (str != NULL) {
|
||||
size_t len = strlen(str);
|
||||
char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
|
||||
if (NULL == tmp) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(tmp, str, len);
|
||||
tmp[len] = '\0';
|
||||
return tmp;
|
||||
return os::strdup_check_oom(str, mtInternal);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2970,14 +2970,15 @@ void os::large_page_init() {
|
||||
int os::create_file_for_heap(const char* dir) {
|
||||
|
||||
const char name_template[] = "/jvmheap.XXXXXX";
|
||||
char *fullname = (char*)os::malloc((strlen(dir) + strlen(name_template) + 1), mtInternal);
|
||||
|
||||
size_t fullname_len = strlen(dir) + strlen(name_template);
|
||||
char *fullname = (char*)os::malloc(fullname_len + 1, mtInternal);
|
||||
if (fullname == NULL) {
|
||||
vm_exit_during_initialization(err_msg("Malloc failed during creation of backing file for heap (%s)", os::strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void)strncpy(fullname, dir, strlen(dir)+1);
|
||||
(void)strncat(fullname, name_template, strlen(name_template));
|
||||
int n = snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template);
|
||||
assert((size_t)n == fullname_len, "Unexpected number of characters in string");
|
||||
|
||||
os::native_path(fullname);
|
||||
|
||||
@ -5319,27 +5320,6 @@ void Parker::unpark() {
|
||||
|
||||
// Platform Monitor implementation
|
||||
|
||||
os::PlatformMonitor::PlatformMonitor() {
|
||||
InitializeConditionVariable(&_cond);
|
||||
InitializeCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
os::PlatformMonitor::~PlatformMonitor() {
|
||||
DeleteCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
void os::PlatformMonitor::lock() {
|
||||
EnterCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
void os::PlatformMonitor::unlock() {
|
||||
LeaveCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
bool os::PlatformMonitor::try_lock() {
|
||||
return TryEnterCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
// Must already be locked
|
||||
int os::PlatformMonitor::wait(jlong millis) {
|
||||
assert(millis >= 0, "negative timeout");
|
||||
@ -5358,14 +5338,6 @@ int os::PlatformMonitor::wait(jlong millis) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void os::PlatformMonitor::notify() {
|
||||
WakeConditionVariable(&_cond);
|
||||
}
|
||||
|
||||
void os::PlatformMonitor::notify_all() {
|
||||
WakeAllConditionVariable(&_cond);
|
||||
}
|
||||
|
||||
// Run the specified command in a separate process. Return its exit value,
|
||||
// or -1 on failure (e.g. can't create a new process).
|
||||
int os::fork_and_exec(char* cmd, bool use_vfork_if_available) {
|
||||
|
@ -148,7 +148,7 @@ private:
|
||||
static volatile intptr_t _crash_mux;
|
||||
};
|
||||
|
||||
class PlatformEvent : public CHeapObj<mtInternal> {
|
||||
class PlatformEvent : public CHeapObj<mtSynchronizer> {
|
||||
private:
|
||||
double CachePad [4] ; // increase odds that _Event is sole occupant of cache line
|
||||
volatile int _Event ;
|
||||
@ -174,7 +174,7 @@ class PlatformEvent : public CHeapObj<mtInternal> {
|
||||
|
||||
|
||||
|
||||
class PlatformParker : public CHeapObj<mtInternal> {
|
||||
class PlatformParker : public CHeapObj<mtSynchronizer> {
|
||||
protected:
|
||||
HANDLE _ParkEvent ;
|
||||
|
||||
@ -188,7 +188,7 @@ class PlatformParker : public CHeapObj<mtInternal> {
|
||||
} ;
|
||||
|
||||
// Platform specific implementation that underpins VM Monitor/Mutex class
|
||||
class PlatformMonitor : public CHeapObj<mtInternal> {
|
||||
class PlatformMonitor : public CHeapObj<mtSynchronizer> {
|
||||
private:
|
||||
CRITICAL_SECTION _mutex; // Native mutex for locking
|
||||
CONDITION_VARIABLE _cond; // Native condition variable for blocking
|
||||
|
@ -86,4 +86,35 @@ inline void os::exit(int num) {
|
||||
win32::exit_process_or_thread(win32::EPT_PROCESS, num);
|
||||
}
|
||||
|
||||
// Platform Monitor implementation
|
||||
|
||||
inline os::PlatformMonitor::PlatformMonitor() {
|
||||
InitializeConditionVariable(&_cond);
|
||||
InitializeCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
inline os::PlatformMonitor::~PlatformMonitor() {
|
||||
DeleteCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::lock() {
|
||||
EnterCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::unlock() {
|
||||
LeaveCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
inline bool os::PlatformMonitor::try_lock() {
|
||||
return TryEnterCriticalSection(&_mutex);
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::notify() {
|
||||
WakeConditionVariable(&_cond);
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::notify_all() {
|
||||
WakeAllConditionVariable(&_cond);
|
||||
}
|
||||
|
||||
#endif // OS_WINDOWS_OS_WINDOWS_INLINE_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, 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
|
||||
@ -191,7 +191,7 @@ int ZBackingFile::create_file_fd(const char* name) const {
|
||||
|
||||
// Try to create an anonymous file using the O_TMPFILE flag. Note that this
|
||||
// flag requires kernel >= 3.11. If this fails we fall back to open/unlink.
|
||||
const int fd_anon = open(path.get(), O_TMPFILE|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
||||
const int fd_anon = os::open(path.get(), O_TMPFILE|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
||||
if (fd_anon == -1) {
|
||||
ZErrno err;
|
||||
log_debug(gc, init)("Failed to create anonymous file in %s (%s)", path.get(),
|
||||
@ -217,7 +217,7 @@ int ZBackingFile::create_file_fd(const char* name) const {
|
||||
snprintf(filename, sizeof(filename), "%s/%s.%d", path.get(), name, os::current_process_id());
|
||||
|
||||
// Create file
|
||||
const int fd = open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
||||
const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
||||
if (fd == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc, init)("Failed to create file %s (%s)", filename, err.to_string());
|
||||
|
@ -242,9 +242,6 @@ public:
|
||||
char* code_snippet() {
|
||||
return _code_snippet;
|
||||
}
|
||||
void set_stack_version(bool flag) {
|
||||
assert(false, "User defined register classes are not allowed to spill to the stack.");
|
||||
}
|
||||
void declare_register_masks(FILE* fp);
|
||||
void build_register_masks(FILE* fp) {
|
||||
// We do not need to generate register masks because we select at runtime
|
||||
|
@ -174,6 +174,12 @@ void CE_Eliminator::block_do(BlockBegin* block) {
|
||||
for_each_phi_fun(t_block, phi, return; );
|
||||
for_each_phi_fun(f_block, phi, return; );
|
||||
|
||||
// Only replace safepoint gotos if state_before information is available (if is a safepoint)
|
||||
bool is_safepoint = if_->is_safepoint();
|
||||
if (!is_safepoint && (t_goto->is_safepoint() || f_goto->is_safepoint())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) substitute conditional expression
|
||||
// with an IfOp followed by a Goto
|
||||
// cut if_ away and get node before
|
||||
@ -202,7 +208,7 @@ void CE_Eliminator::block_do(BlockBegin* block) {
|
||||
|
||||
// append Goto to successor
|
||||
ValueStack* state_before = if_->state_before();
|
||||
Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint());
|
||||
Goto* goto_ = new Goto(sux, state_before, is_safepoint);
|
||||
|
||||
// prepare state for Goto
|
||||
ValueStack* goto_state = if_state;
|
||||
|
@ -1253,7 +1253,7 @@ void ciEnv::dump_replay_data(int compile_id) {
|
||||
static char buffer[O_BUFLEN];
|
||||
int ret = jio_snprintf(buffer, O_BUFLEN, "replay_pid%p_compid%d.log", os::current_process_id(), compile_id);
|
||||
if (ret > 0) {
|
||||
int fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
int fd = os::open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd != -1) {
|
||||
FILE* replay_data_file = os::open(fd, "w");
|
||||
if (replay_data_file != NULL) {
|
||||
@ -1271,7 +1271,7 @@ void ciEnv::dump_inline_data(int compile_id) {
|
||||
static char buffer[O_BUFLEN];
|
||||
int ret = jio_snprintf(buffer, O_BUFLEN, "inline_pid%p_compid%d.log", os::current_process_id(), compile_id);
|
||||
if (ret > 0) {
|
||||
int fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
int fd = os::open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd != -1) {
|
||||
FILE* inline_data_file = os::open(fd, "w");
|
||||
if (inline_data_file != NULL) {
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/constantPool.hpp"
|
||||
#include "oops/method.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/fieldDescriptor.inline.hpp"
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
#include "runtime/reflection.hpp"
|
||||
#include "runtime/safepointVerifiers.hpp"
|
||||
@ -5743,16 +5744,13 @@ void ClassFileParser::prepend_host_package_name(const InstanceKlass* unsafe_anon
|
||||
ClassLoader::package_from_name(unsafe_anonymous_host->name()->as_C_string(), NULL);
|
||||
|
||||
if (host_pkg_name != NULL) {
|
||||
size_t host_pkg_len = strlen(host_pkg_name);
|
||||
int host_pkg_len = (int)strlen(host_pkg_name);
|
||||
int class_name_len = _class_name->utf8_length();
|
||||
char* new_anon_name =
|
||||
NEW_RESOURCE_ARRAY(char, host_pkg_len + 1 + class_name_len);
|
||||
// Copy host package name and trailing /.
|
||||
strncpy(new_anon_name, host_pkg_name, host_pkg_len);
|
||||
new_anon_name[host_pkg_len] = '/';
|
||||
// Append unsafe anonymous class name. The unsafe anonymous class name can contain odd
|
||||
// characters. So, do a strncpy instead of using sprintf("%s...").
|
||||
strncpy(new_anon_name + host_pkg_len + 1, (char *)_class_name->base(), class_name_len);
|
||||
int symbol_len = host_pkg_len + 1 + class_name_len;
|
||||
char* new_anon_name = NEW_RESOURCE_ARRAY(char, symbol_len + 1);
|
||||
int n = os::snprintf(new_anon_name, symbol_len + 1, "%s/%.*s",
|
||||
host_pkg_name, class_name_len, _class_name->base());
|
||||
assert(n == symbol_len, "Unexpected number of characters in string");
|
||||
|
||||
// Decrement old _class_name to avoid leaking.
|
||||
_class_name->decrement_refcount();
|
||||
@ -5761,9 +5759,7 @@ void ClassFileParser::prepend_host_package_name(const InstanceKlass* unsafe_anon
|
||||
// The new class name is created with a refcount of one. When installed into the InstanceKlass,
|
||||
// it'll be two and when the ClassFileParser destructor runs, it'll go back to one and get deleted
|
||||
// when the class is unloaded.
|
||||
_class_name = SymbolTable::new_symbol(new_anon_name,
|
||||
(int)host_pkg_len + 1 + class_name_len,
|
||||
CHECK);
|
||||
_class_name = SymbolTable::new_symbol(new_anon_name, symbol_len, CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,6 @@ static JImagePackageToModule_t JImagePackageToModule = NULL;
|
||||
static JImageFindResource_t JImageFindResource = NULL;
|
||||
static JImageGetResource_t JImageGetResource = NULL;
|
||||
static JImageResourceIterator_t JImageResourceIterator = NULL;
|
||||
static JImage_ResourcePath_t JImageResourcePath = NULL;
|
||||
|
||||
// Globals
|
||||
|
||||
@ -621,13 +620,14 @@ void ClassLoader::setup_module_search_path(const char* path, TRAPS) {
|
||||
update_module_path_entry_list(path, THREAD);
|
||||
}
|
||||
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
void ClassLoader::close_jrt_image() {
|
||||
assert(ClassLoader::has_jrt_entry(), "Not applicable for exploded builds");
|
||||
// Not applicable for exploded builds
|
||||
if (!ClassLoader::has_jrt_entry()) return;
|
||||
_jrt_entry->close_jimage();
|
||||
}
|
||||
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
// Construct the array of module/path pairs as specified to --patch-module
|
||||
// for the boot loader to search ahead of the jimage, if the class being
|
||||
// loaded is defined to a module that has been specified to --patch-module.
|
||||
@ -1094,8 +1094,6 @@ void ClassLoader::load_jimage_library() {
|
||||
guarantee(JImageGetResource != NULL, "function JIMAGE_GetResource not found");
|
||||
JImageResourceIterator = CAST_TO_FN_PTR(JImageResourceIterator_t, os::dll_lookup(handle, "JIMAGE_ResourceIterator"));
|
||||
guarantee(JImageResourceIterator != NULL, "function JIMAGE_ResourceIterator not found");
|
||||
JImageResourcePath = CAST_TO_FN_PTR(JImage_ResourcePath_t, os::dll_lookup(handle, "JIMAGE_ResourcePath"));
|
||||
guarantee(JImageResourcePath != NULL, "function JIMAGE_ResourcePath not found");
|
||||
}
|
||||
|
||||
jboolean ClassLoader::decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg) {
|
||||
|
@ -247,12 +247,12 @@ class ClassLoader: AllStatic {
|
||||
|
||||
static void load_zip_library();
|
||||
static void load_jimage_library();
|
||||
|
||||
public:
|
||||
static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st,
|
||||
bool throw_exception,
|
||||
bool is_boot_append, TRAPS);
|
||||
|
||||
public:
|
||||
|
||||
// If the package for the fully qualified class name is in the boot
|
||||
// loader's package entry table then add_package() sets the classpath_index
|
||||
// field so that get_system_package() will know to return a non-null value
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, 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
|
||||
@ -203,13 +203,13 @@ void ClassLoaderExt::process_jar_manifest(ClassPathEntry* entry,
|
||||
file_end = end;
|
||||
}
|
||||
|
||||
int name_len = (int)strlen(file_start);
|
||||
size_t name_len = strlen(file_start);
|
||||
if (name_len > 0) {
|
||||
ResourceMark rm(THREAD);
|
||||
char* libname = NEW_RESOURCE_ARRAY(char, dir_len + name_len + 1);
|
||||
*libname = 0;
|
||||
strncat(libname, dir_name, dir_len);
|
||||
strncat(libname, file_start, name_len);
|
||||
size_t libname_len = dir_len + name_len;
|
||||
char* libname = NEW_RESOURCE_ARRAY(char, libname_len + 1);
|
||||
int n = os::snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start);
|
||||
assert((size_t)n == libname_len, "Unexpected number of characters in string");
|
||||
trace_class_path("library = ", libname);
|
||||
ClassLoader::update_class_path_entry_list(libname, true, false);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2019, 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
|
||||
@ -198,7 +198,7 @@ HashtableTextDump::HashtableTextDump(const char* filename) : _fd(-1) {
|
||||
quit("Unable to get hashtable dump file size", filename);
|
||||
}
|
||||
_size = st.st_size;
|
||||
_fd = open(filename, O_RDONLY | O_BINARY, 0);
|
||||
_fd = os::open(filename, O_RDONLY | O_BINARY, 0);
|
||||
if (_fd < 0) {
|
||||
quit("Unable to open hashtable dump file", filename);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, 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
|
||||
@ -46,22 +46,22 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
|
||||
InstanceKlass* ik,
|
||||
Symbol* class_name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain, TRAPS) {
|
||||
Handle protection_domain,
|
||||
const ClassFileStream *cfs,
|
||||
TRAPS) {
|
||||
#if INCLUDE_CDS && INCLUDE_JVMTI
|
||||
assert(ik != NULL, "sanity");
|
||||
assert(ik->is_shared(), "expecting a shared class");
|
||||
|
||||
if (JvmtiExport::should_post_class_file_load_hook()) {
|
||||
assert(THREAD->is_Java_thread(), "must be JavaThread");
|
||||
|
||||
// Post the CFLH
|
||||
JvmtiCachedClassFileData* cached_class_file = NULL;
|
||||
JvmtiCachedClassFileData* archived_class_data = ik->get_archived_class_data();
|
||||
assert(archived_class_data != NULL, "shared class has no archived class data");
|
||||
unsigned char* ptr =
|
||||
VM_RedefineClasses::get_cached_class_file_bytes(archived_class_data);
|
||||
unsigned char* end_ptr =
|
||||
ptr + VM_RedefineClasses::get_cached_class_file_len(archived_class_data);
|
||||
if (cfs == NULL) {
|
||||
cfs = FileMapInfo::open_stream_for_jvmti(ik, CHECK_NULL);
|
||||
}
|
||||
unsigned char* ptr = (unsigned char*)cfs->buffer();
|
||||
unsigned char* end_ptr = ptr + cfs->length();
|
||||
unsigned char* old_ptr = ptr;
|
||||
JvmtiExport::post_class_file_load_hook(class_name,
|
||||
class_loader,
|
||||
@ -75,25 +75,9 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
|
||||
ClassLoaderData* loader_data =
|
||||
ClassLoaderData::class_loader_data(class_loader());
|
||||
int path_index = ik->shared_classpath_index();
|
||||
const char* pathname;
|
||||
if (path_index < 0) {
|
||||
// shared classes loaded by user defined class loader
|
||||
// do not have shared_classpath_index
|
||||
ModuleEntry* mod_entry = ik->module();
|
||||
if (mod_entry != NULL && (mod_entry->location() != NULL)) {
|
||||
ResourceMark rm;
|
||||
pathname = (const char*)(mod_entry->location()->as_C_string());
|
||||
} else {
|
||||
pathname = "";
|
||||
}
|
||||
} else {
|
||||
SharedClassPathEntry* ent =
|
||||
(SharedClassPathEntry*)FileMapInfo::shared_path(path_index);
|
||||
pathname = ent == NULL ? NULL : ent->name();
|
||||
}
|
||||
ClassFileStream* stream = new ClassFileStream(ptr,
|
||||
end_ptr - ptr,
|
||||
pathname,
|
||||
cfs->source(),
|
||||
ClassFileStream::verify);
|
||||
ClassFileParser parser(stream,
|
||||
class_name,
|
||||
@ -236,24 +220,6 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
|
||||
#if INCLUDE_CDS
|
||||
if (DumpSharedSpaces) {
|
||||
ClassLoader::record_result(result, stream, THREAD);
|
||||
#if INCLUDE_JVMTI
|
||||
assert(cached_class_file == NULL, "Sanity");
|
||||
// Archive the class stream data into the optional data section
|
||||
JvmtiCachedClassFileData *p;
|
||||
int len;
|
||||
const unsigned char *bytes;
|
||||
// event based tracing might set cached_class_file
|
||||
if ((bytes = result->get_cached_class_file_bytes()) != NULL) {
|
||||
len = result->get_cached_class_file_len();
|
||||
} else {
|
||||
len = stream->length();
|
||||
bytes = stream->buffer();
|
||||
}
|
||||
p = (JvmtiCachedClassFileData*)os::malloc(offset_of(JvmtiCachedClassFileData, data) + len, mtInternal);
|
||||
p->length = len;
|
||||
memcpy(p->data, bytes, len);
|
||||
result->set_archived_class_data(p);
|
||||
#endif // INCLUDE_JVMTI
|
||||
}
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
|
@ -80,7 +80,9 @@ class KlassFactory : AllStatic {
|
||||
InstanceKlass* ik,
|
||||
Symbol* class_name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain, TRAPS);
|
||||
Handle protection_domain,
|
||||
const ClassFileStream *cfs,
|
||||
TRAPS);
|
||||
};
|
||||
|
||||
#endif // SHARE_CLASSFILE_KLASSFACTORY_HPP
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "classfile/stackMapTable.hpp"
|
||||
#include "classfile/verifier.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/constantPool.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/fieldType.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
|
@ -436,18 +436,16 @@ Symbol* SymbolTable::lookup_only_unicode(const jchar* name, int utf16_length,
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolTable::add(ClassLoaderData* loader_data, const constantPoolHandle& cp,
|
||||
int names_count, const char** names, int* lengths,
|
||||
int* cp_indices, unsigned int* hashValues, TRAPS) {
|
||||
void SymbolTable::new_symbols(ClassLoaderData* loader_data, const constantPoolHandle& cp,
|
||||
int names_count, const char** names, int* lengths,
|
||||
int* cp_indices, unsigned int* hashValues, TRAPS) {
|
||||
bool c_heap = !loader_data->is_the_null_class_loader_data();
|
||||
for (int i = 0; i < names_count; i++) {
|
||||
const char *name = names[i];
|
||||
int len = lengths[i];
|
||||
unsigned int hash = hashValues[i];
|
||||
Symbol* sym = SymbolTable::the_table()->lookup_common(name, len, hash);
|
||||
if (sym == NULL) {
|
||||
sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, c_heap, CHECK);
|
||||
}
|
||||
assert(SymbolTable::the_table()->lookup_shared(name, len, hash) == NULL, "must have checked already");
|
||||
Symbol* sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, c_heap, CHECK);
|
||||
assert(sym->refcount() != 0, "lookup should have incremented the count");
|
||||
cp->symbol_at_put(cp_indices[i], sym);
|
||||
}
|
||||
|
@ -144,18 +144,11 @@ private:
|
||||
Symbol* do_add_if_needed(const char* name, int len, uintx hash, bool heap, TRAPS);
|
||||
|
||||
// Adding elements
|
||||
static void add(ClassLoaderData* loader_data,
|
||||
const constantPoolHandle& cp, int names_count,
|
||||
const char** names, int* lengths, int* cp_indices,
|
||||
unsigned int* hashValues, TRAPS);
|
||||
|
||||
static void new_symbols(ClassLoaderData* loader_data,
|
||||
const constantPoolHandle& cp, int names_count,
|
||||
const char** name, int* lengths,
|
||||
int* cp_indices, unsigned int* hashValues,
|
||||
TRAPS) {
|
||||
add(loader_data, cp, names_count, name, lengths, cp_indices, hashValues, THREAD);
|
||||
}
|
||||
TRAPS);
|
||||
|
||||
static Symbol* lookup_shared(const char* name, int len, unsigned int hash);
|
||||
Symbol* lookup_dynamic(const char* name, int len, unsigned int hash);
|
||||
|
@ -1174,7 +1174,7 @@ InstanceKlass* SystemDictionary::load_shared_boot_class(Symbol* class_name,
|
||||
TRAPS) {
|
||||
InstanceKlass* ik = SystemDictionaryShared::find_builtin_class(class_name);
|
||||
if (ik != NULL && ik->is_shared_boot_class()) {
|
||||
return load_shared_class(ik, Handle(), Handle(), THREAD);
|
||||
return load_shared_class(ik, Handle(), Handle(), NULL, THREAD);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -1274,7 +1274,9 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
|
||||
|
||||
InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
|
||||
Handle class_loader,
|
||||
Handle protection_domain, TRAPS) {
|
||||
Handle protection_domain,
|
||||
const ClassFileStream *cfs,
|
||||
TRAPS) {
|
||||
|
||||
if (ik != NULL) {
|
||||
Symbol* class_name = ik->name();
|
||||
@ -1321,7 +1323,7 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
|
||||
}
|
||||
|
||||
InstanceKlass* new_ik = KlassFactory::check_shared_class_file_load_hook(
|
||||
ik, class_name, class_loader, protection_domain, CHECK_NULL);
|
||||
ik, class_name, class_loader, protection_domain, cfs, CHECK_NULL);
|
||||
if (new_ik != NULL) {
|
||||
// The class is changed by CFLH. Return the new class. The shared class is
|
||||
// not used.
|
||||
|
@ -628,6 +628,7 @@ protected:
|
||||
static InstanceKlass* load_shared_class(InstanceKlass* ik,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
const ClassFileStream *cfs,
|
||||
TRAPS);
|
||||
static InstanceKlass* load_shared_boot_class(Symbol* class_name,
|
||||
TRAPS);
|
||||
|
@ -803,7 +803,7 @@ InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader(
|
||||
SystemDictionary::is_platform_class_loader(class_loader()))) {
|
||||
Handle protection_domain =
|
||||
SystemDictionaryShared::init_security_info(class_loader, ik, CHECK_NULL);
|
||||
return load_shared_class(ik, class_loader, protection_domain, THREAD);
|
||||
return load_shared_class(ik, class_loader, protection_domain, NULL, THREAD);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@ -873,13 +873,15 @@ InstanceKlass* SystemDictionaryShared::lookup_from_stream(Symbol* class_name,
|
||||
}
|
||||
|
||||
return acquire_class_for_current_thread(record->_klass, class_loader,
|
||||
protection_domain, THREAD);
|
||||
protection_domain, cfs,
|
||||
THREAD);
|
||||
}
|
||||
|
||||
InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread(
|
||||
InstanceKlass *ik,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
const ClassFileStream *cfs,
|
||||
TRAPS) {
|
||||
ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader());
|
||||
|
||||
@ -900,7 +902,8 @@ InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread(
|
||||
loader_data->add_class(ik);
|
||||
|
||||
// Load and check super/interfaces, restore unsharable info
|
||||
InstanceKlass* shared_klass = load_shared_class(ik, class_loader, protection_domain, THREAD);
|
||||
InstanceKlass* shared_klass = load_shared_class(ik, class_loader, protection_domain,
|
||||
cfs, THREAD);
|
||||
if (shared_klass == NULL || HAS_PENDING_EXCEPTION) {
|
||||
// TODO: clean up <ik> so it can be used again
|
||||
return NULL;
|
||||
|
@ -207,6 +207,7 @@ private:
|
||||
InstanceKlass *ik,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
const ClassFileStream* cfs,
|
||||
TRAPS);
|
||||
static DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k);
|
||||
static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2019, 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
|
||||
@ -2981,18 +2981,16 @@ void ClassVerifier::verify_anewarray(
|
||||
}
|
||||
// add one dimension to component
|
||||
length++;
|
||||
arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length);
|
||||
arr_sig_str[0] = '[';
|
||||
strncpy(&arr_sig_str[1], component_name, length - 1);
|
||||
arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length + 1);
|
||||
int n = os::snprintf(arr_sig_str, length + 1, "[%s", component_name);
|
||||
assert(n == length, "Unexpected number of characters in string");
|
||||
} else { // it's an object or interface
|
||||
const char* component_name = component_type.name()->as_utf8();
|
||||
// add one dimension to component with 'L' prepended and ';' postpended.
|
||||
length = (int)strlen(component_name) + 3;
|
||||
arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length);
|
||||
arr_sig_str[0] = '[';
|
||||
arr_sig_str[1] = 'L';
|
||||
strncpy(&arr_sig_str[2], component_name, length - 2);
|
||||
arr_sig_str[length - 1] = ';';
|
||||
arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length + 1);
|
||||
int n = os::snprintf(arr_sig_str, length + 1, "[L%s;", component_name);
|
||||
assert(n == length, "Unexpected number of characters in string");
|
||||
}
|
||||
Symbol* arr_sig = create_temporary_symbol(
|
||||
arr_sig_str, length, CHECK_VERIFY(this));
|
||||
|
@ -49,7 +49,7 @@ class Verifier : AllStatic {
|
||||
|
||||
// Return false if the class is loaded by the bootstrap loader,
|
||||
// or if defineClass was called requesting skipping verification
|
||||
// -Xverify:all/none override this value
|
||||
// -Xverify:all overrides this value
|
||||
static bool should_verify_for(oop class_loader, bool should_verify_class);
|
||||
|
||||
// Relax certain access checks to enable some broken 1.1 apps to run on 1.2.
|
||||
|
@ -321,16 +321,26 @@ void G1PLABAllocator::flush_and_retire_stats() {
|
||||
}
|
||||
}
|
||||
|
||||
void G1PLABAllocator::waste(size_t& wasted, size_t& undo_wasted) {
|
||||
wasted = 0;
|
||||
undo_wasted = 0;
|
||||
size_t G1PLABAllocator::waste() const {
|
||||
size_t result = 0;
|
||||
for (uint state = 0; state < InCSetState::Num; state++) {
|
||||
PLAB * const buf = _alloc_buffers[state];
|
||||
if (buf != NULL) {
|
||||
wasted += buf->waste();
|
||||
undo_wasted += buf->undo_waste();
|
||||
result += buf->waste();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t G1PLABAllocator::undo_waste() const {
|
||||
size_t result = 0;
|
||||
for (uint state = 0; state < InCSetState::Num; state++) {
|
||||
PLAB * const buf = _alloc_buffers[state];
|
||||
if (buf != NULL) {
|
||||
result += buf->undo_waste();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool G1ArchiveAllocator::_archive_check_enabled = false;
|
||||
|
@ -155,7 +155,8 @@ private:
|
||||
public:
|
||||
G1PLABAllocator(G1Allocator* allocator);
|
||||
|
||||
void waste(size_t& wasted, size_t& undo_wasted);
|
||||
size_t waste() const;
|
||||
size_t undo_waste() const;
|
||||
|
||||
// Allocate word_sz words in dest, either directly into the regions or by
|
||||
// allocating a new PLAB. Returns the address of the allocated memory, NULL if
|
||||
|
@ -3282,10 +3282,6 @@ public:
|
||||
|
||||
_root_processor->evacuate_roots(pss, worker_id);
|
||||
|
||||
// We pass a weak code blobs closure to the remembered set scanning because we want to avoid
|
||||
// treating the nmethods visited to act as roots for concurrent marking.
|
||||
// We only want to make sure that the oops in the nmethods are adjusted with regard to the
|
||||
// objects copied by the current evacuation.
|
||||
_g1h->g1_rem_set()->oops_into_collection_set_do(pss, worker_id);
|
||||
|
||||
double strong_roots_sec = os::elapsedTime() - start_strong_roots_sec;
|
||||
@ -3303,27 +3299,22 @@ public:
|
||||
|
||||
G1GCPhaseTimes* p = _g1h->g1_policy()->phase_times();
|
||||
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_id, elapsed_sec - term_sec);
|
||||
|
||||
p->record_or_add_thread_work_item(G1GCPhaseTimes::ObjCopy,
|
||||
worker_id,
|
||||
pss->lab_waste_words() * HeapWordSize,
|
||||
G1GCPhaseTimes::ObjCopyLABWaste);
|
||||
p->record_or_add_thread_work_item(G1GCPhaseTimes::ObjCopy,
|
||||
worker_id,
|
||||
pss->lab_undo_waste_words() * HeapWordSize,
|
||||
G1GCPhaseTimes::ObjCopyLABUndoWaste);
|
||||
|
||||
p->record_time_secs(G1GCPhaseTimes::Termination, worker_id, term_sec);
|
||||
p->record_thread_work_item(G1GCPhaseTimes::Termination, worker_id, evac_term_attempts);
|
||||
}
|
||||
|
||||
assert(pss->queue_is_empty(), "should be empty");
|
||||
|
||||
if (log_is_enabled(Debug, gc, task, stats)) {
|
||||
MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
|
||||
size_t lab_waste;
|
||||
size_t lab_undo_waste;
|
||||
pss->waste(lab_waste, lab_undo_waste);
|
||||
_g1h->print_termination_stats(worker_id,
|
||||
(os::elapsedTime() - start_sec) * 1000.0, /* elapsed time */
|
||||
strong_roots_sec * 1000.0, /* strong roots time */
|
||||
term_sec * 1000.0, /* evac term time */
|
||||
evac_term_attempts, /* evac term attempts */
|
||||
lab_waste, /* alloc buffer waste */
|
||||
lab_undo_waste /* undo waste */
|
||||
);
|
||||
}
|
||||
|
||||
// Close the inner scope so that the ResourceMark and HandleMark
|
||||
// destructors are executed here and are included as part of the
|
||||
// "GC Worker Time".
|
||||
@ -3332,31 +3323,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void G1CollectedHeap::print_termination_stats_hdr() {
|
||||
log_debug(gc, task, stats)("GC Termination Stats");
|
||||
log_debug(gc, task, stats)(" elapsed --strong roots-- -------termination------- ------waste (KiB)------");
|
||||
log_debug(gc, task, stats)("thr ms ms %% ms %% attempts total alloc undo");
|
||||
log_debug(gc, task, stats)("--- --------- --------- ------ --------- ------ -------- ------- ------- -------");
|
||||
}
|
||||
|
||||
void G1CollectedHeap::print_termination_stats(uint worker_id,
|
||||
double elapsed_ms,
|
||||
double strong_roots_ms,
|
||||
double term_ms,
|
||||
size_t term_attempts,
|
||||
size_t alloc_buffer_waste,
|
||||
size_t undo_waste) const {
|
||||
log_debug(gc, task, stats)
|
||||
("%3d %9.2f %9.2f %6.2f "
|
||||
"%9.2f %6.2f " SIZE_FORMAT_W(8) " "
|
||||
SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7),
|
||||
worker_id, elapsed_ms, strong_roots_ms, strong_roots_ms * 100 / elapsed_ms,
|
||||
term_ms, term_ms * 100 / elapsed_ms, term_attempts,
|
||||
(alloc_buffer_waste + undo_waste) * HeapWordSize / K,
|
||||
alloc_buffer_waste * HeapWordSize / K,
|
||||
undo_waste * HeapWordSize / K);
|
||||
}
|
||||
|
||||
void G1CollectedHeap::complete_cleaning(BoolObjectClosure* is_alive,
|
||||
bool class_unloading_occurred) {
|
||||
uint num_workers = workers()->active_workers();
|
||||
@ -3767,8 +3733,6 @@ void G1CollectedHeap::evacuate_collection_set(G1ParScanThreadStateSet* per_threa
|
||||
G1RootProcessor root_processor(this, n_workers);
|
||||
G1ParTask g1_par_task(this, per_thread_states, _task_queues, &root_processor, n_workers);
|
||||
|
||||
print_termination_stats_hdr();
|
||||
|
||||
workers()->run_task(&g1_par_task);
|
||||
end_par_time_sec = os::elapsedTime();
|
||||
|
||||
|
@ -738,16 +738,6 @@ private:
|
||||
void pre_evacuate_collection_set();
|
||||
void post_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* pss);
|
||||
|
||||
// Print the header for the per-thread termination statistics.
|
||||
static void print_termination_stats_hdr();
|
||||
// Print actual per-thread termination statistics.
|
||||
void print_termination_stats(uint worker_id,
|
||||
double elapsed_ms,
|
||||
double strong_roots_ms,
|
||||
double term_ms,
|
||||
size_t term_attempts,
|
||||
size_t alloc_buffer_waste,
|
||||
size_t undo_waste) const;
|
||||
// Update object copying statistics.
|
||||
void record_obj_copy_mem_stats();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, 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
|
||||
@ -71,26 +71,19 @@ template <class T> void G1VerifyOopClosure::do_oop_work(T* p) {
|
||||
}
|
||||
if (!_g1h->is_in_closed_subset(obj)) {
|
||||
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
|
||||
yy.print_cr("Field " PTR_FORMAT
|
||||
" of live obj " PTR_FORMAT " in region "
|
||||
"[" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(p), p2i(_containing_obj),
|
||||
p2i(from->bottom()), p2i(from->end()));
|
||||
yy.print_cr("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region " HR_FORMAT,
|
||||
p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from));
|
||||
print_object(&yy, _containing_obj);
|
||||
yy.print_cr("points to obj " PTR_FORMAT " not in the heap",
|
||||
p2i(obj));
|
||||
p2i(obj));
|
||||
} else {
|
||||
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
|
||||
HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj);
|
||||
yy.print_cr("Field " PTR_FORMAT
|
||||
" of live obj " PTR_FORMAT " in region "
|
||||
"[" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(p), p2i(_containing_obj),
|
||||
p2i(from->bottom()), p2i(from->end()));
|
||||
yy.print_cr("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region " HR_FORMAT,
|
||||
p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from));
|
||||
print_object(&yy, _containing_obj);
|
||||
yy.print_cr("points to dead obj " PTR_FORMAT " in region "
|
||||
"[" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(obj), p2i(to->bottom()), p2i(to->end()));
|
||||
yy.print_cr("points to dead obj " PTR_FORMAT " in region " HR_FORMAT,
|
||||
p2i(obj), HR_FORMAT_PARAMS(to));
|
||||
print_object(&yy, obj);
|
||||
}
|
||||
yy.print_cr("----------");
|
||||
|
@ -60,6 +60,9 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
|
||||
_gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray<double>(max_gc_threads, "SystemDictionary Roots (ms):");
|
||||
_gc_par_phases[CLDGRoots] = new WorkerDataArray<double>(max_gc_threads, "CLDG Roots (ms):");
|
||||
_gc_par_phases[JVMTIRoots] = new WorkerDataArray<double>(max_gc_threads, "JVMTI Roots (ms):");
|
||||
#if INCLUDE_AOT
|
||||
_gc_par_phases[AOTCodeRoots] = new WorkerDataArray<double>(max_gc_threads, "AOT Root Scan (ms):");
|
||||
#endif
|
||||
_gc_par_phases[CMRefRoots] = new WorkerDataArray<double>(max_gc_threads, "CM RefProcessor Roots (ms):");
|
||||
_gc_par_phases[WaitForStrongCLD] = new WorkerDataArray<double>(max_gc_threads, "Wait For Strong CLD (ms):");
|
||||
_gc_par_phases[WeakCLDRoots] = new WorkerDataArray<double>(max_gc_threads, "Weak CLD Roots (ms):");
|
||||
@ -74,9 +77,6 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
|
||||
_gc_par_phases[ScanRS] = new WorkerDataArray<double>(max_gc_threads, "Scan RS (ms):");
|
||||
_gc_par_phases[OptScanRS] = new WorkerDataArray<double>(max_gc_threads, "Optional Scan RS (ms):");
|
||||
_gc_par_phases[CodeRoots] = new WorkerDataArray<double>(max_gc_threads, "Code Root Scanning (ms):");
|
||||
#if INCLUDE_AOT
|
||||
_gc_par_phases[AOTCodeRoots] = new WorkerDataArray<double>(max_gc_threads, "AOT Root Scanning (ms):");
|
||||
#endif
|
||||
_gc_par_phases[ObjCopy] = new WorkerDataArray<double>(max_gc_threads, "Object Copy (ms):");
|
||||
_gc_par_phases[OptObjCopy] = new WorkerDataArray<double>(max_gc_threads, "Optional Object Copy (ms):");
|
||||
_gc_par_phases[Termination] = new WorkerDataArray<double>(max_gc_threads, "Termination (ms):");
|
||||
@ -107,6 +107,11 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
|
||||
_update_rs_skipped_cards = new WorkerDataArray<size_t>(max_gc_threads, "Skipped Cards:");
|
||||
_gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_skipped_cards, UpdateRSSkippedCards);
|
||||
|
||||
_obj_copy_lab_waste = new WorkerDataArray<size_t>(max_gc_threads, "LAB Waste");
|
||||
_gc_par_phases[ObjCopy]->link_thread_work_items(_obj_copy_lab_waste, ObjCopyLABWaste);
|
||||
_obj_copy_lab_undo_waste = new WorkerDataArray<size_t>(max_gc_threads, "LAB Undo Waste");
|
||||
_gc_par_phases[ObjCopy]->link_thread_work_items(_obj_copy_lab_undo_waste, ObjCopyLABUndoWaste);
|
||||
|
||||
_termination_attempts = new WorkerDataArray<size_t>(max_gc_threads, "Termination Attempts:");
|
||||
_gc_par_phases[Termination]->link_thread_work_items(_termination_attempts);
|
||||
|
||||
@ -383,15 +388,12 @@ double G1GCPhaseTimes::print_evacuate_collection_set() const {
|
||||
for (int i = ThreadRoots; i <= SATBFiltering; i++) {
|
||||
trace_phase(_gc_par_phases[i]);
|
||||
}
|
||||
debug_phase(_gc_par_phases[UpdateRS]);
|
||||
if (G1HotCardCache::default_use_cache()) {
|
||||
trace_phase(_gc_par_phases[ScanHCC]);
|
||||
debug_phase(_gc_par_phases[ScanHCC]);
|
||||
}
|
||||
debug_phase(_gc_par_phases[UpdateRS]);
|
||||
debug_phase(_gc_par_phases[ScanRS]);
|
||||
debug_phase(_gc_par_phases[CodeRoots]);
|
||||
#if INCLUDE_AOT
|
||||
debug_phase(_gc_par_phases[AOTCodeRoots]);
|
||||
#endif
|
||||
debug_phase(_gc_par_phases[ObjCopy]);
|
||||
debug_phase(_gc_par_phases[Termination]);
|
||||
debug_phase(_gc_par_phases[Other]);
|
||||
@ -503,6 +505,9 @@ const char* G1GCPhaseTimes::phase_name(GCParPhases phase) {
|
||||
"SystemDictionaryRoots",
|
||||
"CLDGRoots",
|
||||
"JVMTIRoots",
|
||||
#if INCLUDE_AOT
|
||||
"AOTCodeRoots",
|
||||
#endif
|
||||
"CMRefRoots",
|
||||
"WaitForStrongCLD",
|
||||
"WeakCLDRoots",
|
||||
@ -512,9 +517,6 @@ const char* G1GCPhaseTimes::phase_name(GCParPhases phase) {
|
||||
"ScanRS",
|
||||
"OptScanRS",
|
||||
"CodeRoots",
|
||||
#if INCLUDE_AOT
|
||||
"AOTCodeRoots",
|
||||
#endif
|
||||
"ObjCopy",
|
||||
"OptObjCopy",
|
||||
"Termination",
|
||||
|
@ -55,6 +55,9 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
SystemDictionaryRoots,
|
||||
CLDGRoots,
|
||||
JVMTIRoots,
|
||||
#if INCLUDE_AOT
|
||||
AOTCodeRoots,
|
||||
#endif
|
||||
CMRefRoots,
|
||||
WaitForStrongCLD,
|
||||
WeakCLDRoots,
|
||||
@ -64,9 +67,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
ScanRS,
|
||||
OptScanRS,
|
||||
CodeRoots,
|
||||
#if INCLUDE_AOT
|
||||
AOTCodeRoots,
|
||||
#endif
|
||||
ObjCopy,
|
||||
OptObjCopy,
|
||||
Termination,
|
||||
@ -93,6 +93,11 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
UpdateRSSkippedCards
|
||||
};
|
||||
|
||||
enum GCObjCopyWorkItems {
|
||||
ObjCopyLABWaste,
|
||||
ObjCopyLABUndoWaste
|
||||
};
|
||||
|
||||
enum GCOptCSetWorkItems {
|
||||
OptCSetScannedCards,
|
||||
OptCSetClaimedCards,
|
||||
@ -114,6 +119,9 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
WorkerDataArray<size_t>* _scan_rs_claimed_cards;
|
||||
WorkerDataArray<size_t>* _scan_rs_skipped_cards;
|
||||
|
||||
WorkerDataArray<size_t>* _obj_copy_lab_waste;
|
||||
WorkerDataArray<size_t>* _obj_copy_lab_undo_waste;
|
||||
|
||||
WorkerDataArray<size_t>* _opt_cset_scanned_cards;
|
||||
WorkerDataArray<size_t>* _opt_cset_claimed_cards;
|
||||
WorkerDataArray<size_t>* _opt_cset_skipped_cards;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2019, 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
|
||||
@ -106,8 +106,12 @@ G1ParScanThreadState::~G1ParScanThreadState() {
|
||||
delete[] _oops_into_optional_regions;
|
||||
}
|
||||
|
||||
void G1ParScanThreadState::waste(size_t& wasted, size_t& undo_wasted) {
|
||||
_plab_allocator->waste(wasted, undo_wasted);
|
||||
size_t G1ParScanThreadState::lab_waste_words() const {
|
||||
return _plab_allocator->waste();
|
||||
}
|
||||
|
||||
size_t G1ParScanThreadState::lab_undo_waste_words() const {
|
||||
return _plab_allocator->undo_waste();
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
|
@ -127,9 +127,8 @@ public:
|
||||
G1EvacuationRootClosures* closures() { return _closures; }
|
||||
uint worker_id() { return _worker_id; }
|
||||
|
||||
// Returns the current amount of waste due to alignment or not being able to fit
|
||||
// objects within LABs and the undo waste.
|
||||
virtual void waste(size_t& wasted, size_t& undo_wasted);
|
||||
size_t lab_waste_words() const;
|
||||
size_t lab_undo_waste_words() const;
|
||||
|
||||
size_t* surviving_young_words() {
|
||||
// We add one to hide entry 0 which accumulates surviving words for
|
||||
|
@ -409,6 +409,10 @@ void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) {
|
||||
|
||||
void G1ScanRSForRegionClosure::scan_strong_code_roots(HeapRegion* r) {
|
||||
EventGCPhaseParallel event;
|
||||
// We pass a weak code blobs closure to the remembered set scanning because we want to avoid
|
||||
// treating the nmethods visited to act as roots for concurrent marking.
|
||||
// We only want to make sure that the oops in the nmethods are adjusted with regard to the
|
||||
// objects copied by the current evacuation.
|
||||
r->strong_code_roots_do(_pss->closures()->weak_codeblobs());
|
||||
event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2019, 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
|
||||
@ -336,8 +336,8 @@ class VerifyStrongCodeRootOopClosure: public OopClosure {
|
||||
// Object is in the region. Check that its less than top
|
||||
if (_hr->top() <= (HeapWord*)obj) {
|
||||
// Object is above top
|
||||
log_error(gc, verify)("Object " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ") is above top " PTR_FORMAT,
|
||||
p2i(obj), p2i(_hr->bottom()), p2i(_hr->end()), p2i(_hr->top()));
|
||||
log_error(gc, verify)("Object " PTR_FORMAT " in region " HR_FORMAT " is above top ",
|
||||
p2i(obj), HR_FORMAT_PARAMS(_hr));
|
||||
_failures = true;
|
||||
return;
|
||||
}
|
||||
@ -415,8 +415,8 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const
|
||||
// on its strong code root list
|
||||
if (is_empty()) {
|
||||
if (strong_code_roots_length > 0) {
|
||||
log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] is empty but has " SIZE_FORMAT " code root entries",
|
||||
p2i(bottom()), p2i(end()), strong_code_roots_length);
|
||||
log_error(gc, verify)("region " HR_FORMAT " is empty but has " SIZE_FORMAT " code root entries",
|
||||
HR_FORMAT_PARAMS(this), strong_code_roots_length);
|
||||
*failures = true;
|
||||
}
|
||||
return;
|
||||
@ -524,21 +524,22 @@ public:
|
||||
ResourceMark rm;
|
||||
if (!_g1h->is_in_closed_subset(obj)) {
|
||||
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
|
||||
log.error("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end()));
|
||||
log.error("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region " HR_FORMAT,
|
||||
p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from));
|
||||
LogStream ls(log.error());
|
||||
print_object(&ls, _containing_obj);
|
||||
HeapRegion* const to = _g1h->heap_region_containing(obj);
|
||||
log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT " remset %s", p2i(obj), HR_FORMAT_PARAMS(to), to->rem_set()->get_state_str());
|
||||
log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT " remset %s",
|
||||
p2i(obj), HR_FORMAT_PARAMS(to), to->rem_set()->get_state_str());
|
||||
} else {
|
||||
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
|
||||
HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj);
|
||||
log.error("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end()));
|
||||
log.error("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region " HR_FORMAT,
|
||||
p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from));
|
||||
LogStream ls(log.error());
|
||||
print_object(&ls, _containing_obj);
|
||||
log.error("points to dead obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(obj), p2i(to->bottom()), p2i(to->end()));
|
||||
log.error("points to dead obj " PTR_FORMAT " in region " HR_FORMAT,
|
||||
p2i(obj), HR_FORMAT_PARAMS(to));
|
||||
print_object(&ls, obj);
|
||||
}
|
||||
log.error("----------");
|
||||
@ -593,12 +594,13 @@ public:
|
||||
log.error("----------");
|
||||
}
|
||||
log.error("Missing rem set entry:");
|
||||
log.error("Field " PTR_FORMAT " of obj " PTR_FORMAT ", in region " HR_FORMAT,
|
||||
p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from));
|
||||
log.error("Field " PTR_FORMAT " of obj " PTR_FORMAT " in region " HR_FORMAT,
|
||||
p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from));
|
||||
ResourceMark rm;
|
||||
LogStream ls(log.error());
|
||||
_containing_obj->print_on(&ls);
|
||||
log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT " remset %s", p2i(obj), HR_FORMAT_PARAMS(to), to->rem_set()->get_state_str());
|
||||
log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT " remset %s",
|
||||
p2i(obj), HR_FORMAT_PARAMS(to), to->rem_set()->get_state_str());
|
||||
if (oopDesc::is_oop(obj)) {
|
||||
obj->print_on(&ls);
|
||||
}
|
||||
|
@ -335,7 +335,7 @@ void ShenandoahBarrierSet::enqueue(oop obj) {
|
||||
// Filter marked objects before hitting the SATB queues. The same predicate would
|
||||
// be used by SATBMQ::filter to eliminate already marked objects downstream, but
|
||||
// filtering here helps to avoid wasteful SATB queueing work to begin with.
|
||||
if (!_heap->requires_marking(obj)) return;
|
||||
if (!_heap->requires_marking<false>(obj)) return;
|
||||
|
||||
Thread* thr = Thread::current();
|
||||
if (thr->is_Java_thread()) {
|
||||
|
@ -2639,6 +2639,10 @@ GrowableArray<MemoryPool*> ShenandoahHeap::memory_pools() {
|
||||
return memory_pools;
|
||||
}
|
||||
|
||||
MemoryUsage ShenandoahHeap::memory_usage() {
|
||||
return _memory_pool->get_memory_usage();
|
||||
}
|
||||
|
||||
void ShenandoahHeap::enter_evacuation() {
|
||||
_oom_evac_handler.enter_evacuation();
|
||||
}
|
||||
|
@ -511,6 +511,7 @@ public:
|
||||
|
||||
GrowableArray<GCMemoryManager*> memory_managers();
|
||||
GrowableArray<MemoryPool*> memory_pools();
|
||||
MemoryUsage memory_usage();
|
||||
GCTracer* tracer();
|
||||
GCTimer* gc_timer() const;
|
||||
CollectorPolicy* collector_policy() const;
|
||||
@ -676,6 +677,7 @@ public:
|
||||
void reset_mark_bitmap();
|
||||
|
||||
// SATB barriers hooks
|
||||
template<bool RESOLVE>
|
||||
inline bool requires_marking(const void* entry) const;
|
||||
void force_satb_flush_all_threads();
|
||||
|
||||
|
@ -316,8 +316,13 @@ inline oop ShenandoahHeap::evacuate_object(oop p, Thread* thread) {
|
||||
}
|
||||
}
|
||||
|
||||
template<bool RESOLVE>
|
||||
inline bool ShenandoahHeap::requires_marking(const void* entry) const {
|
||||
return !_marking_context->is_marked(oop(entry));
|
||||
oop obj = oop(entry);
|
||||
if (RESOLVE) {
|
||||
obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
|
||||
}
|
||||
return !_marking_context->is_marked(obj);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
ShenandoahMemoryPool::ShenandoahMemoryPool(ShenandoahHeap* heap) :
|
||||
CollectedMemoryPool("Shenandoah",
|
||||
heap->capacity(),
|
||||
heap->initial_capacity(),
|
||||
heap->max_capacity(),
|
||||
true /* support_usage_threshold */),
|
||||
_heap(heap) {}
|
||||
@ -37,9 +37,15 @@ MemoryUsage ShenandoahMemoryPool::get_memory_usage() {
|
||||
size_t used = used_in_bytes();
|
||||
size_t committed = _heap->committed();
|
||||
|
||||
// These asserts can never fail: max is stable, and all updates to other values never overflow max.
|
||||
assert(initial <= max, "initial: " SIZE_FORMAT ", max: " SIZE_FORMAT, initial, max);
|
||||
assert(used <= max, "used: " SIZE_FORMAT ", max: " SIZE_FORMAT, used, max);
|
||||
assert(committed <= max, "committed: " SIZE_FORMAT ", max: " SIZE_FORMAT, committed, max);
|
||||
|
||||
// Committed and used are updated concurrently and independently. They can momentarily break
|
||||
// the assert below, which would also fail in downstream code. To avoid that, adjust values
|
||||
// to make sense under the race. See JDK-8207200.
|
||||
committed = MAX2(used, committed);
|
||||
assert(used <= committed, "used: " SIZE_FORMAT ", committed: " SIZE_FORMAT, used, committed);
|
||||
|
||||
return MemoryUsage(initial, used, committed, max);
|
||||
|
@ -49,12 +49,9 @@ SATBMarkQueue& ShenandoahSATBMarkQueueSet::satb_queue_for_thread(JavaThread* con
|
||||
return ShenandoahThreadLocalData::satb_mark_queue(t);
|
||||
}
|
||||
|
||||
static inline bool discard_entry(const void* entry, ShenandoahHeap* heap) {
|
||||
return !heap->requires_marking(entry);
|
||||
}
|
||||
|
||||
template <bool RESOLVE>
|
||||
class ShenandoahSATBMarkQueueFilterFn {
|
||||
ShenandoahHeap* _heap;
|
||||
ShenandoahHeap* const _heap;
|
||||
|
||||
public:
|
||||
ShenandoahSATBMarkQueueFilterFn(ShenandoahHeap* heap) : _heap(heap) {}
|
||||
@ -62,13 +59,17 @@ public:
|
||||
// Return true if entry should be filtered out (removed), false if
|
||||
// it should be retained.
|
||||
bool operator()(const void* entry) const {
|
||||
return discard_entry(entry, _heap);
|
||||
return !_heap->requires_marking<RESOLVE>(entry);
|
||||
}
|
||||
};
|
||||
|
||||
void ShenandoahSATBMarkQueueSet::filter(SATBMarkQueue* queue) {
|
||||
assert(_heap != NULL, "SATB queue set not initialized");
|
||||
apply_filter(ShenandoahSATBMarkQueueFilterFn(_heap), queue);
|
||||
if (_heap->has_forwarded_objects()) {
|
||||
apply_filter(ShenandoahSATBMarkQueueFilterFn<true>(_heap), queue);
|
||||
} else {
|
||||
apply_filter(ShenandoahSATBMarkQueueFilterFn<false>(_heap), queue);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShenandoahSATBMarkQueue::should_enqueue_buffer() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -26,6 +26,7 @@
|
||||
|
||||
ZGlobalsForVMStructs::ZGlobalsForVMStructs() :
|
||||
_ZGlobalPhase(&ZGlobalPhase),
|
||||
_ZGlobalSeqNum(&ZGlobalSeqNum),
|
||||
_ZAddressGoodMask(&ZAddressGoodMask),
|
||||
_ZAddressBadMask(&ZAddressBadMask),
|
||||
_ZAddressWeakBadMask(&ZAddressWeakBadMask),
|
||||
|
@ -42,6 +42,8 @@ public:
|
||||
|
||||
uint32_t* _ZGlobalPhase;
|
||||
|
||||
uint32_t* _ZGlobalSeqNum;
|
||||
|
||||
uintptr_t* _ZAddressGoodMask;
|
||||
uintptr_t* _ZAddressBadMask;
|
||||
uintptr_t* _ZAddressWeakBadMask;
|
||||
@ -55,6 +57,7 @@ typedef ZAddressRangeMap<ZPageTableEntry, ZPageSizeMinShift> ZAddressRangeMapFor
|
||||
#define VM_STRUCTS_ZGC(nonstatic_field, volatile_nonstatic_field, static_field) \
|
||||
static_field(ZGlobalsForVMStructs, _instance_p, ZGlobalsForVMStructs*) \
|
||||
nonstatic_field(ZGlobalsForVMStructs, _ZGlobalPhase, uint32_t*) \
|
||||
nonstatic_field(ZGlobalsForVMStructs, _ZGlobalSeqNum, uint32_t*) \
|
||||
nonstatic_field(ZGlobalsForVMStructs, _ZAddressGoodMask, uintptr_t*) \
|
||||
nonstatic_field(ZGlobalsForVMStructs, _ZAddressBadMask, uintptr_t*) \
|
||||
nonstatic_field(ZGlobalsForVMStructs, _ZAddressWeakBadMask, uintptr_t*) \
|
||||
@ -67,7 +70,10 @@ typedef ZAddressRangeMap<ZPageTableEntry, ZPageSizeMinShift> ZAddressRangeMapFor
|
||||
nonstatic_field(ZHeap, _pagetable, ZPageTable) \
|
||||
\
|
||||
nonstatic_field(ZPage, _type, const uint8_t) \
|
||||
nonstatic_field(ZPage, _seqnum, uint32_t) \
|
||||
nonstatic_field(ZPage, _virtual, const ZVirtualMemory) \
|
||||
volatile_nonstatic_field(ZPage, _top, uintptr_t) \
|
||||
volatile_nonstatic_field(ZPage, _refcount, uint32_t) \
|
||||
nonstatic_field(ZPage, _forwarding, ZForwardingTable) \
|
||||
\
|
||||
nonstatic_field(ZPageAllocator, _physical, ZPhysicalMemoryManager) \
|
||||
@ -101,6 +107,7 @@ typedef ZAddressRangeMap<ZPageTableEntry, ZPageSizeMinShift> ZAddressRangeMapFor
|
||||
declare_constant(ZAddressOffsetShift) \
|
||||
declare_constant(ZAddressOffsetBits) \
|
||||
declare_constant(ZAddressOffsetMask) \
|
||||
declare_constant(ZAddressOffsetMax) \
|
||||
declare_constant(ZAddressSpaceStart)
|
||||
|
||||
#define VM_TYPES_ZGC(declare_type, declare_toplevel_type, declare_integer_type) \
|
||||
|
@ -27,12 +27,12 @@
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zLock.inline.hpp"
|
||||
#include "gc/z/zOopClosures.hpp"
|
||||
#include "gc/z/zNMethodTable.hpp"
|
||||
#include "gc/z/zNMethod.hpp"
|
||||
#include "gc/z/zThreadLocalData.hpp"
|
||||
#include "logging/log.hpp"
|
||||
|
||||
bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) {
|
||||
ZLocker<ZReentrantLock> locker(ZNMethodTable::lock_for_nmethod(nm));
|
||||
ZLocker<ZReentrantLock> locker(ZNMethod::lock_for_nmethod(nm));
|
||||
log_trace(nmethod, barrier)("Entered critical zone for %p", nm);
|
||||
|
||||
if (!is_armed(nm)) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,7 +27,7 @@
|
||||
#include "gc/z/zCollectedHeap.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zHeap.inline.hpp"
|
||||
#include "gc/z/zNMethodTable.hpp"
|
||||
#include "gc/z/zNMethod.hpp"
|
||||
#include "gc/z/zServiceability.hpp"
|
||||
#include "gc/z/zStat.hpp"
|
||||
#include "gc/z/zUtils.inline.hpp"
|
||||
@ -118,10 +118,6 @@ bool ZCollectedHeap::is_in_closed_subset(const void* p) const {
|
||||
return is_in(p);
|
||||
}
|
||||
|
||||
void ZCollectedHeap::fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap) {
|
||||
// Does nothing, not a parsable heap
|
||||
}
|
||||
|
||||
HeapWord* ZCollectedHeap::allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) {
|
||||
const size_t size_in_bytes = ZUtils::words_to_bytes(align_object_size(requested_size));
|
||||
const uintptr_t addr = _heap.alloc_tlab(size_in_bytes);
|
||||
@ -259,11 +255,11 @@ bool ZCollectedHeap::block_is_obj(const HeapWord* addr) const {
|
||||
}
|
||||
|
||||
void ZCollectedHeap::register_nmethod(nmethod* nm) {
|
||||
ZNMethodTable::register_nmethod(nm);
|
||||
ZNMethod::register_nmethod(nm);
|
||||
}
|
||||
|
||||
void ZCollectedHeap::unregister_nmethod(nmethod* nm) {
|
||||
ZNMethodTable::unregister_nmethod(nm);
|
||||
ZNMethod::unregister_nmethod(nm);
|
||||
}
|
||||
|
||||
void ZCollectedHeap::verify_nmethod(nmethod* nm) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, 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
|
||||
@ -75,8 +75,6 @@ public:
|
||||
virtual bool is_in(const void* p) const;
|
||||
virtual bool is_in_closed_subset(const void* p) const;
|
||||
|
||||
virtual void fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap);
|
||||
|
||||
virtual HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded);
|
||||
virtual MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data,
|
||||
size_t size,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,7 +30,7 @@
|
||||
#include "gc/z/zLargePages.hpp"
|
||||
#include "gc/z/zNUMA.hpp"
|
||||
#include "gc/z/zStat.hpp"
|
||||
#include "gc/z/zStatTLAB.hpp"
|
||||
#include "gc/z/zThreadLocalAllocBuffer.hpp"
|
||||
#include "gc/z/zTracer.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
@ -46,7 +46,7 @@ ZInitialize::ZInitialize(ZBarrierSet* barrier_set) {
|
||||
ZNUMA::initialize();
|
||||
ZCPU::initialize();
|
||||
ZStatValue::initialize();
|
||||
ZStatTLAB::initialize();
|
||||
ZThreadLocalAllocBuffer::initialize();
|
||||
ZTracer::initialize();
|
||||
ZLargePages::initialize();
|
||||
ZBarrierSet::set_barrier_set(barrier_set);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,9 +32,9 @@
|
||||
#include "gc/z/zPageTable.inline.hpp"
|
||||
#include "gc/z/zRootsIterator.hpp"
|
||||
#include "gc/z/zStat.hpp"
|
||||
#include "gc/z/zStatTLAB.hpp"
|
||||
#include "gc/z/zTask.hpp"
|
||||
#include "gc/z/zThread.hpp"
|
||||
#include "gc/z/zThreadLocalAllocBuffer.hpp"
|
||||
#include "gc/z/zUtils.inline.hpp"
|
||||
#include "gc/z/zWorkers.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
@ -121,24 +121,19 @@ void ZMark::prepare_mark() {
|
||||
class ZMarkRootsIteratorClosure : public ZRootsIteratorClosure {
|
||||
public:
|
||||
ZMarkRootsIteratorClosure() {
|
||||
ZStatTLAB::reset();
|
||||
ZThreadLocalAllocBuffer::reset_statistics();
|
||||
}
|
||||
|
||||
~ZMarkRootsIteratorClosure() {
|
||||
ZStatTLAB::publish();
|
||||
ZThreadLocalAllocBuffer::publish_statistics();
|
||||
}
|
||||
|
||||
virtual void do_thread(Thread* thread) {
|
||||
ZRootsIteratorClosure::do_thread(thread);
|
||||
|
||||
// Update thread local address bad mask
|
||||
ZThreadLocalData::set_address_bad_mask(thread, ZAddressBadMask);
|
||||
|
||||
// Retire TLAB
|
||||
if (UseTLAB && thread->is_Java_thread()) {
|
||||
thread->tlab().retire(ZStatTLAB::get());
|
||||
thread->tlab().resize();
|
||||
}
|
||||
ZThreadLocalAllocBuffer::retire(thread);
|
||||
}
|
||||
|
||||
virtual void do_oop(oop* p) {
|
||||
|
394
src/hotspot/share/gc/z/zNMethod.cpp
Normal file
394
src/hotspot/share/gc/z/zNMethod.cpp
Normal file
@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "code/relocInfo.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "code/icBuffer.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zLock.inline.hpp"
|
||||
#include "gc/z/zNMethod.hpp"
|
||||
#include "gc/z/zNMethodData.hpp"
|
||||
#include "gc/z/zNMethodTable.hpp"
|
||||
#include "gc/z/zOopClosures.inline.hpp"
|
||||
#include "gc/z/zTask.hpp"
|
||||
#include "gc/z/zWorkers.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
static ZNMethodData* gc_data(const nmethod* nm) {
|
||||
return nm->gc_data<ZNMethodData>();
|
||||
}
|
||||
|
||||
static void set_gc_data(nmethod* nm, ZNMethodData* data) {
|
||||
return nm->set_gc_data<ZNMethodData>(data);
|
||||
}
|
||||
|
||||
void ZNMethod::attach_gc_data(nmethod* nm) {
|
||||
GrowableArray<oop*> immediate_oops;
|
||||
bool non_immediate_oops = false;
|
||||
|
||||
// Find all oops relocations
|
||||
RelocIterator iter(nm);
|
||||
while (iter.next()) {
|
||||
if (iter.type() != relocInfo::oop_type) {
|
||||
// Not an oop
|
||||
continue;
|
||||
}
|
||||
|
||||
oop_Relocation* r = iter.oop_reloc();
|
||||
|
||||
if (!r->oop_is_immediate()) {
|
||||
// Non-immediate oop found
|
||||
non_immediate_oops = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r->oop_value() != NULL) {
|
||||
// Non-NULL immediate oop found. NULL oops can safely be
|
||||
// ignored since the method will be re-registered if they
|
||||
// are later patched to be non-NULL.
|
||||
immediate_oops.push(r->oop_addr());
|
||||
}
|
||||
}
|
||||
|
||||
// Attach GC data to nmethod
|
||||
ZNMethodData* data = gc_data(nm);
|
||||
if (data == NULL) {
|
||||
data = ZNMethodData::create(nm);
|
||||
set_gc_data(nm, data);
|
||||
}
|
||||
|
||||
// Attach oops in GC data
|
||||
ZNMethodDataOops* const new_oops = ZNMethodDataOops::create(immediate_oops, non_immediate_oops);
|
||||
ZNMethodDataOops* const old_oops = data->swap_oops(new_oops);
|
||||
ZNMethodDataOops::destroy(old_oops);
|
||||
}
|
||||
|
||||
void ZNMethod::detach_gc_data(nmethod* nm) {
|
||||
// Destroy GC data
|
||||
ZNMethodData::destroy(gc_data(nm));
|
||||
set_gc_data(nm, NULL);
|
||||
}
|
||||
|
||||
ZReentrantLock* ZNMethod::lock_for_nmethod(nmethod* nm) {
|
||||
ZNMethodData* const data = gc_data(nm);
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return data->lock();
|
||||
}
|
||||
|
||||
void ZNMethod::log_register(const nmethod* nm) {
|
||||
LogTarget(Trace, gc, nmethod) log;
|
||||
if (!log.is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ZNMethodDataOops* const oops = gc_data(nm)->oops();
|
||||
|
||||
log.print("Register NMethod: %s.%s (" PTR_FORMAT "), "
|
||||
"Compiler: %s, Oops: %d, ImmediateOops: " SIZE_FORMAT ", NonImmediateOops: %s",
|
||||
nm->method()->method_holder()->external_name(),
|
||||
nm->method()->name()->as_C_string(),
|
||||
p2i(nm),
|
||||
nm->compiler_name(),
|
||||
nm->oops_count() - 1,
|
||||
oops->immediates_count(),
|
||||
oops->has_non_immediates() ? "Yes" : "No");
|
||||
|
||||
LogTarget(Trace, gc, nmethod, oops) log_oops;
|
||||
if (!log_oops.is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Print nmethod oops table
|
||||
{
|
||||
oop* const begin = nm->oops_begin();
|
||||
oop* const end = nm->oops_end();
|
||||
for (oop* p = begin; p < end; p++) {
|
||||
log_oops.print(" Oop[" SIZE_FORMAT "] " PTR_FORMAT " (%s)",
|
||||
(p - begin), p2i(*p), (*p)->klass()->external_name());
|
||||
}
|
||||
}
|
||||
|
||||
// Print nmethod immediate oops
|
||||
{
|
||||
oop** const begin = oops->immediates_begin();
|
||||
oop** const end = oops->immediates_end();
|
||||
for (oop** p = begin; p < end; p++) {
|
||||
log_oops.print(" ImmediateOop[" SIZE_FORMAT "] " PTR_FORMAT " @ " PTR_FORMAT " (%s)",
|
||||
(p - begin), p2i(**p), p2i(*p), (**p)->klass()->external_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZNMethod::log_unregister(const nmethod* nm) {
|
||||
LogTarget(Debug, gc, nmethod) log;
|
||||
if (!log.is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.print("Unregister NMethod: %s.%s (" PTR_FORMAT ")",
|
||||
nm->method()->method_holder()->external_name(),
|
||||
nm->method()->name()->as_C_string(),
|
||||
p2i(nm));
|
||||
}
|
||||
|
||||
void ZNMethod::register_nmethod(nmethod* nm) {
|
||||
ResourceMark rm;
|
||||
|
||||
// Create and attach gc data
|
||||
attach_gc_data(nm);
|
||||
|
||||
log_register(nm);
|
||||
|
||||
ZNMethodTable::register_nmethod(nm);
|
||||
|
||||
// Disarm nmethod entry barrier
|
||||
disarm_nmethod(nm);
|
||||
}
|
||||
|
||||
void ZNMethod::unregister_nmethod(nmethod* nm) {
|
||||
assert(CodeCache_lock->owned_by_self(), "Lock must be held");
|
||||
|
||||
if (Thread::current()->is_Code_cache_sweeper_thread()) {
|
||||
// The sweeper must wait for any ongoing iteration to complete
|
||||
// before it can unregister an nmethod.
|
||||
ZNMethodTable::wait_until_iteration_done();
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
|
||||
log_unregister(nm);
|
||||
|
||||
ZNMethodTable::unregister_nmethod(nm);
|
||||
|
||||
// Destroy and detach gc data
|
||||
detach_gc_data(nm);
|
||||
}
|
||||
|
||||
void ZNMethod::disarm_nmethod(nmethod* nm) {
|
||||
BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
|
||||
if (bs != NULL) {
|
||||
bs->disarm(nm);
|
||||
}
|
||||
}
|
||||
|
||||
void ZNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) {
|
||||
// Process oops table
|
||||
{
|
||||
oop* const begin = nm->oops_begin();
|
||||
oop* const end = nm->oops_end();
|
||||
for (oop* p = begin; p < end; p++) {
|
||||
if (*p != Universe::non_oop_word()) {
|
||||
cl->do_oop(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZNMethodDataOops* const oops = gc_data(nm)->oops();
|
||||
|
||||
// Process immediate oops
|
||||
{
|
||||
oop** const begin = oops->immediates_begin();
|
||||
oop** const end = oops->immediates_end();
|
||||
for (oop** p = begin; p < end; p++) {
|
||||
if (**p != Universe::non_oop_word()) {
|
||||
cl->do_oop(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process non-immediate oops
|
||||
if (oops->has_non_immediates()) {
|
||||
nm->fix_oop_relocations();
|
||||
}
|
||||
}
|
||||
|
||||
class ZNMethodToOopsDoClosure : public NMethodClosure {
|
||||
private:
|
||||
OopClosure* _cl;
|
||||
|
||||
public:
|
||||
ZNMethodToOopsDoClosure(OopClosure* cl) :
|
||||
_cl(cl) {}
|
||||
|
||||
virtual void do_nmethod(nmethod* nm) {
|
||||
ZNMethod::nmethod_oops_do(nm, _cl);
|
||||
}
|
||||
};
|
||||
|
||||
void ZNMethod::oops_do_begin() {
|
||||
ZNMethodTable::nmethods_do_begin();
|
||||
}
|
||||
|
||||
void ZNMethod::oops_do_end() {
|
||||
ZNMethodTable::nmethods_do_end();
|
||||
}
|
||||
|
||||
void ZNMethod::oops_do(OopClosure* cl) {
|
||||
ZNMethodToOopsDoClosure nmethod_cl(cl);
|
||||
ZNMethodTable::nmethods_do(&nmethod_cl);
|
||||
}
|
||||
|
||||
class ZNMethodUnlinkClosure : public NMethodClosure {
|
||||
private:
|
||||
bool _unloading_occurred;
|
||||
volatile bool _failed;
|
||||
|
||||
void set_failed() {
|
||||
Atomic::store(true, &_failed);
|
||||
}
|
||||
|
||||
public:
|
||||
ZNMethodUnlinkClosure(bool unloading_occurred) :
|
||||
_unloading_occurred(unloading_occurred),
|
||||
_failed(false) {}
|
||||
|
||||
virtual void do_nmethod(nmethod* nm) {
|
||||
if (failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nm->is_alive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZLocker<ZReentrantLock> locker(ZNMethod::lock_for_nmethod(nm));
|
||||
|
||||
if (nm->is_unloading()) {
|
||||
// Unlinking of the dependencies must happen before the
|
||||
// handshake separating unlink and purge.
|
||||
nm->flush_dependencies(false /* delete_immediately */);
|
||||
|
||||
// We don't need to take the lock when unlinking nmethods from
|
||||
// the Method, because it is only concurrently unlinked by
|
||||
// the entry barrier, which acquires the per nmethod lock.
|
||||
nm->unlink_from_method(false /* acquire_lock */);
|
||||
return;
|
||||
}
|
||||
|
||||
// Heal oops and disarm
|
||||
ZNMethodOopClosure cl;
|
||||
ZNMethod::nmethod_oops_do(nm, &cl);
|
||||
ZNMethod::disarm_nmethod(nm);
|
||||
|
||||
// Clear compiled ICs and exception caches
|
||||
if (!nm->unload_nmethod_caches(_unloading_occurred)) {
|
||||
set_failed();
|
||||
}
|
||||
}
|
||||
|
||||
bool failed() const {
|
||||
return Atomic::load(&_failed);
|
||||
}
|
||||
};
|
||||
|
||||
class ZNMethodUnlinkTask : public ZTask {
|
||||
private:
|
||||
ZNMethodUnlinkClosure _cl;
|
||||
ICRefillVerifier* _verifier;
|
||||
|
||||
public:
|
||||
ZNMethodUnlinkTask(bool unloading_occurred, ICRefillVerifier* verifier) :
|
||||
ZTask("ZNMethodUnlinkTask"),
|
||||
_cl(unloading_occurred),
|
||||
_verifier(verifier) {
|
||||
ZNMethodTable::nmethods_do_begin();
|
||||
}
|
||||
|
||||
~ZNMethodUnlinkTask() {
|
||||
ZNMethodTable::nmethods_do_end();
|
||||
}
|
||||
|
||||
virtual void work() {
|
||||
ICRefillVerifierMark mark(_verifier);
|
||||
ZNMethodTable::nmethods_do(&_cl);
|
||||
}
|
||||
|
||||
bool success() const {
|
||||
return !_cl.failed();
|
||||
}
|
||||
};
|
||||
|
||||
void ZNMethod::unlink(ZWorkers* workers, bool unloading_occurred) {
|
||||
for (;;) {
|
||||
ICRefillVerifier verifier;
|
||||
|
||||
{
|
||||
ZNMethodUnlinkTask task(unloading_occurred, &verifier);
|
||||
workers->run_concurrent(&task);
|
||||
if (task.success()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleaning failed because we ran out of transitional IC stubs,
|
||||
// so we have to refill and try again. Refilling requires taking
|
||||
// a safepoint, so we temporarily leave the suspendible thread set.
|
||||
SuspendibleThreadSetLeaver sts;
|
||||
InlineCacheBuffer::refill_ic_stubs();
|
||||
}
|
||||
}
|
||||
|
||||
class ZNMethodPurgeClosure : public NMethodClosure {
|
||||
public:
|
||||
virtual void do_nmethod(nmethod* nm) {
|
||||
if (nm->is_alive() && nm->is_unloading()) {
|
||||
nm->make_unloaded();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ZNMethodPurgeTask : public ZTask {
|
||||
private:
|
||||
ZNMethodPurgeClosure _cl;
|
||||
|
||||
public:
|
||||
ZNMethodPurgeTask() :
|
||||
ZTask("ZNMethodPurgeTask"),
|
||||
_cl() {
|
||||
ZNMethodTable::nmethods_do_begin();
|
||||
}
|
||||
|
||||
~ZNMethodPurgeTask() {
|
||||
ZNMethodTable::nmethods_do_end();
|
||||
}
|
||||
|
||||
virtual void work() {
|
||||
ZNMethodTable::nmethods_do(&_cl);
|
||||
}
|
||||
};
|
||||
|
||||
void ZNMethod::purge(ZWorkers* workers) {
|
||||
ZNMethodPurgeTask task;
|
||||
workers->run_concurrent(&task);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, 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
|
||||
@ -21,39 +21,40 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4904495
|
||||
* @summary Verify that "shortcuts" are used when printing annotations.
|
||||
* @library ../../lib
|
||||
* @modules jdk.javadoc
|
||||
* @compile ../../lib/OldToolTester.java Main.java
|
||||
* @run main Main
|
||||
*/
|
||||
#ifndef SHARE_GC_Z_ZNMETHOD_HPP
|
||||
#define SHARE_GC_Z_ZNMETHOD_HPP
|
||||
|
||||
import java.io.IOException;
|
||||
import com.sun.javadoc.*;
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
public class Main extends OldToolTester.Doclet {
|
||||
class nmethod;
|
||||
class OopClosure;
|
||||
class ZReentrantLock;
|
||||
class ZWorkers;
|
||||
|
||||
private static final OldToolTester tester = new OldToolTester("Main", "pkg1");
|
||||
class ZNMethod : public AllStatic {
|
||||
private:
|
||||
static void attach_gc_data(nmethod* nm);
|
||||
static void detach_gc_data(nmethod* nm);
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
tester.run();
|
||||
tester.verify();
|
||||
}
|
||||
static void log_register(const nmethod* nm);
|
||||
static void log_unregister(const nmethod* nm);
|
||||
|
||||
public static boolean start(RootDoc root) {
|
||||
try {
|
||||
for (ClassDoc cd : root.classes()) {
|
||||
if (cd.isInterface()) {
|
||||
tester.printClass(cd);
|
||||
}
|
||||
}
|
||||
public:
|
||||
static void register_nmethod(nmethod* nm);
|
||||
static void unregister_nmethod(nmethod* nm);
|
||||
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void disarm_nmethod(nmethod* nm);
|
||||
|
||||
static void nmethod_oops_do(nmethod* nm, OopClosure* cl);
|
||||
|
||||
static void oops_do_begin();
|
||||
static void oops_do_end();
|
||||
static void oops_do(OopClosure* cl);
|
||||
|
||||
static ZReentrantLock* lock_for_nmethod(nmethod* nm);
|
||||
|
||||
static void unlink(ZWorkers* workers, bool unloading_occurred);
|
||||
static void purge(ZWorkers* workers);
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_Z_ZNMETHOD_HPP
|
69
src/hotspot/share/gc/z/zNMethodAllocator.cpp
Normal file
69
src/hotspot/share/gc/z/zNMethodAllocator.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zArray.inline.hpp"
|
||||
#include "gc/z/zNMethodAllocator.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
ZArray<void*> ZNMethodAllocator::_deferred_frees;
|
||||
bool ZNMethodAllocator::_defer_frees(false);
|
||||
|
||||
void ZNMethodAllocator::immediate_free(void* data) {
|
||||
FREE_C_HEAP_ARRAY(uint8_t, data);
|
||||
}
|
||||
|
||||
void ZNMethodAllocator::deferred_free(void* data) {
|
||||
_deferred_frees.add(data);
|
||||
}
|
||||
|
||||
void* ZNMethodAllocator::allocate(size_t size) {
|
||||
return NEW_C_HEAP_ARRAY(uint8_t, size, mtGC);
|
||||
}
|
||||
|
||||
void ZNMethodAllocator::free(void* data) {
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_defer_frees) {
|
||||
deferred_free(data);
|
||||
} else {
|
||||
immediate_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
void ZNMethodAllocator::activate_deferred_frees() {
|
||||
assert(_deferred_frees.is_empty(), "precondition");
|
||||
_defer_frees = true;
|
||||
}
|
||||
|
||||
void ZNMethodAllocator::deactivate_and_process_deferred_frees() {
|
||||
_defer_frees = false;
|
||||
|
||||
ZArrayIterator<void*> iter(&_deferred_frees);
|
||||
for (void* data; iter.next(&data);) {
|
||||
immediate_free(data);
|
||||
}
|
||||
_deferred_frees.clear();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 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
|
||||
@ -21,26 +21,26 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package pkg1;
|
||||
#ifndef SHARE_GC_Z_ZNMETHODALLOCATOR_HPP
|
||||
#define SHARE_GC_Z_ZNMETHODALLOCATOR_HPP
|
||||
|
||||
import java.lang.annotation.*;
|
||||
#include "memory/allocation.hpp"
|
||||
#include "gc/z/zArray.hpp"
|
||||
|
||||
public class A {
|
||||
class ZNMethodAllocator : public AllStatic {
|
||||
private:
|
||||
static ZArray<void*> _deferred_frees;
|
||||
static bool _defer_frees;
|
||||
|
||||
@Retention(BOGUS) // illegal
|
||||
public @interface A1 {}
|
||||
static void immediate_free(void* data);
|
||||
static void deferred_free(void* data);
|
||||
|
||||
@Target({BOGUS}) // illegal
|
||||
public @interface A2 {}
|
||||
public:
|
||||
static void* allocate(size_t size);
|
||||
static void free(void* data);
|
||||
|
||||
@Retention(true) // illegal
|
||||
public @interface A3 {}
|
||||
static void activate_deferred_frees();
|
||||
static void deactivate_and_process_deferred_frees();
|
||||
};
|
||||
|
||||
public @interface A4 {
|
||||
ElementType value() default BOGUS; // illegal
|
||||
}
|
||||
|
||||
public @interface A5 {
|
||||
int[] value() default {true}; // illegal
|
||||
}
|
||||
}
|
||||
#endif // SHARE_GC_Z_ZNMETHODALLOCATOR_HPP
|
103
src/hotspot/share/gc/z/zNMethodData.cpp
Normal file
103
src/hotspot/share/gc/z/zNMethodData.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zLock.inline.hpp"
|
||||
#include "gc/z/zNMethodAllocator.hpp"
|
||||
#include "gc/z/zNMethodData.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
|
||||
size_t ZNMethodDataOops::header_size() {
|
||||
const size_t size = sizeof(ZNMethodDataOops);
|
||||
assert(is_aligned(size, sizeof(oop*)), "Header misaligned");
|
||||
return size;
|
||||
}
|
||||
|
||||
ZNMethodDataOops* ZNMethodDataOops::create(const GrowableArray<oop*>& immediates, bool has_non_immediates) {
|
||||
// Allocate memory for the ZNMethodDataOops object
|
||||
// plus the immediate oop* array that follows right after.
|
||||
const size_t size = ZNMethodDataOops::header_size() + (sizeof(oop*) * immediates.length());
|
||||
void* const mem = ZNMethodAllocator::allocate(size);
|
||||
return ::new (mem) ZNMethodDataOops(immediates, has_non_immediates);
|
||||
}
|
||||
|
||||
void ZNMethodDataOops::destroy(ZNMethodDataOops* oops) {
|
||||
ZNMethodAllocator::free(oops);
|
||||
}
|
||||
|
||||
ZNMethodDataOops::ZNMethodDataOops(const GrowableArray<oop*>& immediates, bool has_non_immediates) :
|
||||
_nimmediates(immediates.length()),
|
||||
_has_non_immediates(has_non_immediates) {
|
||||
// Save all immediate oops
|
||||
for (size_t i = 0; i < _nimmediates; i++) {
|
||||
immediates_begin()[i] = immediates.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZNMethodDataOops::immediates_count() const {
|
||||
return _nimmediates;
|
||||
}
|
||||
|
||||
oop** ZNMethodDataOops::immediates_begin() const {
|
||||
// The immediate oop* array starts immediately after this object
|
||||
return (oop**)((uintptr_t)this + header_size());
|
||||
}
|
||||
|
||||
oop** ZNMethodDataOops::immediates_end() const {
|
||||
return immediates_begin() + immediates_count();
|
||||
}
|
||||
|
||||
bool ZNMethodDataOops::has_non_immediates() const {
|
||||
return _has_non_immediates;
|
||||
}
|
||||
|
||||
ZNMethodData* ZNMethodData::create(nmethod* nm) {
|
||||
void* const mem = ZNMethodAllocator::allocate(sizeof(ZNMethodData));
|
||||
return ::new (mem) ZNMethodData(nm);
|
||||
}
|
||||
|
||||
void ZNMethodData::destroy(ZNMethodData* data) {
|
||||
ZNMethodAllocator::free(data->oops());
|
||||
ZNMethodAllocator::free(data);
|
||||
}
|
||||
|
||||
ZNMethodData::ZNMethodData(nmethod* nm) :
|
||||
_lock(),
|
||||
_oops(NULL) {}
|
||||
|
||||
ZReentrantLock* ZNMethodData::lock() {
|
||||
return &_lock;
|
||||
}
|
||||
|
||||
ZNMethodDataOops* ZNMethodData::oops() const {
|
||||
return OrderAccess::load_acquire(&_oops);
|
||||
}
|
||||
|
||||
ZNMethodDataOops* ZNMethodData::swap_oops(ZNMethodDataOops* new_oops) {
|
||||
return Atomic::xchg(new_oops, &_oops);
|
||||
}
|
71
src/hotspot/share/gc/z/zNMethodData.hpp
Normal file
71
src/hotspot/share/gc/z/zNMethodData.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "gc/z/zLock.hpp"
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
#ifndef SHARE_GC_Z_ZNMETHODDATA_HPP
|
||||
#define SHARE_GC_Z_ZNMETHODDATA_HPP
|
||||
|
||||
class nmethod;
|
||||
template <typename T> class GrowableArray;
|
||||
|
||||
class ZNMethodDataOops {
|
||||
private:
|
||||
const size_t _nimmediates;
|
||||
bool _has_non_immediates;
|
||||
|
||||
static size_t header_size();
|
||||
|
||||
ZNMethodDataOops(const GrowableArray<oop*>& immediates, bool has_non_immediates);
|
||||
|
||||
public:
|
||||
static ZNMethodDataOops* create(const GrowableArray<oop*>& immediates, bool has_non_immediates);
|
||||
static void destroy(ZNMethodDataOops* oops);
|
||||
|
||||
size_t immediates_count() const;
|
||||
oop** immediates_begin() const;
|
||||
oop** immediates_end() const;
|
||||
|
||||
bool has_non_immediates() const;
|
||||
};
|
||||
|
||||
class ZNMethodData {
|
||||
private:
|
||||
ZReentrantLock _lock;
|
||||
ZNMethodDataOops* volatile _oops;
|
||||
|
||||
ZNMethodData(nmethod* nm);
|
||||
|
||||
public:
|
||||
static ZNMethodData* create(nmethod* nm);
|
||||
static void destroy(ZNMethodData* data);
|
||||
|
||||
ZReentrantLock* lock();
|
||||
|
||||
ZNMethodDataOops* oops() const;
|
||||
ZNMethodDataOops* swap_oops(ZNMethodDataOops* oops);
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_Z_ZNMETHODDATA_HPP
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,205 +27,38 @@
|
||||
#include "code/icBuffer.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "gc/z/zArray.inline.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zHash.inline.hpp"
|
||||
#include "gc/z/zLock.inline.hpp"
|
||||
#include "gc/z/zNMethodAllocator.hpp"
|
||||
#include "gc/z/zNMethodData.hpp"
|
||||
#include "gc/z/zNMethodTable.hpp"
|
||||
#include "gc/z/zNMethodTableEntry.hpp"
|
||||
#include "gc/z/zNMethodTableIteration.hpp"
|
||||
#include "gc/z/zOopClosures.inline.hpp"
|
||||
#include "gc/z/zTask.hpp"
|
||||
#include "gc/z/zWorkers.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
class ZNMethodDataImmediateOops {
|
||||
private:
|
||||
const size_t _nimmediate_oops;
|
||||
|
||||
static size_t header_size();
|
||||
|
||||
ZNMethodDataImmediateOops(const GrowableArray<oop*>& immediate_oops);
|
||||
|
||||
public:
|
||||
static ZNMethodDataImmediateOops* create(const GrowableArray<oop*>& immediate_oops);
|
||||
static void destroy(ZNMethodDataImmediateOops* data_immediate_oops);
|
||||
|
||||
size_t immediate_oops_count() const;
|
||||
oop** immediate_oops_begin() const;
|
||||
oop** immediate_oops_end() const;
|
||||
};
|
||||
|
||||
size_t ZNMethodDataImmediateOops::header_size() {
|
||||
const size_t size = sizeof(ZNMethodDataImmediateOops);
|
||||
assert(is_aligned(size, sizeof(oop*)), "Header misaligned");
|
||||
return size;
|
||||
}
|
||||
|
||||
ZNMethodDataImmediateOops* ZNMethodDataImmediateOops::create(const GrowableArray<oop*>& immediate_oops) {
|
||||
// Allocate memory for the ZNMethodDataImmediateOops object
|
||||
// plus the immediate oop* array that follows right after.
|
||||
const size_t size = ZNMethodDataImmediateOops::header_size() + (sizeof(oop*) * immediate_oops.length());
|
||||
void* const data_immediate_oops = NEW_C_HEAP_ARRAY(uint8_t, size, mtGC);
|
||||
return ::new (data_immediate_oops) ZNMethodDataImmediateOops(immediate_oops);
|
||||
}
|
||||
|
||||
void ZNMethodDataImmediateOops::destroy(ZNMethodDataImmediateOops* data_immediate_oops) {
|
||||
ZNMethodTable::safe_delete(data_immediate_oops);
|
||||
}
|
||||
|
||||
ZNMethodDataImmediateOops::ZNMethodDataImmediateOops(const GrowableArray<oop*>& immediate_oops) :
|
||||
_nimmediate_oops(immediate_oops.length()) {
|
||||
// Save all immediate oops
|
||||
for (size_t i = 0; i < _nimmediate_oops; i++) {
|
||||
immediate_oops_begin()[i] = immediate_oops.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZNMethodDataImmediateOops::immediate_oops_count() const {
|
||||
return _nimmediate_oops;
|
||||
}
|
||||
|
||||
oop** ZNMethodDataImmediateOops::immediate_oops_begin() const {
|
||||
// The immediate oop* array starts immediately after this object
|
||||
return (oop**)((uintptr_t)this + header_size());
|
||||
}
|
||||
|
||||
oop** ZNMethodDataImmediateOops::immediate_oops_end() const {
|
||||
return immediate_oops_begin() + immediate_oops_count();
|
||||
}
|
||||
|
||||
class ZNMethodData {
|
||||
private:
|
||||
ZReentrantLock _lock;
|
||||
ZNMethodDataImmediateOops* volatile _immediate_oops;
|
||||
|
||||
ZNMethodData(nmethod* nm);
|
||||
|
||||
public:
|
||||
static ZNMethodData* create(nmethod* nm);
|
||||
static void destroy(ZNMethodData* data);
|
||||
|
||||
ZReentrantLock* lock();
|
||||
|
||||
ZNMethodDataImmediateOops* immediate_oops() const;
|
||||
ZNMethodDataImmediateOops* swap_immediate_oops(const GrowableArray<oop*>& immediate_oops);
|
||||
};
|
||||
|
||||
ZNMethodData* ZNMethodData::create(nmethod* nm) {
|
||||
void* const method = NEW_C_HEAP_ARRAY(uint8_t, sizeof(ZNMethodData), mtGC);
|
||||
return ::new (method) ZNMethodData(nm);
|
||||
}
|
||||
|
||||
void ZNMethodData::destroy(ZNMethodData* data) {
|
||||
ZNMethodDataImmediateOops::destroy(data->immediate_oops());
|
||||
ZNMethodTable::safe_delete(data);
|
||||
}
|
||||
|
||||
ZNMethodData::ZNMethodData(nmethod* nm) :
|
||||
_lock(),
|
||||
_immediate_oops(NULL) {}
|
||||
|
||||
ZReentrantLock* ZNMethodData::lock() {
|
||||
return &_lock;
|
||||
}
|
||||
|
||||
ZNMethodDataImmediateOops* ZNMethodData::immediate_oops() const {
|
||||
return OrderAccess::load_acquire(&_immediate_oops);
|
||||
}
|
||||
|
||||
ZNMethodDataImmediateOops* ZNMethodData::swap_immediate_oops(const GrowableArray<oop*>& immediate_oops) {
|
||||
ZNMethodDataImmediateOops* const data_immediate_oops =
|
||||
immediate_oops.is_empty() ? NULL : ZNMethodDataImmediateOops::create(immediate_oops);
|
||||
return Atomic::xchg(data_immediate_oops, &_immediate_oops);
|
||||
}
|
||||
|
||||
static ZNMethodData* gc_data(const nmethod* nm) {
|
||||
return nm->gc_data<ZNMethodData>();
|
||||
}
|
||||
|
||||
static void set_gc_data(nmethod* nm, ZNMethodData* data) {
|
||||
return nm->set_gc_data<ZNMethodData>(data);
|
||||
}
|
||||
|
||||
ZNMethodTableEntry* ZNMethodTable::_table = NULL;
|
||||
size_t ZNMethodTable::_size = 0;
|
||||
ZLock ZNMethodTable::_iter_lock;
|
||||
ZNMethodTableEntry* ZNMethodTable::_iter_table = NULL;
|
||||
size_t ZNMethodTable::_iter_table_size = 0;
|
||||
ZArray<void*> ZNMethodTable::_iter_deferred_deletes;
|
||||
size_t ZNMethodTable::_nregistered = 0;
|
||||
size_t ZNMethodTable::_nunregistered = 0;
|
||||
volatile size_t ZNMethodTable::_claimed = 0;
|
||||
ZNMethodTableIteration ZNMethodTable::_iteration;
|
||||
|
||||
void ZNMethodTable::safe_delete(void* data) {
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZLocker<ZLock> locker(&_iter_lock);
|
||||
if (_iter_table != NULL) {
|
||||
// Iteration in progress, defer delete
|
||||
_iter_deferred_deletes.add(data);
|
||||
} else {
|
||||
// Iteration not in progress, delete now
|
||||
FREE_C_HEAP_ARRAY(uint8_t, data);
|
||||
}
|
||||
ZNMethodTableEntry* ZNMethodTable::create(size_t size) {
|
||||
void* const mem = ZNMethodAllocator::allocate(size * sizeof(ZNMethodTableEntry));
|
||||
return ::new (mem) ZNMethodTableEntry[size];
|
||||
}
|
||||
|
||||
ZNMethodTableEntry ZNMethodTable::create_entry(nmethod* nm) {
|
||||
GrowableArray<oop*> immediate_oops;
|
||||
bool non_immediate_oops = false;
|
||||
|
||||
// Find all oops relocations
|
||||
RelocIterator iter(nm);
|
||||
while (iter.next()) {
|
||||
if (iter.type() != relocInfo::oop_type) {
|
||||
// Not an oop
|
||||
continue;
|
||||
}
|
||||
|
||||
oop_Relocation* r = iter.oop_reloc();
|
||||
|
||||
if (!r->oop_is_immediate()) {
|
||||
// Non-immediate oop found
|
||||
non_immediate_oops = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r->oop_value() != NULL) {
|
||||
// Non-NULL immediate oop found. NULL oops can safely be
|
||||
// ignored since the method will be re-registered if they
|
||||
// are later patched to be non-NULL.
|
||||
immediate_oops.push(r->oop_addr());
|
||||
}
|
||||
}
|
||||
|
||||
// Attach GC data to nmethod
|
||||
ZNMethodData* data = gc_data(nm);
|
||||
if (data == NULL) {
|
||||
data = ZNMethodData::create(nm);
|
||||
set_gc_data(nm, data);
|
||||
}
|
||||
|
||||
// Attach immediate oops in GC data
|
||||
ZNMethodDataImmediateOops* const old_data_immediate_oops = data->swap_immediate_oops(immediate_oops);
|
||||
ZNMethodDataImmediateOops::destroy(old_data_immediate_oops);
|
||||
|
||||
// Create entry
|
||||
return ZNMethodTableEntry(nm, non_immediate_oops, !immediate_oops.is_empty());
|
||||
}
|
||||
|
||||
ZReentrantLock* ZNMethodTable::lock_for_nmethod(nmethod* nm) {
|
||||
ZNMethodData* const data = gc_data(nm);
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return data->lock();
|
||||
void ZNMethodTable::destroy(ZNMethodTableEntry* table) {
|
||||
ZNMethodAllocator::free(table);
|
||||
}
|
||||
|
||||
size_t ZNMethodTable::first_index(const nmethod* nm, size_t size) {
|
||||
@ -241,8 +74,8 @@ size_t ZNMethodTable::next_index(size_t prev_index, size_t size) {
|
||||
return (prev_index + 1) & mask;
|
||||
}
|
||||
|
||||
bool ZNMethodTable::register_entry(ZNMethodTableEntry* table, size_t size, ZNMethodTableEntry entry) {
|
||||
const nmethod* const nm = entry.method();
|
||||
bool ZNMethodTable::register_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm) {
|
||||
const ZNMethodTableEntry entry(nm);
|
||||
size_t index = first_index(nm, size);
|
||||
|
||||
for (;;) {
|
||||
@ -265,11 +98,6 @@ bool ZNMethodTable::register_entry(ZNMethodTableEntry* table, size_t size, ZNMet
|
||||
}
|
||||
|
||||
void ZNMethodTable::unregister_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm) {
|
||||
if (size == 0) {
|
||||
// Table is empty
|
||||
return;
|
||||
}
|
||||
|
||||
size_t index = first_index(nm, size);
|
||||
|
||||
for (;;) {
|
||||
@ -279,10 +107,6 @@ void ZNMethodTable::unregister_entry(ZNMethodTableEntry* table, size_t size, nme
|
||||
if (table_entry.registered() && table_entry.method() == nm) {
|
||||
// Remove entry
|
||||
table[index] = ZNMethodTableEntry(true /* unregistered */);
|
||||
|
||||
// Destroy GC data
|
||||
ZNMethodData::destroy(gc_data(nm));
|
||||
set_gc_data(nm, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -291,7 +115,8 @@ void ZNMethodTable::unregister_entry(ZNMethodTableEntry* table, size_t size, nme
|
||||
}
|
||||
|
||||
void ZNMethodTable::rebuild(size_t new_size) {
|
||||
ZLocker<ZLock> locker(&_iter_lock);
|
||||
assert(CodeCache_lock->owned_by_self(), "Lock must be held");
|
||||
|
||||
assert(is_power_of_2(new_size), "Invalid size");
|
||||
|
||||
log_debug(gc, nmethod)("Rebuilding NMethod Table: "
|
||||
@ -303,20 +128,18 @@ void ZNMethodTable::rebuild(size_t new_size) {
|
||||
_nunregistered, percent_of(_nunregistered, _size), 0.0);
|
||||
|
||||
// Allocate new table
|
||||
ZNMethodTableEntry* const new_table = new ZNMethodTableEntry[new_size];
|
||||
ZNMethodTableEntry* const new_table = ZNMethodTable::create(new_size);
|
||||
|
||||
// Transfer all registered entries
|
||||
for (size_t i = 0; i < _size; i++) {
|
||||
const ZNMethodTableEntry entry = _table[i];
|
||||
if (entry.registered()) {
|
||||
register_entry(new_table, new_size, entry);
|
||||
register_entry(new_table, new_size, entry.method());
|
||||
}
|
||||
}
|
||||
|
||||
if (_iter_table != _table) {
|
||||
// Delete old table
|
||||
delete [] _table;
|
||||
}
|
||||
// Free old table
|
||||
ZNMethodTable::destroy(_table);
|
||||
|
||||
// Install new table
|
||||
_table = new_table;
|
||||
@ -353,61 +176,6 @@ void ZNMethodTable::rebuild_if_needed() {
|
||||
}
|
||||
}
|
||||
|
||||
void ZNMethodTable::log_register(const nmethod* nm, ZNMethodTableEntry entry) {
|
||||
LogTarget(Trace, gc, nmethod) log;
|
||||
if (!log.is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.print("Register NMethod: %s.%s (" PTR_FORMAT "), "
|
||||
"Compiler: %s, Oops: %d, ImmediateOops: " SIZE_FORMAT ", NonImmediateOops: %s",
|
||||
nm->method()->method_holder()->external_name(),
|
||||
nm->method()->name()->as_C_string(),
|
||||
p2i(nm),
|
||||
nm->compiler_name(),
|
||||
nm->oops_count() - 1,
|
||||
entry.immediate_oops() ? gc_data(nm)->immediate_oops()->immediate_oops_count() : 0,
|
||||
entry.non_immediate_oops() ? "Yes" : "No");
|
||||
|
||||
LogTarget(Trace, gc, nmethod, oops) log_oops;
|
||||
if (!log_oops.is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Print nmethod oops table
|
||||
oop* const begin = nm->oops_begin();
|
||||
oop* const end = nm->oops_end();
|
||||
for (oop* p = begin; p < end; p++) {
|
||||
log_oops.print(" Oop[" SIZE_FORMAT "] " PTR_FORMAT " (%s)",
|
||||
(p - begin), p2i(*p), (*p)->klass()->external_name());
|
||||
}
|
||||
|
||||
if (entry.immediate_oops()) {
|
||||
// Print nmethod immediate oops
|
||||
const ZNMethodDataImmediateOops* const nmi = gc_data(nm)->immediate_oops();
|
||||
if (nmi != NULL) {
|
||||
oop** const begin = nmi->immediate_oops_begin();
|
||||
oop** const end = nmi->immediate_oops_end();
|
||||
for (oop** p = begin; p < end; p++) {
|
||||
log_oops.print(" ImmediateOop[" SIZE_FORMAT "] " PTR_FORMAT " @ " PTR_FORMAT " (%s)",
|
||||
(p - begin), p2i(**p), p2i(*p), (**p)->klass()->external_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZNMethodTable::log_unregister(const nmethod* nm) {
|
||||
LogTarget(Debug, gc, nmethod) log;
|
||||
if (!log.is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.print("Unregister NMethod: %s.%s (" PTR_FORMAT ")",
|
||||
nm->method()->method_holder()->external_name(),
|
||||
nm->method()->name()->as_C_string(),
|
||||
p2i(nm));
|
||||
}
|
||||
|
||||
size_t ZNMethodTable::registered_nmethods() {
|
||||
return _nregistered;
|
||||
}
|
||||
@ -418,48 +186,29 @@ size_t ZNMethodTable::unregistered_nmethods() {
|
||||
|
||||
void ZNMethodTable::register_nmethod(nmethod* nm) {
|
||||
assert(CodeCache_lock->owned_by_self(), "Lock must be held");
|
||||
ResourceMark rm;
|
||||
|
||||
// Grow/Shrink/Prune table if needed
|
||||
rebuild_if_needed();
|
||||
|
||||
// Create entry
|
||||
const ZNMethodTableEntry entry = create_entry(nm);
|
||||
|
||||
log_register(nm, entry);
|
||||
|
||||
// Insert new entry
|
||||
if (register_entry(_table, _size, entry)) {
|
||||
if (register_entry(_table, _size, nm)) {
|
||||
// New entry registered. When register_entry() instead returns
|
||||
// false the nmethod was already in the table so we do not want
|
||||
// to increase number of registered entries in that case.
|
||||
_nregistered++;
|
||||
}
|
||||
|
||||
// Disarm nmethod entry barrier
|
||||
disarm_nmethod(nm);
|
||||
}
|
||||
|
||||
void ZNMethodTable::sweeper_wait_for_iteration() {
|
||||
// The sweeper must wait for any ongoing iteration to complete
|
||||
// before it can unregister an nmethod.
|
||||
if (!Thread::current()->is_Code_cache_sweeper_thread()) {
|
||||
return;
|
||||
}
|
||||
void ZNMethodTable::wait_until_iteration_done() {
|
||||
assert(CodeCache_lock->owned_by_self(), "Lock must be held");
|
||||
|
||||
while (_iter_table != NULL) {
|
||||
MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
os::naked_short_sleep(1);
|
||||
while (_iteration.in_progress()) {
|
||||
CodeCache_lock->wait(Monitor::_no_safepoint_check_flag);
|
||||
}
|
||||
}
|
||||
|
||||
void ZNMethodTable::unregister_nmethod(nmethod* nm) {
|
||||
assert(CodeCache_lock->owned_by_self(), "Lock must be held");
|
||||
ResourceMark rm;
|
||||
|
||||
sweeper_wait_for_iteration();
|
||||
|
||||
log_unregister(nm);
|
||||
|
||||
// Remove entry
|
||||
unregister_entry(_table, _size, nm);
|
||||
@ -467,248 +216,29 @@ void ZNMethodTable::unregister_nmethod(nmethod* nm) {
|
||||
_nregistered--;
|
||||
}
|
||||
|
||||
void ZNMethodTable::disarm_nmethod(nmethod* nm) {
|
||||
BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
|
||||
if (bs != NULL) {
|
||||
bs->disarm(nm);
|
||||
}
|
||||
}
|
||||
|
||||
void ZNMethodTable::nmethod_entries_do_begin() {
|
||||
void ZNMethodTable::nmethods_do_begin() {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
ZLocker<ZLock> locker(&_iter_lock);
|
||||
|
||||
// Make sure we don't free data while iterating
|
||||
ZNMethodAllocator::activate_deferred_frees();
|
||||
|
||||
// Prepare iteration
|
||||
_iter_table = _table;
|
||||
_iter_table_size = _size;
|
||||
_claimed = 0;
|
||||
assert(_iter_deferred_deletes.is_empty(), "Should be emtpy");
|
||||
_iteration.nmethods_do_begin(_table, _size);
|
||||
}
|
||||
|
||||
void ZNMethodTable::nmethod_entries_do_end() {
|
||||
void ZNMethodTable::nmethods_do_end() {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
ZLocker<ZLock> locker(&_iter_lock);
|
||||
|
||||
// Finish iteration
|
||||
if (_iter_table != _table) {
|
||||
delete [] _iter_table;
|
||||
}
|
||||
_iter_table = NULL;
|
||||
assert(_claimed >= _iter_table_size, "Failed to claim all table entries");
|
||||
_iteration.nmethods_do_end();
|
||||
|
||||
// Process deferred deletes
|
||||
ZArrayIterator<void*> iter(&_iter_deferred_deletes);
|
||||
for (void* data; iter.next(&data);) {
|
||||
FREE_C_HEAP_ARRAY(uint8_t, data);
|
||||
}
|
||||
_iter_deferred_deletes.clear();
|
||||
// Process deferred frees
|
||||
ZNMethodAllocator::deactivate_and_process_deferred_frees();
|
||||
|
||||
// Notify iteration done
|
||||
CodeCache_lock->notify_all();
|
||||
}
|
||||
|
||||
void ZNMethodTable::entry_oops_do(ZNMethodTableEntry entry, OopClosure* cl) {
|
||||
nmethod* const nm = entry.method();
|
||||
|
||||
// Process oops table
|
||||
oop* const begin = nm->oops_begin();
|
||||
oop* const end = nm->oops_end();
|
||||
for (oop* p = begin; p < end; p++) {
|
||||
if (*p != Universe::non_oop_word()) {
|
||||
cl->do_oop(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Process immediate oops
|
||||
if (entry.immediate_oops()) {
|
||||
const ZNMethodDataImmediateOops* const nmi = gc_data(nm)->immediate_oops();
|
||||
if (nmi != NULL) {
|
||||
oop** const begin = nmi->immediate_oops_begin();
|
||||
oop** const end = nmi->immediate_oops_end();
|
||||
for (oop** p = begin; p < end; p++) {
|
||||
if (**p != Universe::non_oop_word()) {
|
||||
cl->do_oop(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process non-immediate oops
|
||||
if (entry.non_immediate_oops()) {
|
||||
nmethod* const nm = entry.method();
|
||||
nm->fix_oop_relocations();
|
||||
}
|
||||
}
|
||||
|
||||
class ZNMethodTableEntryToOopsDo : public ZNMethodTableEntryClosure {
|
||||
private:
|
||||
OopClosure* _cl;
|
||||
|
||||
public:
|
||||
ZNMethodTableEntryToOopsDo(OopClosure* cl) :
|
||||
_cl(cl) {}
|
||||
|
||||
void do_nmethod_entry(ZNMethodTableEntry entry) {
|
||||
ZNMethodTable::entry_oops_do(entry, _cl);
|
||||
}
|
||||
};
|
||||
|
||||
void ZNMethodTable::oops_do(OopClosure* cl) {
|
||||
ZNMethodTableEntryToOopsDo entry_cl(cl);
|
||||
nmethod_entries_do(&entry_cl);
|
||||
}
|
||||
|
||||
void ZNMethodTable::nmethod_entries_do(ZNMethodTableEntryClosure* cl) {
|
||||
for (;;) {
|
||||
// Claim table partition. Each partition is currently sized to span
|
||||
// two cache lines. This number is just a guess, but seems to work well.
|
||||
const size_t partition_size = (ZCacheLineSize * 2) / sizeof(ZNMethodTableEntry);
|
||||
const size_t partition_start = MIN2(Atomic::add(partition_size, &_claimed) - partition_size, _iter_table_size);
|
||||
const size_t partition_end = MIN2(partition_start + partition_size, _iter_table_size);
|
||||
if (partition_start == partition_end) {
|
||||
// End of table
|
||||
break;
|
||||
}
|
||||
|
||||
// Process table partition
|
||||
for (size_t i = partition_start; i < partition_end; i++) {
|
||||
const ZNMethodTableEntry entry = _iter_table[i];
|
||||
if (entry.registered()) {
|
||||
cl->do_nmethod_entry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ZNMethodTableUnlinkClosure : public ZNMethodTableEntryClosure {
|
||||
private:
|
||||
bool _unloading_occurred;
|
||||
volatile bool _failed;
|
||||
|
||||
void set_failed() {
|
||||
Atomic::store(true, &_failed);
|
||||
}
|
||||
|
||||
public:
|
||||
ZNMethodTableUnlinkClosure(bool unloading_occurred) :
|
||||
_unloading_occurred(unloading_occurred),
|
||||
_failed(false) {}
|
||||
|
||||
virtual void do_nmethod_entry(ZNMethodTableEntry entry) {
|
||||
if (failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nmethod* const nm = entry.method();
|
||||
if (!nm->is_alive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZLocker<ZReentrantLock> locker(ZNMethodTable::lock_for_nmethod(nm));
|
||||
|
||||
if (nm->is_unloading()) {
|
||||
// Unlinking of the dependencies must happen before the
|
||||
// handshake separating unlink and purge.
|
||||
nm->flush_dependencies(false /* delete_immediately */);
|
||||
|
||||
// We don't need to take the lock when unlinking nmethods from
|
||||
// the Method, because it is only concurrently unlinked by
|
||||
// the entry barrier, which acquires the per nmethod lock.
|
||||
nm->unlink_from_method(false /* acquire_lock */);
|
||||
return;
|
||||
}
|
||||
|
||||
// Heal oops and disarm
|
||||
ZNMethodOopClosure cl;
|
||||
ZNMethodTable::entry_oops_do(entry, &cl);
|
||||
ZNMethodTable::disarm_nmethod(nm);
|
||||
|
||||
// Clear compiled ICs and exception caches
|
||||
if (!nm->unload_nmethod_caches(_unloading_occurred)) {
|
||||
set_failed();
|
||||
}
|
||||
}
|
||||
|
||||
bool failed() const {
|
||||
return Atomic::load(&_failed);
|
||||
}
|
||||
};
|
||||
|
||||
class ZNMethodTableUnlinkTask : public ZTask {
|
||||
private:
|
||||
ZNMethodTableUnlinkClosure _cl;
|
||||
ICRefillVerifier* _verifier;
|
||||
|
||||
public:
|
||||
ZNMethodTableUnlinkTask(bool unloading_occurred, ICRefillVerifier* verifier) :
|
||||
ZTask("ZNMethodTableUnlinkTask"),
|
||||
_cl(unloading_occurred),
|
||||
_verifier(verifier) {
|
||||
ZNMethodTable::nmethod_entries_do_begin();
|
||||
}
|
||||
|
||||
~ZNMethodTableUnlinkTask() {
|
||||
ZNMethodTable::nmethod_entries_do_end();
|
||||
}
|
||||
|
||||
virtual void work() {
|
||||
ICRefillVerifierMark mark(_verifier);
|
||||
ZNMethodTable::nmethod_entries_do(&_cl);
|
||||
}
|
||||
|
||||
bool success() const {
|
||||
return !_cl.failed();
|
||||
}
|
||||
};
|
||||
|
||||
void ZNMethodTable::unlink(ZWorkers* workers, bool unloading_occurred) {
|
||||
for (;;) {
|
||||
ICRefillVerifier verifier;
|
||||
|
||||
{
|
||||
ZNMethodTableUnlinkTask task(unloading_occurred, &verifier);
|
||||
workers->run_concurrent(&task);
|
||||
if (task.success()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleaning failed because we ran out of transitional IC stubs,
|
||||
// so we have to refill and try again. Refilling requires taking
|
||||
// a safepoint, so we temporarily leave the suspendible thread set.
|
||||
SuspendibleThreadSetLeaver sts;
|
||||
InlineCacheBuffer::refill_ic_stubs();
|
||||
}
|
||||
}
|
||||
|
||||
class ZNMethodTablePurgeClosure : public ZNMethodTableEntryClosure {
|
||||
public:
|
||||
virtual void do_nmethod_entry(ZNMethodTableEntry entry) {
|
||||
nmethod* const nm = entry.method();
|
||||
if (nm->is_alive() && nm->is_unloading()) {
|
||||
nm->make_unloaded();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ZNMethodTablePurgeTask : public ZTask {
|
||||
private:
|
||||
ZNMethodTablePurgeClosure _cl;
|
||||
|
||||
public:
|
||||
ZNMethodTablePurgeTask() :
|
||||
ZTask("ZNMethodTablePurgeTask"),
|
||||
_cl() {
|
||||
ZNMethodTable::nmethod_entries_do_begin();
|
||||
}
|
||||
|
||||
~ZNMethodTablePurgeTask() {
|
||||
ZNMethodTable::nmethod_entries_do_end();
|
||||
}
|
||||
|
||||
virtual void work() {
|
||||
ZNMethodTable::nmethod_entries_do(&_cl);
|
||||
}
|
||||
};
|
||||
|
||||
void ZNMethodTable::purge(ZWorkers* workers) {
|
||||
ZNMethodTablePurgeTask task;
|
||||
workers->run_concurrent(&task);
|
||||
void ZNMethodTable::nmethods_do(NMethodClosure* cl) {
|
||||
_iteration.nmethods_do(cl);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -24,66 +24,46 @@
|
||||
#ifndef SHARE_GC_Z_ZNMETHODTABLE_HPP
|
||||
#define SHARE_GC_Z_ZNMETHODTABLE_HPP
|
||||
|
||||
#include "gc/z/zArray.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zLock.hpp"
|
||||
#include "gc/z/zNMethodTableEntry.hpp"
|
||||
#include "gc/z/zNMethodTableIteration.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class nmethod;
|
||||
class NMethodClosure;
|
||||
class ZNMethodTableEntry;
|
||||
class ZWorkers;
|
||||
|
||||
class ZNMethodTableEntryClosure {
|
||||
public:
|
||||
virtual void do_nmethod_entry(ZNMethodTableEntry entry) = 0;
|
||||
};
|
||||
|
||||
class ZNMethodTable : public AllStatic {
|
||||
private:
|
||||
static ZNMethodTableEntry* _table;
|
||||
static size_t _size;
|
||||
static ZLock _iter_lock;
|
||||
static ZNMethodTableEntry* _iter_table;
|
||||
static size_t _iter_table_size;
|
||||
static ZArray<void*> _iter_deferred_deletes;
|
||||
static size_t _nregistered;
|
||||
static size_t _nunregistered;
|
||||
static volatile size_t _claimed ATTRIBUTE_ALIGNED(ZCacheLineSize);
|
||||
static ZNMethodTableEntry* _table;
|
||||
static size_t _size;
|
||||
static size_t _nregistered;
|
||||
static size_t _nunregistered;
|
||||
static ZNMethodTableIteration _iteration;
|
||||
|
||||
static ZNMethodTableEntry create_entry(nmethod* nm);
|
||||
static ZNMethodTableEntry* create(size_t size);
|
||||
static void destroy(ZNMethodTableEntry* table);
|
||||
|
||||
static size_t first_index(const nmethod* nm, size_t size);
|
||||
static size_t next_index(size_t prev_index, size_t size);
|
||||
|
||||
static void sweeper_wait_for_iteration();
|
||||
|
||||
static bool register_entry(ZNMethodTableEntry* table, size_t size, ZNMethodTableEntry entry);
|
||||
static bool register_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm);
|
||||
static void unregister_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm);
|
||||
|
||||
static void rebuild(size_t new_size);
|
||||
static void rebuild_if_needed();
|
||||
|
||||
static void log_register(const nmethod* nm, ZNMethodTableEntry entry);
|
||||
static void log_unregister(const nmethod* nm);
|
||||
|
||||
public:
|
||||
static void safe_delete(void* data);
|
||||
|
||||
static size_t registered_nmethods();
|
||||
static size_t unregistered_nmethods();
|
||||
|
||||
static void register_nmethod(nmethod* nm);
|
||||
static void unregister_nmethod(nmethod* nm);
|
||||
static void disarm_nmethod(nmethod* nm);
|
||||
|
||||
static ZReentrantLock* lock_for_nmethod(nmethod* nm);
|
||||
static void wait_until_iteration_done();
|
||||
|
||||
static void oops_do(OopClosure* cl);
|
||||
|
||||
static void entry_oops_do(ZNMethodTableEntry entry, OopClosure* cl);
|
||||
|
||||
static void nmethod_entries_do_begin();
|
||||
static void nmethod_entries_do_end();
|
||||
static void nmethod_entries_do(ZNMethodTableEntryClosure* cl);
|
||||
static void nmethods_do_begin();
|
||||
static void nmethods_do_end();
|
||||
static void nmethods_do(NMethodClosure* cl);
|
||||
|
||||
static void unlink(ZWorkers* workers, bool unloading_occurred);
|
||||
static void purge(ZWorkers* workers);
|
||||
|
@ -32,16 +32,16 @@
|
||||
// --------------------------
|
||||
//
|
||||
// 6
|
||||
// 3 3 2 1 0
|
||||
// +--------------------------------------------------------------------+-+-+-+
|
||||
// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111|1|1|1|
|
||||
// +--------------------------------------------------------------------+-+-+-+
|
||||
// | | | |
|
||||
// | 2-2 Non-immediate Oops Flag (1-bits) * | |
|
||||
// | | |
|
||||
// | 1-1 Immediate Oops/Unregistered Flag (1-bits) * |
|
||||
// | |
|
||||
// | 0-0 Registered Flag (1-bits) *
|
||||
// 3 2 1 0
|
||||
// +---------------------------------------------------------------------+-+-+
|
||||
// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 111111|1|1|
|
||||
// +---------------------------------------------------------------------+-+-+
|
||||
// | | |
|
||||
// | | |
|
||||
// | | |
|
||||
// | 1-1 Unregistered Flag (1-bits) * |
|
||||
// | |
|
||||
// | 0-0 Registered Flag (1-bits) *
|
||||
// |
|
||||
// * 63-3 NMethod Address (61-bits)
|
||||
//
|
||||
@ -52,22 +52,20 @@ class ZNMethodTableEntry : public CHeapObj<mtGC> {
|
||||
private:
|
||||
typedef ZBitField<uint64_t, bool, 0, 1> field_registered;
|
||||
typedef ZBitField<uint64_t, bool, 1, 1> field_unregistered;
|
||||
typedef ZBitField<uint64_t, bool, 1, 1> field_immediate_oops;
|
||||
typedef ZBitField<uint64_t, bool, 2, 1> field_non_immediate_oops;
|
||||
typedef ZBitField<uint64_t, nmethod*, 3, 61, 3> field_method;
|
||||
typedef ZBitField<uint64_t, nmethod*, 2, 62, 2> field_method;
|
||||
|
||||
uint64_t _entry;
|
||||
|
||||
public:
|
||||
explicit ZNMethodTableEntry(bool unregistered = false) :
|
||||
_entry(field_unregistered::encode(unregistered) |
|
||||
field_registered::encode(false)) {}
|
||||
_entry(field_registered::encode(false) |
|
||||
field_unregistered::encode(unregistered) |
|
||||
field_method::encode(NULL)) {}
|
||||
|
||||
ZNMethodTableEntry(nmethod* method, bool non_immediate_oops, bool immediate_oops) :
|
||||
_entry(field_method::encode(method) |
|
||||
field_non_immediate_oops::encode(non_immediate_oops) |
|
||||
field_immediate_oops::encode(immediate_oops) |
|
||||
field_registered::encode(true)) {}
|
||||
explicit ZNMethodTableEntry(nmethod* method) :
|
||||
_entry(field_registered::encode(true) |
|
||||
field_unregistered::encode(false) |
|
||||
field_method::encode(method)) {}
|
||||
|
||||
bool registered() const {
|
||||
return field_registered::decode(_entry);
|
||||
@ -77,14 +75,6 @@ public:
|
||||
return field_unregistered::decode(_entry);
|
||||
}
|
||||
|
||||
bool immediate_oops() const {
|
||||
return field_immediate_oops::decode(_entry);
|
||||
}
|
||||
|
||||
bool non_immediate_oops() const {
|
||||
return field_non_immediate_oops::decode(_entry);
|
||||
}
|
||||
|
||||
nmethod* method() const {
|
||||
return field_method::decode(_entry);
|
||||
}
|
||||
|
76
src/hotspot/share/gc/z/zNMethodTableIteration.cpp
Normal file
76
src/hotspot/share/gc/z/zNMethodTableIteration.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zNMethodTableEntry.hpp"
|
||||
#include "gc/z/zNMethodTableIteration.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
ZNMethodTableIteration::ZNMethodTableIteration() :
|
||||
_table(NULL),
|
||||
_size(0),
|
||||
_claimed(0) {}
|
||||
|
||||
bool ZNMethodTableIteration::in_progress() const {
|
||||
return _table != NULL;
|
||||
}
|
||||
|
||||
void ZNMethodTableIteration::nmethods_do_begin(ZNMethodTableEntry* table, size_t size) {
|
||||
assert(!in_progress(), "precondition");
|
||||
|
||||
_table = table;
|
||||
_size = size;
|
||||
_claimed = 0;
|
||||
}
|
||||
|
||||
void ZNMethodTableIteration::nmethods_do_end() {
|
||||
assert(_claimed >= _size, "Failed to claim all table entries");
|
||||
|
||||
// Finish iteration
|
||||
_table = NULL;
|
||||
}
|
||||
|
||||
void ZNMethodTableIteration::nmethods_do(NMethodClosure* cl) {
|
||||
for (;;) {
|
||||
// Claim table partition. Each partition is currently sized to span
|
||||
// two cache lines. This number is just a guess, but seems to work well.
|
||||
const size_t partition_size = (ZCacheLineSize * 2) / sizeof(ZNMethodTableEntry);
|
||||
const size_t partition_start = MIN2(Atomic::add(partition_size, &_claimed) - partition_size, _size);
|
||||
const size_t partition_end = MIN2(partition_start + partition_size, _size);
|
||||
if (partition_start == partition_end) {
|
||||
// End of table
|
||||
break;
|
||||
}
|
||||
|
||||
// Process table partition
|
||||
for (size_t i = partition_start; i < partition_end; i++) {
|
||||
const ZNMethodTableEntry entry = _table[i];
|
||||
if (entry.registered()) {
|
||||
cl->do_nmethod(entry.method());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 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
|
||||
@ -21,17 +21,28 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public class LambdaConstructTest {
|
||||
public static void main(String[] args) {
|
||||
#ifndef SHARE_GC_Z_ZNMETHODTABLEITERATION_HPP
|
||||
#define SHARE_GC_Z_ZNMETHODTABLEITERATION_HPP
|
||||
|
||||
System.out.println("=== LambdaConstructTest ===");
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
|
||||
// Lambda Runnable
|
||||
Runnable lambda = () -> System.out.println("it's a Lambda world!");
|
||||
class NMethodClosure;
|
||||
class ZNMethodTableEntry;
|
||||
|
||||
// Run it!
|
||||
lambda.run();
|
||||
class ZNMethodTableIteration {
|
||||
private:
|
||||
ZNMethodTableEntry* _table;
|
||||
size_t _size;
|
||||
volatile size_t _claimed ATTRIBUTE_ALIGNED(ZCacheLineSize);
|
||||
|
||||
}
|
||||
}
|
||||
public:
|
||||
ZNMethodTableIteration();
|
||||
|
||||
bool in_progress() const;
|
||||
|
||||
void nmethods_do_begin(ZNMethodTableEntry* table, size_t size);
|
||||
void nmethods_do_end();
|
||||
void nmethods_do(NMethodClosure* cl);
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_Z_ZNMETHODTABLEITERATION_HPP
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,28 +31,20 @@
|
||||
#include "gc/z/zRelocationSet.inline.hpp"
|
||||
#include "gc/z/zRootsIterator.hpp"
|
||||
#include "gc/z/zTask.hpp"
|
||||
#include "gc/z/zThreadLocalAllocBuffer.hpp"
|
||||
#include "gc/z/zWorkers.hpp"
|
||||
|
||||
ZRelocate::ZRelocate(ZWorkers* workers) :
|
||||
_workers(workers) {}
|
||||
|
||||
class ZRelocateRootsIteratorClosure : public ZRootsIteratorClosure {
|
||||
private:
|
||||
static void remap_address(HeapWord** p) {
|
||||
*p = (HeapWord*)ZAddress::good_or_null((uintptr_t)*p);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void do_thread(Thread* thread) {
|
||||
ZRootsIteratorClosure::do_thread(thread);
|
||||
|
||||
// Update thread local address bad mask
|
||||
ZThreadLocalData::set_address_bad_mask(thread, ZAddressBadMask);
|
||||
|
||||
// Remap TLAB
|
||||
if (UseTLAB && thread->is_Java_thread()) {
|
||||
thread->tlab().addresses_do(remap_address);
|
||||
}
|
||||
ZThreadLocalAllocBuffer::remap(thread);
|
||||
}
|
||||
|
||||
virtual void do_oop(oop* p) {
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "gc/z/zBarrierSetNMethod.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zNMethodTable.hpp"
|
||||
#include "gc/z/zNMethod.hpp"
|
||||
#include "gc/z/zOopClosures.inline.hpp"
|
||||
#include "gc/z/zRootsIterator.hpp"
|
||||
#include "gc/z/zStat.hpp"
|
||||
@ -135,29 +135,38 @@ void ZParallelWeakOopsDo<T, F>::weak_oops_do(BoolObjectClosure* is_alive, ZRoots
|
||||
}
|
||||
}
|
||||
|
||||
class ZCodeBlobClosure : public CodeBlobToOopClosure {
|
||||
class ZRootsIteratorCodeBlobClosure : public CodeBlobToOopClosure {
|
||||
private:
|
||||
BarrierSetNMethod* _bs;
|
||||
|
||||
public:
|
||||
ZCodeBlobClosure(OopClosure* cl) :
|
||||
ZRootsIteratorCodeBlobClosure(OopClosure* cl) :
|
||||
CodeBlobToOopClosure(cl, true /* fix_relocations */),
|
||||
_bs(BarrierSet::barrier_set()->barrier_set_nmethod()) {}
|
||||
|
||||
virtual void do_code_blob(CodeBlob* cb) {
|
||||
nmethod* const nm = cb->as_nmethod_or_null();
|
||||
if (nm == NULL || nm->test_set_oops_do_mark()) {
|
||||
return;
|
||||
if (nm != NULL && !nm->test_set_oops_do_mark()) {
|
||||
CodeBlobToOopClosure::do_code_blob(cb);
|
||||
_bs->disarm(nm);
|
||||
}
|
||||
CodeBlobToOopClosure::do_code_blob(cb);
|
||||
_bs->disarm(nm);
|
||||
}
|
||||
};
|
||||
|
||||
void ZRootsIteratorClosure::do_thread(Thread* thread) {
|
||||
ZCodeBlobClosure code_cl(this);
|
||||
thread->oops_do(this, ClassUnloading ? &code_cl : NULL);
|
||||
}
|
||||
class ZRootsIteratorThreadClosure : public ThreadClosure {
|
||||
private:
|
||||
ZRootsIteratorClosure* _cl;
|
||||
|
||||
public:
|
||||
ZRootsIteratorThreadClosure(ZRootsIteratorClosure* cl) :
|
||||
_cl(cl) {}
|
||||
|
||||
virtual void do_thread(Thread* thread) {
|
||||
ZRootsIteratorCodeBlobClosure code_cl(_cl);
|
||||
thread->oops_do(_cl, ClassUnloading ? &code_cl : NULL);
|
||||
_cl->do_thread(thread);
|
||||
}
|
||||
};
|
||||
|
||||
ZRootsIterator::ZRootsIterator() :
|
||||
_universe(this),
|
||||
@ -175,7 +184,7 @@ ZRootsIterator::ZRootsIterator() :
|
||||
if (ClassUnloading) {
|
||||
nmethod::oops_do_marking_prologue();
|
||||
} else {
|
||||
ZNMethodTable::nmethod_entries_do_begin();
|
||||
ZNMethod::oops_do_begin();
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +194,7 @@ ZRootsIterator::~ZRootsIterator() {
|
||||
if (ClassUnloading) {
|
||||
nmethod::oops_do_marking_epilogue();
|
||||
} else {
|
||||
ZNMethodTable::nmethod_entries_do_end();
|
||||
ZNMethod::oops_do_end();
|
||||
}
|
||||
JvmtiExport::gc_epilogue();
|
||||
|
||||
@ -227,12 +236,13 @@ void ZRootsIterator::do_system_dictionary(ZRootsIteratorClosure* cl) {
|
||||
void ZRootsIterator::do_threads(ZRootsIteratorClosure* cl) {
|
||||
ZStatTimer timer(ZSubPhasePauseRootsThreads);
|
||||
ResourceMark rm;
|
||||
Threads::possibly_parallel_threads_do(true, cl);
|
||||
ZRootsIteratorThreadClosure thread_cl(cl);
|
||||
Threads::possibly_parallel_threads_do(true, &thread_cl);
|
||||
}
|
||||
|
||||
void ZRootsIterator::do_code_cache(ZRootsIteratorClosure* cl) {
|
||||
ZStatTimer timer(ZSubPhasePauseRootsCodeCache);
|
||||
ZNMethodTable::oops_do(cl);
|
||||
ZNMethod::oops_do(cl);
|
||||
}
|
||||
|
||||
void ZRootsIterator::oops_do(ZRootsIteratorClosure* cl, bool visit_jvmti_weak_export) {
|
||||
|
@ -31,9 +31,9 @@
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class ZRootsIteratorClosure : public OopClosure, public ThreadClosure {
|
||||
class ZRootsIteratorClosure : public OopClosure {
|
||||
public:
|
||||
virtual void do_thread(Thread* thread);
|
||||
virtual void do_thread(Thread* thread) {}
|
||||
};
|
||||
|
||||
typedef OopStorage::ParState<true /* concurrent */, false /* is_const */> ZOopStorageIterator;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -21,19 +21,23 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "gc/z/zStatTLAB.hpp"
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zAddress.inline.hpp"
|
||||
#include "gc/z/zThreadLocalAllocBuffer.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
|
||||
ZPerWorker<ThreadLocalAllocStats>* ZStatTLAB::_stats = NULL;
|
||||
ZPerWorker<ThreadLocalAllocStats>* ZThreadLocalAllocBuffer::_stats = NULL;
|
||||
|
||||
void ZStatTLAB::initialize() {
|
||||
void ZThreadLocalAllocBuffer::initialize() {
|
||||
if (UseTLAB) {
|
||||
assert(_stats == NULL, "Already initialized");
|
||||
_stats = new ZPerWorker<ThreadLocalAllocStats>();
|
||||
reset();
|
||||
reset_statistics();
|
||||
}
|
||||
}
|
||||
|
||||
void ZStatTLAB::reset() {
|
||||
void ZThreadLocalAllocBuffer::reset_statistics() {
|
||||
if (UseTLAB) {
|
||||
ZPerWorkerIterator<ThreadLocalAllocStats> iter(_stats);
|
||||
for (ThreadLocalAllocStats* stats; iter.next(&stats);) {
|
||||
@ -42,15 +46,7 @@ void ZStatTLAB::reset() {
|
||||
}
|
||||
}
|
||||
|
||||
ThreadLocalAllocStats* ZStatTLAB::get() {
|
||||
if (UseTLAB) {
|
||||
return _stats->addr();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ZStatTLAB::publish() {
|
||||
void ZThreadLocalAllocBuffer::publish_statistics() {
|
||||
if (UseTLAB) {
|
||||
ThreadLocalAllocStats total;
|
||||
|
||||
@ -62,3 +58,22 @@ void ZStatTLAB::publish() {
|
||||
total.publish();
|
||||
}
|
||||
}
|
||||
|
||||
static void fixup_address(HeapWord** p) {
|
||||
*p = (HeapWord*)ZAddress::good_or_null((uintptr_t)*p);
|
||||
}
|
||||
|
||||
void ZThreadLocalAllocBuffer::retire(Thread* thread) {
|
||||
if (UseTLAB && thread->is_Java_thread()) {
|
||||
ThreadLocalAllocStats* const stats = _stats->addr();
|
||||
thread->tlab().addresses_do(fixup_address);
|
||||
thread->tlab().retire(stats);
|
||||
thread->tlab().resize();
|
||||
}
|
||||
}
|
||||
|
||||
void ZThreadLocalAllocBuffer::remap(Thread* thread) {
|
||||
if (UseTLAB && thread->is_Java_thread()) {
|
||||
thread->tlab().addresses_do(fixup_address);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -21,22 +21,25 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_Z_ZSTATTLAB_HPP
|
||||
#define SHARE_GC_Z_ZSTATTLAB_HPP
|
||||
#ifndef SHARE_GC_Z_ZTHREADLOCALALLOCBUFFER_HPP
|
||||
#define SHARE_GC_Z_ZTHREADLOCALALLOCBUFFER_HPP
|
||||
|
||||
#include "gc/shared/threadLocalAllocBuffer.hpp"
|
||||
#include "gc/z/zValue.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class ZStatTLAB : public AllStatic {
|
||||
class ZThreadLocalAllocBuffer : public AllStatic {
|
||||
private:
|
||||
static ZPerWorker<ThreadLocalAllocStats>* _stats;
|
||||
|
||||
public:
|
||||
static void initialize();
|
||||
static void reset();
|
||||
static ThreadLocalAllocStats* get();
|
||||
static void publish();
|
||||
|
||||
static void reset_statistics();
|
||||
static void publish_statistics();
|
||||
|
||||
static void retire(Thread* thread);
|
||||
static void remap(Thread* thread);
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_Z_ZSTATTLAB_HPP
|
||||
#endif // SHARE_GC_Z_ZTHREADLOCALALLOCBUFFER_HPP
|
@ -30,7 +30,7 @@
|
||||
#include "gc/shared/gcBehaviours.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "gc/z/zLock.inline.hpp"
|
||||
#include "gc/z/zNMethodTable.hpp"
|
||||
#include "gc/z/zNMethod.hpp"
|
||||
#include "gc/z/zOopClosures.hpp"
|
||||
#include "gc/z/zStat.hpp"
|
||||
#include "gc/z/zUnload.hpp"
|
||||
@ -75,7 +75,7 @@ private:
|
||||
public:
|
||||
virtual bool is_unloading(CompiledMethod* method) const {
|
||||
nmethod* const nm = method->as_nmethod();
|
||||
ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm);
|
||||
ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm);
|
||||
if (lock == NULL) {
|
||||
return is_unloading(nm);
|
||||
} else {
|
||||
@ -89,7 +89,7 @@ class ZCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour {
|
||||
public:
|
||||
virtual bool lock(CompiledMethod* method) {
|
||||
nmethod* const nm = method->as_nmethod();
|
||||
ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm);
|
||||
ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm);
|
||||
if (lock != NULL) {
|
||||
lock->lock();
|
||||
}
|
||||
@ -98,7 +98,7 @@ public:
|
||||
|
||||
virtual void unlock(CompiledMethod* method) {
|
||||
nmethod* const nm = method->as_nmethod();
|
||||
ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm);
|
||||
ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm);
|
||||
if (lock != NULL) {
|
||||
lock->unlock();
|
||||
}
|
||||
@ -110,7 +110,7 @@ public:
|
||||
}
|
||||
|
||||
nmethod* const nm = method->as_nmethod();
|
||||
ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm);
|
||||
ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm);
|
||||
return lock == NULL || lock->is_owned();
|
||||
}
|
||||
};
|
||||
@ -149,7 +149,7 @@ void ZUnload::unlink() {
|
||||
|
||||
Klass::clean_weak_klass_links(unloading_occurred);
|
||||
|
||||
ZNMethodTable::unlink(_workers, unloading_occurred);
|
||||
ZNMethod::unlink(_workers, unloading_occurred);
|
||||
|
||||
DependencyContext::cleaning_end();
|
||||
}
|
||||
@ -157,7 +157,7 @@ void ZUnload::unlink() {
|
||||
void ZUnload::purge() {
|
||||
{
|
||||
SuspendibleThreadSetJoiner sts;
|
||||
ZNMethodTable::purge(_workers);
|
||||
ZNMethod::purge(_workers);
|
||||
}
|
||||
|
||||
ClassLoaderDataGraph::purge();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user