Compare commits
98 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f0d089b25 | |||
| 764e83c46c | |||
| 92e236a361 | |||
| 4d812a6486 | |||
| f3cf3e2036 | |||
| 9139138393 | |||
| efd8ae1047 | |||
| 079d77cc05 | |||
| 0d2320aea2 | |||
| f5a59340d9 | |||
| c328739ac0 | |||
| 134c07f4fa | |||
| 3eefd7ab1b | |||
| 858880932a | |||
| 4555cf2137 | |||
| 1d3c7e247c | |||
| 5962e8294d | |||
| 5eaf42f6da | |||
| 3ef007ac23 | |||
| 157c49276b | |||
| 88521b3587 | |||
| 3d47518697 | |||
| 2749a4c0b4 | |||
| 982afa5d48 | |||
| 16bf2730aa | |||
| 782b49e89e | |||
| 88dfb74bbe | |||
| a0d9b0affd | |||
| 9646856512 | |||
| aa0fbef91a | |||
| 993f7b35cf | |||
| 844f1fea58 | |||
| 3efdba901c | |||
| 4771360c9b | |||
| f9ee545b2e | |||
| bc6d4fd10d | |||
| 1f74b50bfa | |||
| b8207347b8 | |||
| 66a0483a94 | |||
| 5a912628cd | |||
| 740621f198 | |||
| 0ffccaa083 | |||
| 34dda4ecd8 | |||
| 0a2e196bea | |||
| 3b1f2030f2 | |||
| 48c84947b9 | |||
| d426d66b5e | |||
| b86a56e118 | |||
| e102078b9f | |||
| 70ca4da98e | |||
| b545bc4e05 | |||
| ebce9ef9e7 | |||
| 910c71ce2f | |||
| 86d80bd392 | |||
| 8b81f8fbb8 | |||
| e1502b52f0 | |||
| 714b4f6bfd | |||
| 75984f1302 | |||
| 4d4c0b4f41 | |||
| 241381ba70 | |||
| 7be42518fe | |||
| 660d0aae3d | |||
| ade47e8030 | |||
| 911e50be4c | |||
| 1abe579042 | |||
| 8a73ccfa9c | |||
| 1604ad70cc | |||
| 99ece546ab | |||
| 39392a489e | |||
| dcc4ac85d0 | |||
| b1467bd6af | |||
| 80133d4dc7 | |||
| 21c05fd3dd | |||
| dbbfbc5f59 | |||
| 1c5eca05ee | |||
| 52854620e4 | |||
| e9157bb2d5 | |||
| be0f370e5b | |||
| cc939a54f1 | |||
| 94a288ae65 | |||
| 0afbe386ec | |||
| 652063d7ba | |||
| 3ae762db82 | |||
| 63ee524331 | |||
| b340e037e8 | |||
| bc674c21af | |||
| 77e09a3d6d | |||
| 1c3df50209 | |||
| f332e84d9b | |||
| 7fd3f27741 | |||
| b4a43ca56d | |||
| 1f1f460b3f | |||
| edc9c7f08c | |||
| 1a0ce5d6f4 | |||
| 5c1ff40e29 | |||
| da75a9c979 | |||
| 0239ef4597 | |||
| 4061f762d8 |
+16
-5
@@ -146,6 +146,7 @@ Performance</a>
|
||||
<li><a href="#virus-checking" id="toc-virus-checking">Virus
|
||||
Checking</a></li>
|
||||
<li><a href="#ccache" id="toc-ccache">Ccache</a></li>
|
||||
<li><a href="#sccache" id="toc-sccache">Sccache</a></li>
|
||||
<li><a href="#precompiled-headers"
|
||||
id="toc-precompiled-headers">Precompiled Headers</a></li>
|
||||
<li><a href="#icecc-icecream" id="toc-icecc-icecream">Icecc /
|
||||
@@ -365,11 +366,13 @@ free disk space is required.</p>
|
||||
also possible to use <a href="#cross-compiling">cross-compiling</a>.</p>
|
||||
<h4 id="branch-protection">Branch Protection</h4>
|
||||
<p>In order to use Branch Protection features in the VM,
|
||||
<code>--enable-branch-protection</code> must be used. This option
|
||||
requires C++ compiler support (GCC 9.1.0+ or Clang 10+). The resulting
|
||||
build can be run on both machines with and without support for branch
|
||||
protection in hardware. Branch Protection is only supported for Linux
|
||||
targets.</p>
|
||||
<code>--enable-branch-protection</code> must be used. This option requires C++
|
||||
compiler support for <code>-mbranch-protection=standard</code> in GCC 9.1.0+ or
|
||||
Clang 10+ on Linux/AArch64 or for <code>/guard:signret</code> in Visual Studio
|
||||
2019+ on Windows/ARM64. The resulting build can be run on both machines with and
|
||||
without support for branch protection in hardware. Branch Protection is fully
|
||||
supported for the Linux/AArch64 target and only partially supported for the
|
||||
Windows/ARM64 targets.</p>
|
||||
<h3 id="building-on-32-bit-arm">Building on 32-bit ARM</h3>
|
||||
<p>This is not recommended. Instead, see the section on <a
|
||||
href="#cross-compiling">Cross-compiling</a>.</p>
|
||||
@@ -1814,6 +1817,14 @@ Using ccache can radically speed up compilation of native code if you
|
||||
often rebuild the same sources. Your mileage may vary however, so we
|
||||
recommend evaluating it for yourself. To enable it, make sure it's on
|
||||
the path and configure with <code>--enable-ccache</code>.</p>
|
||||
<h3 id="sccache">Sccache</h3>
|
||||
<p>The JDK build supports building with sccache when using gcc, clang, or
|
||||
Microsoft toolchains. To enable it, make sure the sccache binary is on the path
|
||||
(or specify the path to the binary using the <code>SCCACHE</code> argument to
|
||||
the configure script) and configure with <code>--enable-sccache</code>. To
|
||||
optionally specify where sccache stores its cache files, use
|
||||
<code>--with-sccache-dir</code>. Precompiled headers are disabled when sccache
|
||||
is enabled.</p>
|
||||
<h3 id="precompiled-headers">Precompiled Headers</h3>
|
||||
<p>By default, the Hotspot build uses pre-compiled headers (PCH) on the
|
||||
toolchains were it is properly supported (clang, gcc, and Visual
|
||||
|
||||
+14
-3
@@ -171,9 +171,11 @@ possible to use [cross-compiling](#cross-compiling).
|
||||
|
||||
In order to use Branch Protection features in the VM,
|
||||
`--enable-branch-protection` must be used. This option requires C++ compiler
|
||||
support (GCC 9.1.0+ or Clang 10+). The resulting build can be run on both
|
||||
machines with and without support for branch protection in hardware. Branch
|
||||
Protection is only supported for Linux targets.
|
||||
support for `-mbranch-protection=standard` in GCC 9.1.0+ or Clang 10+ on
|
||||
Linux/AArch64 or for `/guard:signret` in Visual Studio 2019+ on Windows/ARM64.
|
||||
The resulting build can be run on both machines with and without support for
|
||||
branch protection in hardware. Branch Protection is fully supported for the
|
||||
Linux/AArch64 target and only partially supported for the Windows/ARM64 target.
|
||||
|
||||
### Building on 32-bit ARM
|
||||
|
||||
@@ -1555,6 +1557,15 @@ the same sources. Your mileage may vary however, so we recommend evaluating it
|
||||
for yourself. To enable it, make sure it's on the path and configure with
|
||||
`--enable-ccache`.
|
||||
|
||||
### Sccache
|
||||
|
||||
The JDK build supports building with sccache when using gcc, clang, or Microsoft
|
||||
toolchains. To enable it, make sure the sccache binary is on the path (or
|
||||
specify the path to the binary using the `SCCACHE` argument to the configure
|
||||
script) and configure with `--enable-sccache`. To optionally specify where
|
||||
sccache stores its cache files, use `--with-sccache-dir`. Precompiled headers
|
||||
are disabled when sccache is enabled.
|
||||
|
||||
### Precompiled Headers
|
||||
|
||||
By default, the Hotspot build uses pre-compiled headers (PCH) on the toolchains
|
||||
|
||||
+5
-1
@@ -1420,6 +1420,9 @@ clean: $(CLEAN_DIR_TARGETS)
|
||||
clean-docs:
|
||||
$(call CleanDocs)
|
||||
|
||||
clean-microbenchmark:
|
||||
$(call CleanMicrobenchmark)
|
||||
|
||||
clean-compile-commands:
|
||||
$(call CleanMakeSupportDir,compile-commands)
|
||||
|
||||
@@ -1468,7 +1471,8 @@ dist-clean: clean
|
||||
)
|
||||
$(ECHO) Cleaned everything, you will have to re-run configure.
|
||||
|
||||
ALL_TARGETS += clean clean-docs clean-compile-commands dist-clean $(CLEAN_DIR_TARGETS) \
|
||||
ALL_TARGETS += clean clean-docs clean-microbenchmark clean-compile-commands \
|
||||
dist-clean $(CLEAN_DIR_TARGETS) \
|
||||
$(CLEAN_SUPPORT_DIR_TARGETS) $(CLEAN_TEST_TARGETS) $(CLEAN_PHASE_TARGETS) \
|
||||
$(CLEAN_MODULE_TARGETS) $(CLEAN_MODULE_PHASE_TARGETS)
|
||||
|
||||
|
||||
@@ -65,6 +65,14 @@ define CleanDocs
|
||||
@$(ECHO) " done"
|
||||
endef
|
||||
|
||||
define CleanMicrobenchmark
|
||||
@$(PRINTF) "Cleaning microbenchmark build artifacts ..."
|
||||
@$(ECHO) "" $(LOG_DEBUG)
|
||||
$(RM) -r $(SUPPORT_OUTPUTDIR)/test/micro
|
||||
$(RM) -r $(TEST_IMAGE_DIR)/micro
|
||||
@$(ECHO) " done"
|
||||
endef
|
||||
|
||||
# Cleans the dir given as $1
|
||||
define CleanDir
|
||||
@$(PRINTF) "Cleaning %s build artifacts ..." "$(strip $1)"
|
||||
|
||||
@@ -252,6 +252,109 @@ AC_DEFUN([BPERF_SETUP_CCACHE_USAGE],
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([BPERF_SETUP_SCCACHE],
|
||||
[
|
||||
# Check if sccache is available
|
||||
SCCACHE_AVAILABLE=true
|
||||
|
||||
UTIL_LOOKUP_TOOLCHAIN_PROGS(SCCACHE, sccache)
|
||||
|
||||
AC_MSG_CHECKING([if sccache is available])
|
||||
if test "x$TOOLCHAIN_TYPE" != "xgcc" && test "x$TOOLCHAIN_TYPE" != "xclang" && \
|
||||
test "x$TOOLCHAIN_TYPE" != "xmicrosoft"; then
|
||||
AC_MSG_RESULT([no, not supported for toolchain type $TOOLCHAIN_TYPE])
|
||||
SCCACHE_AVAILABLE=false
|
||||
elif test "x$SCCACHE" = "x"; then
|
||||
AC_MSG_RESULT([no, sccache binary missing or not executable])
|
||||
SCCACHE_AVAILABLE=false
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
|
||||
SCCACHE_STATUS=""
|
||||
UTIL_ARG_ENABLE(NAME: sccache, DEFAULT: false, AVAILABLE: $SCCACHE_AVAILABLE,
|
||||
DESC: [enable using sccache to speed up recompilations],
|
||||
CHECKING_MSG: [if sccache is enabled],
|
||||
IF_ENABLED: [
|
||||
if test "x$CCACHE" != x; then
|
||||
AC_MSG_ERROR([Cannot enable both ccache and sccache])
|
||||
fi
|
||||
# Versions of sccache before 0.10.0 can restore stale or incorrect
|
||||
# dependency files for cached C/C++ compilations, breaking our build.
|
||||
SCCACHE_VERSION=[`$SCCACHE --version | head -n1 | $CUT -d " " -f 2 | $TR -d '\r'`]
|
||||
if test "x$SCCACHE_VERSION" = x; then
|
||||
AC_MSG_ERROR([Could not determine sccache version])
|
||||
fi
|
||||
HAS_BAD_SCCACHE=[`$ECHO $SCCACHE_VERSION | \
|
||||
$GREP -e '^0\.[0-9]\.' -e '^0\.[0-9]$'`]
|
||||
if test "x$HAS_BAD_SCCACHE" != "x"; then
|
||||
AC_MSG_ERROR([[sccache 0.10.0 or later is required, found $SCCACHE_VERSION]])
|
||||
fi
|
||||
SCCACHE_STATUS="Active ($SCCACHE_VERSION)"
|
||||
],
|
||||
IF_DISABLED: [
|
||||
SCCACHE=""
|
||||
])
|
||||
AC_SUBST(SCCACHE)
|
||||
|
||||
AC_ARG_WITH([sccache-dir],
|
||||
[AS_HELP_STRING([--with-sccache-dir],
|
||||
[where to store sccache files @<:@~/.cache/sccache@:>@])])
|
||||
|
||||
if test "x$with_sccache_dir" != x; then
|
||||
SCCACHE_DIR="$with_sccache_dir"
|
||||
SCCACHE_DIR_FOR_SCCACHE="$SCCACHE_DIR"
|
||||
|
||||
# Ideally, we'd use `UTIL_FIXUP_PATH()`, but it expects the supplied path to
|
||||
# already exist, which might not be true for the sccache directory during
|
||||
# the configure step. As a workaround, we manually invoke fixpath.sh.
|
||||
if test "x$OPENJDK_BUILD_OS" = "xwindows"; then
|
||||
SCCACHE_DIR_FOR_SCCACHE=`$FIXPATH_BASE -m print "$SCCACHE_DIR_FOR_SCCACHE"`
|
||||
fi
|
||||
|
||||
SET_SCCACHE_DIR="SCCACHE_DIR=$SCCACHE_DIR_FOR_SCCACHE"
|
||||
if test "x$SCCACHE" = x; then
|
||||
AC_MSG_WARN([--with-sccache-dir has no meaning when sccache is not enabled])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$SCCACHE" != x; then
|
||||
BPERF_SETUP_SCCACHE_USAGE
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([BPERF_SETUP_SCCACHE_USAGE],
|
||||
[
|
||||
if test "x$SCCACHE" != x; then
|
||||
if test "x$USE_PRECOMPILED_HEADER" = "xtrue"; then
|
||||
if test "x$PRECOMPILED_HEADERS_EXPLICITLY_SET" = "xtrue"; then
|
||||
AC_MSG_ERROR([Cannot use sccache with precompiled headers. Use --disable-precompiled-headers.])
|
||||
else
|
||||
AC_MSG_NOTICE([Disabling precompiled headers because sccache is enabled])
|
||||
USE_PRECOMPILED_HEADER=false
|
||||
fi
|
||||
fi
|
||||
|
||||
# On Windows, the sccache binary must be launched through fixpath and the
|
||||
# compiler argument passed to sccache must be the actual compiler
|
||||
# (gcc/clang/cl) and not another fixpath invocation, otherwise sccache will
|
||||
# try to execute fixpath as the compiler.
|
||||
[ if [[ "$OPENJDK_BUILD_OS" = "windows" && "$SCCACHE" =~ ^"$FIXPATH " ]]; then ]
|
||||
[ if [[ "$CC" =~ ^"$FIXPATH " ]]; then ]
|
||||
CC="${CC#"$FIXPATH "}"
|
||||
[ fi ]
|
||||
[ if [[ "$CXX" =~ ^"$FIXPATH " ]]; then ]
|
||||
CXX="${CXX#"$FIXPATH "}"
|
||||
[ fi ]
|
||||
[ fi ]
|
||||
|
||||
if test "x$SET_SCCACHE_DIR" != x; then
|
||||
SCCACHE="$SET_SCCACHE_DIR $SCCACHE"
|
||||
mkdir -p "$SCCACHE_DIR" > /dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Runs icecc-create-env once and prints the error if it fails
|
||||
@@ -372,7 +475,13 @@ AC_DEFUN_ONCE([BPERF_SETUP_PRECOMPILED_HEADERS],
|
||||
|
||||
UTIL_ARG_ENABLE(NAME: precompiled-headers, DEFAULT: auto,
|
||||
RESULT: USE_PRECOMPILED_HEADER, AVAILABLE: $PRECOMPILED_HEADERS_AVAILABLE,
|
||||
DESC: [enable using precompiled headers when compiling C++])
|
||||
DESC: [enable using precompiled headers when compiling C++],
|
||||
IF_GIVEN: [
|
||||
PRECOMPILED_HEADERS_EXPLICITLY_SET=true
|
||||
],
|
||||
IF_NOT_GIVEN: [
|
||||
PRECOMPILED_HEADERS_EXPLICITLY_SET=false
|
||||
])
|
||||
AC_SUBST(USE_PRECOMPILED_HEADER)
|
||||
])
|
||||
|
||||
|
||||
@@ -293,6 +293,9 @@ BPERF_SETUP_PRECOMPILED_HEADERS
|
||||
# Setup use of ccache, if available
|
||||
BPERF_SETUP_CCACHE
|
||||
|
||||
# Setup use of sccache, if available
|
||||
BPERF_SETUP_SCCACHE
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# And now the finish...
|
||||
|
||||
@@ -945,11 +945,21 @@ AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
|
||||
[
|
||||
# Is branch protection available?
|
||||
BRANCH_PROTECTION_AVAILABLE=false
|
||||
BRANCH_PROTECTION_FLAG="-mbranch-protection=standard"
|
||||
BRANCH_PROTECTION_CFLAG=""
|
||||
BRANCH_PROTECTION_ASFLAG=""
|
||||
|
||||
if test "x$OPENJDK_TARGET_CPU" = xaarch64; then
|
||||
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$BRANCH_PROTECTION_FLAG],
|
||||
BRANCH_PROTECTION_CFLAG="-mbranch-protection=standard"
|
||||
# The GCC/Clang assembler accepts the same flag as the compiler.
|
||||
BRANCH_PROTECTION_ASFLAG="$BRANCH_PROTECTION_CFLAG"
|
||||
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$BRANCH_PROTECTION_CFLAG],
|
||||
IF_TRUE: [BRANCH_PROTECTION_AVAILABLE=true])
|
||||
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
BRANCH_PROTECTION_CFLAG="/guard:signret"
|
||||
# MSVC's assembler does not support branch protection flags, so
|
||||
# BRANCH_PROTECTION_ASFLAG is intentionally left empty.
|
||||
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$BRANCH_PROTECTION_CFLAG],
|
||||
IF_TRUE: [BRANCH_PROTECTION_AVAILABLE=true])
|
||||
fi
|
||||
fi
|
||||
@@ -957,5 +967,5 @@ AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
|
||||
UTIL_ARG_ENABLE(NAME: branch-protection, DEFAULT: false,
|
||||
RESULT: BRANCH_PROTECTION_ENABLED, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE,
|
||||
DESC: [enable branch protection when compiling C/C++],
|
||||
IF_ENABLED: [BRANCH_PROTECTION_CFLAGS=$BRANCH_PROTECTION_FLAG])
|
||||
IF_ENABLED: [BRANCH_PROTECTION_CFLAGS=$BRANCH_PROTECTION_CFLAG])
|
||||
])
|
||||
|
||||
@@ -211,7 +211,7 @@ AC_DEFUN([FLAGS_SETUP_ASFLAGS_CPU_DEP],
|
||||
fi
|
||||
|
||||
if test "x$BRANCH_PROTECTION_ENABLED" = "xtrue"; then
|
||||
$2JVM_ASFLAGS="${$2JVM_ASFLAGS} $BRANCH_PROTECTION_FLAG"
|
||||
$2JVM_ASFLAGS="${$2JVM_ASFLAGS} $BRANCH_PROTECTION_ASFLAG"
|
||||
fi
|
||||
|
||||
AC_SUBST($2JVM_ASFLAGS)
|
||||
|
||||
@@ -335,6 +335,9 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS],
|
||||
if test "x$CCACHE_STATUS" != "x"; then
|
||||
$ECHO "* ccache status: $CCACHE_STATUS"
|
||||
fi
|
||||
if test "x$SCCACHE_STATUS" != "x"; then
|
||||
$ECHO "* sccache status: $SCCACHE_STATUS"
|
||||
fi
|
||||
$ECHO ""
|
||||
|
||||
if test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = "xtrue"; then
|
||||
|
||||
@@ -545,7 +545,7 @@ ADLC_LANGSTD_CXXFLAGS := @ADLC_LANGSTD_CXXFLAGS@
|
||||
ADLC_LDFLAGS := @ADLC_LDFLAGS@
|
||||
|
||||
# Tools that potentially need to be cross compilation aware.
|
||||
CC := @CCACHE@ @ICECC@ @CC@
|
||||
CC := @SCCACHE@ @CCACHE@ @ICECC@ @CC@
|
||||
|
||||
# CFLAGS used to compile the jdk native libraries (C-code)
|
||||
CFLAGS_JDKLIB := @CFLAGS_JDKLIB@
|
||||
@@ -571,7 +571,7 @@ EXTRA_CXXFLAGS := @EXTRA_CXXFLAGS@
|
||||
EXTRA_LDFLAGS := @EXTRA_LDFLAGS@
|
||||
EXTRA_ASFLAGS := @EXTRA_ASFLAGS@
|
||||
|
||||
CXX := @CCACHE@ @ICECC@ @CXX@
|
||||
CXX := @SCCACHE@ @CCACHE@ @ICECC@ @CXX@
|
||||
|
||||
CPP := @CPP@
|
||||
|
||||
@@ -740,6 +740,7 @@ RCFLAGS := @RCFLAGS@
|
||||
AWK := @AWK@
|
||||
BASENAME := @BASENAME@
|
||||
CAT := @CAT@
|
||||
SCCACHE := @SCCACHE@
|
||||
CCACHE := @CCACHE@
|
||||
# CD is going away, but remains to cater for legacy makefiles.
|
||||
CD := cd
|
||||
|
||||
@@ -148,8 +148,8 @@ endef
|
||||
# BIN store classes here
|
||||
# MODULE Name of module being compiled. If set, classes are put in BIN/MODULE.
|
||||
# CLASSPATH a list of additional entries to set as classpath to javac
|
||||
# INCLUDES myapp.foo means will only compile java files in myapp.foo or any of its sub-packages.
|
||||
# EXCLUDES myapp.foo means will do not compile java files in myapp.foo or any of its sub-packages.
|
||||
# INCLUDES myapp/foo means will only compile java files in myapp.foo or any of its sub-packages.
|
||||
# EXCLUDES myapp/foo means will do not compile java files in myapp.foo or any of its sub-packages.
|
||||
# COPY .prp means copy all prp files to the corresponding package in BIN.
|
||||
# COPY_FILES myapp/foo/setting.txt means copy this file over to the package myapp/foo
|
||||
# CLEAN .properties means copy and clean all properties file to the corresponding package in BIN.
|
||||
|
||||
@@ -210,6 +210,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \
|
||||
DISABLED_WARNINGS_gcc_postaloc.cpp := address, \
|
||||
DISABLED_WARNINGS_gcc_safepointMechanism.cpp := stringop-overflow, \
|
||||
DISABLED_WARNINGS_gcc_shenandoahGenerationalHeap.cpp := stringop-overflow, \
|
||||
DISABLED_WARNINGS_gcc_shenandoahHeap.cpp := stringop-overflow, \
|
||||
DISABLED_WARNINGS_gcc_shenandoahLock.cpp := stringop-overflow, \
|
||||
DISABLED_WARNINGS_gcc_stubGenerator_s390.cpp := unused-const-variable, \
|
||||
DISABLED_WARNINGS_gcc_synchronizer.cpp := stringop-overflow, \
|
||||
|
||||
@@ -77,44 +77,74 @@ MICROBENCHMARK_MANIFEST := Build: $(FULL_VERSION)\n\
|
||||
# jmh uses annotation processors to generate the benchmark jar and thus
|
||||
# requires the use of -processor option during benchmark compilation.
|
||||
|
||||
MICROBENCHMARK_PREVIEW_PACKAGES := \
|
||||
org/openjdk/bench/valhalla \
|
||||
org/openjdk/bench/java/lang/stable
|
||||
|
||||
MICROBENCHMARK_JAVAC_FLAGS := \
|
||||
--add-exports java.base/jdk.internal.classfile.components=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.classfile.impl=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.event=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.jimage=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.util=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.value=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.vm.annotation=ALL-UNNAMED \
|
||||
--add-exports java.base/sun.invoke.util=ALL-UNNAMED \
|
||||
--add-exports java.base/sun.security.util=ALL-UNNAMED \
|
||||
--add-exports java.base/sun.security.util.math=ALL-UNNAMED \
|
||||
--add-exports java.base/sun.security.util.math.intpoly=ALL-UNNAMED \
|
||||
-XDsuppressNotes \
|
||||
-processor org.openjdk.jmh.generators.BenchmarkProcessor \
|
||||
-s $(MICROBENCHMARK_GENSRC)
|
||||
|
||||
# For code built with --enable-preview we need to patch java.base
|
||||
# to include preview classes not found in interim javac
|
||||
MICROBENCHMARK_JAVAC_PREVIEW_FLAGS := \
|
||||
$(MICROBENCHMARK_JAVAC_FLAGS) \
|
||||
--enable-preview \
|
||||
--patch-module java.base=$(SUPPORT_OUTPUTDIR)/preview/java.base
|
||||
|
||||
MICROBENCHMARK_JAVA_FLAGS := \
|
||||
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
|
||||
--add-modules jdk.unsupported \
|
||||
--limit-modules java.management
|
||||
|
||||
MICROBENCHMARK_DISABLED_WARNINGS := restricted this-escape processing \
|
||||
rawtypes removal cast serial preview unchecked deprecation \
|
||||
dangling-doc-comments
|
||||
|
||||
# Build microbenchmark suite for the current JDK
|
||||
# Need to patch java.base to include preview classes not found in interim javac
|
||||
$(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK_PREVIEW, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
|
||||
SMALL_JAVA := false, \
|
||||
CLASSPATH := $(JMH_COMPILE_JARS), \
|
||||
INCLUDES := $(MICROBENCHMARK_PREVIEW_PACKAGES), \
|
||||
CREATE_API_DIGEST := true, \
|
||||
DISABLED_WARNINGS := $(MICROBENCHMARK_DISABLED_WARNINGS), \
|
||||
SRC := $(MICROBENCHMARK_SRC), \
|
||||
BIN := $(MICROBENCHMARK_CLASSES), \
|
||||
JAVAC_FLAGS := $(MICROBENCHMARK_JAVAC_PREVIEW_FLAGS), \
|
||||
JAVA_FLAGS := $(MICROBENCHMARK_JAVA_FLAGS), \
|
||||
))
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
|
||||
SMALL_JAVA := false, \
|
||||
CLASSPATH := $(JMH_COMPILE_JARS), \
|
||||
CREATE_API_DIGEST := true, \
|
||||
DISABLED_WARNINGS := restricted this-escape processing rawtypes removal cast \
|
||||
serial preview unchecked deprecation dangling-doc-comments, \
|
||||
EXCLUDES := $(MICROBENCHMARK_PREVIEW_PACKAGES), \
|
||||
DISABLED_WARNINGS := $(MICROBENCHMARK_DISABLED_WARNINGS), \
|
||||
SRC := $(MICROBENCHMARK_SRC), \
|
||||
BIN := $(MICROBENCHMARK_CLASSES), \
|
||||
JAVAC_FLAGS := \
|
||||
--add-exports java.base/jdk.internal.classfile.components=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.classfile.impl=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.event=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.jimage=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.util=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.value=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.vm.annotation=ALL-UNNAMED \
|
||||
--add-exports java.base/sun.invoke.util=ALL-UNNAMED \
|
||||
--add-exports java.base/sun.security.util=ALL-UNNAMED \
|
||||
--add-exports java.base/sun.security.util.math=ALL-UNNAMED \
|
||||
--add-exports java.base/sun.security.util.math.intpoly=ALL-UNNAMED \
|
||||
--enable-preview \
|
||||
--patch-module java.base=$(SUPPORT_OUTPUTDIR)/preview/java.base \
|
||||
-XDsuppressNotes \
|
||||
-processor org.openjdk.jmh.generators.BenchmarkProcessor \
|
||||
-s $(MICROBENCHMARK_GENSRC), \
|
||||
JAVA_FLAGS := \
|
||||
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
|
||||
--add-modules jdk.unsupported \
|
||||
--enable-preview \
|
||||
--limit-modules java.management, \
|
||||
JAVAC_FLAGS := $(MICROBENCHMARK_JAVAC_FLAGS), \
|
||||
JAVA_FLAGS := $(MICROBENCHMARK_JAVA_FLAGS), \
|
||||
))
|
||||
|
||||
$(BUILD_JDK_MICROBENCHMARK_PREVIEW): $(JMH_COMPILE_JARS)
|
||||
|
||||
$(BUILD_JDK_MICROBENCHMARK): $(JMH_COMPILE_JARS)
|
||||
|
||||
# Unpacking dependencies for inclusion in the benchmark JARs
|
||||
@@ -139,12 +169,16 @@ $(eval $(call SetupCopyFiles, COPY_JAXP_TEST_XML, \
|
||||
|
||||
# Create benchmarks JAR file with benchmarks for both the old and new JDK
|
||||
$(eval $(call SetupJarArchive, BUILD_JDK_JAR, \
|
||||
DEPENDENCIES := $(BUILD_JDK_MICROBENCHMARK) $(JMH_UNPACKED_JARS_DONE) $(COPY_JAXP_TEST_XML), \
|
||||
DEPENDENCIES := $(BUILD_JDK_MICROBENCHMARK_PREVIEW) \
|
||||
$(BUILD_JDK_MICROBENCHMARK) $(JMH_UNPACKED_JARS_DONE) \
|
||||
$(COPY_JAXP_TEST_XML), \
|
||||
SRCS := $(MICROBENCHMARK_CLASSES) $(JMH_UNPACKED_DIR), \
|
||||
BIN := $(MICROBENCHMARK_JAR_BIN), \
|
||||
SUFFIXES := .*, \
|
||||
EXCLUDE_FILES := _the.BUILD_JDK_MICROBENCHMARK_batch \
|
||||
_the.BUILD_JDK_MICROBENCHMARK.vardeps _unpacked.marker, \
|
||||
_the.BUILD_JDK_MICROBENCHMARK.vardeps _unpacked.marker \
|
||||
_the.BUILD_JDK_MICROBENCHMARK_PREVIEW_batch \
|
||||
_the.BUILD_JDK_MICROBENCHMARK_PREVIEW.vardeps, \
|
||||
EXTRA_MANIFEST_ATTR := $(MICROBENCHMARK_MANIFEST), \
|
||||
JARMAIN := org.openjdk.jmh.Main, \
|
||||
JAR := $(MICROBENCHMARK_JAR), \
|
||||
|
||||
@@ -457,17 +457,18 @@ class Address {
|
||||
|
||||
Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type);
|
||||
|
||||
Address(Register base, RegisterOrConstant index, extend ext = lsl()) {
|
||||
Address(Register base, RegisterOrConstant index, extend ext = lsl(0)) {
|
||||
if (index.is_register()) {
|
||||
_mode = base_plus_offset_reg;
|
||||
new (&_nonliteral) Nonliteral(base, index.as_register(), 0, ext);
|
||||
} else {
|
||||
guarantee(ext.option() == ext::uxtx, "should be");
|
||||
assert(index.is_constant(), "should be");
|
||||
assert(ext.shift() == 0, "must be");
|
||||
_mode = base_plus_offset;
|
||||
new (&_nonliteral) Nonliteral(base,
|
||||
noreg,
|
||||
index.as_constant() << ext.shift());
|
||||
index.as_constant());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,10 +182,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register t1,
|
||||
// Finish fast lock unsuccessfully. MUST branch to with flag == NE
|
||||
Label slow_path;
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
str(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
str(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(t1, obj, rscratch2);
|
||||
@@ -245,60 +243,55 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register t1,
|
||||
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
|
||||
const ByteSize omc_obj_offset = OMCache::obj_offset();
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
assert(t1_monitor == t1_mark, "should be the same here");
|
||||
} else {
|
||||
const Register t1_hash = t1;
|
||||
Label monitor_found;
|
||||
const Register t1_hash = t1;
|
||||
Label monitor_found;
|
||||
|
||||
// Save the mark, we might need it to extract the hash.
|
||||
mov(t3, t1_mark);
|
||||
// Save the mark, we might need it to extract the hash.
|
||||
mov(t3, t1_mark);
|
||||
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
|
||||
ldr(t1_monitor, Address(rthread, thr_omc_offset + omc_monitor_offset));
|
||||
ldr(t2, Address(rthread, thr_omc_offset + omc_obj_offset));
|
||||
cmp(obj, t2);
|
||||
br(Assembler::EQ, monitor_found);
|
||||
ldr(t1_monitor, Address(rthread, thr_omc_offset + omc_monitor_offset));
|
||||
ldr(t2, Address(rthread, thr_omc_offset + omc_obj_offset));
|
||||
cmp(obj, t2);
|
||||
br(Assembler::EQ, monitor_found);
|
||||
|
||||
// Look for the monitor in the table.
|
||||
// Look for the monitor in the table.
|
||||
|
||||
// Get the hash code.
|
||||
ubfx(t1_hash, t3, markWord::hash_shift, markWord::hash_bits);
|
||||
// Get the hash code.
|
||||
ubfx(t1_hash, t3, markWord::hash_shift, markWord::hash_bits);
|
||||
|
||||
// Get the table and calculate the bucket's address
|
||||
lea(t3, ExternalAddress(ObjectMonitorTable::current_table_address()));
|
||||
ldr(t3, Address(t3));
|
||||
ldr(t2, Address(t3, ObjectMonitorTable::table_capacity_mask_offset()));
|
||||
ands(t1_hash, t1_hash, t2);
|
||||
ldr(t3, Address(t3, ObjectMonitorTable::table_buckets_offset()));
|
||||
// Get the table and calculate the bucket's address
|
||||
lea(t3, ExternalAddress(ObjectMonitorTable::current_table_address()));
|
||||
ldr(t3, Address(t3));
|
||||
ldr(t2, Address(t3, ObjectMonitorTable::table_capacity_mask_offset()));
|
||||
ands(t1_hash, t1_hash, t2);
|
||||
ldr(t3, Address(t3, ObjectMonitorTable::table_buckets_offset()));
|
||||
|
||||
// Read the monitor from the bucket.
|
||||
ldr(t1_monitor, Address(t3, t1_hash, Address::lsl(LogBytesPerWord)));
|
||||
// Read the monitor from the bucket.
|
||||
ldr(t1_monitor, Address(t3, t1_hash, Address::lsl(LogBytesPerWord)));
|
||||
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed).
|
||||
cmp(t1_monitor, (unsigned char)ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
br(Assembler::LO, slow_path);
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed).
|
||||
cmp(t1_monitor, (unsigned char)ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
br(Assembler::LO, slow_path);
|
||||
|
||||
// Check if object matches.
|
||||
ldr(t3, Address(t1_monitor, ObjectMonitor::object_offset()));
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, t3, t3, t2, slow_path);
|
||||
cmp(t3, obj);
|
||||
br(Assembler::NE, slow_path);
|
||||
// Check if object matches.
|
||||
ldr(t3, Address(t1_monitor, ObjectMonitor::object_offset()));
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, t3, t3, t2, slow_path);
|
||||
cmp(t3, obj);
|
||||
br(Assembler::NE, slow_path);
|
||||
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
str(t1_monitor, Address(rthread, thr_omc_offset + omc_monitor_offset));
|
||||
str(obj, Address(rthread, thr_omc_offset + omc_obj_offset));
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
str(t1_monitor, Address(rthread, thr_omc_offset + omc_monitor_offset));
|
||||
str(obj, Address(rthread, thr_omc_offset + omc_obj_offset));
|
||||
|
||||
bind(monitor_found);
|
||||
}
|
||||
bind(monitor_found);
|
||||
|
||||
const Register t2_owner_addr = t2;
|
||||
const Register t3_owner = t3;
|
||||
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
|
||||
const Address owner_address(t1_monitor, ObjectMonitor::owner_offset() - monitor_tag);
|
||||
const Address recursions_address(t1_monitor, ObjectMonitor::recursions_offset() - monitor_tag);
|
||||
const Address owner_address(t1_monitor, ObjectMonitor::owner_offset());
|
||||
const Address recursions_address(t1_monitor, ObjectMonitor::recursions_offset());
|
||||
|
||||
Label monitor_locked;
|
||||
|
||||
@@ -318,10 +311,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register t1,
|
||||
increment(recursions_address, 1);
|
||||
|
||||
bind(monitor_locked);
|
||||
if (UseObjectMonitorTable) {
|
||||
// Cache the monitor for unlock.
|
||||
str(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
}
|
||||
// Cache the monitor for unlock.
|
||||
str(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
}
|
||||
|
||||
bind(locked);
|
||||
@@ -388,7 +379,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box, Register t1,
|
||||
// Because we got here by popping (meaning we pushed in locked)
|
||||
// there will be no monitor in the box. So we need to push back the obj
|
||||
// so that the runtime can fix any potential anonymous owner.
|
||||
tbnz(t1_mark, exact_log2(markWord::monitor_value), UseObjectMonitorTable ? push_and_slow_path : inflated);
|
||||
tbnz(t1_mark, exact_log2(markWord::monitor_value), push_and_slow_path);
|
||||
|
||||
// Try to unlock. Transition lock bits 0b00 => 0b01
|
||||
assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea");
|
||||
@@ -430,17 +421,10 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box, Register t1,
|
||||
|
||||
const Register t1_monitor = t1;
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
assert(t1_monitor == t1_mark, "should be the same here");
|
||||
|
||||
// Untag the monitor.
|
||||
add(t1_monitor, t1_mark, -(int)markWord::monitor_value);
|
||||
} else {
|
||||
ldr(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
// null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
|
||||
cmp(t1_monitor, checked_cast<uint8_t>(alignof(ObjectMonitor*)));
|
||||
br(Assembler::LO, slow_path);
|
||||
}
|
||||
ldr(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
// null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
|
||||
cmp(t1_monitor, checked_cast<uint8_t>(alignof(ObjectMonitor*)));
|
||||
br(Assembler::LO, slow_path);
|
||||
|
||||
const Register t2_recursions = t2;
|
||||
Label not_recursive;
|
||||
@@ -3032,4 +3016,4 @@ void C2_MacroAssembler::sve_sdiv_short(FloatRegister dst_src1, FloatRegister src
|
||||
sve_sdiv(src1, S, ptrue, vtmp2);
|
||||
// Narrow the two INT result halves back to SHORT.
|
||||
sve_uzp1(dst_src1, H, vtmp1, src1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -805,8 +805,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
|
||||
}
|
||||
|
||||
bool frame::was_augmented_on_entry(int& real_size) const {
|
||||
assert(is_compiled_frame(), "");
|
||||
if (_cb->as_nmethod_or_null()->needs_stack_repair()) {
|
||||
assert(_cb != nullptr && _cb->is_nmethod(), "");
|
||||
if (_cb->as_nmethod()->needs_stack_repair()) {
|
||||
// The stack increment resides just below the saved FP on the stack and
|
||||
// records the total frame size excluding the two words for saving FP and LR
|
||||
// (see MacroAssembler::remove_frame).
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetAssembler.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
@@ -405,10 +406,22 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
|
||||
assert_different_registers(obj, tmp1, tmp2);
|
||||
// Check if the oop is in the right area of memory
|
||||
__ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
|
||||
__ ldr(tmp2, Address(tmp2));
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
|
||||
__ ldr(tmp2, Address(tmp2));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
}
|
||||
|
||||
// Compare tmp1 and tmp2. We don't use a compare
|
||||
// instruction here because the flags register is live.
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
|
||||
#include "gc/shenandoah/mode/shenandoahMode.hpp"
|
||||
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
|
||||
@@ -213,13 +214,16 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
|
||||
|
||||
// Test for in-cset
|
||||
if (is_strong) {
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ lea(rscratch2, ExternalAddress(AOTRuntimeConstants::cset_base_address()));
|
||||
__ ldr(rscratch2, Address(rscratch2));
|
||||
__ lea(rscratch1, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
|
||||
__ ldrw(rscratch1, Address(rscratch1));
|
||||
__ lsrv(rscratch1, r0, rscratch1);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ mov(rscratch2, ShenandoahHeap::in_cset_fast_test_addr());
|
||||
__ lsr(rscratch1, r0, ShenandoahHeapRegion::region_size_bytes_shift_jint());
|
||||
}
|
||||
@@ -421,11 +425,22 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) {
|
||||
assert_different_registers(obj, tmp1, tmp2);
|
||||
// Check if the oop is in the right area of memory
|
||||
__ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
|
||||
__ ldr(tmp2, Address(tmp2));
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
|
||||
__ ldr(tmp2, Address(tmp2));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
}
|
||||
// Compare tmp1 and tmp2. We don't use a compare
|
||||
// instruction here because the flags register is live.
|
||||
__ eor(tmp1, tmp1, tmp2);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "code/vmreg.inline.hpp"
|
||||
#include "gc/z/zAddress.hpp"
|
||||
@@ -1351,6 +1352,7 @@ void ZBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
|
||||
assert_different_registers(obj, tmp1, tmp2);
|
||||
// C1 calls verfy_oop in the middle of barriers, before they have been uncolored
|
||||
// and after being colored. Therefore, we must deal with colored oops as well.
|
||||
Label done;
|
||||
@@ -1390,9 +1392,20 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Registe
|
||||
|
||||
__ bind(check_zaddress);
|
||||
// Check if the oop is in the right area of memory
|
||||
__ mov(tmp1, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, tmp1, obj);
|
||||
__ mov(obj, (intptr_t) Universe::verify_oop_bits());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ lea(tmp1, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
|
||||
__ ldr(tmp1, Address(tmp1));
|
||||
__ andr(tmp1, tmp1, obj);
|
||||
__ lea(obj, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
|
||||
__ ldr(obj, Address(obj));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ mov(tmp1, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, tmp1, obj);
|
||||
__ mov(obj, (intptr_t) Universe::verify_oop_bits());
|
||||
}
|
||||
__ cmp(tmp1, obj);
|
||||
__ br(Assembler::NE, error);
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ define_pd_global(size_t, CodeCacheSegmentSize, 64);
|
||||
define_pd_global(uint, CodeEntryAlignment, 64);
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (2)
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (NOT_WINDOWS(2) WINDOWS_ONLY(3))
|
||||
#define DEFAULT_STACK_RED_PAGES (1)
|
||||
// Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the
|
||||
// stack if compiled for unix and LP64. To pass stack overflow tests we need
|
||||
|
||||
@@ -2025,7 +2025,15 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
ss.print("verify_oop: %s: %s (%s:%d)", reg->name(), s, file, line);
|
||||
b = code_string(ss.as_string());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
|
||||
// this will duplicate string to preserve it
|
||||
b = AOTCodeCache::add_C_string(ss.as_string());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
b = code_string(ss.as_string());
|
||||
}
|
||||
}
|
||||
BLOCK_COMMENT("verify_oop {");
|
||||
|
||||
@@ -2061,7 +2069,15 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
ss.print("verify_oop_addr: %s (%s:%d)", s, file, line);
|
||||
b = code_string(ss.as_string());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
|
||||
// this will duplicate string to preserve it
|
||||
b = AOTCodeCache::add_C_string(ss.as_string());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
b = code_string(ss.as_string());
|
||||
}
|
||||
}
|
||||
BLOCK_COMMENT("verify_oop_addr {");
|
||||
|
||||
@@ -2396,16 +2412,6 @@ void MacroAssembler::test_field_is_flat(Register flags, Register temp_reg, Label
|
||||
void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int32_t test_bit, bool jmp_set, Label& jmp_label) {
|
||||
// load mark word
|
||||
ldr(temp_reg, Address(oop, oopDesc::mark_offset_in_bytes()));
|
||||
if (!UseObjectMonitorTable) {
|
||||
Label test_mark_word;
|
||||
// check displaced
|
||||
tst(temp_reg, markWord::unlocked_value);
|
||||
br(Assembler::NE, test_mark_word);
|
||||
// slow path use klass prototype
|
||||
load_prototype_header(temp_reg, oop);
|
||||
|
||||
bind(test_mark_word);
|
||||
}
|
||||
andr(temp_reg, temp_reg, test_bit);
|
||||
if (jmp_set) {
|
||||
cbnz(temp_reg, jmp_label);
|
||||
@@ -7885,10 +7891,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register t1, R
|
||||
// instruction emitted as it is part of C1's null check semantics.
|
||||
ldr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
str(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
str(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(t1, obj, rscratch1);
|
||||
|
||||
@@ -505,8 +505,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
|
||||
}
|
||||
|
||||
bool frame::was_augmented_on_entry(int& real_size) const {
|
||||
assert(is_compiled_frame(), "");
|
||||
if (_cb->as_nmethod_or_null()->needs_stack_repair()) {
|
||||
assert(_cb != nullptr && _cb->is_nmethod(), "");
|
||||
if (_cb->as_nmethod()->needs_stack_repair()) {
|
||||
Unimplemented();
|
||||
}
|
||||
real_size = _cb->frame_size();
|
||||
|
||||
@@ -2450,7 +2450,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register tmp1,
|
||||
payload_address(value, value, tmp1, tmp2);
|
||||
|
||||
Register layout_info = field_offset;
|
||||
lbz(tmp1, in_bytes(ResolvedFieldEntry::field_index_offset()), entry);
|
||||
lhz(tmp1, in_bytes(ResolvedFieldEntry::field_index_offset()), entry);
|
||||
ld(tmp2, in_bytes(ResolvedFieldEntry::field_holder_offset()), entry);
|
||||
inline_layout_info(tmp2, tmp1, layout_info);
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->try_resolve_jobject_in_native(masm, Robj, R3_ARG1, R4_ARG2, Rtmp, slow);
|
||||
|
||||
__ srwi(Rtmp, R5_ARG3, jfieldIDWorkaround::offset_shift); // offset
|
||||
__ srdi(Rtmp, R5_ARG3, jfieldIDWorkaround::offset_shift); // offset
|
||||
|
||||
assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
|
||||
speculative_load_pclist[count] = __ pc(); // Used by the segfault handler
|
||||
|
||||
@@ -2688,7 +2688,6 @@ void MacroAssembler::tlab_allocate(
|
||||
void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register obj, Register box,
|
||||
Register tmp1, Register tmp2, Register tmp3) {
|
||||
assert_different_registers(obj, box, tmp1, tmp2, tmp3);
|
||||
assert(UseObjectMonitorTable || tmp3 == noreg, "tmp3 not needed");
|
||||
assert(flag == CR0, "bad condition register");
|
||||
|
||||
// Handle inflated monitor.
|
||||
@@ -2698,11 +2697,9 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
|
||||
// Finish fast lock unsuccessfully. MUST branch to with flag == EQ
|
||||
Label slow_path;
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
li(tmp1, 0);
|
||||
std(tmp1, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
li(tmp1, 0);
|
||||
std(tmp1, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(tmp1, obj);
|
||||
@@ -2760,9 +2757,9 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
|
||||
|
||||
// mark contains the tagged ObjectMonitor*.
|
||||
const uintptr_t monitor_tag = markWord::monitor_value;
|
||||
const Register monitor = UseObjectMonitorTable ? tmp1 : noreg;
|
||||
const Register monitor = tmp1;
|
||||
const Register owner_addr = tmp2;
|
||||
const Register thread_id = UseObjectMonitorTable ? tmp3 : tmp1;
|
||||
const Register thread_id = tmp3;
|
||||
// Offsets into the current thread's object monitor cache (omc).
|
||||
const ByteSize thr_omc_offset = JavaThread::om_cache_offset();
|
||||
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
|
||||
@@ -2770,61 +2767,55 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
|
||||
|
||||
Label monitor_locked;
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
// Compute owner address.
|
||||
addi(owner_addr, mark, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag);
|
||||
mark = noreg;
|
||||
} else {
|
||||
const Register tmp3_bucket = tmp3;
|
||||
const Register tmp2_hash = tmp2;
|
||||
Label monitor_found;
|
||||
const Register tmp3_bucket = tmp3;
|
||||
const Register tmp2_hash = tmp2;
|
||||
Label monitor_found;
|
||||
|
||||
// Save the mark, we might need it to extract the hash.
|
||||
mr(tmp2_hash, mark);
|
||||
// Save the mark, we might need it to extract the hash.
|
||||
mr(tmp2_hash, mark);
|
||||
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
|
||||
ld(R0, in_bytes(thr_omc_offset + omc_obj_offset), R16_thread);
|
||||
ld(monitor, in_bytes(thr_omc_offset + omc_monitor_offset), R16_thread);
|
||||
cmpd(CR0, R0, obj);
|
||||
beq(CR0, monitor_found);
|
||||
ld(R0, in_bytes(thr_omc_offset + omc_obj_offset), R16_thread);
|
||||
ld(monitor, in_bytes(thr_omc_offset + omc_monitor_offset), R16_thread);
|
||||
cmpd(CR0, R0, obj);
|
||||
beq(CR0, monitor_found);
|
||||
|
||||
// Look for the monitor in the table.
|
||||
// Look for the monitor in the table.
|
||||
|
||||
// Get the hash code.
|
||||
srdi(tmp2_hash, tmp2_hash, markWord::hash_shift);
|
||||
// Get the hash code.
|
||||
srdi(tmp2_hash, tmp2_hash, markWord::hash_shift);
|
||||
|
||||
// Get the table and calculate the bucket's address
|
||||
int simm16_rest = load_const_optimized(tmp3, ObjectMonitorTable::current_table_address(), R0, true);
|
||||
ld_ptr(tmp3, simm16_rest, tmp3);
|
||||
ld(tmp1, in_bytes(ObjectMonitorTable::table_capacity_mask_offset()), tmp3);
|
||||
andr(tmp2_hash, tmp2_hash, tmp1);
|
||||
ld(tmp3_bucket, in_bytes(ObjectMonitorTable::table_buckets_offset()), tmp3);
|
||||
// Get the table and calculate the bucket's address
|
||||
int simm16_rest = load_const_optimized(tmp3, ObjectMonitorTable::current_table_address(), R0, true);
|
||||
ld_ptr(tmp3, simm16_rest, tmp3);
|
||||
ld(tmp1, in_bytes(ObjectMonitorTable::table_capacity_mask_offset()), tmp3);
|
||||
andr(tmp2_hash, tmp2_hash, tmp1);
|
||||
ld(tmp3_bucket, in_bytes(ObjectMonitorTable::table_buckets_offset()), tmp3);
|
||||
|
||||
// Read the monitor from the bucket.
|
||||
sldi(tmp2_hash, tmp2_hash, LogBytesPerWord);
|
||||
ldx(monitor, tmp3_bucket, tmp2_hash);
|
||||
// Read the monitor from the bucket.
|
||||
sldi(tmp2_hash, tmp2_hash, LogBytesPerWord);
|
||||
ldx(monitor, tmp3_bucket, tmp2_hash);
|
||||
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed).
|
||||
cmpldi(CR0, monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
blt(CR0, slow_path);
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed).
|
||||
cmpldi(CR0, monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
blt(CR0, slow_path);
|
||||
|
||||
// Check if object matches.
|
||||
ld(tmp3, in_bytes(ObjectMonitor::object_offset()), monitor);
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp3, tmp3, tmp2, slow_path);
|
||||
cmpd(CR0, tmp3, obj);
|
||||
bne(CR0, slow_path);
|
||||
// Check if object matches.
|
||||
ld(tmp3, in_bytes(ObjectMonitor::object_offset()), monitor);
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp3, tmp3, tmp2, slow_path);
|
||||
cmpd(CR0, tmp3, obj);
|
||||
bne(CR0, slow_path);
|
||||
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
std(monitor, in_bytes(thr_omc_offset + omc_monitor_offset), R16_thread);
|
||||
std(obj, in_bytes(thr_omc_offset + omc_obj_offset), R16_thread);
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
std(monitor, in_bytes(thr_omc_offset + omc_monitor_offset), R16_thread);
|
||||
std(obj, in_bytes(thr_omc_offset + omc_obj_offset), R16_thread);
|
||||
|
||||
bind(monitor_found);
|
||||
bind(monitor_found);
|
||||
|
||||
// Compute owner address.
|
||||
addi(owner_addr, monitor, in_bytes(ObjectMonitor::owner_offset()));
|
||||
}
|
||||
// Compute owner address.
|
||||
addi(owner_addr, monitor, in_bytes(ObjectMonitor::owner_offset()));
|
||||
|
||||
// Try to CAS owner (no owner => current thread's _monitor_owner_id).
|
||||
assert_different_registers(thread_id, monitor, owner_addr, box, R0);
|
||||
@@ -2843,23 +2834,14 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
|
||||
bne(CR0, slow_path);
|
||||
|
||||
// Recursive.
|
||||
if (!UseObjectMonitorTable) {
|
||||
assert_different_registers(tmp1, owner_addr);
|
||||
ld(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr);
|
||||
addi(tmp1, tmp1, 1);
|
||||
std(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr);
|
||||
} else {
|
||||
assert_different_registers(tmp2, monitor);
|
||||
ld(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
|
||||
addi(tmp2, tmp2, 1);
|
||||
std(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
|
||||
}
|
||||
assert_different_registers(tmp2, monitor);
|
||||
ld(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
|
||||
addi(tmp2, tmp2, 1);
|
||||
std(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
|
||||
|
||||
bind(monitor_locked);
|
||||
if (UseObjectMonitorTable) {
|
||||
// Cache the monitor for unlock.
|
||||
std(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
|
||||
}
|
||||
// Cache the monitor for unlock.
|
||||
std(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
|
||||
}
|
||||
|
||||
bind(locked);
|
||||
@@ -2926,11 +2908,7 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
|
||||
// Check for monitor (0b10).
|
||||
ld(mark, oopDesc::mark_offset_in_bytes(), obj);
|
||||
andi_(t, mark, markWord::monitor_value);
|
||||
if (!UseObjectMonitorTable) {
|
||||
bne(CR0, inflated);
|
||||
} else {
|
||||
bne(CR0, push_and_slow);
|
||||
}
|
||||
bne(CR0, push_and_slow);
|
||||
|
||||
#ifdef ASSERT
|
||||
// Check header not unlocked (0b01).
|
||||
@@ -2980,15 +2958,10 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
|
||||
const Register monitor = mark;
|
||||
const uintptr_t monitor_tag = markWord::monitor_value;
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
// Untag the monitor.
|
||||
subi(monitor, mark, monitor_tag);
|
||||
} else {
|
||||
ld(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
|
||||
// null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
|
||||
cmpldi(CR0, monitor, checked_cast<uint8_t>(alignof(ObjectMonitor*)));
|
||||
blt(CR0, slow_path);
|
||||
}
|
||||
ld(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
|
||||
// null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
|
||||
cmpldi(CR0, monitor, checked_cast<uint8_t>(alignof(ObjectMonitor*)));
|
||||
blt(CR0, slow_path);
|
||||
|
||||
const Register recursions = tmp2;
|
||||
Label not_recursive;
|
||||
@@ -3359,16 +3332,6 @@ void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int
|
||||
Label& jmp_label, bool maybe_far) {
|
||||
// load mark word
|
||||
ld(temp_reg, oopDesc::mark_offset_in_bytes(), oop);
|
||||
if (!UseObjectMonitorTable) {
|
||||
Label test_mark_word;
|
||||
// if unlocked bit is set we can directly use the mark word
|
||||
andi_(R0, temp_reg, markWord::unlocked_value);
|
||||
bne(CR0, test_mark_word);
|
||||
// slow path use klass prototype
|
||||
load_prototype_header(temp_reg, oop);
|
||||
|
||||
bind(test_mark_word);
|
||||
}
|
||||
andi_(R0, temp_reg, test_bit);
|
||||
if (maybe_far) {
|
||||
bc_far_optimized(jmp_set ? Assembler::bcondCRbiIs0 : Assembler::bcondCRbiIs1,
|
||||
@@ -4907,11 +4870,9 @@ void MacroAssembler::fast_lock(Register box, Register obj, Register t1, Register
|
||||
Label push;
|
||||
const Register t = R0;
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
li(t, 0);
|
||||
std(t, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
li(t, 0);
|
||||
std(t, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(t1, obj);
|
||||
|
||||
@@ -10985,24 +10985,7 @@ instruct partialSubtypeCheckConstSuper(rarg3RegP sub, rarg2RegP super_reg, immP
|
||||
|
||||
// inlined locking and unlocking
|
||||
|
||||
instruct cmpFastLock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{
|
||||
predicate(!UseObjectMonitorTable);
|
||||
match(Set crx (FastLock oop box));
|
||||
effect(TEMP tmp1, TEMP tmp2);
|
||||
|
||||
format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2" %}
|
||||
ins_encode %{
|
||||
__ fast_lock($crx$$CondRegister, $oop$$Register, $box$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register, noreg /*tmp3*/);
|
||||
// If locking was successful, crx should indicate 'EQ'.
|
||||
// The compiler generates a branch to the runtime call to
|
||||
// _complete_monitor_locking_Java for the case where crx is 'NE'.
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct cmpFastLockMonitorTable(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, flagsRegCR1 cr1) %{
|
||||
predicate(UseObjectMonitorTable);
|
||||
instruct cmpFastLock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, flagsRegCR1 cr1) %{
|
||||
match(Set crx (FastLock oop box));
|
||||
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr1);
|
||||
|
||||
|
||||
@@ -2525,8 +2525,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
|
||||
// Try fastpath for locking.
|
||||
// fast_lock kills r_temp_1, r_temp_2, r_temp_3.
|
||||
Register r_temp_3_or_noreg = UseObjectMonitorTable ? r_temp_3 : noreg;
|
||||
__ compiler_fast_lock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3_or_noreg);
|
||||
__ compiler_fast_lock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
|
||||
__ beq(CR0, locked);
|
||||
|
||||
// None of the above fast optimizations worked so we have to get into the
|
||||
|
||||
@@ -2609,7 +2609,8 @@ void TemplateTable::jvmti_post_field_access(Register Rcache, Register Rscratch,
|
||||
// Restore object pointer.
|
||||
__ pop_ptr(R17_tos);
|
||||
__ verify_oop(R17_tos);
|
||||
} else {
|
||||
}
|
||||
if (Rcache.is_volatile()) {
|
||||
// Cache is still needed to get class or obj.
|
||||
__ load_field_entry(Rcache, Rscratch);
|
||||
}
|
||||
@@ -3322,7 +3323,7 @@ void TemplateTable::fast_storefield(TosState state) {
|
||||
{
|
||||
Label is_flat, done;
|
||||
__ test_field_is_flat(Rflags, is_flat);
|
||||
__ null_check_throw(Rclass_or_obj, -1, Rscratch);
|
||||
__ null_check_throw(R17_tos, -1, Rscratch);
|
||||
do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
|
||||
__ b(done);
|
||||
__ bind(is_flat);
|
||||
@@ -3384,7 +3385,7 @@ void TemplateTable::fast_accessfield(TosState state) {
|
||||
Label LisVolatile;
|
||||
ByteSize cp_base_offset = ConstantPoolCache::base_offset();
|
||||
|
||||
const Register Rcache = R3_ARG1,
|
||||
const Register Rcache = R31, // Needs to survive C call.
|
||||
Rclass_or_obj = R17_tos,
|
||||
Roffset = R22_tmp2,
|
||||
Rflags = R23_tmp3,
|
||||
|
||||
@@ -84,10 +84,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box,
|
||||
// Finish fast lock unsuccessfully. slow_path MUST branch to with flag != 0
|
||||
Label slow_path;
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
sd(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
sd(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(tmp1, obj);
|
||||
@@ -149,61 +147,56 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box,
|
||||
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
|
||||
const ByteSize omc_obj_offset = OMCache::obj_offset();
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
assert(tmp1_monitor == tmp1_mark, "should be the same here");
|
||||
} else {
|
||||
const Register tmp2_hash = tmp2;
|
||||
const Register tmp3_bucket = tmp3;
|
||||
Label monitor_found;
|
||||
const Register tmp2_hash = tmp2;
|
||||
const Register tmp3_bucket = tmp3;
|
||||
Label monitor_found;
|
||||
|
||||
// Save the mark, we might need it to extract the hash.
|
||||
mv(tmp2_hash, tmp1_mark);
|
||||
// Save the mark, we might need it to extract the hash.
|
||||
mv(tmp2_hash, tmp1_mark);
|
||||
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
|
||||
ld(tmp1_monitor, Address(xthread, thr_omc_offset + omc_monitor_offset));
|
||||
ld(tmp4, Address(xthread, thr_omc_offset + omc_obj_offset));
|
||||
beq(obj, tmp4, monitor_found);
|
||||
ld(tmp1_monitor, Address(xthread, thr_omc_offset + omc_monitor_offset));
|
||||
ld(tmp4, Address(xthread, thr_omc_offset + omc_obj_offset));
|
||||
beq(obj, tmp4, monitor_found);
|
||||
|
||||
// Look for the monitor in the table.
|
||||
// Look for the monitor in the table.
|
||||
|
||||
// Get the hash code.
|
||||
srli(tmp2_hash, tmp2_hash, markWord::hash_shift);
|
||||
// Get the hash code.
|
||||
srli(tmp2_hash, tmp2_hash, markWord::hash_shift);
|
||||
|
||||
// Get the table and calculate the bucket's address.
|
||||
la(tmp3_t, ExternalAddress(ObjectMonitorTable::current_table_address()));
|
||||
ld(tmp3_t, Address(tmp3_t));
|
||||
ld(tmp1, Address(tmp3_t, ObjectMonitorTable::table_capacity_mask_offset()));
|
||||
andr(tmp2_hash, tmp2_hash, tmp1);
|
||||
ld(tmp3_t, Address(tmp3_t, ObjectMonitorTable::table_buckets_offset()));
|
||||
// Get the table and calculate the bucket's address.
|
||||
la(tmp3_t, ExternalAddress(ObjectMonitorTable::current_table_address()));
|
||||
ld(tmp3_t, Address(tmp3_t));
|
||||
ld(tmp1, Address(tmp3_t, ObjectMonitorTable::table_capacity_mask_offset()));
|
||||
andr(tmp2_hash, tmp2_hash, tmp1);
|
||||
ld(tmp3_t, Address(tmp3_t, ObjectMonitorTable::table_buckets_offset()));
|
||||
|
||||
// Read the monitor from the bucket.
|
||||
shadd(tmp3_bucket, tmp2_hash, tmp3_t, tmp4, LogBytesPerWord);
|
||||
ld(tmp1_monitor, Address(tmp3_bucket));
|
||||
// Read the monitor from the bucket.
|
||||
shadd(tmp3_bucket, tmp2_hash, tmp3_t, tmp4, LogBytesPerWord);
|
||||
ld(tmp1_monitor, Address(tmp3_bucket));
|
||||
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed).
|
||||
mv(tmp2, ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
bltu(tmp1_monitor, tmp2, slow_path);
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed).
|
||||
mv(tmp2, ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
bltu(tmp1_monitor, tmp2, slow_path);
|
||||
|
||||
// Check if object matches.
|
||||
ld(tmp3, Address(tmp1_monitor, ObjectMonitor::object_offset()));
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp3, tmp3, tmp2, slow_path);
|
||||
bne(tmp3, obj, slow_path);
|
||||
// Check if object matches.
|
||||
ld(tmp3, Address(tmp1_monitor, ObjectMonitor::object_offset()));
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp3, tmp3, tmp2, slow_path);
|
||||
bne(tmp3, obj, slow_path);
|
||||
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
sd(tmp1_monitor, Address(xthread, thr_omc_offset + omc_monitor_offset));
|
||||
sd(obj, Address(xthread, thr_omc_offset + omc_obj_offset));
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
sd(tmp1_monitor, Address(xthread, thr_omc_offset + omc_monitor_offset));
|
||||
sd(obj, Address(xthread, thr_omc_offset + omc_obj_offset));
|
||||
|
||||
bind(monitor_found);
|
||||
}
|
||||
bind(monitor_found);
|
||||
|
||||
const Register tmp2_owner_addr = tmp2;
|
||||
const Register tmp3_owner = tmp3;
|
||||
|
||||
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
|
||||
const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset() - monitor_tag);
|
||||
const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset() - monitor_tag);
|
||||
const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset());
|
||||
const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset());
|
||||
|
||||
Label monitor_locked;
|
||||
|
||||
@@ -224,10 +217,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box,
|
||||
increment(recursions_address, 1, tmp2, tmp3);
|
||||
|
||||
bind(monitor_locked);
|
||||
if (UseObjectMonitorTable) {
|
||||
// Cache the monitor for unlock.
|
||||
sd(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
}
|
||||
// Cache the monitor for unlock.
|
||||
sd(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
}
|
||||
|
||||
bind(locked);
|
||||
@@ -300,7 +291,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box,
|
||||
// there will be no monitor in the box. So we need to push back the obj
|
||||
// so that the runtime can fix any potential anonymous owner.
|
||||
test_bit(tmp3_t, tmp1_mark, exact_log2(markWord::monitor_value));
|
||||
bnez(tmp3_t, UseObjectMonitorTable ? push_and_slow_path : inflated);
|
||||
bnez(tmp3_t, push_and_slow_path);
|
||||
|
||||
// Try to unlock. Transition lock bits 0b00 => 0b01
|
||||
assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea");
|
||||
@@ -344,16 +335,10 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box,
|
||||
|
||||
const Register tmp1_monitor = tmp1;
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
assert(tmp1_monitor == tmp1_mark, "should be the same here");
|
||||
// Untag the monitor.
|
||||
subi(tmp1_monitor, tmp1_mark, (int)markWord::monitor_value);
|
||||
} else {
|
||||
ld(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
// No valid pointer below alignof(ObjectMonitor*). Take the slow path.
|
||||
mv(tmp3_t, alignof(ObjectMonitor*));
|
||||
bltu(tmp1_monitor, tmp3_t, slow_path);
|
||||
}
|
||||
ld(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
// No valid pointer below alignof(ObjectMonitor*). Take the slow path.
|
||||
mv(tmp3_t, alignof(ObjectMonitor*));
|
||||
bltu(tmp1_monitor, tmp3_t, slow_path);
|
||||
|
||||
const Register tmp2_recursions = tmp2;
|
||||
Label not_recursive;
|
||||
@@ -1852,7 +1837,7 @@ void C2_MacroAssembler::arrays_hashcode_v(Register ary, Register cnt, Register r
|
||||
|
||||
vsetvli(consumed, cnt, Assembler::e32, Assembler::m2);
|
||||
vle32_v(v_coeffs, t1); // 31^^(stride - 1) ... 31^^0
|
||||
vmv_v_x(v_sum, x0);
|
||||
vmv_v_i(v_sum, 0);
|
||||
|
||||
bind(VEC_LOOP);
|
||||
arrays_hashcode_elload_v(v_src, v_tmp, ary, eltype);
|
||||
@@ -2617,7 +2602,7 @@ void C2_MacroAssembler::java_round_float_v(VectorRegister dst, VectorRegister sr
|
||||
// replacing vfclass with feq as performance optimization
|
||||
vmfeq_vv(v0, src, src);
|
||||
// set dst = 0 in cases of NaN
|
||||
vmv_v_x(dst, zr);
|
||||
vmv_v_i(dst, 0);
|
||||
|
||||
// dst = (src + 0.5) rounded down towards negative infinity
|
||||
vfadd_vf(dst, src, ftmp, Assembler::v0_t);
|
||||
@@ -2641,7 +2626,7 @@ void C2_MacroAssembler::java_round_double_v(VectorRegister dst, VectorRegister s
|
||||
// replacing vfclass with feq as performance optimization
|
||||
vmfeq_vv(v0, src, src);
|
||||
// set dst = 0 in cases of NaN
|
||||
vmv_v_x(dst, zr);
|
||||
vmv_v_i(dst, 0);
|
||||
|
||||
// dst = (src + 0.5) rounded down towards negative infinity
|
||||
vfadd_vf(dst, src, ftmp, Assembler::v0_t);
|
||||
@@ -2699,7 +2684,7 @@ void C2_MacroAssembler::clear_array_v(Register base, Register cnt) {
|
||||
|
||||
// making zero words
|
||||
vsetvli(t0, cnt, Assembler::e64, Assembler::m4);
|
||||
vxor_vv(v4, v4, v4);
|
||||
vmv_v_i(v4, 0);
|
||||
|
||||
bind(loop);
|
||||
vsetvli(t0, cnt, Assembler::e64, Assembler::m4);
|
||||
@@ -3296,7 +3281,7 @@ void C2_MacroAssembler::integer_narrow_v(VectorRegister dst, BasicType dst_bt, u
|
||||
#define VFCVT_SAFE(VFLOATCVT) \
|
||||
void C2_MacroAssembler::VFLOATCVT##_safe(VectorRegister dst, VectorRegister src) { \
|
||||
assert_different_registers(dst, src); \
|
||||
vxor_vv(dst, dst, dst); \
|
||||
vmv_v_i(dst, 0); \
|
||||
vmfeq_vv(v0, src, src); \
|
||||
VFLOATCVT(dst, src, Assembler::v0_t); \
|
||||
}
|
||||
|
||||
@@ -629,8 +629,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
|
||||
}
|
||||
|
||||
bool frame::was_augmented_on_entry(int& real_size) const {
|
||||
assert(is_compiled_frame(), "");
|
||||
assert(!_cb->as_nmethod_or_null()->needs_stack_repair(), "unimplemented");
|
||||
assert(_cb != nullptr && _cb->is_nmethod(), "");
|
||||
assert(!_cb->as_nmethod()->needs_stack_repair(), "unimplemented");
|
||||
real_size = _cb->frame_size();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -118,13 +118,20 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
|
||||
// Iterate from start card to end card (inclusive).
|
||||
__ bind(loop);
|
||||
if (UseCondCardMark) {
|
||||
// All non-clean cards (dirty, to-cset, from-remset) have bit0 == 0.
|
||||
static_assert((G1CardTable::g1_dirty_card & 1U) == 0
|
||||
&& (G1CardTable::g1_to_cset_card & 1U) == 0
|
||||
&& (G1CardTable::g1_from_remset_card & 1U) == 0,
|
||||
"cards needing scan must have bit0 == 0");
|
||||
// Clean card has bit0 == 1.
|
||||
static_assert(((uint)G1CardTable::clean_card_val() & 1U) == 1,
|
||||
"clean card must have bit0 == 1");
|
||||
__ lbu(tmp, Address(start, 0));
|
||||
static_assert((uint)G1CardTable::clean_card_val() == 0xff, "must be");
|
||||
__ subi(tmp, tmp, G1CardTable::clean_card_val()); // Convert to clean_card_value() to a comparison
|
||||
// against zero to avoid use of an extra temp.
|
||||
__ bnez(tmp, next);
|
||||
__ test_bit(tmp, tmp, 0); // test bit0: clean has bit0 == 1, non-clean has bit0 == 0
|
||||
__ beqz(tmp, next); // skip store if already non-clean
|
||||
}
|
||||
|
||||
// `sb zr` writes 0, which must be the dirty value.
|
||||
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
|
||||
__ sb(zr, Address(start, 0));
|
||||
|
||||
@@ -264,14 +271,23 @@ static void generate_post_barrier(MacroAssembler* masm,
|
||||
Address card_table_address(xthread, G1ThreadLocalData::card_table_base_offset());
|
||||
__ ld(tmp2, card_table_address); // tmp2 := card table base address
|
||||
__ add(tmp1, tmp1, tmp2); // tmp1 := card address
|
||||
|
||||
if (UseCondCardMark) {
|
||||
static_assert((uint)G1CardTable::clean_card_val() == 0xff, "must be");
|
||||
// All non-clean cards (dirty, to-cset, from-remset) have bit0 == 0.
|
||||
static_assert((G1CardTable::g1_dirty_card & 1U) == 0
|
||||
&& (G1CardTable::g1_to_cset_card & 1U) == 0
|
||||
&& (G1CardTable::g1_from_remset_card & 1U) == 0,
|
||||
"cards needing scan must have bit0 == 0");
|
||||
// Clean card has bit0 == 1.
|
||||
static_assert(((uint)G1CardTable::clean_card_val() & 1U) == 1,
|
||||
"clean card must have bit0 == 1");
|
||||
__ lbu(tmp2, Address(tmp1, 0)); // tmp2 := card
|
||||
__ subi(tmp2, tmp2, G1CardTable::clean_card_val()); // Convert to clean_card_value() to a comparison
|
||||
// against zero to avoid use of an extra temp.
|
||||
__ bnez(tmp2, done);
|
||||
__ test_bit(tmp2, tmp2, 0); // test bit0: clean has bit0 == 1, non-clean has bit0 == 0
|
||||
__ beqz(tmp2, done); // skip store if already non-clean
|
||||
}
|
||||
static_assert((uint)G1CardTable::dirty_card_val() == 0, "must be to use zr");
|
||||
|
||||
// `sb zr` writes 0, which must be the dirty value.
|
||||
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
|
||||
__ sb(zr, Address(tmp1, 0));
|
||||
}
|
||||
|
||||
|
||||
@@ -854,7 +854,7 @@ void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
|
||||
// Save the result where needed. Narrow entries return narrowOop (32 bits)
|
||||
// we need to zero the upper 32 bits of x10.
|
||||
if (_narrow) {
|
||||
__ zext_w(_obj, x10);
|
||||
__ zext(_obj, x10, 32);
|
||||
} else {
|
||||
__ mv(_obj, x10);
|
||||
}
|
||||
|
||||
@@ -2182,7 +2182,7 @@ void MacroAssembler::vector_update_crc32(Register crc, Register buf, Register le
|
||||
vsetivli(zr, N, Assembler::e32, Assembler::m1, Assembler::mu, Assembler::tu);
|
||||
}
|
||||
|
||||
vmv_v_x(vcrc, zr);
|
||||
vmv_v_i(vcrc, 0);
|
||||
vmv_s_x(vcrc, crc);
|
||||
|
||||
// multiple of 64
|
||||
@@ -2327,7 +2327,7 @@ void MacroAssembler::kernel_crc32_vclmul_fold_vectorsize_16(Register crc, Regist
|
||||
vle64_v(v6, buf); addi(buf, buf, STEP);
|
||||
vle64_v(v7, buf); addi(buf, buf, STEP);
|
||||
|
||||
vmv_v_x(v31, zr);
|
||||
vmv_v_i(v31, 0);
|
||||
vsetivli(zr, 1, Assembler::e32, Assembler::m1, Assembler::mu, Assembler::tu);
|
||||
vmv_s_x(v31, crc);
|
||||
vsetivli(zr, N, Assembler::e64, Assembler::m1, Assembler::mu, Assembler::tu);
|
||||
@@ -2450,7 +2450,7 @@ void MacroAssembler::kernel_crc32_vclmul_fold_vectorsize_32(Register crc, Regist
|
||||
// now, v1 should contains: 010101...
|
||||
|
||||
// initial crc
|
||||
vmv_v_x(v24, zr);
|
||||
vmv_v_i(v24, 0);
|
||||
vsetivli(zr, 1, Assembler::e32, Assembler::m4, Assembler::mu, Assembler::tu);
|
||||
vmv_s_x(v24, crc);
|
||||
vsetivli(zr, N, Assembler::e64, Assembler::m4, Assembler::mu, Assembler::tu);
|
||||
@@ -3765,16 +3765,6 @@ void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int
|
||||
assert_different_registers(temp_reg, t0);
|
||||
// load mark word
|
||||
ld(temp_reg, Address(oop, oopDesc::mark_offset_in_bytes()));
|
||||
if (!UseObjectMonitorTable) {
|
||||
Label test_mark_word;
|
||||
// check displaced
|
||||
test_bit(t0, temp_reg, exact_log2(markWord::unlocked_value));
|
||||
bnez(t0, test_mark_word);
|
||||
// slow path use klass prototype
|
||||
load_prototype_header(temp_reg, oop);
|
||||
|
||||
bind(test_mark_word);
|
||||
}
|
||||
andi(temp_reg, temp_reg, tst_bit);
|
||||
if (jmp_set) {
|
||||
bnez(temp_reg, jmp_label, /* is_far */ true);
|
||||
@@ -7035,10 +7025,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register tmp1,
|
||||
// instruction emitted as it is part of C1's null check semantics.
|
||||
ld(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
sd(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
sd(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(tmp1, obj);
|
||||
|
||||
@@ -1553,9 +1553,34 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r
|
||||
int src_offset = ra_->reg2offset(src_lo);
|
||||
int dst_offset = ra_->reg2offset(dst_lo);
|
||||
|
||||
if (bottom_type()->isa_vect() != nullptr) {
|
||||
uint ireg = ideal_reg();
|
||||
if (ireg == Op_VecA && masm) {
|
||||
// Stack-to-stack copies use t0 for the value. Bail out if a destination
|
||||
// address also needs t0 to materialize an offset outside the 12-bit range.
|
||||
if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
|
||||
int last_dst_offset = dst_offset;
|
||||
if (bottom_type()->isa_vect() != nullptr) {
|
||||
if (!bottom_type()->isa_pvectmask()) {
|
||||
assert(ideal_reg() == Op_VecA, "Must be");
|
||||
int vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE);
|
||||
last_dst_offset += vector_reg_size_in_bytes - 8;
|
||||
} else {
|
||||
assert(ideal_reg() == Op_RegVectMask, "Must be");
|
||||
int vmask_size_in_bytes = Matcher::scalable_predicate_reg_slots() * 32 / 8;
|
||||
last_dst_offset += vmask_size_in_bytes - 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (masm != nullptr && !Assembler::is_simm12(last_dst_offset)) {
|
||||
// size() emits into a scratch buffer where recording a failure is not allowed.
|
||||
if (!C->output()->in_scratch_emit_size()) {
|
||||
C->record_method_not_compilable("unsupported large stack-to-stack spill copy");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bottom_type()->isa_vect() != nullptr && masm != nullptr) {
|
||||
if (!bottom_type()->isa_pvectmask()) {
|
||||
assert(ideal_reg() == Op_VecA, "Must be");
|
||||
int vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE);
|
||||
if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
|
||||
// stack to stack
|
||||
@@ -1574,7 +1599,8 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
} else if (bottom_type()->isa_pvectmask() && masm) {
|
||||
} else {
|
||||
assert(ideal_reg() == Op_RegVectMask, "Must be");
|
||||
int vmask_size_in_bytes = Matcher::scalable_predicate_reg_slots() * 32 / 8;
|
||||
if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
|
||||
// stack to stack
|
||||
@@ -1677,14 +1703,11 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r
|
||||
st->print("%s", Matcher::regName[dst_lo]);
|
||||
}
|
||||
if (bottom_type()->isa_vect() && !bottom_type()->isa_pvectmask()) {
|
||||
int vsize = 0;
|
||||
if (ideal_reg() == Op_VecA) {
|
||||
vsize = Matcher::scalable_vector_reg_size(T_BYTE) * 8;
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
assert(ideal_reg() == Op_VecA, "Must be");
|
||||
int vsize = Matcher::scalable_vector_reg_size(T_BYTE) * 8;
|
||||
st->print("\t# vector spill size = %d", vsize);
|
||||
} else if (ideal_reg() == Op_RegVectMask) {
|
||||
} else if (bottom_type()->isa_pvectmask()) {
|
||||
assert(ideal_reg() == Op_RegVectMask, "Must be");
|
||||
assert(Matcher::supports_scalable_vector(), "bad register type for spill");
|
||||
int vsize = Matcher::scalable_predicate_reg_slots() * 32;
|
||||
st->print("\t# vmask spill size = %d", vsize);
|
||||
|
||||
@@ -41,7 +41,7 @@ source %{
|
||||
__ vsex_v(reg, base, sew, vm);
|
||||
} else {
|
||||
if (vm == Assembler::v0_t) {
|
||||
__ vxor_vv(reg, reg, reg);
|
||||
__ vmv_v_i(reg, 0);
|
||||
}
|
||||
__ vlex_v(reg, base, sew, vm);
|
||||
}
|
||||
@@ -241,7 +241,7 @@ instruct vstoremask(vReg dst, vRegMask_V0 v0, immI size) %{
|
||||
format %{ "vstoremask $dst, V0 # elem size is $size byte[s]" %}
|
||||
ins_encode %{
|
||||
__ vsetvli_helper(T_BOOLEAN, Matcher::vector_length(this));
|
||||
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
|
||||
__ vmerge_vim(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), 1);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
@@ -4482,7 +4482,7 @@ instruct vmaskAllL(vRegMask dst, iRegL src) %{
|
||||
|
||||
// ------------------------------ Vector mask basic OPs ------------------------
|
||||
|
||||
// vector mask logical ops: and/or/xor
|
||||
// vector mask logical ops: and/and-not/or/xor
|
||||
|
||||
instruct vmask_and(vRegMask dst, vRegMask src1, vRegMask src2) %{
|
||||
match(Set dst (AndVMask src1 src2));
|
||||
@@ -4497,6 +4497,32 @@ instruct vmask_and(vRegMask dst, vRegMask src1, vRegMask src2) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vmask_and_notI(vRegMask dst, vRegMask src1, vRegMask src2, immI_M1 m1) %{
|
||||
match(Set dst (AndVMask src1 (XorVMask src2 (MaskAll m1))));
|
||||
format %{ "vmask_and_notI $dst, $src1, $src2" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
__ vsetvli_helper(bt, Matcher::vector_length(this));
|
||||
__ vmandn_mm(as_VectorRegister($dst$$reg),
|
||||
as_VectorRegister($src1$$reg),
|
||||
as_VectorRegister($src2$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vmask_and_notL(vRegMask dst, vRegMask src1, vRegMask src2, immL_M1 m1) %{
|
||||
match(Set dst (AndVMask src1 (XorVMask src2 (MaskAll m1))));
|
||||
format %{ "vmask_and_notL $dst, $src1, $src2" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
__ vsetvli_helper(bt, Matcher::vector_length(this));
|
||||
__ vmandn_mm(as_VectorRegister($dst$$reg),
|
||||
as_VectorRegister($src1$$reg),
|
||||
as_VectorRegister($src2$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vmask_or(vRegMask dst, vRegMask src1, vRegMask src2) %{
|
||||
match(Set dst (OrVMask src1 src2));
|
||||
format %{ "vmask_or $dst, $src1, $src2" %}
|
||||
@@ -4809,7 +4835,7 @@ instruct vcvtFtoL(vReg dst, vReg src, vRegMask_V0 v0) %{
|
||||
format %{ "vcvtFtoL $dst, $src" %}
|
||||
ins_encode %{
|
||||
__ vsetvli_helper(T_LONG, Matcher::vector_length(this));
|
||||
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
|
||||
__ vsetvli_helper(T_FLOAT, Matcher::vector_length(this), Assembler::mf2);
|
||||
__ vmfeq_vv(as_VectorRegister($v0$$reg), as_VectorRegister($src$$reg), as_VectorRegister($src$$reg));
|
||||
__ vfwcvt_rtz_x_f_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), Assembler::v0_t);
|
||||
@@ -4842,7 +4868,7 @@ instruct vcvtDtoX_narrow(vReg dst, vReg src, vRegMask_V0 v0) %{
|
||||
__ vsetvli_helper(T_DOUBLE, Matcher::vector_length(this));
|
||||
__ vmfeq_vv(as_VectorRegister($v0$$reg), as_VectorRegister($src$$reg), as_VectorRegister($src$$reg));
|
||||
__ vsetvli_helper(T_INT, Matcher::vector_length(this), Assembler::mf2);
|
||||
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
|
||||
__ vfncvt_rtz_x_f_w(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), Assembler::v0_t);
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
if (bt == T_BYTE || bt == T_SHORT) {
|
||||
@@ -4903,7 +4929,7 @@ instruct reinterpretResize(vReg dst, vReg src) %{
|
||||
"invalid vector length");
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
__ vsetvli_helper(bt, Matcher::vector_length(this));
|
||||
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
|
||||
__ vsetvli_helper(T_BYTE, length_in_bytes_resize);
|
||||
__ vmv_v_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg));
|
||||
%}
|
||||
@@ -4931,7 +4957,7 @@ instruct vmask_reinterpret_diff_esize(vRegMask dst, vRegMask_V0 src, vReg tmp) %
|
||||
ins_encode %{
|
||||
BasicType from_bt = Matcher::vector_element_basic_type(this, $src);
|
||||
__ vsetvli_helper(from_bt, Matcher::vector_length(this, $src));
|
||||
__ vxor_vv(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($tmp$$reg), 0);
|
||||
__ vmerge_vim(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), -1);
|
||||
BasicType to_bt = Matcher::vector_element_basic_type(this);
|
||||
__ vsetvli_helper(to_bt, Matcher::vector_length(this));
|
||||
@@ -4990,8 +5016,7 @@ instruct rearrange_masked(vReg dst, vReg src, vReg shuffle, vRegMask_V0 v0) %{
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
__ vsetvli_helper(bt, Matcher::vector_length(this));
|
||||
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
|
||||
as_VectorRegister($dst$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
|
||||
__ vrgather_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
|
||||
as_VectorRegister($shuffle$$reg), Assembler::v0_t);
|
||||
%}
|
||||
@@ -5105,8 +5130,7 @@ instruct vcompress(vReg dst, vReg src, vRegMask_V0 v0) %{
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
__ vsetvli_helper(bt, Matcher::vector_length(this));
|
||||
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
|
||||
as_VectorRegister($dst$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
|
||||
__ vcompress_vm(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
|
||||
as_VectorRegister($v0$$reg));
|
||||
%}
|
||||
@@ -5121,8 +5145,7 @@ instruct vexpand(vReg dst, vReg src, vRegMask_V0 v0, vReg tmp) %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
__ vsetvli_helper(bt, Matcher::vector_length(this));
|
||||
__ viota_m(as_VectorRegister($tmp$$reg), as_VectorRegister($v0$$reg));
|
||||
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
|
||||
as_VectorRegister($dst$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
|
||||
__ vrgather_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
|
||||
as_VectorRegister($tmp$$reg), Assembler::v0_t);
|
||||
%}
|
||||
@@ -5383,8 +5406,7 @@ instruct gather_loadS_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, v
|
||||
Assembler::SEW sew = Assembler::elemtype_to_sew(bt);
|
||||
__ vsetvli_helper(bt, Matcher::vector_length(this));
|
||||
__ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg), (int)sew);
|
||||
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
|
||||
as_VectorRegister($dst$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
|
||||
__ vluxei32_v(as_VectorRegister($dst$$reg), as_Register($mem$$base),
|
||||
as_VectorRegister($tmp$$reg), Assembler::v0_t);
|
||||
%}
|
||||
@@ -5402,8 +5424,7 @@ instruct gather_loadD_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, v
|
||||
__ vsetvli_helper(bt, Matcher::vector_length(this));
|
||||
__ vzext_vf2(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg));
|
||||
__ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew);
|
||||
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
|
||||
as_VectorRegister($dst$$reg));
|
||||
__ vmv_v_i(as_VectorRegister($dst$$reg), 0);
|
||||
__ vluxei64_v(as_VectorRegister($dst$$reg), as_Register($mem$$base),
|
||||
as_VectorRegister($tmp$$reg), Assembler::v0_t);
|
||||
%}
|
||||
|
||||
@@ -760,8 +760,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
|
||||
}
|
||||
|
||||
bool frame::was_augmented_on_entry(int& real_size) const {
|
||||
assert(is_compiled_frame(), "");
|
||||
if (_cb->as_nmethod_or_null()->needs_stack_repair()) {
|
||||
assert(_cb != nullptr && _cb->is_nmethod(), "");
|
||||
if (_cb->as_nmethod()->needs_stack_repair()) {
|
||||
Unimplemented();
|
||||
}
|
||||
real_size = _cb->frame_size();
|
||||
|
||||
@@ -4265,15 +4265,6 @@ void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int
|
||||
assert(test_bit <= 0xFFFF, "must fit in low 16 bits for z_tmll");
|
||||
// Load mark word
|
||||
z_lg(temp_reg, oopDesc::mark_offset_in_bytes(), oop);
|
||||
if (!UseObjectMonitorTable) {
|
||||
Label test_mark_word;
|
||||
// If unlocked bit is set we can directly use the mark word
|
||||
z_tmll(temp_reg, markWord::unlocked_value);
|
||||
z_brnaz(test_mark_word);
|
||||
// Slow path: use klass prototype
|
||||
load_prototype_header(temp_reg, oop);
|
||||
bind(test_mark_word);
|
||||
}
|
||||
z_tmll(temp_reg, test_bit);
|
||||
// Use branch_optimized to handle both near and far branches automatically
|
||||
branch_optimized(jmp_set ? Assembler::bcondNotAllZero : Assembler::bcondAllZero, jmp_label);
|
||||
@@ -6357,11 +6348,9 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register temp1
|
||||
// instruction emitted as it is part of C1's null check semantics.
|
||||
z_lg(mark, Address(obj, mark_offset));
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
const Address om_cache_addr = Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())));
|
||||
z_mvghi(om_cache_addr, 0);
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
const Address om_cache_addr = Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())));
|
||||
z_mvghi(om_cache_addr, 0);
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(temp1, obj);
|
||||
@@ -6506,10 +6495,8 @@ void MacroAssembler::compiler_fast_lock_object(Register obj, Register box, Regis
|
||||
// Finish fast lock unsuccessfully. MUST branch to with flag == EQ
|
||||
NearLabel slow_path;
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
z_mvghi(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
z_mvghi(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(tmp1, obj);
|
||||
@@ -6587,61 +6574,57 @@ void MacroAssembler::compiler_fast_lock_object(Register obj, Register box, Regis
|
||||
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
|
||||
const ByteSize omc_obj_offset = OMCache::obj_offset();
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
assert(tmp1_monitor == mark, "should be the same here");
|
||||
} else {
|
||||
const Register tmp1_bucket = tmp1;
|
||||
const Register hash = Z_R0_scratch;
|
||||
NearLabel monitor_found;
|
||||
const Register tmp1_bucket = tmp1;
|
||||
const Register hash = Z_R0_scratch;
|
||||
NearLabel monitor_found;
|
||||
|
||||
// Save the mark, we might need it to extract the hash.
|
||||
z_lgr(hash, mark);
|
||||
// Save the mark, we might need it to extract the hash.
|
||||
z_lgr(hash, mark);
|
||||
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
|
||||
z_lg(tmp1_monitor, Address(Z_thread, thr_omc_offset + omc_monitor_offset));
|
||||
z_cg(obj, Address(Z_thread, thr_omc_offset + omc_obj_offset));
|
||||
z_bre(monitor_found);
|
||||
z_lg(tmp1_monitor, Address(Z_thread, thr_omc_offset + omc_monitor_offset));
|
||||
z_cg(obj, Address(Z_thread, thr_omc_offset + omc_obj_offset));
|
||||
z_bre(monitor_found);
|
||||
|
||||
// Get the hash code.
|
||||
z_srlg(hash, hash, markWord::hash_shift);
|
||||
// Get the hash code.
|
||||
z_srlg(hash, hash, markWord::hash_shift);
|
||||
|
||||
// Get the table and calculate the bucket's address.
|
||||
load_const_optimized(tmp2, ObjectMonitorTable::current_table_address());
|
||||
z_lg(tmp2, Address(tmp2));
|
||||
z_ng(hash, Address(tmp2, ObjectMonitorTable::table_capacity_mask_offset()));
|
||||
z_lg(tmp1_bucket, Address(tmp2, ObjectMonitorTable::table_buckets_offset()));
|
||||
z_sllg(hash, hash, LogBytesPerWord);
|
||||
z_agr(tmp1_bucket, hash);
|
||||
// Get the table and calculate the bucket's address.
|
||||
load_const_optimized(tmp2, ObjectMonitorTable::current_table_address());
|
||||
z_lg(tmp2, Address(tmp2));
|
||||
z_ng(hash, Address(tmp2, ObjectMonitorTable::table_capacity_mask_offset()));
|
||||
z_lg(tmp1_bucket, Address(tmp2, ObjectMonitorTable::table_buckets_offset()));
|
||||
z_sllg(hash, hash, LogBytesPerWord);
|
||||
z_agr(tmp1_bucket, hash);
|
||||
|
||||
// Read the monitor from the bucket.
|
||||
z_lg(tmp1_monitor, Address(tmp1_bucket));
|
||||
// Read the monitor from the bucket.
|
||||
z_lg(tmp1_monitor, Address(tmp1_bucket));
|
||||
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed).
|
||||
z_clgfi(tmp1_monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
z_brl(slow_path);
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed).
|
||||
z_clgfi(tmp1_monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
z_brl(slow_path);
|
||||
|
||||
// Check if object matches.
|
||||
z_lg(tmp2, Address(tmp1_monitor, ObjectMonitor::object_offset()));
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp2, tmp2, Z_R0_scratch, slow_path);
|
||||
z_cgr(obj, tmp2);
|
||||
z_brne(slow_path);
|
||||
// Check if object matches.
|
||||
z_lg(tmp2, Address(tmp1_monitor, ObjectMonitor::object_offset()));
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, tmp2, tmp2, Z_R0_scratch, slow_path);
|
||||
z_cgr(obj, tmp2);
|
||||
z_brne(slow_path);
|
||||
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
z_stg(tmp1_monitor, Address(Z_thread, thr_omc_offset + omc_monitor_offset));
|
||||
z_stg(obj, Address(Z_thread, thr_omc_offset + omc_obj_offset));
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
z_stg(tmp1_monitor, Address(Z_thread, thr_omc_offset + omc_monitor_offset));
|
||||
z_stg(obj, Address(Z_thread, thr_omc_offset + omc_obj_offset));
|
||||
|
||||
bind(monitor_found);
|
||||
|
||||
bind(monitor_found);
|
||||
}
|
||||
NearLabel monitor_locked;
|
||||
// lock the monitor
|
||||
|
||||
const Register zero = tmp2;
|
||||
|
||||
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
|
||||
const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset() - monitor_tag);
|
||||
const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset() - monitor_tag);
|
||||
const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset());
|
||||
const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset());
|
||||
|
||||
// Try to CAS owner (no owner => current thread's _monitor_owner_id).
|
||||
// If csg succeeds then CR=EQ, otherwise, register zero is filled
|
||||
@@ -6659,10 +6642,8 @@ void MacroAssembler::compiler_fast_lock_object(Register obj, Register box, Regis
|
||||
z_agsi(recursions_address, 1ll);
|
||||
|
||||
bind(monitor_locked);
|
||||
if (UseObjectMonitorTable) {
|
||||
// Cache the monitor for unlock.
|
||||
z_stg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
}
|
||||
// Cache the monitor for unlock.
|
||||
z_stg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
// set the CC now
|
||||
z_cgr(obj, obj);
|
||||
}
|
||||
@@ -6739,11 +6720,7 @@ void MacroAssembler::compiler_fast_unlock_object(Register obj, Register box, Reg
|
||||
// so that the runtime can fix any potential anonymous owner.
|
||||
z_lg(mark, Address(obj, mark_offset));
|
||||
z_tmll(mark, markWord::monitor_value);
|
||||
if (!UseObjectMonitorTable) {
|
||||
z_brnaz(inflated);
|
||||
} else {
|
||||
z_brnaz(push_and_slow_path);
|
||||
}
|
||||
z_brnaz(push_and_slow_path);
|
||||
|
||||
#ifdef ASSERT
|
||||
// Check header not unlocked (0b01).
|
||||
@@ -6802,25 +6779,20 @@ void MacroAssembler::compiler_fast_unlock_object(Register obj, Register box, Reg
|
||||
|
||||
const Register tmp1_monitor = tmp1;
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
assert(tmp1_monitor == mark, "should be the same here");
|
||||
} else {
|
||||
// Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
|
||||
z_lg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
// null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
|
||||
z_cghi(tmp1_monitor, alignof(ObjectMonitor*));
|
||||
// Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
|
||||
z_lg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
// null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
|
||||
z_cghi(tmp1_monitor, alignof(ObjectMonitor*));
|
||||
|
||||
z_brl(slow_path);
|
||||
}
|
||||
z_brl(slow_path);
|
||||
|
||||
// mark contains the tagged ObjectMonitor*.
|
||||
const Register monitor = mark;
|
||||
|
||||
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
|
||||
const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag};
|
||||
const Address succ_address{monitor, ObjectMonitor::succ_offset() - monitor_tag};
|
||||
const Address entry_list_address{monitor, ObjectMonitor::entry_list_offset() - monitor_tag};
|
||||
const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag};
|
||||
const Address recursions_address{monitor, ObjectMonitor::recursions_offset()};
|
||||
const Address succ_address{monitor, ObjectMonitor::succ_offset()};
|
||||
const Address entry_list_address{monitor, ObjectMonitor::entry_list_offset()};
|
||||
const Address owner_address{monitor, ObjectMonitor::owner_offset()};
|
||||
|
||||
NearLabel not_recursive;
|
||||
const Register recursions = tmp2;
|
||||
@@ -6856,9 +6828,6 @@ void MacroAssembler::compiler_fast_unlock_object(Register obj, Register box, Reg
|
||||
|
||||
// Save the monitor pointer in the current thread, so we can try to
|
||||
// reacquire the lock in SharedRuntime::monitor_exit_helper().
|
||||
if (!UseObjectMonitorTable) {
|
||||
z_xilf(monitor, markWord::monitor_value);
|
||||
}
|
||||
z_stg(monitor, Address(Z_thread, JavaThread::unlocked_inflated_monitor_offset()));
|
||||
|
||||
z_ltgr(obj, obj); // Set flag = NE
|
||||
|
||||
@@ -8547,12 +8547,12 @@ void Assembler::vsqrtsh(XMMRegister dst, XMMRegister src) {
|
||||
emit_int16(0x51, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::vfmadd132sh(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
|
||||
void Assembler::vfmadd231sh(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
|
||||
assert(VM_Version::supports_avx512_fp16(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP6, &attributes);
|
||||
emit_int16((unsigned char)0x99, (0xC0 | encode));
|
||||
emit_int16((unsigned char)0xB9, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::vpaddsb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
|
||||
@@ -17057,16 +17057,16 @@ void Assembler::evsqrtph(XMMRegister dst, Address src, int vector_len) {
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::evfmadd132ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
|
||||
void Assembler::evfmadd231ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
|
||||
assert(VM_Version::supports_avx512_fp16(), "");
|
||||
assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "");
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP6, &attributes);
|
||||
emit_int16(0x98, (0xC0 | encode));
|
||||
emit_int16((unsigned char)0xB8, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evfmadd132ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) {
|
||||
void Assembler::evfmadd231ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) {
|
||||
assert(VM_Version::supports_avx512_fp16(), "");
|
||||
assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "");
|
||||
InstructionMark im(this);
|
||||
@@ -17074,7 +17074,7 @@ void Assembler::evfmadd132ph(XMMRegister dst, XMMRegister nds, Address src, int
|
||||
attributes.set_is_evex_instruction();
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
|
||||
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP6, &attributes);
|
||||
emit_int8(0x98);
|
||||
emit_int8((unsigned char)0xB8);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -2569,7 +2569,7 @@ private:
|
||||
void vmulsh(XMMRegister dst, XMMRegister nds, XMMRegister src);
|
||||
void vdivsh(XMMRegister dst, XMMRegister nds, XMMRegister src);
|
||||
void vsqrtsh(XMMRegister dst, XMMRegister src);
|
||||
void vfmadd132sh(XMMRegister dst, XMMRegister src1, XMMRegister src2);
|
||||
void vfmadd231sh(XMMRegister dst, XMMRegister src1, XMMRegister src2);
|
||||
|
||||
// Saturating packed insturctions.
|
||||
void vpaddsb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
||||
@@ -2757,8 +2757,8 @@ private:
|
||||
void evminph(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
|
||||
void evmaxph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
||||
void evmaxph(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
|
||||
void evfmadd132ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
||||
void evfmadd132ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
|
||||
void evfmadd231ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
||||
void evfmadd231ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
|
||||
void evsqrtph(XMMRegister dst, XMMRegister src1, int vector_len);
|
||||
void evsqrtph(XMMRegister dst, Address src1, int vector_len);
|
||||
|
||||
|
||||
@@ -276,10 +276,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register rax_reg,
|
||||
// Finish fast lock unsuccessfully. MUST jump with ZF == 0
|
||||
Label slow_path;
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(rax_reg, obj, t);
|
||||
@@ -293,7 +291,7 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register rax_reg,
|
||||
|
||||
Label push;
|
||||
|
||||
const Register top = UseObjectMonitorTable ? rax_reg : box;
|
||||
const Register top = rax_reg;
|
||||
|
||||
// Load the mark.
|
||||
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
@@ -320,10 +318,9 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register rax_reg,
|
||||
lock(); cmpxchgptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
jcc(Assembler::notEqual, slow_path);
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Need to reload top, clobbered by CAS.
|
||||
movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
|
||||
}
|
||||
// Need to reload top, clobbered by CAS.
|
||||
movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
|
||||
|
||||
bind(push);
|
||||
// After successful lock, push object on lock-stack.
|
||||
movptr(Address(thread, top), obj);
|
||||
@@ -340,63 +337,57 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register rax_reg,
|
||||
const ByteSize omc_monitor_offset = OMCache::monitor_offset();
|
||||
const ByteSize omc_obj_offset = OMCache::obj_offset();
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
assert(mark == monitor, "should be the same here");
|
||||
} else {
|
||||
const Register hash = t;
|
||||
Label monitor_found;
|
||||
const Register hash = t;
|
||||
Label monitor_found;
|
||||
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
// Look for the monitor in the current thread's object monitor cache (omc).
|
||||
|
||||
movptr(monitor, Address(thread, thr_omc_offset + omc_monitor_offset));
|
||||
cmpptr(obj, Address(thread, thr_omc_offset + omc_obj_offset));
|
||||
jccb(Assembler::equal, monitor_found);
|
||||
movptr(monitor, Address(thread, thr_omc_offset + omc_monitor_offset));
|
||||
cmpptr(obj, Address(thread, thr_omc_offset + omc_obj_offset));
|
||||
jccb(Assembler::equal, monitor_found);
|
||||
|
||||
// Look for the monitor in the table.
|
||||
// Look for the monitor in the table.
|
||||
|
||||
// Get the hash code.
|
||||
movptr(hash, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
shrq(hash, markWord::hash_shift);
|
||||
andq(hash, markWord::hash_mask);
|
||||
// Get the hash code.
|
||||
movptr(hash, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
shrq(hash, markWord::hash_shift);
|
||||
andq(hash, markWord::hash_mask);
|
||||
|
||||
// Get the table and calculate the bucket's address.
|
||||
lea(rax_reg, ExternalAddress(ObjectMonitorTable::current_table_address()));
|
||||
movptr(rax_reg, Address(rax_reg));
|
||||
andq(hash, Address(rax_reg, ObjectMonitorTable::table_capacity_mask_offset()));
|
||||
movptr(rax_reg, Address(rax_reg, ObjectMonitorTable::table_buckets_offset()));
|
||||
// Get the table and calculate the bucket's address.
|
||||
lea(rax_reg, ExternalAddress(ObjectMonitorTable::current_table_address()));
|
||||
movptr(rax_reg, Address(rax_reg));
|
||||
andq(hash, Address(rax_reg, ObjectMonitorTable::table_capacity_mask_offset()));
|
||||
movptr(rax_reg, Address(rax_reg, ObjectMonitorTable::table_buckets_offset()));
|
||||
|
||||
// Read the monitor from the bucket.
|
||||
movptr(monitor, Address(rax_reg, hash, Address::times_ptr));
|
||||
// Read the monitor from the bucket.
|
||||
movptr(monitor, Address(rax_reg, hash, Address::times_ptr));
|
||||
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed)
|
||||
cmpptr(monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
jcc(Assembler::below, slow_path);
|
||||
// Check if the monitor in the bucket is special (empty, tombstone or removed)
|
||||
cmpptr(monitor, ObjectMonitorTable::SpecialPointerValues::below_is_special);
|
||||
jcc(Assembler::below, slow_path);
|
||||
|
||||
// Check if object matches.
|
||||
movptr(rax_reg, Address(monitor, ObjectMonitor::object_offset()));
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, rax_reg, rax_reg, slow_path);
|
||||
cmpptr(rax_reg, obj);
|
||||
jcc(Assembler::notEqual, slow_path);
|
||||
// Check if object matches.
|
||||
movptr(rax_reg, Address(monitor, ObjectMonitor::object_offset()));
|
||||
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs_asm->try_peek_weak_handle_in_nmethod(this, rax_reg, rax_reg, slow_path);
|
||||
cmpptr(rax_reg, obj);
|
||||
jcc(Assembler::notEqual, slow_path);
|
||||
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
movptr(Address(thread, thr_omc_offset + omc_monitor_offset), monitor);
|
||||
movptr(Address(thread, thr_omc_offset + omc_obj_offset), obj);
|
||||
// Store the monitor in the current thread's object monitor cache (omc).
|
||||
movptr(Address(thread, thr_omc_offset + omc_monitor_offset), monitor);
|
||||
movptr(Address(thread, thr_omc_offset + omc_obj_offset), obj);
|
||||
|
||||
bind(monitor_found);
|
||||
}
|
||||
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
|
||||
const Address recursions_address(monitor, ObjectMonitor::recursions_offset() - monitor_tag);
|
||||
const Address owner_address(monitor, ObjectMonitor::owner_offset() - monitor_tag);
|
||||
bind(monitor_found);
|
||||
|
||||
const Address recursions_address(monitor, ObjectMonitor::recursions_offset());
|
||||
const Address owner_address(monitor, ObjectMonitor::owner_offset());
|
||||
|
||||
Label monitor_locked;
|
||||
// Lock the monitor.
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Cache the monitor for unlock before trashing box. On failure to acquire
|
||||
// the lock, the slow path will reset the entry accordingly (see CacheSetter).
|
||||
movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), monitor);
|
||||
}
|
||||
// Cache the monitor for unlock before trashing box. On failure to acquire
|
||||
// the lock, the slow path will reset the entry accordingly (see CacheSetter).
|
||||
movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), monitor);
|
||||
|
||||
// Try to CAS owner (no owner => current thread's _monitor_owner_id).
|
||||
xorptr(rax_reg, rax_reg);
|
||||
@@ -481,7 +472,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
|
||||
|
||||
const Register mark = t;
|
||||
const Register monitor = t;
|
||||
const Register top = UseObjectMonitorTable ? t : reg_rax;
|
||||
const Register top = t;
|
||||
const Register box = reg_rax;
|
||||
|
||||
Label dummy;
|
||||
@@ -499,11 +490,6 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
|
||||
// Load top.
|
||||
movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
// Prefetch mark.
|
||||
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
}
|
||||
|
||||
// Check if obj is top of lock-stack.
|
||||
cmpptr(obj, Address(thread, top, Address::times_1, -oopSize));
|
||||
// Top of lock stack was not obj. Must be monitor.
|
||||
@@ -519,10 +505,8 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
|
||||
|
||||
// We elide the monitor check, let the CAS fail instead.
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Load mark.
|
||||
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
}
|
||||
// Load mark.
|
||||
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
|
||||
// Try to unlock. Transition lock bits 0b00 => 0b01
|
||||
movptr(reg_rax, mark);
|
||||
@@ -545,9 +529,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
|
||||
jcc(Assembler::notEqual, inflated_check_lock_stack);
|
||||
stop("Fast Unlock lock on stack");
|
||||
bind(check_done);
|
||||
if (UseObjectMonitorTable) {
|
||||
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
}
|
||||
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
testptr(mark, markWord::monitor_value);
|
||||
jcc(Assembler::notZero, inflated);
|
||||
stop("Fast Unlock not monitor");
|
||||
@@ -555,20 +537,16 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
|
||||
|
||||
bind(inflated);
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
assert(mark == monitor, "should be the same here");
|
||||
} else {
|
||||
// Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
|
||||
movptr(monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
// null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
|
||||
cmpptr(monitor, alignof(ObjectMonitor*));
|
||||
jcc(Assembler::below, slow_path);
|
||||
}
|
||||
const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast<int>(markWord::monitor_value));
|
||||
const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag};
|
||||
const Address succ_address{monitor, ObjectMonitor::succ_offset() - monitor_tag};
|
||||
const Address entry_list_address{monitor, ObjectMonitor::entry_list_offset() - monitor_tag};
|
||||
const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag};
|
||||
// Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
|
||||
movptr(monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
|
||||
// null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
|
||||
cmpptr(monitor, alignof(ObjectMonitor*));
|
||||
jcc(Assembler::below, slow_path);
|
||||
|
||||
const Address recursions_address{monitor, ObjectMonitor::recursions_offset()};
|
||||
const Address succ_address{monitor, ObjectMonitor::succ_offset()};
|
||||
const Address entry_list_address{monitor, ObjectMonitor::entry_list_offset()};
|
||||
const Address owner_address{monitor, ObjectMonitor::owner_offset()};
|
||||
|
||||
Label recursive;
|
||||
|
||||
@@ -593,9 +571,6 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t,
|
||||
|
||||
// Save the monitor pointer in the current thread, so we can try to
|
||||
// reacquire the lock in SharedRuntime::monitor_exit_helper().
|
||||
if (!UseObjectMonitorTable) {
|
||||
andptr(monitor, ~(int32_t)markWord::monitor_value);
|
||||
}
|
||||
movptr(Address(thread, JavaThread::unlocked_inflated_monitor_offset()), monitor);
|
||||
|
||||
orl(t, 1); // Fast Unlock ZF = 0
|
||||
|
||||
@@ -660,8 +660,8 @@ intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp
|
||||
}
|
||||
|
||||
bool frame::was_augmented_on_entry(int& real_size) const {
|
||||
assert(is_compiled_frame(), "");
|
||||
if (_cb->as_nmethod_or_null()->needs_stack_repair()) {
|
||||
assert(_cb != nullptr && _cb->is_nmethod(), "");
|
||||
if (_cb->as_nmethod()->needs_stack_repair()) {
|
||||
// The stack increment resides just below the saved rbp on the stack
|
||||
// and does not account for the return address and rbp (see MacroAssembler::remove_frame).
|
||||
intptr_t* real_frame_size_addr = unextended_sp() + _cb->frame_size() - sender_sp_offset - 1;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetAssembler.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
@@ -363,11 +364,23 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
|
||||
assert_different_registers(obj, tmp1, tmp2);
|
||||
// Check if the oop is in the right area of memory
|
||||
__ movptr(tmp1, obj);
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andptr(tmp1, tmp2);
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
|
||||
__ movptr(tmp2, Address(tmp2));
|
||||
__ andptr(tmp1, tmp2);
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
|
||||
__ movptr(tmp2, Address(tmp2));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andptr(tmp1, tmp2);
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
}
|
||||
__ cmpptr(tmp1, tmp2);
|
||||
__ jcc(Assembler::notZero, error);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
|
||||
#include "gc/shenandoah/mode/shenandoahMode.hpp"
|
||||
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
|
||||
@@ -263,6 +264,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
|
||||
|
||||
// Optimized cset-test
|
||||
__ movptr(tmp1, dst);
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
assert_different_registers(tmp1, tmp2, rcx);
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
|
||||
@@ -272,7 +274,9 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
|
||||
__ pop(rcx);
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::cset_base_address()));
|
||||
__ movptr(tmp2, Address(tmp2));
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ shrptr(tmp1, ShenandoahHeapRegion::region_size_bytes_shift_jint());
|
||||
__ movptr(tmp2, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr());
|
||||
}
|
||||
@@ -504,11 +508,23 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) {
|
||||
assert_different_registers(obj, tmp1, tmp2);
|
||||
// Check if the oop is in the right area of memory
|
||||
__ movptr(tmp1, obj);
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andptr(tmp1, tmp2);
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
|
||||
__ movptr(tmp2, Address(tmp2));
|
||||
__ andptr(tmp1, tmp2);
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
|
||||
__ movptr(tmp2, Address(tmp2));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andptr(tmp1, tmp2);
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
}
|
||||
__ cmpptr(tmp1, tmp2);
|
||||
__ jcc(Assembler::notZero, L_error);
|
||||
|
||||
@@ -839,7 +855,8 @@ void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
|
||||
// If buffer is already full, go slow.
|
||||
__ movptr(tmp, index);
|
||||
__ subptr(tmp, wordSize);
|
||||
__ jccb(Assembler::below, L_pop_and_slow);
|
||||
// VerifyOops adds code for decoded oop and needs long jump here
|
||||
__ jcc(Assembler::below, L_pop_and_slow);
|
||||
__ movptr(index, tmp);
|
||||
__ addptr(tmp, buffer);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "code/vmreg.inline.hpp"
|
||||
#include "compiler/compileTask.hpp"
|
||||
@@ -1501,8 +1502,11 @@ void ZBarrierSetAssembler::retrieve_reloc_addresses(address start, address end,
|
||||
entries.append(nullptr);
|
||||
}
|
||||
|
||||
// Add indirection for AOT code patching
|
||||
address ZPointerLoadShiftTableAddr = (address)&ZPointerLoadShiftTable;
|
||||
|
||||
void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
|
||||
assert_different_registers(obj, tmp1, tmp2);
|
||||
// C1 calls verfy_oop in the middle of barriers, before they have been uncolored
|
||||
// and after being colored. Therefore, we must deal with colored oops as well.
|
||||
Label done;
|
||||
@@ -1533,8 +1537,10 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Registe
|
||||
__ andq(tmp1, tmp2);
|
||||
__ shrq(tmp1, ZPointerRemappedShift);
|
||||
__ andq(tmp1, (1 << ZPointerRemappedBits) - 1);
|
||||
__ lea(tmp2, ExternalAddress((address)&ZPointerLoadShiftTable));
|
||||
|
||||
// This code is not critical - it is used only for VerifyOops in debug VM.
|
||||
// Use inderection by defult without AOT specific code.
|
||||
__ lea(tmp2, ExternalAddress((address)&ZPointerLoadShiftTableAddr));
|
||||
__ movptr(tmp2, Address(tmp2));
|
||||
// Uncolor presumed zpointer
|
||||
assert(obj != rcx, "bad choice of register");
|
||||
if (rcx != tmp1 && rcx != tmp2) {
|
||||
@@ -1558,9 +1564,20 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Registe
|
||||
__ bind(check_zaddress);
|
||||
// Check if the oop is in the right area of memory
|
||||
__ movptr(tmp1, obj);
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andptr(tmp1, tmp2);
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
|
||||
__ movptr(tmp2, Address(tmp2));
|
||||
__ andptr(tmp1, tmp2);
|
||||
__ lea(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
|
||||
__ movptr(tmp2, Address(tmp2));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andptr(tmp1, tmp2);
|
||||
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
}
|
||||
__ cmpptr(tmp1, tmp2);
|
||||
__ jcc(Assembler::notZero, error);
|
||||
|
||||
|
||||
@@ -2444,18 +2444,6 @@ void MacroAssembler::test_field_is_flat(Register flags, Register temp_reg, Label
|
||||
void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int32_t test_bit, bool jmp_set, Label& jmp_label) {
|
||||
// load mark word
|
||||
movptr(temp_reg, Address(oop, oopDesc::mark_offset_in_bytes()));
|
||||
if (!UseObjectMonitorTable) {
|
||||
Label test_mark_word;
|
||||
// check displaced
|
||||
testl(temp_reg, markWord::unlocked_value);
|
||||
jccb(Assembler::notZero, test_mark_word);
|
||||
// slow path use klass prototype
|
||||
push(rscratch1);
|
||||
load_prototype_header(temp_reg, oop, rscratch1);
|
||||
pop(rscratch1);
|
||||
|
||||
bind(test_mark_word);
|
||||
}
|
||||
testl(temp_reg, test_bit);
|
||||
jcc((jmp_set) ? Assembler::notZero : Assembler::zero, jmp_label);
|
||||
}
|
||||
@@ -4912,7 +4900,15 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
ss.print("verify_oop: %s: %s (%s:%d)", reg->name(), s, file, line);
|
||||
b = code_string(ss.as_string());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
|
||||
// this will duplicate string to preserve it
|
||||
b = AOTCodeCache::add_C_string(ss.as_string());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
b = code_string(ss.as_string());
|
||||
}
|
||||
}
|
||||
AddressLiteral buffer((address) b, external_word_Relocation::spec_for_immediate());
|
||||
pushptr(buffer.addr(), rscratch1);
|
||||
@@ -5177,7 +5173,15 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
ss.print("verify_oop_addr: %s (%s:%d)", s, file, line);
|
||||
b = code_string(ss.as_string());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
|
||||
// this will duplicate string to preserve it
|
||||
b = AOTCodeCache::add_C_string(ss.as_string());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
b = code_string(ss.as_string());
|
||||
}
|
||||
}
|
||||
AddressLiteral buffer((address) b, external_word_Relocation::spec_for_immediate());
|
||||
pushptr(buffer.addr(), rscratch1);
|
||||
@@ -10595,10 +10599,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register reg_r
|
||||
// instruction emitted as it is part of C1's null check semantics.
|
||||
movptr(reg_rax, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
|
||||
if (UseObjectMonitorTable) {
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
movptr(Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))), 0);
|
||||
}
|
||||
// Clear cache in case fast locking succeeds or we need to take the slow-path.
|
||||
movptr(Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))), 0);
|
||||
|
||||
if (DiagnoseSyncOnValueBasedClasses != 0) {
|
||||
load_klass(tmp, obj, rscratch1);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2026, 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
|
||||
@@ -59,12 +59,6 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas
|
||||
|
||||
__ movptr(result, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
||||
|
||||
if (!UseObjectMonitorTable) {
|
||||
// check if monitor
|
||||
__ testptr(result, markWord::monitor_value);
|
||||
__ jcc(Assembler::notZero, slowCase);
|
||||
}
|
||||
|
||||
// get hash
|
||||
// Read the header and build a mask to get its hash field.
|
||||
// Depend on hash_mask being at most 32 bits and avoid the use of hash_mask_in_place
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, Intel Corporation. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -254,7 +254,7 @@ static auto whole_shuffle(Register scratch, KRegister mergeMask1, KRegister merg
|
||||
// swap the second operand (zetas) since the odd slots contain the same number
|
||||
// as the corresponding even one. This is indicated by input2NeedsShuffle=false)
|
||||
//
|
||||
// The registers to be multiplied are in input1[] and inputs2[]. The results go
|
||||
// The registers to be multiplied are in input1[] and input2[]. The results go
|
||||
// into output[]. Two scratch[] register arrays are expected. input1[] can
|
||||
// overlap with either output[] or scratch1[]
|
||||
// - If AVX512, all register arrays are of length 4
|
||||
@@ -279,7 +279,7 @@ static auto whole_montMul(XMMRegister montQInvModR, XMMRegister dilithium_q,
|
||||
// If so, use output:
|
||||
const XMMRegister* scratch = scratch1 == input1 ? output: scratch1;
|
||||
|
||||
// scratch = input1_even * intput2_even
|
||||
// scratch = input1_even * input2_even
|
||||
for (int i = 0; i < regCnt; i++) {
|
||||
__ vpmuldq(scratch[i], input1[i], input2[i], vector_len);
|
||||
}
|
||||
@@ -308,7 +308,7 @@ static auto whole_montMul(XMMRegister montQInvModR, XMMRegister dilithium_q,
|
||||
}
|
||||
}
|
||||
|
||||
// scratch1 = input1_even*intput2_even
|
||||
// scratch1 = input1_even*input2_even
|
||||
for (int i = 0; i < regCnt; i++) {
|
||||
__ vpmuldq(scratch1[i], input1[i], input2[i], vector_len);
|
||||
}
|
||||
@@ -423,7 +423,7 @@ static address generate_dilithiumAlmostNtt_avx(StubGenerator *stubgen,
|
||||
// products will be added to and subtracted from the other half of the
|
||||
// coefficients. In each level we just shuffle the coefficients that need to
|
||||
// be multiplied by the zetas in one set, the rest to another set of vector
|
||||
// registers, then redistribute the addition/substraction results.
|
||||
// registers, then redistribute the addition/subtraction results.
|
||||
|
||||
// For levels 0 and 1 the zetas are not different within the 4 xmm registers
|
||||
// that we would use for them, so we use only one register.
|
||||
@@ -649,7 +649,7 @@ static address generate_dilithiumAlmostNtt_avx(StubGenerator *stubgen,
|
||||
}
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -898,7 +898,7 @@ static address generate_dilithiumAlmostInverseNtt_avx(StubGenerator *stubgen,
|
||||
}
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -993,7 +993,7 @@ static address generate_dilithiumNttMult_avx(StubGenerator *stubgen,
|
||||
__ jcc(Assembler::notEqual, L_loop);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -1002,7 +1002,7 @@ static address generate_dilithiumNttMult_avx(StubGenerator *stubgen,
|
||||
return start;
|
||||
}
|
||||
|
||||
// Dilithium Motgomery multiply an array by a constant.
|
||||
// Dilithium Montgomery multiply an array by a constant.
|
||||
// Implements
|
||||
// static int implDilithiumMontMulByConstant(int[] coeffs, int constant) {}
|
||||
//
|
||||
@@ -1089,7 +1089,7 @@ static address generate_dilithiumMontMulByConstant_avx(StubGenerator *stubgen,
|
||||
__ jcc(Assembler::notEqual, L_loop);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -1357,7 +1357,7 @@ static address generate_dilithiumDecomposePoly_avx(StubGenerator *stubgen,
|
||||
__ jcc(Assembler::notEqual, L_loop);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
|
||||
@@ -349,11 +349,13 @@ static void store4regs(Register address, int offset, int sourceRegs[],
|
||||
}
|
||||
}
|
||||
|
||||
// In all 3 invocations of this function we use the same registers:
|
||||
// xmm0-xmm7 for the input and the result,
|
||||
// xmm8-xmm15 as scratch registers and
|
||||
// xmm16-xmm17 for the constants,
|
||||
// so we don't pass register arguments.
|
||||
// This stub helper vectorizes the reduction in implKyberBarrettReduceJava.
|
||||
// In all invocations of this function we use the same registers:
|
||||
// Input: xmm0-xmm7 (signed short coefficients)
|
||||
// xmm16: Barrett multiplier
|
||||
// xmm17: q
|
||||
// Scratch: xmm8-xmm15
|
||||
// Output: xmm0-xmm7 (reduced coefficients each in [0, q])
|
||||
static void barrettReduce(MacroAssembler *_masm) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
__ evpmulhw(xmm(i + 8), k0, xmm(i), xmm16, false, Assembler::AVX_512bit);
|
||||
@@ -490,7 +492,7 @@ address generate_kyberNtt_avx512(StubGenerator *stubgen,
|
||||
store4regs(coeffs, 256, xmm4_7, _masm);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -621,7 +623,7 @@ address generate_kyberInverseNtt_avx512(StubGenerator *stubgen,
|
||||
store4regs(coeffs, 256, xmm12_15, _masm);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -771,7 +773,7 @@ address generate_kyberNttMult_avx512(StubGenerator *stubgen,
|
||||
__ pop_ppx(r12);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -824,7 +826,7 @@ address generate_kyberAddPoly_2_avx512(StubGenerator *stubgen,
|
||||
store4regs(result, 256, xmm4_7, _masm);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -886,7 +888,7 @@ address generate_kyberAddPoly_3_avx512(StubGenerator *stubgen,
|
||||
store4regs(result, 256, xmm4_7, _masm);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -975,7 +977,7 @@ address generate_kyber12To16_avx512(StubGenerator *stubgen,
|
||||
__ jcc(Assembler::greater, VBMILoop);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -1051,7 +1053,7 @@ address generate_kyber12To16_avx512(StubGenerator *stubgen,
|
||||
__ jcc(Assembler::greater, Loop);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
@@ -1096,7 +1098,7 @@ address generate_kyberBarrettReduce_avx512(StubGenerator *stubgen,
|
||||
store4regs(coeffs, 256, xmm4_7, _masm);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ mov64(rax, 0); // return 0
|
||||
__ mov64(rax, 0); // Intrinsic returns a value of 0, whereas Java callees return 1
|
||||
__ ret(0);
|
||||
|
||||
// record the stub entry and end
|
||||
|
||||
@@ -628,7 +628,7 @@ static address generate_sha3_implCompress_avx512(StubId stub_id,
|
||||
// (2) - a lot of shuffles are inevitable, since there are not enough registers.
|
||||
// To save some shuffles, column1-column3 and column2-4 are placed into
|
||||
// the same 128-bit register. Column 0 is also grouped (by rows).
|
||||
// This means the SHA3 state fits into 12.5 regisers, leaving 3 registers as
|
||||
// This means the SHA3 state fits into 12.5 registers, leaving 3 registers as
|
||||
// temporaries. This is mostly sufficient, except for the Theta step, where we
|
||||
// have to buy two slots on the stack
|
||||
static address generate_sha3_implCompress_avx2(StubId stub_id,
|
||||
@@ -693,7 +693,7 @@ static address generate_sha3_implCompress_avx2(StubId stub_id,
|
||||
__ subptr(rsp, reg_size*2);
|
||||
|
||||
// Registers for memory load
|
||||
// Notice the careful 'missalignment' of pairs.
|
||||
// Notice the careful 'misalignment' of pairs.
|
||||
// This helps XOR for all blocksizes
|
||||
XMMRegister a0a1, _a2, a3a4;
|
||||
XMMRegister a5a6, a7a8, _a9;
|
||||
|
||||
+16
-15
@@ -24809,12 +24809,11 @@ instruct long_to_mask_evex(kReg dst, rRegL src) %{
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct mask_opers_evex(kReg dst, kReg src1, kReg src2, kReg kscratch) %{
|
||||
instruct mask_opers_evex(kReg dst, kReg src1, kReg src2) %{
|
||||
match(Set dst (AndVMask src1 src2));
|
||||
match(Set dst (OrVMask src1 src2));
|
||||
match(Set dst (XorVMask src1 src2));
|
||||
effect(TEMP kscratch);
|
||||
format %{ "mask_opers_evex $dst, $src1, $src2\t! using $kscratch as TEMP" %}
|
||||
format %{ "mask_opers_evex $dst, $src1, $src2" %}
|
||||
ins_encode %{
|
||||
const MachNode* mask1 = static_cast<const MachNode*>(this->in(this->operand_index($src1)));
|
||||
const MachNode* mask2 = static_cast<const MachNode*>(this->in(this->operand_index($src2)));
|
||||
@@ -25247,11 +25246,10 @@ instruct scalar_minmax_HF_reg(regF dst, regF src1, regF src2, kReg ktmp, regF xt
|
||||
|
||||
instruct scalar_fma_HF_reg(regF dst, regF src1, regF src2)
|
||||
%{
|
||||
match(Set dst (FmaHF src2 (Binary dst src1)));
|
||||
effect(DEF dst);
|
||||
format %{ "scalar_fma_fp16 $dst, $src1, $src2\t# $dst = $dst * $src1 + $src2 fma packedH" %}
|
||||
match(Set dst (FmaHF dst (Binary src1 src2)));
|
||||
format %{ "scalar_fma_fp16 $dst, $src1, $src2\t# $dst = $src1 * $src2 + $dst fma packedH" %}
|
||||
ins_encode %{
|
||||
__ vfmadd132sh($dst$$XMMRegister, $src2$$XMMRegister, $src1$$XMMRegister);
|
||||
__ vfmadd231sh($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
@@ -25270,6 +25268,7 @@ instruct vector_sqrt_HF_reg(vec dst, vec src)
|
||||
|
||||
instruct vector_sqrt_HF_mem(vec dst, memory src)
|
||||
%{
|
||||
predicate(Matcher::vector_length_in_bytes(n) > 8);
|
||||
match(Set dst (SqrtVHF (VectorReinterpret (LoadVector src))));
|
||||
format %{ "vector_sqrt_fp16_mem $dst, $src" %}
|
||||
ins_encode %{
|
||||
@@ -25297,6 +25296,7 @@ instruct vector_binOps_HF_reg(vec dst, vec src1, vec src2)
|
||||
|
||||
instruct vector_binOps_HF_mem(vec dst, vec src1, memory src2)
|
||||
%{
|
||||
predicate(Matcher::vector_length_in_bytes(n) > 8);
|
||||
match(Set dst (AddVHF src1 (VectorReinterpret (LoadVector src2))));
|
||||
match(Set dst (DivVHF src1 (VectorReinterpret (LoadVector src2))));
|
||||
match(Set dst (MulVHF src1 (VectorReinterpret (LoadVector src2))));
|
||||
@@ -25312,29 +25312,30 @@ instruct vector_binOps_HF_mem(vec dst, vec src1, memory src2)
|
||||
|
||||
instruct vector_fma_HF_reg(vec dst, vec src1, vec src2)
|
||||
%{
|
||||
match(Set dst (FmaVHF src2 (Binary dst src1)));
|
||||
format %{ "vector_fma_fp16 $dst, $src1, $src2\t# $dst = $dst * $src1 + $src2 fma packedH" %}
|
||||
match(Set dst (FmaVHF dst (Binary src1 src2)));
|
||||
format %{ "vector_fma_fp16 $dst, $src1, $src2\t# $dst = $src1 * $src2 + $dst fma packedH" %}
|
||||
ins_encode %{
|
||||
int vlen_enc = vector_length_encoding(this);
|
||||
__ evfmadd132ph($dst$$XMMRegister, $src2$$XMMRegister, $src1$$XMMRegister, vlen_enc);
|
||||
__ evfmadd231ph($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vlen_enc);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct vector_fma_HF_mem(vec dst, memory src1, vec src2)
|
||||
instruct vector_fma_HF_mem(vec dst, vec src1, memory src2)
|
||||
%{
|
||||
match(Set dst (FmaVHF src2 (Binary dst (VectorReinterpret (LoadVector src1)))));
|
||||
format %{ "vector_fma_fp16_mem $dst, $src1, $src2\t# $dst = $dst * $src1 + $src2 fma packedH" %}
|
||||
predicate(Matcher::vector_length_in_bytes(n) > 8);
|
||||
match(Set dst (FmaVHF dst (Binary src1 (VectorReinterpret (LoadVector src2)))));
|
||||
format %{ "vector_fma_fp16_mem $dst, $src1, $src2\t# $dst = $src1 * $src2 + $dst fma packedH" %}
|
||||
ins_encode %{
|
||||
int vlen_enc = vector_length_encoding(this);
|
||||
__ evfmadd132ph($dst$$XMMRegister, $src2$$XMMRegister, $src1$$Address, vlen_enc);
|
||||
__ evfmadd231ph($dst$$XMMRegister, $src1$$XMMRegister, $src2$$Address, vlen_enc);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct vector_minmax_HF_mem_avx10_2(vec dst, vec src1, memory src2)
|
||||
%{
|
||||
predicate(VM_Version::supports_avx10_2());
|
||||
predicate(VM_Version::supports_avx10_2() && Matcher::vector_length_in_bytes(n) > 8);
|
||||
match(Set dst (MinVHF src1 (VectorReinterpret (LoadVector src2))));
|
||||
match(Set dst (MaxVHF src1 (VectorReinterpret (LoadVector src2))));
|
||||
format %{ "vector_min_max_fp16_mem $dst, $src1, $src2" %}
|
||||
|
||||
@@ -1897,7 +1897,11 @@ static bool checked_mprotect(char* addr, size_t size, int prot) {
|
||||
}
|
||||
}
|
||||
|
||||
assert(rc == true, "mprotect failed.");
|
||||
if (!rc) {
|
||||
// Reporting success via mprotect but failing to mprotect is a symptom of calling mprotect
|
||||
// on SystemV-memory. It should not happen for mmap-mode.
|
||||
assert(!g_multipage_support.can_use_64K_mmap_pages, "Should only happen in old-style shmat mode");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,9 @@
|
||||
#include "utilities/population_count.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
#include "windbghelp.hpp"
|
||||
#if defined(_M_ARM64)
|
||||
#include CPU_HEADER(pauth)
|
||||
#endif
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "jfr/support/jfrNativeLibraryLoadEvent.hpp"
|
||||
@@ -6637,6 +6640,19 @@ bool os::win32::platform_print_native_stack(outputStream* st, const void* contex
|
||||
int count = 0;
|
||||
address lastpc_internal = 0;
|
||||
while (count++ < StackPrintLimit) {
|
||||
#if defined(_M_ARM64)
|
||||
// On Windows/ARM64, when the CPU is using authenticated pointers, return
|
||||
// addresses are signed. Unfortunately, `StackWalk64()` does not strip the
|
||||
// pointer signature, so we need to do this ourself. Since stripping the
|
||||
// signature is an idempotent operation, we don't need to guard this call
|
||||
// based on whether pointer authentication is enabled.
|
||||
address original = (address)stk.AddrPC.Offset;
|
||||
address stripped = pauth_strip_pointer(original);
|
||||
stk.AddrPC.Offset = (DWORD64)(uintptr_t)stripped;
|
||||
|
||||
// We updated the stack frame's PC, so keep the context's PC in sync.
|
||||
ctx.Pc = stk.AddrPC.Offset;
|
||||
#endif
|
||||
intptr_t* sp = (intptr_t*)stk.AddrStack.Offset;
|
||||
intptr_t* fp = (intptr_t*)stk.AddrFrame.Offset; // NOT necessarily the same as ctx.Rbp!
|
||||
address pc = (address)stk.AddrPC.Offset;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
;
|
||||
; Copyright (c) 2026, Microsoft 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.
|
||||
;
|
||||
|
||||
; Remove the AArch64 pointer signature from the pointer argument
|
||||
;
|
||||
; Both XPACI and XPACLRI can get the job done, with XPACI being more
|
||||
; convenient since it can work with any general purpose register. However,
|
||||
; unlike XPACI, XPACLRI can be encoded using hint instructions, thus letting
|
||||
; us compile this function using older compilers.
|
||||
;
|
||||
; Since XPACLRI implicitly uses the link register (x30) and we instead want
|
||||
; to remove the signature from the function argument (in x0), we temporarily
|
||||
; save x30 before restoring it at the end.
|
||||
|
||||
ALIGN 4
|
||||
EXPORT pauth_drop_signature_win_arm64
|
||||
AREA pauth_text, CODE
|
||||
|
||||
pauth_drop_signature_win_arm64
|
||||
mov x9, x30
|
||||
mov x30, x0
|
||||
hint #7
|
||||
mov x0, x30
|
||||
mov x30, x9
|
||||
ret
|
||||
|
||||
END
|
||||
@@ -28,9 +28,10 @@
|
||||
// OS specific Support for ROP Protection in VM code.
|
||||
// For more details on PAC see pauth_aarch64.hpp.
|
||||
|
||||
extern "C" address pauth_drop_signature_win_arm64(address p);
|
||||
|
||||
inline address pauth_strip_pointer(address ptr) {
|
||||
// No PAC support in windows as of yet.
|
||||
return ptr;
|
||||
return pauth_drop_signature_win_arm64(ptr);
|
||||
}
|
||||
|
||||
inline address pauth_sign_return_address(address ret_addr) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2026, 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
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "compiler/compilationMemoryStatistic.hpp"
|
||||
#include "compiler/compileLog.hpp"
|
||||
#include "compiler/compiler_globals.hpp"
|
||||
#include "compiler/compilerDefinitions.hpp"
|
||||
#include "compiler/compilerDirectives.hpp"
|
||||
#include "compiler/compileTask.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@@ -556,6 +557,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho
|
||||
, _directive(directive)
|
||||
, _env(env)
|
||||
, _log(env->log())
|
||||
, _stress(_directive, _log, compiler_c1)
|
||||
, _method(method)
|
||||
, _osr_bci(osr_bci)
|
||||
, _hir(nullptr)
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "compiler/compiler_globals.hpp"
|
||||
#include "compiler/compilerDefinitions.inline.hpp"
|
||||
#include "compiler/compilerDirectives.hpp"
|
||||
#include "compiler/stress.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
|
||||
@@ -70,6 +71,7 @@ class Compilation: public StackObj {
|
||||
DirectiveSet* _directive;
|
||||
ciEnv* _env;
|
||||
CompileLog* _log;
|
||||
Stress _stress;
|
||||
ciMethod* _method;
|
||||
int _osr_bci;
|
||||
IR* _hir;
|
||||
@@ -138,6 +140,7 @@ class Compilation: public StackObj {
|
||||
DirectiveSet* directive() const { return _directive; }
|
||||
CompileLog* log() const { return _log; }
|
||||
AbstractCompiler* compiler() const { return _compiler; }
|
||||
Stress& stress() { return _stress; }
|
||||
bool has_exception_handlers() const { return _has_exception_handlers; }
|
||||
bool has_fpu_code() const { return _has_fpu_code; }
|
||||
bool has_unsafe_access() const { return _has_unsafe_access; }
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
|
||||
DEBUG_ONLY(InstanceKlass* _aot_init_class = nullptr;)
|
||||
DEBUG_ONLY(InstanceKlass* _aot_init_test_class = nullptr;)
|
||||
|
||||
bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
assert(!ArchiveBuilder::is_active() || !ArchiveBuilder::current()->is_in_buffer_space(ik), "must be source klass");
|
||||
@@ -65,10 +65,10 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
//
|
||||
// Check that no user code is executed during the assembly phase. Otherwise the user
|
||||
// code may introduce undesirable environment dependencies into the heap image.
|
||||
// If any of these two flags are set, we allow user code to be executed
|
||||
// If AOTInitTestClass is set, we allow user code to be executed
|
||||
// in the assembly phase. Note that these flags are strictly for the purpose
|
||||
// of testing HotSpot and are not available in product builds.
|
||||
if (AOTInitTestClass == nullptr && ArchiveHeapTestClass == nullptr) {
|
||||
if (AOTInitTestClass == nullptr) {
|
||||
if (ik->defined_by_boot_loader()) {
|
||||
// We allow boot classes to be AOT-initialized, except for classes from
|
||||
// -Xbootclasspath (cp index >= 1) be AOT-initialized, as such classes may be
|
||||
@@ -258,7 +258,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
if (ik == _aot_init_class) {
|
||||
if (ik == _aot_init_test_class) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -356,12 +356,12 @@ void AOTClassInitializer::init_test_class(TRAPS) {
|
||||
vm_exit_during_initialization("Invalid name for AOTInitTestClass", AOTInitTestClass);
|
||||
}
|
||||
|
||||
_aot_init_class = InstanceKlass::cast(k);
|
||||
_aot_init_class->initialize(CHECK);
|
||||
_aot_init_test_class = InstanceKlass::cast(k);
|
||||
_aot_init_test_class->initialize(CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
bool AOTClassInitializer::has_test_class() {
|
||||
return _aot_init_class != nullptr;
|
||||
return _aot_init_test_class != nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -98,6 +98,7 @@ public:
|
||||
|
||||
int current() const { return _current; }
|
||||
bool is_empty() const { return _array.length() == 0; }
|
||||
int size() const { return _array.length(); }
|
||||
};
|
||||
|
||||
class BootCpClassLocationStream : public ClassLocationStream {
|
||||
@@ -435,7 +436,7 @@ bool AOTClassLocation::check(const char* runtime_path, bool has_aot_linked_class
|
||||
}
|
||||
}
|
||||
|
||||
log_info(class, path)("ok");
|
||||
log_info(class, path)("ok (file size and timestamp have not changed)");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -633,7 +634,7 @@ void AOTClassLocationConfig::add_class_location(JavaThread* current, GrowableCla
|
||||
// other via cpattr.
|
||||
bool found_duplicate = false;
|
||||
for (int i = boot_cp_start_index(); i < tmp_array.length(); i++) {
|
||||
if (strcmp(tmp_array.at(i)->path(), libname) == 0) {
|
||||
if (os::same_files(tmp_array.at(i)->path(), libname)) {
|
||||
found_duplicate = true;
|
||||
break;
|
||||
}
|
||||
@@ -760,7 +761,7 @@ bool AOTClassLocationConfig::check_classpaths(bool is_boot_classpath, bool has_a
|
||||
LogTarget(Info, class, path) lt;
|
||||
if (lt.is_enabled()) {
|
||||
LogStream ls(lt);
|
||||
ls.print("Checking %s classpath", which);
|
||||
ls.print("Checking %s classpath from index [%d]", which, index_start);
|
||||
ls.print_cr("%s", use_lcp_match ? " (with longest common prefix substitution)" : "");
|
||||
ls.print("- expected : '");
|
||||
print_dumptime_classpath(ls, index_start, index_end, use_lcp_match, _dumptime_lcp_len, runtime_lcp, runtime_lcp_len);
|
||||
@@ -832,68 +833,94 @@ bool AOTClassLocationConfig::check_paths_existence(ClassLocationStream& runtime_
|
||||
return exist;
|
||||
}
|
||||
|
||||
bool AOTClassLocationConfig::check_module_paths(bool has_aot_linked_classes, int index_start, int index_end,
|
||||
ClassLocationStream& runtime_css,
|
||||
bool* has_extra_module_paths) const {
|
||||
if (index_start >= index_end && runtime_css.is_empty()) { // nothing to check
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AOTClassLocationConfig::check_module_paths(bool has_aot_linked_classes, bool has_full_module_graph,
|
||||
ModulePathClassLocationStream& runtime_module_css) const {
|
||||
const int index_start = module_path_start_index();
|
||||
const int index_end = module_path_end_index();
|
||||
ResourceMark rm;
|
||||
|
||||
LogTarget(Info, class, path) lt;
|
||||
if (lt.is_enabled()) {
|
||||
LogStream ls(lt);
|
||||
ls.print_cr("Checking module paths");
|
||||
ls.print_cr("Checking module paths from index [%d]", index_start);
|
||||
ls.print("- expected : '");
|
||||
print_dumptime_classpath(ls, index_start, index_end, false, 0, nullptr, 0);
|
||||
ls.print_cr("'");
|
||||
ls.print("- actual : '");
|
||||
runtime_css.print(&ls);
|
||||
runtime_module_css.print(&ls);
|
||||
ls.print_cr("'");
|
||||
}
|
||||
|
||||
// Make sure all the dumptime module paths exist and are unchanged
|
||||
// All JAR files in the dumptime module paths must exist and must be unchanged,
|
||||
// or else we have a "hard" failure, as we can no longer guarantee that archived
|
||||
// classes from the module paths remain unchanged at runtime.
|
||||
for (int i = index_start; i < index_end; i++) {
|
||||
const AOTClassLocation* cs = class_location_at(i);
|
||||
const char* dumptime_path = cs->path();
|
||||
|
||||
assert(!cs->from_cpattr(), "not applicable for module path");
|
||||
log_info(class, path)("Checking '%s' %s", dumptime_path, cs->file_type_string());
|
||||
log_info(class, path)("Checking [%d] '%s' %s", i, dumptime_path, cs->file_type_string());
|
||||
|
||||
if (!cs->check(dumptime_path, has_aot_linked_classes)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We allow runtime_css to be a superset of the module paths specified in dumptime. E.g.,
|
||||
// Dumptime: A:C
|
||||
// Runtime: A:B:C
|
||||
runtime_css.start();
|
||||
for (int i = index_start; i < index_end; i++) {
|
||||
const AOTClassLocation* cs = class_location_at(i);
|
||||
const char* dumptime_path = cs->path();
|
||||
|
||||
while (true) {
|
||||
if (!runtime_css.has_next()) {
|
||||
aot_log_warning(aot)("module path has fewer elements than expected");
|
||||
*has_extra_module_paths = true;
|
||||
return true;
|
||||
if (!check_module_paths_exact_match(runtime_module_css)) {
|
||||
if (CDSConfig::new_aot_flags_used()) {
|
||||
// New AOT workflow requires an exact match for --module-paths.
|
||||
return false;
|
||||
} else {
|
||||
// For classical CDS, we have a "soft" failure if the runtime module paths are
|
||||
// not an exact match with the dumptime module paths:
|
||||
// Classes from the module path will not be loaded if they are
|
||||
// rejected by SystemDictionary::is_shared_class_visible().
|
||||
if (has_full_module_graph) {
|
||||
CDSConfig::disable_full_module_graph();
|
||||
AOTMetaspace::report_loading_error("full module graph: disabled because extra module path(s) are specified");
|
||||
}
|
||||
// Both this->class_locations() and runtime_css are alphabetically sorted. Skip
|
||||
// items in runtime_css until we see dumptime_path.
|
||||
const char* runtime_path = runtime_css.get_next();
|
||||
if (!os::same_files(dumptime_path, runtime_path)) {
|
||||
*has_extra_module_paths = true;
|
||||
return true;
|
||||
} else {
|
||||
break;
|
||||
|
||||
if (CDSConfig::is_dumping_dynamic_archive() && num_module_paths() > 0) {
|
||||
CDSConfig::disable_dumping_dynamic_archive();
|
||||
aot_log_warning(aot)("Dynamic archiving is disabled because base layer archive has a different module path");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_css.has_next()) {
|
||||
*has_extra_module_paths = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AOTClassLocationConfig::check_module_paths_exact_match(ModulePathClassLocationStream& runtime_module_css) const {
|
||||
if (runtime_module_css.has_non_jar_modules()) {
|
||||
AOTMetaspace::report_loading_error("module path contains sub-directories or non-JAR files (incompatible with full module graph)");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int index_start = module_path_start_index();
|
||||
const int index_end = module_path_end_index();
|
||||
|
||||
runtime_module_css.start();
|
||||
for (int i = index_start; i < index_end; i++) {
|
||||
const AOTClassLocation* cs = class_location_at(i);
|
||||
const char* dumptime_path = cs->path();
|
||||
|
||||
if (!runtime_module_css.has_next()) {
|
||||
AOTMetaspace::report_loading_error("module path has fewer elements (%d) than expected (%d)", runtime_module_css.size(), num_module_paths());
|
||||
return false;
|
||||
}
|
||||
const char* runtime_path = runtime_module_css.get_next();
|
||||
// Both dumptime and runtime module paths are alphabetically sorted, so we just need to
|
||||
// compare each element at the same position.
|
||||
if (!os::same_files(dumptime_path, runtime_path)) {
|
||||
AOTMetaspace::report_loading_error("module path at [%d] is different: expected %s actual %s",
|
||||
i, dumptime_path, runtime_path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_module_css.has_next()) {
|
||||
AOTMetaspace::report_loading_error("module path has more elements (%d) than expected (%d)", runtime_module_css.size(), num_module_paths());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -967,12 +994,13 @@ bool AOTClassLocationConfig::need_lcp_match_helper(int start, int end, ClassLoca
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_linked_classes, bool* has_extra_module_paths) const {
|
||||
bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_linked_classes, bool has_full_module_graph) const {
|
||||
ResourceMark rm;
|
||||
AllClassLocationStreams all_css;
|
||||
|
||||
log_locations(cache_filename, /*is_write=*/false);
|
||||
|
||||
// (1) Check JRT modules image
|
||||
const char* jrt = ClassLoader::get_jrt_entry()->name();
|
||||
log_info(class, path)("Checking [0] (modules image)");
|
||||
bool success = class_location_at(0)->check(jrt, has_aot_linked_classes);
|
||||
@@ -980,13 +1008,9 @@ bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_l
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
if (class_locations()->length() == 1) {
|
||||
if ((module_path_start_index() >= module_path_end_index()) && Arguments::get_property("jdk.module.path") != nullptr) {
|
||||
*has_extra_module_paths = true;
|
||||
} else {
|
||||
*has_extra_module_paths = false;
|
||||
}
|
||||
} else {
|
||||
|
||||
{
|
||||
// (2) Check boot/app classpath
|
||||
bool use_lcp_match = need_lcp_match(all_css);
|
||||
const char* runtime_lcp;
|
||||
size_t runtime_lcp_len;
|
||||
@@ -1011,11 +1035,10 @@ bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_l
|
||||
log_info(class, path)("Archived app classpath validation: %s", success ? "passed" : "failed");
|
||||
}
|
||||
|
||||
// (3) Check module paths
|
||||
if (success) {
|
||||
success = check_module_paths(has_aot_linked_classes, module_path_start_index(), module_path_end_index(),
|
||||
all_css.module_path(), has_extra_module_paths);
|
||||
log_info(class, path)("Archived module path validation: %s%s", success ? "passed" : "failed",
|
||||
(*has_extra_module_paths) ? " (extra module paths found)" : "");
|
||||
success = check_module_paths(has_aot_linked_classes, has_full_module_graph, all_css.module_path());
|
||||
log_info(class, path)("Archived module path validation: %s", success ? "passed" : "failed");
|
||||
}
|
||||
|
||||
if (runtime_lcp_len > 0) {
|
||||
@@ -1033,7 +1056,7 @@ bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_l
|
||||
if (CDSConfig::is_dumping_final_static_archive()) {
|
||||
aot_log_error(aot)("class path and/or module path are not compatible with the "
|
||||
"ones specified when the AOTConfiguration file was recorded%s", hint_msg);
|
||||
vm_exit_during_initialization("Unable to use create AOT cache.", nullptr);
|
||||
AOTMetaspace::unrecoverable_writing_error("Unable to use create AOT cache.");
|
||||
} else {
|
||||
aot_log_error(aot)("%s%s", mismatch_msg, hint_msg);
|
||||
AOTMetaspace::unrecoverable_loading_error();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, 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
|
||||
@@ -36,6 +36,7 @@
|
||||
class AllClassLocationStreams;
|
||||
class ClassLocationStream;
|
||||
class ClassPathZipEntry;
|
||||
class ModulePathClassLocationStream;
|
||||
class LogStream;
|
||||
|
||||
// An AOTClassLocation is a location where the application is configured to load Java classes
|
||||
@@ -164,8 +165,8 @@ class AOTClassLocationConfig : public CHeapObj<mtClassShared> {
|
||||
bool check_classpaths(bool is_boot_classpath, bool has_aot_linked_classes,
|
||||
int index_start, int index_end, ClassLocationStream& runtime_css,
|
||||
bool use_lcp_match, const char* runtime_lcp, size_t runtime_lcp_len) const;
|
||||
bool check_module_paths(bool has_aot_linked_classes, int index_start, int index_end, ClassLocationStream& runtime_css,
|
||||
bool* has_extra_module_paths) const;
|
||||
bool check_module_paths(bool has_aot_linked_classes, bool has_full_module_graph, ModulePathClassLocationStream& runtime_module_css) const;
|
||||
bool check_module_paths_exact_match(ModulePathClassLocationStream& runtime_module_css) const;
|
||||
bool file_exists(const char* filename) const;
|
||||
bool check_paths_existence(ClassLocationStream& runtime_css) const;
|
||||
|
||||
@@ -270,7 +271,7 @@ public:
|
||||
AOTClassLocationConfig* write_to_archive() const;
|
||||
|
||||
// Functions used only during runtime
|
||||
bool validate(const char* cache_filename, bool has_aot_linked_classes, bool* has_extra_module_paths) const;
|
||||
bool validate(const char* cache_filename, bool has_aot_linked_classes, bool has_full_module_graph) const;
|
||||
|
||||
bool is_valid_classpath_index(int classpath_index, InstanceKlass* ik);
|
||||
|
||||
|
||||
@@ -85,6 +85,9 @@ void AOTLinkedClassBulkLoader::preload_classes_impl(TRAPS) {
|
||||
initiate_loading(THREAD, "app", h_system_loader, table->boot2());
|
||||
initiate_loading(THREAD, "app", h_system_loader, table->platform());
|
||||
preload_classes_in_table(table->app(), "app", h_system_loader, CHECK);
|
||||
|
||||
// Do this after all boot/platform/app classes are loaded, but before bytecode execution.
|
||||
HeapShared::load_cached_resolved_methods();
|
||||
}
|
||||
|
||||
void AOTLinkedClassBulkLoader::preload_classes_in_table(Array<InstanceKlass*>* classes,
|
||||
|
||||
@@ -117,7 +117,6 @@ void* AOTMetaspace::_aot_metaspace_static_top = nullptr;
|
||||
intx AOTMetaspace::_relocation_delta;
|
||||
char* AOTMetaspace::_requested_base_address;
|
||||
Array<Method*>* AOTMetaspace::_archived_method_handle_intrinsics = nullptr;
|
||||
bool AOTMetaspace::_use_optimized_module_handling = true;
|
||||
int volatile AOTMetaspace::_preimage_static_archive_dumped = 0;
|
||||
FileMapInfo* AOTMetaspace::_output_mapinfo = nullptr;
|
||||
|
||||
@@ -1192,8 +1191,8 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS
|
||||
AOTReferenceObjSupport::initialize(CHECK);
|
||||
AOTReferenceObjSupport::stabilize_cached_reference_objects(CHECK);
|
||||
} else {
|
||||
log_info(aot)("Not dumping heap, reset CDSConfig::_is_using_optimized_module_handling");
|
||||
CDSConfig::stop_using_optimized_module_handling();
|
||||
log_info(aot)("Not dumping heap, disable full module graph");
|
||||
CDSConfig::disable_full_module_graph();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1467,6 +1466,7 @@ bool AOTMetaspace::in_aot_cache_static_region(void* p) {
|
||||
// - There's an error that indicates that the archive(s) files were corrupt or otherwise damaged.
|
||||
// - When -XX:+RequireSharedSpaces is specified, AND the JVM cannot load the archive(s) due
|
||||
// to version or classpath mismatch.
|
||||
[[noreturn]]
|
||||
void AOTMetaspace::unrecoverable_loading_error(const char* message) {
|
||||
report_loading_error("%s", message);
|
||||
|
||||
@@ -1477,6 +1477,7 @@ void AOTMetaspace::unrecoverable_loading_error(const char* message) {
|
||||
} else {
|
||||
vm_exit_during_initialization("Unable to use shared archive. Unrecoverable archive loading error (run with -Xlog:aot,cds for details)", message);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void AOTMetaspace::report_loading_error(const char* format, ...) {
|
||||
@@ -1512,15 +1513,17 @@ void AOTMetaspace::report_loading_error(const char* format, ...) {
|
||||
|
||||
// This function is called when the JVM is unable to write the specified CDS archive due to an
|
||||
// unrecoverable error.
|
||||
[[noreturn]]
|
||||
void AOTMetaspace::unrecoverable_writing_error(const char* message) {
|
||||
writing_error(message);
|
||||
vm_direct_exit(1);
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// This function is called when the JVM is unable to write the specified CDS archive due to a
|
||||
// an error. The error will be propagated
|
||||
void AOTMetaspace::writing_error(const char* message) {
|
||||
aot_log_error(aot)("An error has occurred while writing the shared archive file.");
|
||||
aot_log_error(aot)("An error has occurred while writing the %s.", CDSConfig::type_of_archive_being_written());
|
||||
if (message != nullptr) {
|
||||
aot_log_error(aot)("%s", message);
|
||||
}
|
||||
@@ -1853,7 +1856,6 @@ MapArchiveResult AOTMetaspace::map_archives(FileMapInfo* static_mapinfo, FileMap
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_CLASS_SPACE
|
||||
log_info(aot)("initial optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled");
|
||||
log_info(aot)("initial full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled");
|
||||
} else {
|
||||
unmap_archive(static_mapinfo);
|
||||
|
||||
@@ -58,7 +58,6 @@ class AOTMetaspace : AllStatic {
|
||||
static void* _aot_metaspace_static_top;
|
||||
static intx _relocation_delta;
|
||||
static char* _requested_base_address;
|
||||
static bool _use_optimized_module_handling;
|
||||
static Array<Method*>* _archived_method_handle_intrinsics;
|
||||
static int volatile _preimage_static_archive_dumped;
|
||||
static FileMapInfo* _output_mapinfo;
|
||||
@@ -120,9 +119,9 @@ public:
|
||||
|
||||
static bool preimage_static_archive_dumped() NOT_CDS_RETURN_(false);
|
||||
|
||||
static void unrecoverable_loading_error(const char* message = "unrecoverable error");
|
||||
[[noreturn]] static void unrecoverable_loading_error(const char* message = "unrecoverable error");
|
||||
static void report_loading_error(const char* format, ...) ATTRIBUTE_PRINTF(1, 0);
|
||||
static void unrecoverable_writing_error(const char* message = nullptr);
|
||||
[[noreturn]] static void unrecoverable_writing_error(const char* message = nullptr);
|
||||
static void writing_error(const char* message = nullptr);
|
||||
|
||||
static void make_method_handle_intrinsics_shareable() NOT_CDS_RETURN;
|
||||
@@ -184,10 +183,6 @@ public:
|
||||
return is_windows;
|
||||
}
|
||||
|
||||
// Can we skip some expensive operations related to modules?
|
||||
static bool use_optimized_module_handling() { return NOT_CDS(false) CDS_ONLY(_use_optimized_module_handling); }
|
||||
static void disable_optimized_module_handling() { _use_optimized_module_handling = false; }
|
||||
|
||||
// Check if the supplied shared base address can be used as the encoding base.
|
||||
static bool shared_base_valid(char* shared_base);
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ bool CDSConfig::_is_dumping_static_archive = false;
|
||||
bool CDSConfig::_is_dumping_preimage_static_archive = false;
|
||||
bool CDSConfig::_is_dumping_final_static_archive = false;
|
||||
bool CDSConfig::_is_dumping_dynamic_archive = false;
|
||||
bool CDSConfig::_is_using_optimized_module_handling = true;
|
||||
bool CDSConfig::_is_dumping_full_module_graph = true;
|
||||
bool CDSConfig::_is_using_full_module_graph = true;
|
||||
bool CDSConfig::_has_aot_linked_classes = false;
|
||||
@@ -325,8 +324,8 @@ void CDSConfig::ergo_init_classic_archive_paths() {
|
||||
|
||||
void CDSConfig::check_internal_module_property(const char* key, const char* value) {
|
||||
if (Arguments::is_incompatible_cds_internal_module_property(key)) {
|
||||
stop_using_optimized_module_handling();
|
||||
aot_log_info(aot)("optimized module handling: disabled due to incompatible property: %s=%s", key, value);
|
||||
disable_full_module_graph();
|
||||
aot_log_info(aot)("full mmodule graph: disabled due to incompatible property: %s=%s", key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,9 +579,8 @@ void CDSConfig::check_aotmode_record() {
|
||||
_is_dumping_static_archive = true;
|
||||
_is_dumping_preimage_static_archive = true;
|
||||
|
||||
// At VM exit, the module graph may be contaminated with program states.
|
||||
// At the end of the training run, the module graph may be contaminated with program states.
|
||||
// We will rebuild the module graph when dumping the CDS final image.
|
||||
_is_using_optimized_module_handling = false;
|
||||
_is_using_full_module_graph = false;
|
||||
_is_dumping_full_module_graph = false;
|
||||
}
|
||||
@@ -769,11 +767,20 @@ void CDSConfig::setup_compiler_args() {
|
||||
void CDSConfig::prepare_for_dumping() {
|
||||
assert(CDSConfig::is_dumping_archive(), "sanity");
|
||||
|
||||
if (is_dumping_classic_static_archive() && AOTClassLinking) {
|
||||
if (FLAG_IS_CMDLINE(AOTClassLinking)) {
|
||||
log_warning(cds)("AOTClassLinking is not supported for classic CDS archive");
|
||||
}
|
||||
FLAG_SET_ERGO(AOTClassLinking, false);
|
||||
FLAG_SET_ERGO(AOTInvokeDynamicLinking, false);
|
||||
}
|
||||
|
||||
if (is_dumping_dynamic_archive() && AOTClassLinking) {
|
||||
if (FLAG_IS_CMDLINE(AOTClassLinking)) {
|
||||
log_warning(cds)("AOTClassLinking is not supported for dynamic CDS archive");
|
||||
}
|
||||
FLAG_SET_ERGO(AOTClassLinking, false);
|
||||
FLAG_SET_ERGO(AOTInvokeDynamicLinking, false);
|
||||
}
|
||||
|
||||
if (is_dumping_dynamic_archive() && !is_using_archive()) {
|
||||
@@ -863,13 +870,6 @@ bool CDSConfig::is_dumping_regenerated_lambdaform_invokers() {
|
||||
}
|
||||
}
|
||||
|
||||
void CDSConfig::stop_using_optimized_module_handling() {
|
||||
_is_using_optimized_module_handling = false;
|
||||
_is_dumping_full_module_graph = false; // This requires is_using_optimized_module_handling()
|
||||
_is_using_full_module_graph = false; // This requires is_using_optimized_module_handling()
|
||||
}
|
||||
|
||||
|
||||
CDSConfig::DumperThreadMark::DumperThreadMark(JavaThread* current) {
|
||||
assert(_dumper_thread == nullptr, "sanity");
|
||||
_dumper_thread = current;
|
||||
@@ -958,7 +958,7 @@ bool CDSConfig::is_preserving_verification_constraints() {
|
||||
} else if (is_dumping_final_static_archive()) { // writing AOT cache
|
||||
return is_dumping_aot_linked_classes();
|
||||
} else if (is_dumping_classic_static_archive()) {
|
||||
return is_dumping_aot_linked_classes();
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -1018,6 +1018,12 @@ bool CDSConfig::is_using_klass_subgraphs() {
|
||||
!CDSConfig::is_dumping_final_static_archive());
|
||||
}
|
||||
|
||||
// Prevent the JVM from dumping or using the archived full module graph
|
||||
void CDSConfig::disable_full_module_graph() {
|
||||
_is_dumping_full_module_graph = false;
|
||||
_is_using_full_module_graph = false;
|
||||
}
|
||||
|
||||
bool CDSConfig::is_using_full_module_graph() {
|
||||
if (ClassLoaderDataShared::is_full_module_graph_loaded()) {
|
||||
return true;
|
||||
@@ -1058,7 +1064,7 @@ void CDSConfig::stop_using_full_module_graph(const char* reason) {
|
||||
}
|
||||
|
||||
bool CDSConfig::is_dumping_aot_linked_classes() {
|
||||
if (is_dumping_classic_static_archive() || is_dumping_final_static_archive()) {
|
||||
if (is_dumping_final_static_archive()) {
|
||||
// FMG is required to guarantee that all cached boot/platform/app classes
|
||||
// are visible in the production run, so they can be unconditionally
|
||||
// loaded during VM bootstrap.
|
||||
|
||||
@@ -38,7 +38,6 @@ class CDSConfig : public AllStatic {
|
||||
static bool _is_dumping_preimage_static_archive;
|
||||
static bool _is_dumping_final_static_archive;
|
||||
static bool _is_dumping_dynamic_archive;
|
||||
static bool _is_using_optimized_module_handling;
|
||||
static bool _is_dumping_full_module_graph;
|
||||
static bool _is_using_full_module_graph;
|
||||
static bool _has_aot_linked_classes;
|
||||
@@ -156,10 +155,6 @@ public:
|
||||
// This is *Legacy* optimization for lambdas before JEP 483. May be removed in the future.
|
||||
static bool is_dumping_lambdas_in_legacy_mode() NOT_CDS_RETURN_(false);
|
||||
|
||||
// optimized_module_handling -- can we skip some expensive operations related to modules?
|
||||
static bool is_using_optimized_module_handling() { return CDS_ONLY(_is_using_optimized_module_handling) NOT_CDS(false); }
|
||||
static void stop_using_optimized_module_handling() NOT_CDS_RETURN;
|
||||
|
||||
static bool is_logging_lambda_form_invokers() NOT_CDS_RETURN_(false);
|
||||
static bool is_dumping_regenerated_lambdaform_invokers() NOT_CDS_RETURN_(false);
|
||||
|
||||
@@ -194,9 +189,10 @@ public:
|
||||
static bool is_dumping_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
static bool is_dumping_method_handles() NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
|
||||
// full_module_graph (requires optimized_module_handling)
|
||||
// full_module_graph (jdk.internal.module.ArchivedBootLayer::archivedBootLayer)
|
||||
static bool is_dumping_full_module_graph() { return CDS_ONLY(_is_dumping_full_module_graph) NOT_CDS(false); }
|
||||
static bool is_using_full_module_graph() NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
static void disable_full_module_graph() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void stop_dumping_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void stop_using_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2026, 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
|
||||
@@ -65,11 +65,6 @@
|
||||
"Average number of symbols per bucket in shared table") \
|
||||
range(2, 246) \
|
||||
\
|
||||
develop(ccstr, ArchiveHeapTestClass, nullptr, \
|
||||
"For JVM internal testing only. The static field named " \
|
||||
"\"archivedObjects\" of the specified class is stored in the " \
|
||||
"CDS archive heap") \
|
||||
\
|
||||
develop(ccstr, AOTInitTestClass, nullptr, \
|
||||
"For JVM internal testing only. The specified class is stored " \
|
||||
"in the initialized state in the AOT cache ") \
|
||||
|
||||
@@ -66,9 +66,11 @@
|
||||
// the virtual printing functions in AnyObj).
|
||||
|
||||
using GrowableArray_ModuleEntry_ptr = GrowableArray<ModuleEntry*>;
|
||||
using GrowableArray_SigEntry = GrowableArray<SigEntry>;
|
||||
|
||||
#define DEBUG_CPP_VTABLE_TYPES_DO(f) \
|
||||
f(GrowableArray_ModuleEntry_ptr) \
|
||||
f(GrowableArray_SigEntry) \
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -311,7 +311,6 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
|
||||
_type_profile_casts = TypeProfileCasts;
|
||||
_spec_trap_limit_extra_entries = SpecTrapLimitExtraEntries;
|
||||
_max_heap_size = MaxHeapSize;
|
||||
_use_optimized_module_handling = CDSConfig::is_using_optimized_module_handling();
|
||||
_aot_class_linking_value = AOTClassLinking;
|
||||
_has_aot_linked_classes = CDSConfig::is_dumping_aot_linked_classes();
|
||||
_has_full_module_graph = CDSConfig::is_dumping_full_module_graph();
|
||||
@@ -396,7 +395,6 @@ void FileMapHeader::print(outputStream* st) {
|
||||
|
||||
st->print_cr("- _rw_ptrmap_start_pos: %zu", _rw_ptrmap_start_pos);
|
||||
st->print_cr("- _ro_ptrmap_start_pos: %zu", _ro_ptrmap_start_pos);
|
||||
st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
|
||||
st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
|
||||
st->print_cr("- has_valhalla_patched_classes %d", _has_valhalla_patched_classes);
|
||||
_must_match.print(st);
|
||||
@@ -407,8 +405,8 @@ bool FileMapInfo::validate_class_location() {
|
||||
assert(CDSConfig::is_using_archive(), "runtime only");
|
||||
|
||||
AOTClassLocationConfig* config = header()->class_location_config();
|
||||
bool has_extra_module_paths = false;
|
||||
if (!config->validate(full_path(), header()->has_aot_linked_classes(), &has_extra_module_paths)) {
|
||||
|
||||
if (!config->validate(full_path(), header()->has_aot_linked_classes(), header()->has_full_module_graph())) {
|
||||
if (PrintSharedArchiveAndExit) {
|
||||
AOTMetaspace::set_archive_loading_failed();
|
||||
return true;
|
||||
@@ -417,11 +415,6 @@ bool FileMapInfo::validate_class_location() {
|
||||
}
|
||||
}
|
||||
|
||||
if (header()->has_full_module_graph() && has_extra_module_paths) {
|
||||
CDSConfig::stop_using_optimized_module_handling();
|
||||
AOTMetaspace::report_loading_error("optimized module handling: disabled because extra module path(s) are specified");
|
||||
}
|
||||
|
||||
if (CDSConfig::is_dumping_dynamic_archive()) {
|
||||
// Only support dynamic dumping with the usage of the default CDS archive
|
||||
// or a simple base archive.
|
||||
@@ -432,13 +425,6 @@ bool FileMapInfo::validate_class_location() {
|
||||
aot_log_warning(aot)(
|
||||
"Dynamic archiving is disabled because base layer archive has appended boot classpath");
|
||||
}
|
||||
if (config->num_module_paths() > 0) {
|
||||
if (has_extra_module_paths) {
|
||||
CDSConfig::disable_dumping_dynamic_archive();
|
||||
aot_log_warning(aot)(
|
||||
"Dynamic archiving is disabled because base layer archive has a different module path");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
@@ -1872,6 +1858,13 @@ bool FileMapInfo::validate_aot_class_linking() {
|
||||
#endif
|
||||
}
|
||||
|
||||
if (CDSConfig::is_dumping_final_static_archive() && header()->aot_class_linking_value() && !CDSConfig::is_dumping_aot_linked_classes()) {
|
||||
ResourceMark rm;
|
||||
const char* msg = err_msg("AOT class linking was enabled in training run but has been disabled%s",
|
||||
(CDSConfig::is_dumping_full_module_graph() ? "" : " due to incompatible module options"));
|
||||
AOTMetaspace::unrecoverable_writing_error(msg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2056,11 +2049,6 @@ bool FileMapHeader::validate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_use_optimized_module_handling && !CDSConfig::is_dumping_final_static_archive()) {
|
||||
CDSConfig::stop_using_optimized_module_handling();
|
||||
aot_log_info(aot)("optimized module handling: disabled because archive was created without optimized module handling");
|
||||
}
|
||||
|
||||
if (is_static()) {
|
||||
// Only the static archive can contain the full module graph.
|
||||
if (!_has_full_module_graph) {
|
||||
|
||||
@@ -173,9 +173,6 @@ private:
|
||||
bool _has_platform_or_app_classes; // Archive contains app or platform classes
|
||||
char* _requested_base_address; // Archive relocation is not necessary if we map with this base address.
|
||||
char* _mapped_base_address; // Actual base address where archive is mapped.
|
||||
|
||||
bool _use_optimized_module_handling;// No module-relation VM options were specified, so we can skip
|
||||
// some expensive operations.
|
||||
bool _has_aot_linked_classes; // Was the CDS archive created with -XX:+AOTClassLinking
|
||||
bool _aot_class_linking_value; // The value of the AOTClassLinking variable when this archive was created
|
||||
bool _has_full_module_graph; // Does this CDS archive contain the full archived module graph?
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "cds/aotStreamedHeapLoader.hpp"
|
||||
#include "cds/aotStreamedHeapWriter.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/archiveUtils.hpp"
|
||||
#include "cds/archiveUtils.inline.hpp"
|
||||
#include "cds/cds_globals.hpp"
|
||||
#include "cds/cdsConfig.hpp"
|
||||
#include "cds/cdsEnumKlass.hpp"
|
||||
@@ -67,6 +67,7 @@
|
||||
#include "oops/oopHandle.inline.hpp"
|
||||
#include "oops/typeArrayOop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "prims/resolvedMethodTable.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/fieldDescriptor.inline.hpp"
|
||||
#include "runtime/globals_extension.hpp"
|
||||
@@ -105,14 +106,6 @@ size_t HeapShared::_alloc_size[HeapShared::ALLOC_STAT_SLOTS];
|
||||
size_t HeapShared::_total_obj_count;
|
||||
size_t HeapShared::_total_obj_size;
|
||||
|
||||
#ifndef PRODUCT
|
||||
#define ARCHIVE_TEST_FIELD_NAME "archivedObjects"
|
||||
static Array<char>* _archived_ArchiveHeapTestClass = nullptr;
|
||||
static const char* _test_class_name = nullptr;
|
||||
static Klass* _test_class = nullptr;
|
||||
static const ArchivedKlassSubGraphInfoRecord* _test_class_record = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef ASSERT
|
||||
// All classes that have at least one instance in the cached heap.
|
||||
static ArchivableKlassTable* _dumptime_classes_with_cached_oops = nullptr;
|
||||
@@ -142,9 +135,6 @@ static ArchivableStaticFieldInfo archive_subgraph_entry_fields[] = {
|
||||
{ARCHIVED_BOOT_LAYER_CLASS, ARCHIVED_BOOT_LAYER_FIELD},
|
||||
{"java/lang/Module$ArchivedData", "archivedData"},
|
||||
|
||||
#ifndef PRODUCT
|
||||
{nullptr, nullptr}, // Extra slot for -XX:ArchiveHeapTestClass
|
||||
#endif
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
@@ -153,6 +143,8 @@ ArchivedKlassSubGraphInfoRecord* HeapShared::_run_time_special_subgraph;
|
||||
GrowableArrayCHeap<oop, mtClassShared>* HeapShared::_pending_roots = nullptr;
|
||||
OopHandle HeapShared::_scratch_basic_type_mirrors[T_VOID+1];
|
||||
MetaspaceObjToOopHandleTable* HeapShared::_scratch_objects_table = nullptr;
|
||||
static GrowableArray<int>* _dumptime_resolved_methods = nullptr;
|
||||
static Array<int>* _runtime_resolved_methods = nullptr;
|
||||
|
||||
static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], InstanceKlass* ik) {
|
||||
for (int i = 0; fields[i].valid(); i++) {
|
||||
@@ -651,6 +643,7 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra
|
||||
m = RegeneratedClasses::maybe_get_regenerated_object(m);
|
||||
InstanceKlass* method_holder = m->method_holder();
|
||||
AOTArtifactFinder::add_cached_class(method_holder);
|
||||
_dumptime_resolved_methods->append(HeapShared::append_root(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -723,6 +716,7 @@ void HeapShared::remove_scratch_resolved_references(ConstantPool* src) {
|
||||
|
||||
void HeapShared::init_dumping() {
|
||||
_scratch_objects_table = new (mtClass)MetaspaceObjToOopHandleTable();
|
||||
_dumptime_resolved_methods = new (mtClassShared) GrowableArray<int>(100, mtClassShared);
|
||||
_pending_roots = new GrowableArrayCHeap<oop, mtClassShared>(500);
|
||||
_pending_roots->append(nullptr); // root index 0 represents a null oop
|
||||
DEBUG_ONLY(_dumptime_classes_with_cached_oops = new (mtClassShared)ArchivableKlassTable());
|
||||
@@ -823,6 +817,7 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) {
|
||||
|
||||
oop orig_mirror;
|
||||
if (RegeneratedClasses::is_regenerated_object(ik)) {
|
||||
assert(!ik->is_inline_klass(), "not supported");
|
||||
InstanceKlass* orig_ik = RegeneratedClasses::get_original_object(ik);
|
||||
precond(orig_ik->is_initialized());
|
||||
orig_mirror = orig_ik->java_mirror();
|
||||
@@ -892,6 +887,16 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) {
|
||||
assert(success, "sanity");
|
||||
}
|
||||
|
||||
if (ik->is_inline_klass()) {
|
||||
InlineKlass* ilk = InlineKlass::cast(ik);
|
||||
if (ilk->supports_nullable_layouts()) {
|
||||
oop null_reset_value = ilk->null_reset_value();
|
||||
m->obj_field_put(ilk->null_reset_value_offset(), null_reset_value);
|
||||
bool success = archive_reachable_objects_from(1, _dump_time_special_subgraph, null_reset_value);
|
||||
assert(success, "sanity");
|
||||
}
|
||||
}
|
||||
|
||||
if (log_is_enabled(Debug, aot, init)) {
|
||||
ResourceMark rm;
|
||||
log_debug(aot, init)("copied %3d field(s) in aot-initialized mirror %s%s%s", nfields, ik->external_name(),
|
||||
@@ -922,14 +927,6 @@ void HeapShared::copy_java_mirror(oop orig_mirror, oop scratch_m) {
|
||||
if (k != nullptr && k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
|
||||
if (ik->is_inline_klass() && ik->is_initialized()) {
|
||||
// Only concrete value classes need the null_reset field
|
||||
InlineKlass* ilk = InlineKlass::cast(k);
|
||||
if (ilk->supports_nullable_layouts()) {
|
||||
scratch_m->obj_field_put(ilk->null_reset_value_offset(), ilk->null_reset_value());
|
||||
}
|
||||
}
|
||||
|
||||
if (ik->has_acmp_maps_offset()) {
|
||||
int maps_offset = ik->acmp_maps_offset();
|
||||
oop maps = orig_mirror->obj_field(maps_offset);
|
||||
@@ -1032,6 +1029,10 @@ void HeapShared::write_heap(AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeap
|
||||
delete _pending_roots;
|
||||
_pending_roots = nullptr;
|
||||
|
||||
_runtime_resolved_methods = ArchiveUtils::archive_array(_dumptime_resolved_methods);
|
||||
delete _dumptime_resolved_methods;
|
||||
_dumptime_resolved_methods = nullptr;
|
||||
|
||||
make_archived_object_cache_gc_safe();
|
||||
}
|
||||
|
||||
@@ -1144,8 +1145,13 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) {
|
||||
} else if (orig_k->is_objArray_klass()) {
|
||||
Klass* abk = ObjArrayKlass::cast(orig_k)->bottom_klass();
|
||||
if (abk->is_instance_klass()) {
|
||||
assert(InstanceKlass::cast(abk)->defined_by_boot_loader(),
|
||||
"must be boot class");
|
||||
if (!AOTClassInitializer::has_test_class()) {
|
||||
// Without `-XX:AOTInitTestClass`, no Java code outside of the boot loader will
|
||||
// be executed in the AOT assembly phase, so we can't have an initialized class
|
||||
// outside of the boot loader.
|
||||
assert(InstanceKlass::cast(abk)->defined_by_boot_loader(),
|
||||
"must be boot class");
|
||||
}
|
||||
check_allowed_klass(InstanceKlass::cast(ObjArrayKlass::cast(orig_k)->bottom_klass()));
|
||||
}
|
||||
if (orig_k == Universe::objectArrayKlass()) {
|
||||
@@ -1196,19 +1202,9 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (!ik->module()->is_named() && ik->package() == nullptr && ArchiveHeapTestClass != nullptr) {
|
||||
// This class is loaded by ArchiveHeapTestClass
|
||||
return;
|
||||
}
|
||||
const char* testcls_msg = ", or a test class in an unnamed package of an unnamed module";
|
||||
#else
|
||||
const char* testcls_msg = "";
|
||||
#endif
|
||||
|
||||
ResourceMark rm;
|
||||
log_error(aot, heap)("Class %s not allowed in archive heap. Must be in java.base%s%s",
|
||||
ik->external_name(), lambda_msg, testcls_msg);
|
||||
log_error(aot, heap)("Class %s not allowed in archive heap. Must be in java.base%s",
|
||||
ik->external_name(), lambda_msg);
|
||||
AOTMetaspace::unrecoverable_writing_error();
|
||||
}
|
||||
|
||||
@@ -1318,34 +1314,35 @@ void HeapShared::write_subgraph_info_table() {
|
||||
d_table->iterate(©);
|
||||
writer.dump(&_run_time_subgraph_info_table, "subgraphs");
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (ArchiveHeapTestClass != nullptr) {
|
||||
size_t len = strlen(ArchiveHeapTestClass) + 1;
|
||||
Array<char>* array = ArchiveBuilder::new_ro_array<char>((int)len);
|
||||
strncpy(array->adr_at(0), ArchiveHeapTestClass, len);
|
||||
_archived_ArchiveHeapTestClass = array;
|
||||
}
|
||||
#endif
|
||||
if (log_is_enabled(Info, aot, heap)) {
|
||||
print_stats();
|
||||
}
|
||||
}
|
||||
|
||||
void HeapShared::serialize_tables(SerializeClosure* soc) {
|
||||
|
||||
#ifndef PRODUCT
|
||||
soc->do_ptr(&_archived_ArchiveHeapTestClass);
|
||||
if (soc->reading() && _archived_ArchiveHeapTestClass != nullptr) {
|
||||
_test_class_name = _archived_ArchiveHeapTestClass->adr_at(0);
|
||||
setup_test_class(_test_class_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
_run_time_subgraph_info_table.serialize_header(soc);
|
||||
soc->do_ptr(&_run_time_special_subgraph);
|
||||
soc->do_ptr(&_runtime_resolved_methods);
|
||||
DEBUG_ONLY(soc->do_ptr(&_runtime_classes_with_cached_oops));
|
||||
}
|
||||
|
||||
void HeapShared::load_cached_resolved_methods() {
|
||||
precond(CDSConfig::is_using_aot_linked_classes());
|
||||
if (_runtime_resolved_methods != nullptr) {
|
||||
JavaThread* current = JavaThread::current();
|
||||
HandleMark hm(current);
|
||||
for (int i = 0; i < _runtime_resolved_methods->length(); i++) {
|
||||
int root_index = _runtime_resolved_methods->at(i);
|
||||
Handle mem_name(current, get_root(root_index, /*clear=*/true));
|
||||
Method* method = java_lang_invoke_ResolvedMethodName::vmtarget(mem_name());
|
||||
InstanceKlass* holder = method->method_holder();
|
||||
holder->set_has_resolved_methods();
|
||||
oop o = ResolvedMethodTable::add_method(method, mem_name);
|
||||
precond(o == mem_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void verify_the_heap(Klass* k, const char* which) {
|
||||
if (VerifyArchivedFields > 0) {
|
||||
ResourceMark rm;
|
||||
@@ -1471,13 +1468,13 @@ void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k
|
||||
}
|
||||
|
||||
if (k->name()->equals("jdk/internal/module/ArchivedModuleGraph") &&
|
||||
!CDSConfig::is_using_optimized_module_handling() &&
|
||||
!CDSConfig::is_using_full_module_graph() &&
|
||||
// archive was created with --module-path
|
||||
AOTClassLocationConfig::runtime()->num_module_paths() > 0) {
|
||||
// ArchivedModuleGraph was created with a --module-path that's different than the runtime --module-path.
|
||||
// Thus, it might contain references to modules that do not exist at runtime. We cannot use it.
|
||||
log_info(aot, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_optimized_module_handling=%s num_module_paths=%d",
|
||||
BOOL_TO_STR(CDSConfig::is_using_optimized_module_handling()),
|
||||
log_info(aot, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_full_module_graph=%s num_module_paths=%d",
|
||||
BOOL_TO_STR(CDSConfig::is_using_full_module_graph()),
|
||||
AOTClassLocationConfig::runtime()->num_module_paths());
|
||||
return;
|
||||
}
|
||||
@@ -1509,13 +1506,6 @@ HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAP
|
||||
unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(k);
|
||||
const ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (_test_class_name != nullptr && k->name()->equals(_test_class_name) && record != nullptr) {
|
||||
_test_class = k;
|
||||
_test_class_record = record;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize from archived data. Currently this is done only
|
||||
// during VM initialization time. No lock is needed.
|
||||
if (record == nullptr) {
|
||||
@@ -2140,18 +2130,6 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
|
||||
TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name);
|
||||
ResourceMark rm; // for stringStream::as_string() etc.
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool is_test_class = (ArchiveHeapTestClass != nullptr) && (strcmp(info->klass_name, ArchiveHeapTestClass) == 0);
|
||||
const char* test_class_name = ArchiveHeapTestClass;
|
||||
#else
|
||||
bool is_test_class = false;
|
||||
const char* test_class_name = ""; // avoid C++ printf checks warnings.
|
||||
#endif
|
||||
|
||||
if (is_test_class) {
|
||||
log_warning(aot)("Loading ArchiveHeapTestClass %s ...", test_class_name);
|
||||
}
|
||||
|
||||
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
@@ -2170,35 +2148,15 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
|
||||
assert(InstanceKlass::cast(ik)->defined_by_boot_loader(),
|
||||
"Only support boot classes");
|
||||
|
||||
if (is_test_class) {
|
||||
if (ik->module()->is_named()) {
|
||||
// We don't want ArchiveHeapTestClass to be abused to easily load/initialize arbitrary
|
||||
// core-lib classes. You need to at least append to the bootclasspath.
|
||||
stringStream st;
|
||||
st.print("ArchiveHeapTestClass %s is not in unnamed module", test_class_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
|
||||
if (ik->package() != nullptr) {
|
||||
// This restriction makes HeapShared::is_a_test_class_in_unnamed_module() easy.
|
||||
stringStream st;
|
||||
st.print("ArchiveHeapTestClass %s is not in unnamed package", test_class_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
} else {
|
||||
if (ik->module()->name() != vmSymbols::java_base()) {
|
||||
// We don't want to deal with cases when a module is unavailable at runtime.
|
||||
// FUTURE -- load from archived heap only when module graph has not changed
|
||||
// between dump and runtime.
|
||||
stringStream st;
|
||||
st.print("%s is not in java.base module", info->klass_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
if (ik->module()->name() != vmSymbols::java_base()) {
|
||||
// We don't want to deal with cases when a module is unavailable at runtime.
|
||||
// FUTURE -- load from archived heap only when module graph has not changed
|
||||
// between dump and runtime.
|
||||
stringStream st;
|
||||
st.print("%s is not in java.base module", info->klass_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||
}
|
||||
|
||||
if (is_test_class) {
|
||||
log_warning(aot)("Initializing ArchiveHeapTestClass %s ...", test_class_name);
|
||||
}
|
||||
ik->initialize(CHECK);
|
||||
|
||||
ArchivableStaticFieldFinder finder(ik, field_name);
|
||||
@@ -2222,89 +2180,8 @@ void HeapShared::init_subgraph_entry_fields(TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void HeapShared::setup_test_class(const char* test_class_name) {
|
||||
ArchivableStaticFieldInfo* p = archive_subgraph_entry_fields;
|
||||
int num_slots = sizeof(archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
|
||||
assert(p[num_slots - 2].klass_name == nullptr, "must have empty slot that's patched below");
|
||||
assert(p[num_slots - 1].klass_name == nullptr, "must have empty slot that marks the end of the list");
|
||||
|
||||
if (test_class_name != nullptr) {
|
||||
p[num_slots - 2].klass_name = test_class_name;
|
||||
p[num_slots - 2].field_name = ARCHIVE_TEST_FIELD_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
// See if ik is one of the test classes that are pulled in by -XX:ArchiveHeapTestClass
|
||||
// during runtime. This may be called before the module system is initialized so
|
||||
// we cannot rely on InstanceKlass::module(), etc.
|
||||
bool HeapShared::is_a_test_class_in_unnamed_module(Klass* ik) {
|
||||
if (_test_class != nullptr) {
|
||||
if (ik == _test_class) {
|
||||
return true;
|
||||
}
|
||||
Array<Klass*>* klasses = _test_class_record->subgraph_object_klasses();
|
||||
if (klasses == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < klasses->length(); i++) {
|
||||
Klass* k = klasses->at(i);
|
||||
if (k == ik) {
|
||||
Symbol* name;
|
||||
if (k->is_instance_klass()) {
|
||||
name = InstanceKlass::cast(k)->name();
|
||||
} else if (k->is_objArray_klass()) {
|
||||
Klass* bk = ObjArrayKlass::cast(k)->bottom_klass();
|
||||
if (!bk->is_instance_klass()) {
|
||||
return false;
|
||||
}
|
||||
name = bk->name();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See KlassSubGraphInfo::check_allowed_klass() - we only allow test classes
|
||||
// to be:
|
||||
// (A) java.base classes (which must not be in the unnamed module)
|
||||
// (B) test classes which must be in the unnamed package of the unnamed module.
|
||||
// So if we see a '/' character in the class name, it must be in (A);
|
||||
// otherwise it must be in (B).
|
||||
if (name->index_of_at(0, "/", 1) >= 0) {
|
||||
return false; // (A)
|
||||
}
|
||||
|
||||
return true; // (B)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HeapShared::initialize_test_class_from_archive(JavaThread* current) {
|
||||
Klass* k = _test_class;
|
||||
if (k != nullptr && is_archived_heap_in_use()) {
|
||||
JavaThread* THREAD = current;
|
||||
ExceptionMark em(THREAD);
|
||||
const ArchivedKlassSubGraphInfoRecord* record =
|
||||
resolve_or_init_classes_for_subgraph_of(k, /*do_init=*/false, THREAD);
|
||||
|
||||
// The _test_class is in the unnamed module, so it can't call CDS.initializeFromArchive()
|
||||
// from its <clinit> method. So we set up its "archivedObjects" field first, before
|
||||
// calling its <clinit>. This is not strictly clean, but it's a convenient way to write unit
|
||||
// test cases (see test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java).
|
||||
if (record != nullptr) {
|
||||
init_archived_fields_for(k, record);
|
||||
}
|
||||
resolve_or_init_classes_for_subgraph_of(k, /*do_init=*/true, THREAD);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void HeapShared::init_for_dumping(TRAPS) {
|
||||
if (CDSConfig::is_dumping_heap()) {
|
||||
setup_test_class(ArchiveHeapTestClass);
|
||||
init_subgraph_entry_fields(CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,7 +442,6 @@ private:
|
||||
// Run-time only
|
||||
static void clear_root(int index);
|
||||
static void get_segment_indexes(int index, int& segment_index, int& internal_index);
|
||||
static void setup_test_class(const char* test_class_name) PRODUCT_RETURN;
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
public:
|
||||
@@ -468,11 +467,7 @@ private:
|
||||
static void init_heap_writer() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void serialize_tables(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
#ifndef PRODUCT
|
||||
static bool is_a_test_class_in_unnamed_module(Klass* ik) NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
static void initialize_test_class_from_archive(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
#endif
|
||||
static void load_cached_resolved_methods() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
static void initialize_java_lang_invoke(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void init_classes_for_special_subgraph(Handle loader, TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
@@ -235,6 +235,13 @@ ciConstant ciInstance::field_value_by_offset(int field_offset) {
|
||||
return field_value(field);
|
||||
}
|
||||
|
||||
intptr_t ciInstance::hash() const {
|
||||
VM_ENTRY_MARK;
|
||||
oop obj = get_oop();
|
||||
markWord mark = obj->mark();
|
||||
if (mark.is_marked()) return markWord::no_hash;
|
||||
return mark.hash();
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// ciInstance::print_impl
|
||||
//
|
||||
|
||||
@@ -67,6 +67,8 @@ public:
|
||||
// Constant value of a field at the specified offset.
|
||||
ciConstant field_value_by_offset(int field_offset);
|
||||
|
||||
intptr_t hash() const;
|
||||
|
||||
ciKlass* java_lang_Class_klass();
|
||||
char* java_lang_String_str(char* buf, size_t buflen);
|
||||
};
|
||||
|
||||
@@ -698,6 +698,28 @@ bool ciInstanceKlass::has_object_fields() const {
|
||||
);
|
||||
}
|
||||
|
||||
int ciInstanceKlass::number_of_nonoop_entries_in_acmp_map() const {
|
||||
VM_ENTRY_MARK;
|
||||
return get_instanceKlass()->acmp_maps_array()->at(0);
|
||||
}
|
||||
int ciInstanceKlass::number_of_oop_entries_in_acmp_map() const {
|
||||
VM_ENTRY_MARK;
|
||||
const Array<int>* acmp_maps = get_instanceKlass()->acmp_maps_array();
|
||||
int number_of_nonoop_entries = acmp_maps->at(0);
|
||||
return acmp_maps->length() - number_of_nonoop_entries * 2 - 1;
|
||||
}
|
||||
AcmpMapSegment ciInstanceKlass::get_nonoop_segment_of_acmp_map(int i) const {
|
||||
VM_ENTRY_MARK;
|
||||
const Array<int>* acmp_maps = get_instanceKlass()->acmp_maps_array();
|
||||
#ifdef ASSERT
|
||||
int number_of_nonoop_entries = acmp_maps->at(0);
|
||||
assert(0 <= i && i < number_of_nonoop_entries, "illegal index, should be in range [0, %d)", number_of_nonoop_entries);
|
||||
#endif
|
||||
int offset = acmp_maps->at(2 * i + 1);
|
||||
int size = acmp_maps->at(2 * i + 2);
|
||||
return AcmpMapSegment(offset, size);
|
||||
}
|
||||
|
||||
bool ciInstanceKlass::compute_has_trusted_loader() {
|
||||
ASSERT_IN_VM;
|
||||
oop loader_oop = loader();
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "ci/ciFlags.hpp"
|
||||
#include "ci/ciKlass.hpp"
|
||||
#include "ci/ciSymbol.hpp"
|
||||
#include "classfile/classFileParser.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
|
||||
// ciInstanceKlass
|
||||
@@ -262,6 +263,10 @@ public:
|
||||
return _nonstatic_fields->at(i);
|
||||
}
|
||||
|
||||
int number_of_oop_entries_in_acmp_map() const;
|
||||
int number_of_nonoop_entries_in_acmp_map() const;
|
||||
AcmpMapSegment get_nonoop_segment_of_acmp_map(int i) const;
|
||||
|
||||
ciInstanceKlass* unique_concrete_subklass();
|
||||
bool has_finalizable_subclass();
|
||||
|
||||
|
||||
@@ -5483,6 +5483,34 @@ void ClassFileParser::set_fast_acmp_members(InlineKlass* vk) const {
|
||||
#endif // VM_LITTLE_ENDIAN
|
||||
}
|
||||
|
||||
// See the declarations of _fast_hashcode_offset and _fast_hashcode_shift in InlineKlass::Members
|
||||
// for details about the fast path logic, and the meaning of these values.
|
||||
void ClassFileParser::set_fast_hashcode_members(InlineKlass* vk) const {
|
||||
if (_layout_info->_oop_acmp_map->length() > 0) { // Oops are not allowed in the fast path
|
||||
return;
|
||||
}
|
||||
if (_layout_info->_nonoop_acmp_map->length() >= 2) { // We handle at most one segment...
|
||||
return;
|
||||
}
|
||||
|
||||
if (_layout_info->_nonoop_acmp_map->length() == 0) {
|
||||
vk->set_fast_hashcode_offset(0);
|
||||
vk->set_fast_hashcode_shift(0);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(_layout_info->_nonoop_acmp_map->length() == 1, "trivially");
|
||||
|
||||
int piece_size = _layout_info->_nonoop_acmp_map->at(0)._size;
|
||||
if (piece_size != 1 && piece_size != 2 && piece_size != 4 && piece_size != 8) { // ...and it must have a convenient size
|
||||
return;
|
||||
}
|
||||
|
||||
int piece_start = _layout_info->_nonoop_acmp_map->at(0)._offset;
|
||||
vk->set_fast_hashcode_offset(piece_start - (BytesPerLong - piece_size));
|
||||
vk->set_fast_hashcode_shift(BitsPerByte * (BytesPerLong - piece_size));
|
||||
}
|
||||
|
||||
void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
|
||||
bool changed_by_loadhook,
|
||||
const ClassInstanceInfo& cl_inst_info,
|
||||
@@ -5722,6 +5750,10 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
|
||||
set_fast_acmp_members(vk);
|
||||
}
|
||||
|
||||
if (UseHashcodeFastPath) {
|
||||
set_fast_hashcode_members(vk);
|
||||
}
|
||||
|
||||
vk->initialize_calling_convention(CHECK);
|
||||
}
|
||||
|
||||
|
||||
@@ -543,6 +543,7 @@ class ClassFileParser {
|
||||
|
||||
void create_acmp_maps(InstanceKlass* ik, TRAPS);
|
||||
void set_fast_acmp_members(InlineKlass* vk) const;
|
||||
void set_fast_hashcode_members(InlineKlass* vk) const;
|
||||
|
||||
public:
|
||||
ClassFileParser(ClassFileStream* stream,
|
||||
|
||||
@@ -617,18 +617,7 @@ void ModuleEntryTable::patch_javabase_entries(JavaThread* current, Handle module
|
||||
for (int i = 0; i < list_length; i++) {
|
||||
Klass* k = list->at(i);
|
||||
assert(k->is_klass(), "List should only hold classes");
|
||||
#ifndef PRODUCT
|
||||
if (HeapShared::is_a_test_class_in_unnamed_module(k)) {
|
||||
// We allow -XX:ArchiveHeapTestClass to archive additional classes
|
||||
// into the CDS heap, but these must be in the unnamed module.
|
||||
ModuleEntry* unnamed_module = ClassLoaderData::the_null_class_loader_data()->unnamed_module();
|
||||
Handle unnamed_module_handle(current, unnamed_module->module_oop());
|
||||
java_lang_Class::fixup_module_field(k, unnamed_module_handle);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
java_lang_Class::fixup_module_field(k, module_handle);
|
||||
}
|
||||
java_lang_Class::fixup_module_field(k, module_handle);
|
||||
k->class_loader_data()->dec_keep_alive_ref_count();
|
||||
}
|
||||
|
||||
|
||||
@@ -587,29 +587,59 @@ Modules::ArchivedProperty& Modules::archived_prop(size_t i) {
|
||||
|
||||
void Modules::ArchivedProperty::runtime_check() const {
|
||||
ResourceMark rm;
|
||||
const char* runtime_value = get_flattened_value();
|
||||
const char* old_value = _archived_value;
|
||||
const char* new_value = get_flattened_value();
|
||||
aot_log_info(aot)("archived module property %s: %s", _prop,
|
||||
_archived_value != nullptr ? _archived_value : "(null)");
|
||||
old_value != nullptr ? old_value : "(null)");
|
||||
|
||||
bool disable = false;
|
||||
if (runtime_value == nullptr) {
|
||||
if (_archived_value != nullptr) {
|
||||
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified during dump time but not during runtime", _prop, _archived_value);
|
||||
disable = true;
|
||||
bool mismatch = false;
|
||||
const char* old_label1;
|
||||
const char* old_label2;
|
||||
const char* new_label1;
|
||||
const char* new_label2;
|
||||
|
||||
if (CDSConfig::is_dumping_final_static_archive()) {
|
||||
old_label1 = "in AOTConfiguration";
|
||||
old_label2 = ", AOTConfiguration =";
|
||||
new_label1 = "for current JVM";
|
||||
new_label2 = "current =";
|
||||
} else if (CDSConfig::new_aot_flags_used()) {
|
||||
old_label1 = "in AOTCache";
|
||||
old_label2 = ", AOTCache =";
|
||||
new_label1 = "for current JVM";
|
||||
new_label2 = "current =";
|
||||
} else {
|
||||
old_label1 = "during dump time";
|
||||
old_label2 = " dump time";
|
||||
new_label1 = "during runtime";
|
||||
new_label2 = "runtime";
|
||||
}
|
||||
|
||||
if (new_value == nullptr) {
|
||||
if (old_value != nullptr) {
|
||||
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified %s but not %s",
|
||||
_prop, old_value, old_label1, new_label1);
|
||||
mismatch = true;
|
||||
}
|
||||
} else {
|
||||
if (_archived_value == nullptr) {
|
||||
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified during runtime but not during dump time", _prop, runtime_value);
|
||||
disable = true;
|
||||
} else if (strcmp(runtime_value, _archived_value) != 0) {
|
||||
AOTMetaspace::report_loading_error("Mismatched values for property %s: runtime %s dump time %s", _prop, runtime_value, _archived_value);
|
||||
disable = true;
|
||||
if (old_value == nullptr) {
|
||||
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified %s but not %s",
|
||||
_prop, new_value, new_label1, old_label1);
|
||||
mismatch = true;
|
||||
} else if (strcmp(new_value, old_value) != 0) {
|
||||
AOTMetaspace::report_loading_error("Mismatched values for property %s: %s %s%s %s",
|
||||
_prop, new_label2, new_value, old_label2, old_value);
|
||||
mismatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (disable) {
|
||||
AOTMetaspace::report_loading_error("Disabling optimized module handling");
|
||||
CDSConfig::stop_using_optimized_module_handling();
|
||||
if (mismatch) {
|
||||
AOTMetaspace::report_loading_error("Disabling full module graph");
|
||||
CDSConfig::disable_full_module_graph();
|
||||
|
||||
if (CDSConfig::is_dumping_final_static_archive()) {
|
||||
AOTMetaspace::unrecoverable_writing_error("mismatched module options");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,7 +716,6 @@ void Modules::serialize_archived_module_info(SerializeClosure* soc) {
|
||||
archived_prop(i).serialize(soc);
|
||||
}
|
||||
if (soc->reading()) {
|
||||
aot_log_info(aot)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled");
|
||||
aot_log_info(aot)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,6 +293,11 @@ class StackMapFrame : public ResourceObj {
|
||||
"Operand stack overflow");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type.is_uninitialized_this()) {
|
||||
_flags |= FLAG_THIS_UNINIT;
|
||||
}
|
||||
|
||||
_stack[_stack_size++] = type;
|
||||
}
|
||||
|
||||
|
||||
@@ -181,6 +181,15 @@ StackMapReader::StackMapReader(ClassVerifier* v, StackMapStream* stream,
|
||||
// There's no stackmap table present. Frame count and size are 0.
|
||||
_frame_count = 0;
|
||||
}
|
||||
|
||||
VerificationType* locals = init_frame->locals();
|
||||
_uninit_in_prev_frame_locals = false;
|
||||
for (int i = 0; i < init_frame->locals_size(); i++) {
|
||||
if (locals[i].is_uninitialized_this()) {
|
||||
_uninit_in_prev_frame_locals = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t StackMapReader::chop(
|
||||
@@ -200,7 +209,8 @@ int32_t StackMapReader::chop(
|
||||
|
||||
#define CHECK_NT CHECK_(VerificationType::bogus_type())
|
||||
|
||||
VerificationType StackMapReader::parse_verification_type(u1* flags, TRAPS) {
|
||||
VerificationType StackMapReader::parse_verification_type(u1* flags, bool parsing_locals, TRAPS) {
|
||||
assert(flags != nullptr, "must be initialized");
|
||||
u1 tag = _stream->get_u1(CHECK_NT);
|
||||
if (tag < (u1)ITEM_UninitializedThis) {
|
||||
return VerificationType::from_tag(tag);
|
||||
@@ -218,8 +228,12 @@ VerificationType StackMapReader::parse_verification_type(u1* flags, TRAPS) {
|
||||
return VerificationType::reference_type(klass_name);
|
||||
}
|
||||
if (tag == ITEM_UninitializedThis) {
|
||||
if (flags != nullptr) {
|
||||
*flags |= FLAG_THIS_UNINIT;
|
||||
*flags |= FLAG_THIS_UNINIT;
|
||||
// An uninitializedThis in the locals array can sometimes be preserved
|
||||
// between frames while uninitializedThis in the stack cannot as the stack
|
||||
// is cleared. Chop and Full frames need special handling.
|
||||
if (parsing_locals) {
|
||||
_uninit_in_prev_frame_locals = true;
|
||||
}
|
||||
return VerificationType::uninitialized_this_type();
|
||||
}
|
||||
@@ -326,8 +340,11 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
offset = _prev_frame->offset() + frame_type + 1;
|
||||
locals = _prev_frame->locals();
|
||||
}
|
||||
|
||||
u1 flags = (u1)_uninit_in_prev_frame_locals;
|
||||
|
||||
frame = new StackMapFrame(
|
||||
offset, _prev_frame->flags(), _prev_frame->locals_size(), 0,
|
||||
offset, flags, _prev_frame->locals_size(), 0,
|
||||
_max_locals, _max_stack, locals, nullptr,
|
||||
_assert_unset_fields_buffer, _verifier);
|
||||
if (_first && locals != nullptr) {
|
||||
@@ -352,7 +369,8 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD(
|
||||
THREAD, VerificationType, 2);
|
||||
u2 stack_size = 1;
|
||||
stack[0] = parse_verification_type(nullptr, CHECK_VERIFY_(_verifier, nullptr));
|
||||
u1 flags = _uninit_in_prev_frame_locals;
|
||||
stack[0] = parse_verification_type(&flags, false /*parsing_locals*/, CHECK_VERIFY_(_verifier, nullptr));
|
||||
if (stack[0].is_category2()) {
|
||||
stack[1] = stack[0].to_category2_2nd();
|
||||
stack_size = 2;
|
||||
@@ -360,7 +378,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
check_verification_type_array_size(
|
||||
stack_size, _max_stack, CHECK_VERIFY_(_verifier, nullptr));
|
||||
frame = new StackMapFrame(
|
||||
offset, _prev_frame->flags(), _prev_frame->locals_size(), stack_size,
|
||||
offset, flags, _prev_frame->locals_size(), stack_size,
|
||||
_max_locals, _max_stack, locals, stack,
|
||||
_assert_unset_fields_buffer, _verifier);
|
||||
if (_first && locals != nullptr) {
|
||||
@@ -394,7 +412,8 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD(
|
||||
THREAD, VerificationType, 2);
|
||||
u2 stack_size = 1;
|
||||
stack[0] = parse_verification_type(nullptr, CHECK_VERIFY_(_verifier, nullptr));
|
||||
u1 flags = _uninit_in_prev_frame_locals;
|
||||
stack[0] = parse_verification_type(&flags, false /*parsing_locals*/, CHECK_VERIFY_(_verifier, nullptr));
|
||||
if (stack[0].is_category2()) {
|
||||
stack[1] = stack[0].to_category2_2nd();
|
||||
stack_size = 2;
|
||||
@@ -402,7 +421,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
check_verification_type_array_size(
|
||||
stack_size, _max_stack, CHECK_VERIFY_(_verifier, nullptr));
|
||||
frame = new StackMapFrame(
|
||||
offset, _prev_frame->flags(), _prev_frame->locals_size(), stack_size,
|
||||
offset, flags, _prev_frame->locals_size(), stack_size,
|
||||
_max_locals, _max_stack, locals, stack,
|
||||
_assert_unset_fields_buffer, _verifier);
|
||||
if (_first && locals != nullptr) {
|
||||
@@ -418,7 +437,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
int length = _prev_frame->locals_size();
|
||||
int chops = SAME_FRAME_EXTENDED - frame_type;
|
||||
int new_length = length;
|
||||
u1 flags = _prev_frame->flags();
|
||||
u1 flags = (u1)_uninit_in_prev_frame_locals;
|
||||
assert(chops == 0 || (frame_type >= CHOP_FRAME_START && frame_type <= CHOP_FRAME_END), "should be");
|
||||
if (chops != 0) {
|
||||
new_length = chop(locals, length, chops);
|
||||
@@ -426,9 +445,11 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
new_length, _max_locals, CHECK_VERIFY_(_verifier, nullptr));
|
||||
// Recompute flags since uninitializedThis could have been chopped.
|
||||
flags = 0;
|
||||
_uninit_in_prev_frame_locals = false;
|
||||
for (int i=0; i<new_length; i++) {
|
||||
if (locals[i].is_uninitialized_this()) {
|
||||
flags |= FLAG_THIS_UNINIT;
|
||||
_uninit_in_prev_frame_locals = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -465,9 +486,9 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
for (int i = 0; i < _prev_frame->locals_size(); i++) {
|
||||
locals[i] = pre_locals[i];
|
||||
}
|
||||
u1 flags = _prev_frame->flags();
|
||||
u1 flags = (u1)_uninit_in_prev_frame_locals;
|
||||
for (int i = 0; i < appends; i++) {
|
||||
locals[real_length] = parse_verification_type(&flags, CHECK_NULL);
|
||||
locals[real_length] = parse_verification_type(&flags, true /*parsing_locals*/, CHECK_NULL);
|
||||
if (locals[real_length].is_category2()) {
|
||||
locals[real_length + 1] = locals[real_length].to_category2_2nd();
|
||||
++real_length;
|
||||
@@ -491,6 +512,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
if (frame_type == FULL_FRAME) {
|
||||
// full_frame
|
||||
u1 flags = 0;
|
||||
_uninit_in_prev_frame_locals = false;
|
||||
u2 locals_size = _stream->get_u2(CHECK_NULL);
|
||||
int real_locals_size = 0;
|
||||
if (locals_size > 0) {
|
||||
@@ -498,7 +520,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
THREAD, VerificationType, locals_size*2);
|
||||
}
|
||||
for (int i = 0; i < locals_size; i++) {
|
||||
locals[real_locals_size] = parse_verification_type(&flags, CHECK_NULL);
|
||||
locals[real_locals_size] = parse_verification_type(&flags, true /*parsing_locals*/, CHECK_NULL);
|
||||
if (locals[real_locals_size].is_category2()) {
|
||||
locals[real_locals_size + 1] =
|
||||
locals[real_locals_size].to_category2_2nd();
|
||||
@@ -516,7 +538,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) {
|
||||
THREAD, VerificationType, stack_size*2);
|
||||
}
|
||||
for (int i = 0; i < stack_size; i++) {
|
||||
stack[real_stack_size] = parse_verification_type(nullptr, CHECK_NULL);
|
||||
stack[real_stack_size] = parse_verification_type(&flags, false /*parsing_locals*/, CHECK_NULL);
|
||||
if (stack[real_stack_size].is_category2()) {
|
||||
stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd();
|
||||
++real_stack_size;
|
||||
|
||||
@@ -134,11 +134,17 @@ class StackMapReader : StackObj {
|
||||
// Check if reading first entry
|
||||
bool _first;
|
||||
|
||||
// We track whether an uninitializedThis was in the previous frame's
|
||||
// locals independently of the flags parameter as most StackMapTable
|
||||
// frames reuse the same locals as the previous frame. Chop and
|
||||
// Full frames need to handle this specially.
|
||||
bool _uninit_in_prev_frame_locals;
|
||||
|
||||
StackMapFrame* next_helper(TRAPS);
|
||||
void check_offset(StackMapFrame* frame);
|
||||
void check_size(TRAPS);
|
||||
int32_t chop(VerificationType* locals, int32_t length, int32_t chops);
|
||||
VerificationType parse_verification_type(u1* flags, TRAPS);
|
||||
VerificationType parse_verification_type(u1* flags, bool parsing_locals, TRAPS);
|
||||
void check_verification_type_array_size(
|
||||
int32_t size, int32_t max_size, TRAPS) {
|
||||
if (size < 0 || size > max_size) {
|
||||
|
||||
@@ -979,7 +979,7 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
|
||||
|
||||
// (2) Check if we are loading into the same module from the same location as in dump time.
|
||||
|
||||
if (CDSConfig::is_using_optimized_module_handling()) {
|
||||
if (CDSConfig::is_using_full_module_graph()) {
|
||||
// Class visibility has not changed between dump time and run time, so a class
|
||||
// that was visible (and thus archived) during dump time is always visible during runtime.
|
||||
assert(SystemDictionary::is_shared_class_visible_impl(class_name, ik, pkg_entry, class_loader),
|
||||
@@ -1003,7 +1003,7 @@ bool SystemDictionary::is_shared_class_visible_impl(Symbol* class_name,
|
||||
// has restricted the classes can be loaded at this step to be only:
|
||||
// [1] cs->is_modules_image(): classes in java.base, or,
|
||||
// [2] HeapShared::is_a_test_class_in_unnamed_module(ik): classes in bootstrap/unnamed module
|
||||
assert(cl->is_modules_image() || HeapShared::is_a_test_class_in_unnamed_module(ik),
|
||||
assert(cl->is_modules_image(),
|
||||
"only these classes can be loaded before the module system is initialized");
|
||||
assert(class_loader.is_null(), "sanity");
|
||||
return true;
|
||||
|
||||
@@ -473,7 +473,7 @@ class methodHandle;
|
||||
\
|
||||
do_class(jdk_internal_util_ArraysSupport, "jdk/internal/util/ArraysSupport") \
|
||||
do_intrinsic(_vectorizedMismatch, jdk_internal_util_ArraysSupport, vectorizedMismatch_name, vectorizedMismatch_signature, F_S)\
|
||||
do_name(vectorizedMismatch_name, "vectorizedMismatch") \
|
||||
do_name(vectorizedMismatch_name, "vectorizedMismatchInternal") \
|
||||
do_signature(vectorizedMismatch_signature, "(Ljava/lang/Object;JLjava/lang/Object;JII)I") \
|
||||
\
|
||||
/* java/lang/ref/Reference */ \
|
||||
|
||||
@@ -215,17 +215,9 @@ void AOTCodeCache::initialize() {
|
||||
return; // AOTCache must be specified to dump and use AOT code
|
||||
}
|
||||
|
||||
if (VerifyOops) {
|
||||
// Disable AOT stub caching when VerifyOops flag is on.
|
||||
// Verify oops code generated a lot of C strings which overflow
|
||||
// AOT C string table (which has fixed size).
|
||||
// AOT C string table will be reworked later to handle such cases.
|
||||
log_info(aot, codecache, init)("AOT Stub Caching is not supported with VerifyOops.");
|
||||
FLAG_SET_ERGO(AOTStubCaching, false);
|
||||
if (InlineTypePassFieldsAsArgs) {
|
||||
log_info(aot, codecache, init)("AOT Adapter Caching is not supported with VerifyOops + InlineTypePassFieldsAsArgs.");
|
||||
FLAG_SET_ERGO(AOTAdapterCaching, false);
|
||||
}
|
||||
if (VerifyOops && InlineTypePassFieldsAsArgs) {
|
||||
log_info(aot, codecache, init)("AOT Adapter Caching is not supported with VerifyOops + InlineTypePassFieldsAsArgs.");
|
||||
FLAG_SET_ERGO(AOTAdapterCaching, false);
|
||||
}
|
||||
|
||||
bool is_dumping = false;
|
||||
@@ -304,6 +296,8 @@ void AOTCodeCache::init2() {
|
||||
|
||||
// Read strings
|
||||
opened_cache->load_strings();
|
||||
} else if (opened_cache->for_dump()) {
|
||||
init_C_strings_caching();
|
||||
}
|
||||
// initialize aot runtime constants as appropriate to this runtime
|
||||
AOTRuntimeConstants::initialize_from_runtime();
|
||||
@@ -367,7 +361,6 @@ AOTCodeCache::AOTCodeCache(bool is_dumping, bool is_using) :
|
||||
_load_entries(nullptr),
|
||||
_search_entries(nullptr),
|
||||
_store_entries(nullptr),
|
||||
_C_strings_buf(nullptr),
|
||||
_store_entries_cnt(0)
|
||||
{
|
||||
// Read header at the begining of cache
|
||||
@@ -1873,7 +1866,7 @@ void AOTCodeReader::read_dbg_strings(DbgStrings& dbg_strings) {
|
||||
// integer ranges defined by the following positive base and max
|
||||
// values i.e. [_extrs_base, _extrs_base + _extrs_max -1],
|
||||
// [_stubs_base, _stubs_base + _stubs_max -1], [_c_str_base,
|
||||
// _c_str_base + _c_str_max -1],
|
||||
// _c_str_base + _C_strings_count],
|
||||
|
||||
#define _extrs_max 500
|
||||
#define _stubs_max static_cast<int>(EntryId::NUM_ENTRYIDS)
|
||||
@@ -1933,6 +1926,8 @@ void AOTCodeAddressTable::init_extrs() {
|
||||
ADD_EXTERNAL_ADDRESS(Thread::current); // used by call_stub
|
||||
ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_StackOverflowError);
|
||||
ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_delayed_StackOverflowError);
|
||||
ADD_EXTERNAL_ADDRESS(StubRoutines::verify_oop_count_addr()); // used by generate_verify_oop()
|
||||
ADD_EXTERNAL_ADDRESS(StubRoutines::verify_oop_subroutine_entry_address());
|
||||
if (InlineTypeReturnedAsFields) {
|
||||
ADD_EXTERNAL_ADDRESS(SharedRuntime::store_inline_type_fields_to_buf);
|
||||
}
|
||||
@@ -2150,9 +2145,10 @@ void AOTCodeAddressTable::init_extrs() {
|
||||
ADD_EXTERNAL_ADDRESS(ZPointerVectorStoreGoodMask);
|
||||
#if defined(AMD64)
|
||||
ADD_EXTERNAL_ADDRESS(&ZPointerLoadShift);
|
||||
ADD_EXTERNAL_ADDRESS(&ZPointerLoadShiftTable);
|
||||
#endif
|
||||
extern address ZPointerLoadShiftTableAddr;
|
||||
ADD_EXTERNAL_ADDRESS(&ZPointerLoadShiftTableAddr);
|
||||
#endif
|
||||
#endif // INCLUDE_ZGC
|
||||
#ifndef ZERO
|
||||
#if defined(AMD64) || defined(AARCH64) || defined(RISCV64)
|
||||
ADD_EXTERNAL_ADDRESS(MacroAssembler::debug64);
|
||||
@@ -2237,64 +2233,68 @@ void AOTCodeAddressTable::set_stubgen_stubs_complete() {
|
||||
}
|
||||
|
||||
#ifdef PRODUCT
|
||||
#define MAX_STR_COUNT 200
|
||||
#define INITIAL_STR_CACHE_SIZE 200
|
||||
#else
|
||||
#define MAX_STR_COUNT 2000
|
||||
#define INITIAL_STR_CACHE_SIZE 2000
|
||||
#endif
|
||||
#define _c_str_max MAX_STR_COUNT
|
||||
static const int _c_str_base = _all_max;
|
||||
|
||||
static const char* _C_strings_in[MAX_STR_COUNT] = {nullptr}; // Incoming strings
|
||||
static const char* _C_strings[MAX_STR_COUNT] = {nullptr}; // Our duplicates
|
||||
static GrowableArray<const char*>* _C_strings = nullptr; // Cached duplicates
|
||||
static GrowableArray<int>* _C_strings_id = nullptr; // id corresponding to index in _C_strings[]
|
||||
static GrowableArray<int>* _C_strings_ix = nullptr; // index in _C_strings[] corresponding to id
|
||||
|
||||
static const char** _cached_C_strings = nullptr;
|
||||
static int _C_strings_count = 0;
|
||||
static int _C_strings_s[MAX_STR_COUNT] = {0};
|
||||
static int _C_strings_id[MAX_STR_COUNT] = {0};
|
||||
static int _C_strings_used = 0;
|
||||
|
||||
void AOTCodeCache::init_C_strings_caching() {
|
||||
assert(_C_strings == nullptr, "Initialize only once");
|
||||
// Allocate arrays in C heap
|
||||
_C_strings = new(mtCode) GrowableArray<const char*>(INITIAL_STR_CACHE_SIZE, 0, nullptr, mtCode);
|
||||
_C_strings_id = new(mtCode) GrowableArray<int>(INITIAL_STR_CACHE_SIZE, 0, -1, mtCode);
|
||||
_C_strings_ix = new(mtCode) GrowableArray<int>(INITIAL_STR_CACHE_SIZE, 0, -1, mtCode);
|
||||
}
|
||||
|
||||
void AOTCodeCache::load_strings() {
|
||||
uint strings_count = _load_header->strings_count();
|
||||
uint strings_count = _load_header->strings_count();
|
||||
if (strings_count == 0) {
|
||||
return;
|
||||
}
|
||||
if (strings_count > MAX_STR_COUNT) {
|
||||
fatal("Invalid strings_count loaded from AOT Code Cache: %d > MAX_STR_COUNT [%d]", strings_count, MAX_STR_COUNT);
|
||||
return;
|
||||
}
|
||||
uint strings_offset = _load_header->strings_offset();
|
||||
|
||||
// First is the array of cached strings length
|
||||
uint* string_lengths = (uint*)addr(strings_offset);
|
||||
strings_offset += (strings_count * sizeof(uint));
|
||||
uint strings_size = _load_header->entries_offset() - strings_offset;
|
||||
// We have to keep cached strings longer than _cache buffer
|
||||
// because they are refernced from compiled code which may
|
||||
// still be executed on VM exit after _cache is freed.
|
||||
char* p = NEW_C_HEAP_ARRAY(char, strings_size+1, mtCode);
|
||||
memcpy(p, addr(strings_offset), strings_size);
|
||||
_C_strings_buf = p;
|
||||
|
||||
// We don't need to duplcate strings from AOT cache to C heap
|
||||
// because we don't remove AOT code cache anymore.
|
||||
_cached_C_strings = NEW_C_HEAP_ARRAY(const char*, strings_count, mtCode);
|
||||
char* start = (char*)addr(strings_offset);
|
||||
char* p = start;
|
||||
for (uint i = 0; i < strings_count; i++) {
|
||||
_C_strings[i] = p;
|
||||
_cached_C_strings[i] = p;
|
||||
uint len = string_lengths[i];
|
||||
_C_strings_s[i] = i;
|
||||
_C_strings_id[i] = i;
|
||||
log_trace(aot, codecache, stringtable)("load_strings: _C_strings[%d] " INTPTR_FORMAT " '%s'", i, p2i(p), p);
|
||||
p += len;
|
||||
}
|
||||
assert((uint)(p - _C_strings_buf) <= strings_size, "(" INTPTR_FORMAT " - " INTPTR_FORMAT ") = %d > %d ", p2i(p), p2i(_C_strings_buf), (uint)(p - _C_strings_buf), strings_size);
|
||||
uint strings_size = _load_header->entries_offset() - strings_offset;
|
||||
assert((uint)(p - start) <= strings_size, "(" INTPTR_FORMAT " - " INTPTR_FORMAT ") = %d > %d ", p2i(p), p2i(start), (uint)(p - start), strings_size);
|
||||
_C_strings_count = strings_count;
|
||||
_C_strings_used = strings_count;
|
||||
log_debug(aot, codecache, init)(" Loaded %d C strings of total length %d at offset %d from AOT Code Cache", _C_strings_count, strings_size, strings_offset);
|
||||
}
|
||||
|
||||
int AOTCodeCache::store_strings() {
|
||||
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
|
||||
if (_C_strings_used > 0) {
|
||||
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
|
||||
uint offset = _write_position;
|
||||
uint length = 0;
|
||||
uint* lengths = (uint *)reserve_bytes(sizeof(uint) * _C_strings_used);
|
||||
if (lengths == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
// Write strings into AOT cache in `id` order.
|
||||
for (int i = 0; i < _C_strings_used; i++) {
|
||||
const char* str = _C_strings[_C_strings_s[i]];
|
||||
const char* str = _C_strings->at(_C_strings_ix->at(i));
|
||||
log_trace(aot, codecache, stringtable)("store_strings: _C_strings[%d] " INTPTR_FORMAT " '%s'", i, p2i(str), str);
|
||||
uint len = (uint)strlen(str) + 1;
|
||||
length += len;
|
||||
@@ -2306,7 +2306,7 @@ int AOTCodeCache::store_strings() {
|
||||
}
|
||||
}
|
||||
log_debug(aot, codecache, exit)(" Wrote %d C strings of total length %d at offset %d to AOT Code Cache",
|
||||
_C_strings_used, length, offset);
|
||||
_C_strings_used, length, offset);
|
||||
}
|
||||
return _C_strings_used;
|
||||
}
|
||||
@@ -2315,57 +2315,50 @@ const char* AOTCodeCache::add_C_string(const char* str) {
|
||||
if (is_on_for_dump() && str != nullptr) {
|
||||
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
|
||||
AOTCodeAddressTable* table = addr_table();
|
||||
if (table != nullptr) {
|
||||
return table->add_C_string(str);
|
||||
}
|
||||
assert(table != nullptr, "should be initialized already");
|
||||
return table->add_C_string(str);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// Identical C strings get the same ID
|
||||
const char* AOTCodeAddressTable::add_C_string(const char* str) {
|
||||
if (_extrs_complete || initializing_extrs) {
|
||||
// Check previous strings address
|
||||
for (int i = 0; i < _C_strings_count; i++) {
|
||||
if (_C_strings_in[i] == str) {
|
||||
return _C_strings[i]; // Found previous one - return our duplicate
|
||||
} else if (strcmp(_C_strings[i], str) == 0) {
|
||||
return _C_strings[i];
|
||||
}
|
||||
}
|
||||
// Add new one
|
||||
if (_C_strings_count < MAX_STR_COUNT) {
|
||||
// Passed in string can be freed and used space become inaccessible.
|
||||
// Keep original address but duplicate string for future compare.
|
||||
_C_strings_id[_C_strings_count] = -1; // Init
|
||||
_C_strings_in[_C_strings_count] = str;
|
||||
const char* dup = os::strdup(str);
|
||||
_C_strings[_C_strings_count++] = dup;
|
||||
log_trace(aot, codecache, stringtable)("add_C_string: [%d] " INTPTR_FORMAT " '%s'", _C_strings_count, p2i(dup), dup);
|
||||
assert_lock_strong(AOTCodeCStrings_lock);
|
||||
for (int i = 0; i < _C_strings_count; i++) {
|
||||
const char* dup = _C_strings->at(i);
|
||||
if (strcmp(dup, str) == 0) {
|
||||
return dup;
|
||||
} else {
|
||||
assert(false, "Number of C strings >= MAX_STR_COUNT");
|
||||
}
|
||||
}
|
||||
return str;
|
||||
// Add one new string.
|
||||
// Passed in string can be freed and used space become inaccessible.
|
||||
// Duplicate string for future compare.
|
||||
const char* dup = os::strdup(str);
|
||||
_C_strings->at_put_grow(_C_strings_count, dup);
|
||||
_C_strings_id->at_put_grow(_C_strings_count, -1);
|
||||
log_trace(aot, codecache, stringtable)("add_C_string: [%d] " INTPTR_FORMAT " '%s'", _C_strings_count, p2i(dup), dup);
|
||||
_C_strings_count++;
|
||||
return dup;
|
||||
}
|
||||
|
||||
int AOTCodeAddressTable::id_for_C_string(address str) {
|
||||
assert(AOTCodeCache::is_on_for_dump(), "should be called only during AOT code cache dump");
|
||||
if (str == nullptr) {
|
||||
return BAD_ADDRESS_ID;
|
||||
}
|
||||
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
|
||||
for (int i = 0; i < _C_strings_count; i++) {
|
||||
if (_C_strings[i] == (const char*)str) { // found
|
||||
int id = _C_strings_id[i];
|
||||
if (_C_strings->at(i) == (const char*)str) { // found
|
||||
int id = _C_strings_id->at(i);
|
||||
if (id >= 0) {
|
||||
assert(id < _C_strings_used, "%d >= %d", id , _C_strings_used);
|
||||
return id; // Found recorded
|
||||
}
|
||||
log_trace(aot, codecache, stringtable)("id_for_C_string: _C_strings[%d ==> %d] " INTPTR_FORMAT " '%s'", i, _C_strings_used, p2i(str), str);
|
||||
// Not found in recorded, add new
|
||||
id = _C_strings_used++;
|
||||
_C_strings_s[id] = i;
|
||||
_C_strings_id[i] = id;
|
||||
_C_strings_ix->at_put_grow(id, i);
|
||||
_C_strings_id->at_put_grow(i, id);
|
||||
log_trace(aot, codecache, stringtable)("id_for_C_string: _C_strings[%d ==> %d] " INTPTR_FORMAT " '%s'", i, id, p2i(str), str);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -2373,8 +2366,10 @@ int AOTCodeAddressTable::id_for_C_string(address str) {
|
||||
}
|
||||
|
||||
address AOTCodeAddressTable::address_for_C_string(int idx) {
|
||||
assert(idx < _C_strings_count, "sanity");
|
||||
return (address)_C_strings[idx];
|
||||
assert(AOTCodeCache::is_on_for_use(), "should be called only when loading from AOT code cache");
|
||||
assert((uint)idx < (uint)_C_strings_count, " %d >= %d", idx, _C_strings_count);
|
||||
precond(_cached_C_strings != nullptr);
|
||||
return (address)_cached_C_strings[idx];
|
||||
}
|
||||
|
||||
static int search_address(address addr, address* table, uint length) {
|
||||
@@ -2391,23 +2386,23 @@ address AOTCodeAddressTable::address_for_id(int idx) {
|
||||
if (idx == -1) {
|
||||
return (address)-1;
|
||||
}
|
||||
uint id = (uint)idx;
|
||||
// special case for symbols based relative to os::init
|
||||
if (id > (_c_str_base + _c_str_max)) {
|
||||
return (address)os::init + idx;
|
||||
}
|
||||
if (idx < 0) {
|
||||
fatal("Incorrect id %d for AOT Code Cache addresses table", id);
|
||||
if (idx >= (_c_str_base + _C_strings_count)) {
|
||||
fatal("recorded id: %d > recorded count %d", idx, (_c_str_base + _C_strings_count));
|
||||
return nullptr;
|
||||
}
|
||||
if (idx < 0) {
|
||||
fatal("Incorrect id %d for AOT Code Cache addresses table", idx);
|
||||
return nullptr;
|
||||
}
|
||||
uint id = (uint)idx;
|
||||
// no need to compare unsigned id against 0
|
||||
if (/* id >= _extrs_base && */ id < _extrs_length) {
|
||||
if (id < _extrs_length) {
|
||||
return _extrs_addr[id - _extrs_base];
|
||||
}
|
||||
if (id >= _stubs_base && id < _c_str_base) {
|
||||
return _stubs_addr[id - _stubs_base];
|
||||
}
|
||||
if (id >= _c_str_base && id < (_c_str_base + (uint)_C_strings_count)) {
|
||||
if (id >= _c_str_base && id < (uint)(_c_str_base + _C_strings_count)) {
|
||||
return address_for_C_string(id - _c_str_base);
|
||||
}
|
||||
fatal("Incorrect id %d for AOT Code Cache addresses table", id);
|
||||
@@ -2454,19 +2449,11 @@ int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeB
|
||||
char* func_name = NEW_RESOURCE_ARRAY(char, buflen);
|
||||
int offset = 0;
|
||||
if (os::dll_address_to_function_name(addr, func_name, buflen, &offset)) {
|
||||
if (offset > 0) {
|
||||
// Could be address of C string
|
||||
uint dist = (uint)pointer_delta(addr, (address)os::init, 1);
|
||||
log_debug(aot, codecache)("Address " INTPTR_FORMAT " (offset %d) for runtime target '%s' is missing in AOT Code Cache addresses table",
|
||||
p2i(addr), dist, (const char*)addr);
|
||||
assert(dist > (uint)(_all_max + MAX_STR_COUNT), "change encoding of distance");
|
||||
return dist;
|
||||
}
|
||||
#ifdef ASSERT
|
||||
reloc.print_current_on(tty);
|
||||
code_blob->print_on(tty);
|
||||
code_blob->print_code_on(tty);
|
||||
assert(false, "Address " INTPTR_FORMAT " for runtime target '%s+%d' is missing in AOT Code Cache addresses table", p2i(addr), func_name, offset);
|
||||
assert(false, "Address " INTPTR_FORMAT " for runtime target <%s+%d>/('%s') is missing in AOT Code Cache addresses table", p2i(addr), func_name, offset, (const char*)addr);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef ASSERT
|
||||
@@ -2512,12 +2499,16 @@ void AOTRuntimeConstants::initialize_from_runtime() {
|
||||
_aot_runtime_constants._card_table_base = card_table_base;
|
||||
_aot_runtime_constants._grain_shift = grain_shift;
|
||||
_aot_runtime_constants._cset_base = cset_base;
|
||||
_aot_runtime_constants._verify_oop_mask = Universe::verify_oop_mask();
|
||||
_aot_runtime_constants._verify_oop_bits = Universe::verify_oop_bits();
|
||||
}
|
||||
|
||||
address AOTRuntimeConstants::_field_addresses_list[] = {
|
||||
((address)&_aot_runtime_constants._card_table_base),
|
||||
((address)&_aot_runtime_constants._grain_shift),
|
||||
((address)&_aot_runtime_constants._cset_base),
|
||||
((address)&_aot_runtime_constants._verify_oop_mask),
|
||||
((address)&_aot_runtime_constants._verify_oop_bits),
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
||||
@@ -304,6 +304,7 @@ public:
|
||||
do_var(bool, UseVectorizedMismatchIntrinsic) \
|
||||
do_var(bool, InlineTypeReturnedAsFields) \
|
||||
do_var(bool, VMContinuations) \
|
||||
do_var(bool, VerifyOops) \
|
||||
do_fun(int, CompressedKlassPointers_shift, CompressedKlassPointers::shift()) \
|
||||
do_fun(bool, JavaAssertions_systemClassDefault, JavaAssertions::systemClassDefault()) \
|
||||
do_fun(bool, JavaAssertions_userClassDefault, JavaAssertions::userClassDefault()) \
|
||||
@@ -464,7 +465,6 @@ private:
|
||||
AOTCodeEntry* _load_entries; // Used when reading cache
|
||||
uint* _search_entries; // sorted by ID table [id, index]
|
||||
AOTCodeEntry* _store_entries; // Used when writing cache
|
||||
const char* _C_strings_buf; // Loaded buffer for _C_strings[] table
|
||||
uint _store_entries_cnt;
|
||||
|
||||
static AOTCodeCache* open_for_use();
|
||||
@@ -498,6 +498,7 @@ public:
|
||||
uint load_size() const { return _load_size; }
|
||||
uint write_position() const { return _write_position; }
|
||||
|
||||
static void init_C_strings_caching();
|
||||
void load_strings();
|
||||
int store_strings();
|
||||
|
||||
@@ -683,6 +684,9 @@ class AOTRuntimeConstants {
|
||||
address _card_table_base;
|
||||
uint _grain_shift;
|
||||
address _cset_base;
|
||||
uintptr_t _verify_oop_mask;
|
||||
uintptr_t _verify_oop_bits;
|
||||
|
||||
static address _field_addresses_list[];
|
||||
static AOTRuntimeConstants _aot_runtime_constants;
|
||||
// private constructor for unique singleton
|
||||
@@ -699,6 +703,8 @@ class AOTRuntimeConstants {
|
||||
static address card_table_base_address();
|
||||
static address grain_shift_address() { return (address)&_aot_runtime_constants._grain_shift; }
|
||||
static address cset_base_address() { return (address)&_aot_runtime_constants._cset_base; }
|
||||
static address verify_oop_mask_address() { return (address)&_aot_runtime_constants._verify_oop_mask; }
|
||||
static address verify_oop_bits_address() { return (address)&_aot_runtime_constants._verify_oop_bits; }
|
||||
static address* field_addresses_list() {
|
||||
return _field_addresses_list;
|
||||
}
|
||||
@@ -707,6 +713,8 @@ class AOTRuntimeConstants {
|
||||
static address card_table_base_address() { return nullptr; }
|
||||
static address grain_shift_address() { return nullptr; }
|
||||
static address cset_base_address() { return nullptr; }
|
||||
static address verify_oop_mask_address() { return nullptr; }
|
||||
static address verify_oop_bits_address() { return nullptr; }
|
||||
static address* field_addresses_list() { return nullptr; }
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -79,8 +79,7 @@ bool CompilationPolicy::must_be_compiled(const methodHandle& m, int comp_level)
|
||||
if (m->has_compiled_code()) return false; // already compiled
|
||||
if (!can_be_compiled(m, comp_level)) return false;
|
||||
|
||||
return !UseInterpreter || // must compile all methods
|
||||
(AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods
|
||||
return !UseInterpreter; // must compile all methods
|
||||
}
|
||||
|
||||
void CompilationPolicy::maybe_compile_early(const methodHandle& m, TRAPS) {
|
||||
|
||||
@@ -1744,7 +1744,7 @@ void CompileBroker::compiler_thread_loop() {
|
||||
// Never compile a method if breakpoints are present in it
|
||||
if (method()->number_of_breakpoints() == 0) {
|
||||
// Compile the method.
|
||||
if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
|
||||
if (UseCompiler && CompileBroker::should_compile_new_jobs()) {
|
||||
invoke_compiler_on_method(task);
|
||||
thread->start_idle_timer();
|
||||
} else {
|
||||
@@ -2152,7 +2152,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
||||
*/
|
||||
void CompileBroker::handle_full_code_cache(CodeBlobType code_blob_type) {
|
||||
UseInterpreter = true;
|
||||
if (UseCompiler || AlwaysCompileLoopMethods ) {
|
||||
if (UseCompiler) {
|
||||
if (xtty != nullptr) {
|
||||
stringStream s;
|
||||
// Dump code cache state into a buffer before locking the tty,
|
||||
|
||||
@@ -369,7 +369,6 @@ public:
|
||||
|
||||
static void disable_compilation_forever() {
|
||||
UseCompiler = false;
|
||||
AlwaysCompileLoopMethods = false;
|
||||
AtomicAccess::xchg(&_should_compile_new_jobs, jint(shutdown_compilation));
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class CompileTask : public CHeapObj<mtCompiler> {
|
||||
Reason_Tiered, // Tiered-policy
|
||||
Reason_Replay, // ciReplay
|
||||
Reason_Whitebox, // Whitebox API
|
||||
Reason_MustBeCompiled, // Used for -Xcomp or AlwaysCompileLoopMethods (see CompilationPolicy::must_be_compiled())
|
||||
Reason_MustBeCompiled, // Used for -Xcomp (see CompilationPolicy::must_be_compiled())
|
||||
Reason_Count
|
||||
};
|
||||
|
||||
@@ -71,9 +71,9 @@ class CompileTask : public CHeapObj<mtCompiler> {
|
||||
"tiered",
|
||||
"replay",
|
||||
"whitebox",
|
||||
"must_be_compiled",
|
||||
"bootstrap"
|
||||
"must_be_compiled"
|
||||
};
|
||||
STATIC_ASSERT(ARRAY_SIZE(reason_names) == Reason_Count);
|
||||
return reason_names[compile_reason];
|
||||
}
|
||||
|
||||
|
||||
@@ -383,6 +383,12 @@
|
||||
"If compilation is stopped with an error, capture diagnostic " \
|
||||
"information at the bailout point") \
|
||||
\
|
||||
product(uint, StressSeed, 0, DIAGNOSTIC, \
|
||||
"Seed for randomized stress testing (if unset, a random one is " \
|
||||
"generated). The seed is recorded in the compilation log, if " \
|
||||
"available.") \
|
||||
range(0, max_juint) \
|
||||
\
|
||||
// end of COMPILER_FLAGS
|
||||
|
||||
DECLARE_FLAGS(COMPILER_FLAGS)
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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 "compiler/compileLog.hpp"
|
||||
#include "compiler/compiler_globals.hpp"
|
||||
#include "compiler/compilerDefinitions.hpp"
|
||||
#include "compiler/compilerDirectives.hpp"
|
||||
#include "compiler/stress.hpp"
|
||||
#include "runtime/globals_extension.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
#ifdef COMPILER2
|
||||
#include "opto/c2_globals.hpp"
|
||||
#endif // COMPILER
|
||||
|
||||
static bool should_initialize_stress_seed(CompilerType comp) {
|
||||
switch (comp) {
|
||||
#ifdef COMPILER1
|
||||
case compiler_c1:
|
||||
return false;
|
||||
#endif // COMPILER1
|
||||
#ifdef COMPILER2
|
||||
case compiler_c2:
|
||||
return StressLCM || StressGCM || StressIGVN || StressCCP ||
|
||||
StressIncrementalInlining || StressMacroExpansion ||
|
||||
StressMacroElimination || StressUnstableIfTraps ||
|
||||
StressBailout || StressLoopPeeling || StressCountedLoop ||
|
||||
StressEliminateAllocations;
|
||||
#endif // COMPILER2
|
||||
default:
|
||||
assert(comp != compiler_none && comp != compiler_number_of_types, "expected valid compiler");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Stress::Stress(DirectiveSet* directives, CompileLog* log, CompilerType comp) {
|
||||
if (!should_initialize_stress_seed(comp)) {
|
||||
_stress_seed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(StressSeed) || (FLAG_IS_ERGO(StressSeed) && directives->RepeatCompilationOption)) {
|
||||
_stress_seed = static_cast<uint>(Ticks::now().nanoseconds());
|
||||
FLAG_SET_ERGO(StressSeed, _stress_seed);
|
||||
} else {
|
||||
_stress_seed = StressSeed;
|
||||
}
|
||||
if (log != nullptr) {
|
||||
log->elem("stress_test seed='%u'", _stress_seed);
|
||||
}
|
||||
}
|
||||
|
||||
uint Stress::random() {
|
||||
_stress_seed = os::next_random(_stress_seed);
|
||||
return _stress_seed;
|
||||
}
|
||||
|
||||
const uint RANDOMIZED_DOMAIN_POW = 29;
|
||||
const uint RANDOMIZED_DOMAIN = 1 << RANDOMIZED_DOMAIN_POW;
|
||||
const uint RANDOMIZED_DOMAIN_MASK = (1 << (RANDOMIZED_DOMAIN_POW + 1)) - 1;
|
||||
|
||||
// This method can be called an arbitrary number of times, with the current count
|
||||
// as the argument. The logic allows for selecting a single candidate from the
|
||||
// running list of candidates as follows:
|
||||
// int count = 0;
|
||||
// Cand* selected = null;
|
||||
// while(cand = cand->next()) {
|
||||
// if (randomized_select(++count)) {
|
||||
// selected = cand;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Including the count equalizes the chances any candidate is "selected".
|
||||
// This is useful when we don't have the complete list of candidates to choose
|
||||
// from uniformly. In this case, we need to adjust the randomicity of the
|
||||
// selection, or else we will end up biasing the selection towards the latter
|
||||
// candidates.
|
||||
//
|
||||
// A quick back-of-the-envelope calculation shows that for the list of n candidates
|
||||
// the equal probability for the candidate to persist as "best" as can be
|
||||
// achieved by replacing it with "next" k-th candidate with the probability
|
||||
// of 1/k. It can be easily shown that by the end of the run, the
|
||||
// probability for any candidate has converged to 1/n, thus giving the
|
||||
// uniform distribution among all the candidates.
|
||||
//
|
||||
// We don't care about the domain size as long as (RANDOMIZED_DOMAIN / count) is large.
|
||||
bool Stress::randomized_select(uint count) {
|
||||
return (random() & RANDOMIZED_DOMAIN_MASK) < (RANDOMIZED_DOMAIN / count);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_COMPILER_STRESS_HPP
|
||||
#define SHARE_COMPILER_STRESS_HPP
|
||||
|
||||
#include "compiler/compileLog.hpp"
|
||||
#include "compiler/compilerDefinitions.hpp"
|
||||
#include "compiler/compilerDirectives.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class Stress : public StackObj {
|
||||
private:
|
||||
uint _stress_seed;
|
||||
|
||||
public:
|
||||
Stress(DirectiveSet* directives, CompileLog* log, CompilerType comp);
|
||||
|
||||
uint random();
|
||||
bool randomized_select(uint count);
|
||||
};
|
||||
|
||||
#endif // SHARE_COMPILER_STRESS_HPP
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2026, 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
|
||||
@@ -282,6 +282,8 @@ CollectedHeap::CollectedHeap() :
|
||||
_last_whole_heap_examined_time_ns(os::javaTimeNanos()),
|
||||
_total_collections(0),
|
||||
_total_full_collections(0),
|
||||
NOT_PRODUCT(_promotion_failure_alot_count(0) COMMA)
|
||||
NOT_PRODUCT(_promotion_failure_alot_gc_number(0) COMMA)
|
||||
_vmthread_cpu_time(0),
|
||||
_gc_cause(GCCause::_no_gc),
|
||||
_gc_lastcause(GCCause::_no_gc)
|
||||
@@ -299,9 +301,6 @@ CollectedHeap::CollectedHeap() :
|
||||
_filler_array_max_size = align_object_size(filler_array_hdr_size() +
|
||||
max_len / elements_per_word);
|
||||
|
||||
NOT_PRODUCT(_promotion_failure_alot_count = 0;)
|
||||
NOT_PRODUCT(_promotion_failure_alot_gc_number = 0;)
|
||||
|
||||
if (UsePerfData) {
|
||||
EXCEPTION_MARK;
|
||||
|
||||
@@ -622,35 +621,31 @@ size_t CollectedHeap::bootstrap_max_memory() const {
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
bool CollectedHeap::promotion_should_fail(volatile size_t* count) {
|
||||
// Access to count is not atomic; the value does not have to be exact.
|
||||
bool CollectedHeap::promotion_should_fail() {
|
||||
// Access to count is not atomic in any way - we can loose updates, overwrite never counts, etc;
|
||||
// the value does not have to be exact.
|
||||
if (PromotionFailureALot) {
|
||||
const size_t gc_num = total_collections();
|
||||
const size_t elapsed_gcs = gc_num - _promotion_failure_alot_gc_number;
|
||||
const size_t elapsed_gcs = gc_num - _promotion_failure_alot_gc_number.load_relaxed();
|
||||
if (elapsed_gcs >= PromotionFailureALotInterval) {
|
||||
// Test for unsigned arithmetic wrap-around.
|
||||
if (++*count >= PromotionFailureALotCount) {
|
||||
*count = 0;
|
||||
// To avoid the base (x86-)costs for atomic RMW operations, use explicit load/store_relaxed() operations.
|
||||
uintx new_count = _promotion_failure_alot_count.load_relaxed() + 1;
|
||||
if (new_count >= PromotionFailureALotCount) {
|
||||
_promotion_failure_alot_count.store_relaxed(0);
|
||||
return true;
|
||||
} else {
|
||||
_promotion_failure_alot_count.store_relaxed(new_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CollectedHeap::promotion_should_fail() {
|
||||
return promotion_should_fail(&_promotion_failure_alot_count);
|
||||
}
|
||||
|
||||
void CollectedHeap::reset_promotion_should_fail(volatile size_t* count) {
|
||||
if (PromotionFailureALot) {
|
||||
_promotion_failure_alot_gc_number = total_collections();
|
||||
*count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CollectedHeap::reset_promotion_should_fail() {
|
||||
reset_promotion_should_fail(&_promotion_failure_alot_count);
|
||||
if (PromotionFailureALot) {
|
||||
_promotion_failure_alot_gc_number.store_relaxed(total_collections());
|
||||
_promotion_failure_alot_count.store_relaxed(0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef PRODUCT
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "memory/metaspace.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/stackChunkOop.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "runtime/perfDataTypes.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
@@ -129,8 +130,8 @@ class CollectedHeap : public CHeapObj<mtGC> {
|
||||
|
||||
unsigned int _total_collections; // ... started
|
||||
unsigned int _total_full_collections; // ... started
|
||||
NOT_PRODUCT(volatile size_t _promotion_failure_alot_count;)
|
||||
NOT_PRODUCT(volatile size_t _promotion_failure_alot_gc_number;)
|
||||
NOT_PRODUCT(Atomic<size_t> _promotion_failure_alot_count;)
|
||||
NOT_PRODUCT(Atomic<size_t> _promotion_failure_alot_gc_number;)
|
||||
|
||||
jlong _vmthread_cpu_time;
|
||||
|
||||
@@ -503,14 +504,11 @@ protected:
|
||||
// Non product verification and debugging.
|
||||
#ifndef PRODUCT
|
||||
// Support for PromotionFailureALot. Return true if it's time to cause a
|
||||
// promotion failure. The no-argument version uses
|
||||
// this->_promotion_failure_alot_count as the counter.
|
||||
bool promotion_should_fail(volatile size_t* count);
|
||||
// promotion failure.
|
||||
bool promotion_should_fail();
|
||||
|
||||
// Reset the PromotionFailureALot counters. Should be called at the end of a
|
||||
// GC in which promotion failure occurred.
|
||||
void reset_promotion_should_fail(volatile size_t* count);
|
||||
void reset_promotion_should_fail();
|
||||
#endif // #ifndef PRODUCT
|
||||
};
|
||||
|
||||
@@ -285,7 +285,7 @@
|
||||
develop(uintx, MaxVirtMemFraction, 2, \
|
||||
"Maximum fraction (1/n) of virtual memory used for ergonomically "\
|
||||
"determining maximum heap size") \
|
||||
range(1, max_uintx) \
|
||||
range(1, max_juint) \
|
||||
\
|
||||
product(bool, UseAdaptiveSizePolicy, true, \
|
||||
"Use adaptive generation sizing policies") \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2022, Red Hat, Inc. All rights reserved.
|
||||
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, 2026, 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
|
||||
@@ -44,16 +44,6 @@ void ShenandoahArguments::initialize() {
|
||||
vm_exit_during_initialization("Shenandoah GC is not supported on this platform.");
|
||||
#endif
|
||||
|
||||
// Shenandoah relies on the object header bits (including the self-forwarded bit
|
||||
// at markWord::self_fwd_mask_in_place) being preserved across monitor inflation,
|
||||
// which only holds with UseObjectMonitorTable.
|
||||
if (!UseObjectMonitorTable) {
|
||||
if (FLAG_IS_CMDLINE(UseObjectMonitorTable)) {
|
||||
vm_exit_during_initialization("Shenandoah requires UseObjectMonitorTable");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseObjectMonitorTable, true);
|
||||
}
|
||||
|
||||
#if 0 // leave this block as stepping stone for future platforms
|
||||
log_warning(gc)("Shenandoah GC is not fully supported on this platform:");
|
||||
log_warning(gc)(" concurrent modes are not supported, only STW cycles are enabled;");
|
||||
|
||||
@@ -110,9 +110,6 @@ public:
|
||||
template <class T>
|
||||
inline oop load_reference_barrier(DecoratorSet decorators, oop obj, T* load_addr);
|
||||
|
||||
template <typename T>
|
||||
inline oop oop_load(DecoratorSet decorators, T* addr);
|
||||
|
||||
template <typename T>
|
||||
inline oop oop_cmpxchg(DecoratorSet decorators, T* addr, oop compare_value, oop new_value);
|
||||
|
||||
@@ -147,6 +144,9 @@ public:
|
||||
typedef BarrierSet::AccessBarrier<decorators, BarrierSetT> Raw;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static oop oop_load_common(DecoratorSet resolved_decorators, T* addr);
|
||||
|
||||
template <typename T>
|
||||
static void oop_store_common(T* addr, oop value);
|
||||
|
||||
|
||||
@@ -233,14 +233,6 @@ inline void ShenandoahBarrierSet::write_ref_field_post(T* field, oop new_value)
|
||||
*byte = CardTable::dirty_card_val();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline oop ShenandoahBarrierSet::oop_load(DecoratorSet decorators, T* addr) {
|
||||
oop value = RawAccess<>::oop_load(addr);
|
||||
value = load_reference_barrier(decorators, value, addr);
|
||||
keep_alive_if_weak(decorators, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline oop ShenandoahBarrierSet::oop_cmpxchg(DecoratorSet decorators, T* addr, oop compare_value, oop new_value) {
|
||||
shenandoah_assert_not_in_cset_except(nullptr, compare_value, (compare_value == nullptr || ShenandoahHeap::heap()->cancelled_gc()));
|
||||
@@ -274,27 +266,35 @@ inline oop ShenandoahBarrierSet::oop_xchg(DecoratorSet decorators, T* addr, oop
|
||||
return RawAccess<>::oop_atomic_xchg(addr, new_value);
|
||||
}
|
||||
|
||||
template <DecoratorSet decorators, typename BarrierSetT>
|
||||
template <typename T>
|
||||
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_common(DecoratorSet resolved_decorators, T* addr) {
|
||||
// This raw access inherits decorators that are needed for proper memory ordering.
|
||||
oop value = Raw::template oop_load<oop>(addr);
|
||||
ShenandoahBarrierSet* bs = barrier_set();
|
||||
value = bs->load_reference_barrier(resolved_decorators, value, addr);
|
||||
bs->keep_alive_if_weak(resolved_decorators, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
template <DecoratorSet decorators, typename BarrierSetT>
|
||||
template <typename T>
|
||||
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_not_in_heap(T* addr) {
|
||||
assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "must be absent");
|
||||
ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
|
||||
return bs->oop_load(decorators, addr);
|
||||
return oop_load_common(decorators, addr);
|
||||
}
|
||||
|
||||
template <DecoratorSet decorators, typename BarrierSetT>
|
||||
template <typename T>
|
||||
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_in_heap(T* addr) {
|
||||
assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "must be absent");
|
||||
ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
|
||||
return bs->oop_load(decorators, addr);
|
||||
return oop_load_common(decorators, addr);
|
||||
}
|
||||
|
||||
template <DecoratorSet decorators, typename BarrierSetT>
|
||||
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_in_heap_at(oop base, ptrdiff_t offset) {
|
||||
ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
|
||||
DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength<decorators>(base, offset);
|
||||
return bs->oop_load(resolved_decorators, AccessInternal::oop_field_addr<decorators>(base, offset));
|
||||
return oop_load_common(resolved_decorators, AccessInternal::oop_field_addr<decorators>(base, offset));
|
||||
}
|
||||
|
||||
template <DecoratorSet decorators, typename BarrierSetT>
|
||||
|
||||
@@ -105,7 +105,7 @@ ShenandoahGC::ShenandoahDegenPoint ShenandoahConcurrentGC::degen_point() const {
|
||||
|
||||
void ShenandoahConcurrentGC::entry_concurrent_update_refs_prepare(ShenandoahHeap* const heap) {
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
const char* msg = conc_init_update_refs_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent init update refs", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_refs_prepare);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -117,8 +117,7 @@ void ShenandoahConcurrentGC::entry_concurrent_update_refs_prepare(ShenandoahHeap
|
||||
void ShenandoahConcurrentGC::entry_update_card_table() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
|
||||
static const char* msg = "Concurrent update cards";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent update cards", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_card_table);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -295,7 +294,7 @@ void ShenandoahConcurrentGC::entry_complete_abbreviated_cycle() {
|
||||
ShenandoahGenerationalHeap* const heap = ShenandoahGenerationalHeap::heap();
|
||||
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
static const char* msg = "Concurrent complete abbreviated cycle";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent complete abbreviated cycle", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::complete_abbreviated);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -376,7 +375,10 @@ void ShenandoahConcurrentGC::vmop_entry_final_verify() {
|
||||
}
|
||||
|
||||
void ShenandoahConcurrentGC::entry_init_mark() {
|
||||
const char* msg = init_mark_event_message();
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
assert(!heap->has_forwarded_objects(), "Should not have forwarded objects here");
|
||||
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Init Mark", "");
|
||||
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::init_mark);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -388,7 +390,11 @@ void ShenandoahConcurrentGC::entry_init_mark() {
|
||||
}
|
||||
|
||||
void ShenandoahConcurrentGC::entry_final_mark() {
|
||||
const char* msg = final_mark_event_message();
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
assert(!heap->has_forwarded_objects() || heap->is_concurrent_old_mark_in_progress(),
|
||||
"Should not have forwarded objects during final mark, unless old gen concurrent mark is running");
|
||||
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Final Mark", "");
|
||||
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_mark);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -400,7 +406,7 @@ void ShenandoahConcurrentGC::entry_final_mark() {
|
||||
}
|
||||
|
||||
void ShenandoahConcurrentGC::entry_init_update_refs() {
|
||||
static const char* msg = "Pause Init Update Refs";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Init Update Refs", "");
|
||||
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::init_update_refs);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -409,7 +415,7 @@ void ShenandoahConcurrentGC::entry_init_update_refs() {
|
||||
}
|
||||
|
||||
void ShenandoahConcurrentGC::entry_final_update_refs() {
|
||||
static const char* msg = "Pause Final Update Refs";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Final Update Refs", "");
|
||||
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_update_refs);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -421,7 +427,7 @@ void ShenandoahConcurrentGC::entry_final_update_refs() {
|
||||
}
|
||||
|
||||
void ShenandoahConcurrentGC::entry_final_verify() {
|
||||
const char* msg = verify_final_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Verify Final", "");
|
||||
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_verify);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -435,7 +441,7 @@ void ShenandoahConcurrentGC::entry_reset() {
|
||||
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
{
|
||||
const char* msg = conc_reset_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent reset", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -450,7 +456,8 @@ void ShenandoahConcurrentGC::entry_scan_remembered_set() {
|
||||
if (_generation->is_young()) {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
const char* msg = "Concurrent remembered set scanning";
|
||||
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent remembered set scanning", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::init_scan_rset);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -466,7 +473,7 @@ void ShenandoahConcurrentGC::entry_scan_remembered_set() {
|
||||
void ShenandoahConcurrentGC::entry_mark_roots() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
const char* msg = "Concurrent marking roots";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent marking roots", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_mark_roots);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -480,8 +487,11 @@ void ShenandoahConcurrentGC::entry_mark_roots() {
|
||||
|
||||
void ShenandoahConcurrentGC::entry_mark() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
assert(!heap->has_forwarded_objects() || heap->is_concurrent_old_mark_in_progress(),
|
||||
"Should not have forwarded objects concurrent mark, unless old gen concurrent mark is running");
|
||||
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
const char* msg = conc_mark_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent marking", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_mark);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -496,7 +506,7 @@ void ShenandoahConcurrentGC::entry_mark() {
|
||||
|
||||
void ShenandoahConcurrentGC::entry_thread_roots() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
static const char* msg = "Concurrent thread roots";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent thread roots", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_thread_roots);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -511,7 +521,7 @@ void ShenandoahConcurrentGC::entry_thread_roots() {
|
||||
|
||||
void ShenandoahConcurrentGC::entry_weak_refs() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
const char* msg = conc_weak_refs_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent weak references", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_refs);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -527,7 +537,7 @@ void ShenandoahConcurrentGC::entry_weak_refs() {
|
||||
void ShenandoahConcurrentGC::entry_weak_roots() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
const char* msg = conc_weak_roots_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent weak roots", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_roots);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -543,7 +553,7 @@ void ShenandoahConcurrentGC::entry_weak_roots() {
|
||||
void ShenandoahConcurrentGC::entry_class_unloading() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
static const char* msg = "Concurrent class unloading";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent class unloading", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_class_unload);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -559,7 +569,7 @@ void ShenandoahConcurrentGC::entry_class_unloading() {
|
||||
void ShenandoahConcurrentGC::entry_strong_roots() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
static const char* msg = "Concurrent strong roots";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent strong roots", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_strong_roots);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -577,7 +587,7 @@ void ShenandoahConcurrentGC::entry_strong_roots() {
|
||||
void ShenandoahConcurrentGC::entry_cleanup_early() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
const char* msg = conc_cleanup_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent cleanup", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_early, true /* log_heap_usage */);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -596,8 +606,7 @@ void ShenandoahConcurrentGC::entry_cleanup_early() {
|
||||
void ShenandoahConcurrentGC::entry_evacuate() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
|
||||
static const char* msg = "Concurrent evacuation";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent evacuation", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_evac);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -613,8 +622,7 @@ void ShenandoahConcurrentGC::entry_evacuate() {
|
||||
void ShenandoahConcurrentGC::entry_update_thread_roots() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
|
||||
static const char* msg = "Concurrent update thread roots";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent update thread roots", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_thread_roots);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -627,7 +635,7 @@ void ShenandoahConcurrentGC::entry_update_thread_roots() {
|
||||
void ShenandoahConcurrentGC::entry_update_refs() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
static const char* msg = "Concurrent update references";
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent update references", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_refs);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -643,7 +651,7 @@ void ShenandoahConcurrentGC::entry_update_refs() {
|
||||
void ShenandoahConcurrentGC::entry_cleanup_complete() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
const char* msg = conc_cleanup_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent cleanup", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_complete, true /* log_heap_usage */);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -655,7 +663,7 @@ void ShenandoahConcurrentGC::entry_cleanup_complete() {
|
||||
void ShenandoahConcurrentGC::entry_reset_after_collect() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
const char* msg = conc_reset_after_collect_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent reset after collect", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset_after_collect);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -1250,7 +1258,7 @@ void ShenandoahConcurrentGC::op_final_update_refs() {
|
||||
void ShenandoahConcurrentGC::entry_final_roots() {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
|
||||
const char* msg = conc_final_roots_event_message();
|
||||
SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent final roots", "");
|
||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_final_roots);
|
||||
EventMark em("%s", msg);
|
||||
|
||||
@@ -1295,100 +1303,3 @@ bool ShenandoahConcurrentGC::check_cancellation_and_abort(ShenandoahDegenPoint p
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::init_mark_event_message() const {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
assert(!heap->has_forwarded_objects(), "Should not have forwarded objects here");
|
||||
if (heap->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Init Mark", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Init Mark", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::final_mark_event_message() const {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
assert(!heap->has_forwarded_objects() || heap->is_concurrent_old_mark_in_progress(),
|
||||
"Should not have forwarded objects during final mark, unless old gen concurrent mark is running");
|
||||
|
||||
if (heap->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Final Mark", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Final Mark", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::conc_mark_event_message() const {
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
assert(!heap->has_forwarded_objects() || heap->is_concurrent_old_mark_in_progress(),
|
||||
"Should not have forwarded objects concurrent mark, unless old gen concurrent mark is running");
|
||||
if (heap->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent marking", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent marking", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::conc_reset_event_message() const {
|
||||
if (ShenandoahHeap::heap()->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::conc_reset_after_collect_event_message() const {
|
||||
if (ShenandoahHeap::heap()->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::verify_final_event_message() const {
|
||||
if (ShenandoahHeap::heap()->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::conc_final_roots_event_message() const {
|
||||
if (ShenandoahHeap::heap()->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Final Roots", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Final Roots", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::conc_weak_refs_event_message() const {
|
||||
if (ShenandoahHeap::heap()->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent weak references", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent weak references", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::conc_weak_roots_event_message() const {
|
||||
if (ShenandoahHeap::heap()->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent weak roots", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent weak roots", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::conc_cleanup_event_message() const {
|
||||
if (ShenandoahHeap::heap()->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent cleanup", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent cleanup", "");
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShenandoahConcurrentGC::conc_init_update_refs_event_message() const {
|
||||
if (ShenandoahHeap::heap()->unload_classes()) {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Init Update Refs", " (unload classes)");
|
||||
} else {
|
||||
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent Init Update Refs", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,20 +132,6 @@ private:
|
||||
void start_mark();
|
||||
|
||||
static bool has_in_place_promotions(ShenandoahHeap* heap);
|
||||
|
||||
// Messages for GC trace events, they have to be immortal for
|
||||
// passing around the logging/tracing systems
|
||||
const char* init_mark_event_message() const;
|
||||
const char* final_mark_event_message() const;
|
||||
const char* verify_final_event_message() const;
|
||||
const char* conc_final_roots_event_message() const;
|
||||
const char* conc_mark_event_message() const;
|
||||
const char* conc_reset_event_message() const;
|
||||
const char* conc_reset_after_collect_event_message() const;
|
||||
const char* conc_weak_refs_event_message() const;
|
||||
const char* conc_weak_roots_event_message() const;
|
||||
const char* conc_cleanup_event_message() const;
|
||||
const char* conc_init_update_refs_event_message() const;
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCONCURRENTGC_HPP
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user