diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 0d8663fab1a..4d1e8a8be3d 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -327,8 +327,8 @@ jobs:
uses: ./.github/workflows/build-macos.yml
with:
platform: macos-x64
- runs-on: 'macos-13'
- xcode-toolset-version: '14.3.1'
+ runs-on: 'macos-15-intel'
+ xcode-toolset-version: '16.4'
configure-arguments: ${{ github.event.inputs.configure-arguments }}
make-arguments: ${{ github.event.inputs.make-arguments }}
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
@@ -340,8 +340,8 @@ jobs:
uses: ./.github/workflows/build-macos.yml
with:
platform: macos-aarch64
- runs-on: 'macos-14'
- xcode-toolset-version: '15.4'
+ runs-on: 'macos-15'
+ xcode-toolset-version: '16.4'
configure-arguments: ${{ github.event.inputs.configure-arguments }}
make-arguments: ${{ github.event.inputs.make-arguments }}
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
@@ -432,9 +432,9 @@ jobs:
with:
platform: macos-aarch64
bootjdk-platform: macos-aarch64
- runs-on: macos-14
+ runs-on: macos-15
dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }}
- xcode-toolset-version: '15.4'
+ xcode-toolset-version: '16.4'
debug-suffix: -debug
test-windows-x64:
diff --git a/.gitignore b/.gitignore
index 9145a9fa67b..852b692f99b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,4 @@ NashornProfile.txt
**/core.[0-9]*
*.rej
*.orig
+test/benchmarks/**/target
diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html
index 7be6867b3ca..f1c25dab7f4 100644
--- a/doc/hotspot-style.html
+++ b/doc/hotspot-style.html
@@ -1859,8 +1859,6 @@ difference.
-Trailing return type syntax for functions (n2541)
Member initializers and aggregates (n3653)
Rvalue references and move semantics
diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md
index facdf68462f..e49f49ec1c9 100644
--- a/doc/hotspot-style.md
+++ b/doc/hotspot-style.md
@@ -1853,9 +1853,6 @@ See Object Lifetime: C++17 6.8/8, C++20 6.7.3/8
### Additional Undecided Features
-* Trailing return type syntax for functions
-([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm))
-
* Member initializers and aggregates
([n3653](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html))
diff --git a/doc/testing.html b/doc/testing.html
index 89a9b1b23b7..b9838735e4f 100644
--- a/doc/testing.html
+++ b/doc/testing.html
@@ -450,7 +450,7 @@ itself (-timeoutFactor). Also, some test cases that
programmatically wait a certain amount of time will apply this factor.
If we run in forced compilation mode (-Xcomp), the build
system will automatically adjust this factor to compensate for less
-performance. Defaults to 1.
+performance. Defaults to 4.
FAILURE_HANDLER_TIMEOUT
Sets the argument -timeoutHandlerTimeout for JTReg. The
default value is 0. This is only valid if the failure handler is
diff --git a/doc/testing.md b/doc/testing.md
index 324f9645c27..0144610a5bf 100644
--- a/doc/testing.md
+++ b/doc/testing.md
@@ -387,7 +387,7 @@ The `TIMEOUT_FACTOR` is forwarded to JTReg framework itself
(`-timeoutFactor`). Also, some test cases that programmatically wait a
certain amount of time will apply this factor. If we run in forced
compilation mode (`-Xcomp`), the build system will automatically
-adjust this factor to compensate for less performance. Defaults to 1.
+adjust this factor to compensate for less performance. Defaults to 4.
#### FAILURE_HANDLER_TIMEOUT
diff --git a/make/Hsdis.gmk b/make/Hsdis.gmk
index a0fc031be1b..469cc488f16 100644
--- a/make/Hsdis.gmk
+++ b/make/Hsdis.gmk
@@ -114,7 +114,6 @@ ifeq ($(HSDIS_BACKEND), binutils)
TOOLCHAIN_TYPE := gcc
OPENJDK_TARGET_OS := linux
OPENJDK_TARGET_OS_TYPE := unix
- CC_OUT_OPTION := -o$(SPACE)
GENDEPS_FLAGS := -MMD -MF
CFLAGS_DEBUG_SYMBOLS := -g
DISABLED_WARNINGS :=
diff --git a/make/RunTests.gmk b/make/RunTests.gmk
index 7b05a0ba12f..947389f64f9 100644
--- a/make/RunTests.gmk
+++ b/make/RunTests.gmk
@@ -946,8 +946,8 @@ define SetupRunJtregTestBody
JTREG_ALL_OPTIONS := $$(JTREG_JAVA_OPTIONS) $$(JTREG_VM_OPTIONS)
JTREG_AUTO_PROBLEM_LISTS :=
- # Please reach consensus before changing this. It was not easy changing it to a `1`.
- JTREG_AUTO_TIMEOUT_FACTOR := 1
+ # Please reach consensus before changing this.
+ JTREG_AUTO_TIMEOUT_FACTOR := 4
ifneq ($$(findstring -Xcomp, $$(JTREG_ALL_OPTIONS)), )
JTREG_AUTO_PROBLEM_LISTS += ProblemList-Xcomp.txt
diff --git a/make/StaticLibs.gmk b/make/StaticLibs.gmk
index 80d6b4538c8..490180eb649 100644
--- a/make/StaticLibs.gmk
+++ b/make/StaticLibs.gmk
@@ -116,6 +116,9 @@ else ifeq ($(call isTargetOs, aix), true)
$(eval STATIC_LIB_EXPORT_FILES += $(lib).exp) \
)
STATIC_LIBS := -Wl,-bexpfull $(STATIC_LIB_FILES) $(addprefix -Wl$(COMMA)-bE:, $(STATIC_LIB_EXPORT_FILES))
+ ifeq ($(DEBUG_LEVEL), slowdebug)
+ STATIC_LIBS += -Wl,-bbigtoc
+ endif
else
$(error Unsupported platform)
endif
diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4
index 5367db46679..8e42f9205a4 100644
--- a/make/autoconf/basic_tools.m4
+++ b/make/autoconf/basic_tools.m4
@@ -363,7 +363,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
# Check if it's a GNU date compatible version
AC_MSG_CHECKING([if date is a GNU compatible version])
- check_date=`$DATE --version 2>&1 | $GREP "GNU\|BusyBox"`
+ check_date=`$DATE --version 2>&1 | $GREP "GNU\|BusyBox\|uutils"`
if test "x$check_date" != x; then
AC_MSG_RESULT([yes])
IS_GNU_DATE=yes
diff --git a/make/autoconf/boot-jdk.m4 b/make/autoconf/boot-jdk.m4
index 4ba1f9f2089..b3dbc292919 100644
--- a/make/autoconf/boot-jdk.m4
+++ b/make/autoconf/boot-jdk.m4
@@ -408,27 +408,6 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK],
AC_MSG_CHECKING([if Boot JDK is 32 or 64 bits])
AC_MSG_RESULT([$BOOT_JDK_BITS])
- # Try to enable CDS
- AC_MSG_CHECKING([for local Boot JDK Class Data Sharing (CDS)])
- BOOT_JDK_CDS_ARCHIVE=$CONFIGURESUPPORT_OUTPUTDIR/classes.jsa
- UTIL_ADD_JVM_ARG_IF_OK([-XX:+UnlockDiagnosticVMOptions -XX:-VerifySharedSpaces -XX:SharedArchiveFile=$BOOT_JDK_CDS_ARCHIVE],boot_jdk_cds_args,[$JAVA])
-
- if test "x$boot_jdk_cds_args" != x; then
- # Try creating a CDS archive
- $JAVA $boot_jdk_cds_args -Xshare:dump > /dev/null 2>&1
- if test $? -eq 0; then
- BOOTJDK_USE_LOCAL_CDS=true
- AC_MSG_RESULT([yes, created])
- else
- # Generation failed, don't use CDS.
- BOOTJDK_USE_LOCAL_CDS=false
- AC_MSG_RESULT([no, creation failed])
- fi
- else
- BOOTJDK_USE_LOCAL_CDS=false
- AC_MSG_RESULT([no, -XX:SharedArchiveFile not supported])
- fi
-
BOOTJDK_SETUP_CLASSPATH
])
@@ -444,13 +423,8 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS],
# Force en-US environment
UTIL_ADD_JVM_ARG_IF_OK([-Duser.language=en -Duser.country=US],boot_jdk_jvmargs,[$JAVA])
- if test "x$BOOTJDK_USE_LOCAL_CDS" = xtrue; then
- # Use our own CDS archive
- UTIL_ADD_JVM_ARG_IF_OK([$boot_jdk_cds_args -Xshare:auto],boot_jdk_jvmargs,[$JAVA])
- else
- # Otherwise optimistically use the system-wide one, if one is present
- UTIL_ADD_JVM_ARG_IF_OK([-Xshare:auto],boot_jdk_jvmargs,[$JAVA])
- fi
+ UTIL_ADD_JVM_ARG_IF_OK([-Xlog:all=off:stdout],boot_jdk_jvmargs,[$JAVA])
+ UTIL_ADD_JVM_ARG_IF_OK([-Xlog:all=warning:stderr],boot_jdk_jvmargs,[$JAVA])
# Finally append user provided options to allow them to override.
UTIL_ADD_JVM_ARG_IF_OK([$USER_BOOT_JDK_OPTIONS],boot_jdk_jvmargs,[$JAVA])
@@ -597,10 +571,9 @@ AC_DEFUN([BOOTJDK_SETUP_BUILD_JDK],
AC_ARG_WITH(build-jdk, [AS_HELP_STRING([--with-build-jdk],
[path to JDK of same version as is being built@<:@the newly built JDK@:>@])])
- CREATE_BUILDJDK=false
- EXTERNAL_BUILDJDK=false
- BUILD_JDK_FOUND="no"
+ EXTERNAL_BUILDJDK_PATH=""
if test "x$with_build_jdk" != "x"; then
+ BUILD_JDK_FOUND=no
BOOTJDK_CHECK_BUILD_JDK([
if test "x$with_build_jdk" != x; then
BUILD_JDK=$with_build_jdk
@@ -608,40 +581,15 @@ AC_DEFUN([BOOTJDK_SETUP_BUILD_JDK],
AC_MSG_NOTICE([Found potential Build JDK using configure arguments])
fi
])
- EXTERNAL_BUILDJDK=true
- else
- if test "x$COMPILE_TYPE" = "xcross"; then
- BUILD_JDK="\$(BUILDJDK_OUTPUTDIR)/jdk"
- BUILD_JDK_FOUND=yes
- CREATE_BUILDJDK=true
+ if test "x$BUILD_JDK_FOUND" != "xyes"; then
AC_MSG_CHECKING([for Build JDK])
- AC_MSG_RESULT([yes, will build it for the host platform])
- else
- BUILD_JDK="\$(JDK_OUTPUTDIR)"
- BUILD_JDK_FOUND=yes
- AC_MSG_CHECKING([for Build JDK])
- AC_MSG_RESULT([yes, will use output dir])
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([Could not find a suitable Build JDK])
fi
+ EXTERNAL_BUILDJDK_PATH="$BUILD_JDK"
fi
- # Since these tools do not yet exist, we cannot use UTIL_FIXUP_EXECUTABLE to
- # detect the need of fixpath
- JMOD="$BUILD_JDK/bin/jmod"
- UTIL_ADD_FIXPATH(JMOD)
- JLINK="$BUILD_JDK/bin/jlink"
- UTIL_ADD_FIXPATH(JLINK)
- AC_SUBST(JMOD)
- AC_SUBST(JLINK)
-
- if test "x$BUILD_JDK_FOUND" != "xyes"; then
- AC_MSG_CHECKING([for Build JDK])
- AC_MSG_RESULT([no])
- AC_MSG_ERROR([Could not find a suitable Build JDK])
- fi
-
- AC_SUBST(CREATE_BUILDJDK)
- AC_SUBST(BUILD_JDK)
- AC_SUBST(EXTERNAL_BUILDJDK)
+ AC_SUBST(EXTERNAL_BUILDJDK_PATH)
])
# The docs-reference JDK is used to run javadoc for the docs-reference targets.
diff --git a/make/autoconf/bootcycle-spec.gmk.template b/make/autoconf/bootcycle-spec.gmk.template
index 8b6035606a5..d17a95e190a 100644
--- a/make/autoconf/bootcycle-spec.gmk.template
+++ b/make/autoconf/bootcycle-spec.gmk.template
@@ -44,7 +44,3 @@ JAVAC_CMD := $(FIXPATH) $(BOOT_JDK)/bin/javac
JAR_CMD := $(FIXPATH) $(BOOT_JDK)/bin/jar
# The bootcycle JVM arguments may differ from the original boot jdk.
JAVA_FLAGS_BIG := @BOOTCYCLE_JVM_ARGS_BIG@
-# Any CDS settings generated for the bootjdk are invalid in the bootcycle build.
-# By filtering out those JVM args, the bootcycle JVM will use its default
-# settings for CDS.
-JAVA_FLAGS := $(filter-out -XX:SharedArchiveFile% -Xshare%, $(JAVA_FLAGS))
diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4
index 6072cbc74dd..9d58a280998 100644
--- a/make/autoconf/flags-cflags.m4
+++ b/make/autoconf/flags-cflags.m4
@@ -37,56 +37,25 @@ AC_DEFUN([FLAGS_SETUP_SHARED_LIBS],
if test "x$TOOLCHAIN_TYPE" = xgcc; then
# Default works for linux, might work on other platforms as well.
SHARED_LIBRARY_FLAGS='-shared'
- # --disable-new-dtags forces use of RPATH instead of RUNPATH for rpaths.
- # This protects internal library dependencies within the JDK from being
- # overridden using LD_LIBRARY_PATH. See JDK-8326891 for more information.
- SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN[$]1 -Wl,--disable-new-dtags'
- SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Wl,-soname=[$]1'
elif test "x$TOOLCHAIN_TYPE" = xclang; then
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
# Linking is different on MacOSX
SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0"
- SET_EXECUTABLE_ORIGIN='-Wl,-rpath,@loader_path$(or [$]1,/.)'
- SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Wl,-install_name,@rpath/[$]1'
elif test "x$OPENJDK_TARGET_OS" = xaix; then
# Linking is different on aix
SHARED_LIBRARY_FLAGS="-shared -Wl,-bM:SRE -Wl,-bnoentry"
- SET_EXECUTABLE_ORIGIN=""
- SET_SHARED_LIBRARY_ORIGIN=''
- SET_SHARED_LIBRARY_NAME=''
else
# Default works for linux, might work on other platforms as well.
SHARED_LIBRARY_FLAGS='-shared'
- SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN[$]1'
- if test "x$OPENJDK_TARGET_OS" = xlinux; then
- SET_EXECUTABLE_ORIGIN="$SET_EXECUTABLE_ORIGIN -Wl,--disable-new-dtags"
- fi
- SET_SHARED_LIBRARY_NAME='-Wl,-soname=[$]1'
-
- # arm specific settings
- if test "x$OPENJDK_TARGET_CPU" = "xarm"; then
- # '-Wl,-z,origin' isn't used on arm.
- SET_SHARED_LIBRARY_ORIGIN='-Wl,-rpath,\$$$$ORIGIN[$]1'
- else
- SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
- fi
fi
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
SHARED_LIBRARY_FLAGS="-dll"
- SET_EXECUTABLE_ORIGIN=''
- SET_SHARED_LIBRARY_ORIGIN=''
- SET_SHARED_LIBRARY_NAME=''
fi
- AC_SUBST(SET_EXECUTABLE_ORIGIN)
- AC_SUBST(SET_SHARED_LIBRARY_ORIGIN)
- AC_SUBST(SET_SHARED_LIBRARY_NAME)
AC_SUBST(SHARED_LIBRARY_FLAGS)
])
@@ -934,48 +903,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
IF_FALSE: [$2FDLIBM_CFLAGS=""])
fi
AC_SUBST($2FDLIBM_CFLAGS)
-
- # Check whether the compiler supports the Arm C Language Extensions (ACLE)
- # for SVE. Set SVE_CFLAGS to -march=armv8-a+sve if it does.
- # ACLE and this flag are required to build the aarch64 SVE related functions in
- # libvectormath. Apple Silicon does not support SVE; use macOS as a proxy for
- # that check.
- if test "x$OPENJDK_TARGET_CPU" = "xaarch64" && test "x$OPENJDK_TARGET_OS" = "xlinux"; then
- if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
- AC_LANG_PUSH(C)
- OLD_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -march=armv8-a+sve"
- AC_MSG_CHECKING([if Arm SVE ACLE is supported])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ],
- [
- svint32_t r = svdup_n_s32(1);
- return 0;
- ])],
- [
- AC_MSG_RESULT([yes])
- $2SVE_CFLAGS="-march=armv8-a+sve"
- # Switching the initialization mode with gcc from 'pattern' to 'zero'
- # avoids the use of unsupported `__builtin_clear_padding` for variable
- # length aggregates
- if test "x$DEBUG_LEVEL" != xrelease && test "x$TOOLCHAIN_TYPE" = xgcc ; then
- INIT_ZERO_FLAG="-ftrivial-auto-var-init=zero"
- FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$INIT_ZERO_FLAG],
- IF_TRUE: [
- $2SVE_CFLAGS="${$2SVE_CFLAGS} $INIT_ZERO_FLAG"
- ]
- )
- fi
- ],
- [
- AC_MSG_RESULT([no])
- $2SVE_CFLAGS=""
- ]
- )
- CFLAGS="$OLD_CFLAGS"
- AC_LANG_POP(C)
- fi
- fi
- AC_SUBST($2SVE_CFLAGS)
])
AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4
index a12a6e7f9a6..66f8904db89 100644
--- a/make/autoconf/flags-ldflags.m4
+++ b/make/autoconf/flags-ldflags.m4
@@ -79,7 +79,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
fi
if test "x$OPENJDK_TARGET_OS" = xaix; then
BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-blibpath:/usr/lib:lib -Wl,-bnoexpall \
- -Wl,-bernotok -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k"
+ -Wl,-bernotok -Wl,-bcdtors:mbr::s -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k"
BASIC_LDFLAGS_JVM_ONLY="$BASIC_LDFLAGS_JVM_ONLY -Wl,-lC_r -Wl,-bbigtoc"
fi
@@ -98,7 +98,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
# Setup OS-dependent LDFLAGS
if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$TOOLCHAIN_TYPE" = xclang; then
- # FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead.
+ # FIXME: We should really generalize SetSharedLibraryOrigin instead.
OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.."
OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN -Wl,-reproducible"
fi
diff --git a/make/autoconf/flags-other.m4 b/make/autoconf/flags-other.m4
index 9d41cf04791..4570f6ede78 100644
--- a/make/autoconf/flags-other.m4
+++ b/make/autoconf/flags-other.m4
@@ -107,6 +107,62 @@ AC_DEFUN([FLAGS_SETUP_NMFLAGS],
AC_SUBST(NMFLAGS)
])
+# Check whether the compiler supports the Arm C Language Extensions (ACLE)
+# for SVE. Set SVE_CFLAGS to -march=armv8-a+sve if it does.
+# ACLE and this flag are required to build the aarch64 SVE related functions
+# in libvectormath.
+AC_DEFUN([FLAGS_SETUP_SVE],
+[
+ AARCH64_SVE_AVAILABLE=false
+ # Apple Silicon does not support SVE; use macOS as a proxy for that check.
+ if test "x$OPENJDK_TARGET_CPU" = "xaarch64" && test "x$OPENJDK_TARGET_OS" = "xlinux"; then
+ if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
+ # check the compiler and binutils support sve or not
+ AC_MSG_CHECKING([if Arm SVE ACLE is supported])
+ AC_LANG_PUSH([C])
+ saved_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -march=armv8-a+sve $CFLAGS_WARNINGS_ARE_ERRORS ARG_ARGUMENT"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+ [
+ #include
+ svfloat64_t a() {}
+ ],
+ [
+ svint32_t r = svdup_n_s32(1)
+ ])],
+ [
+ AARCH64_SVE_AVAILABLE=true
+ ]
+ )
+ CFLAGS="$saved_cflags"
+ AC_LANG_POP([C])
+ AC_MSG_RESULT([$AARCH64_SVE_AVAILABLE])
+ fi
+ fi
+
+ UTIL_ARG_ENABLE(NAME: aarch64-sve, DEFAULT: auto,
+ RESULT: AARCH64_SVE_ENABLED,
+ DESC: [Use SVE when compiling libsleef],
+ AVAILABLE: $AARCH64_SVE_AVAILABLE)
+ SVE_CFLAGS=""
+ if test "x$AARCH64_SVE_ENABLED" = xtrue; then
+ SVE_CFLAGS="-march=armv8-a+sve"
+ # Switching the initialization mode with gcc from 'pattern' to 'zero'
+ # avoids the use of unsupported `__builtin_clear_padding` for variable
+ # length aggregates
+ if test "x$DEBUG_LEVEL" != xrelease && test "x$TOOLCHAIN_TYPE" = xgcc ; then
+ AC_MSG_CHECKING([Switching the initialization mode with gcc from pattern to zero])
+ INIT_ZERO_FLAG="-ftrivial-auto-var-init=zero"
+ FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$INIT_ZERO_FLAG],
+ IF_TRUE: [
+ SVE_CFLAGS="${SVE_CFLAGS} $INIT_ZERO_FLAG"
+ ]
+ )
+ fi
+ fi
+ AC_SUBST(SVE_CFLAGS)
+])
+
################################################################################
# platform independent
AC_DEFUN([FLAGS_SETUP_ASFLAGS],
diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4
index c810d15ebbc..c47947154c2 100644
--- a/make/autoconf/flags.m4
+++ b/make/autoconf/flags.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2025, 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
@@ -319,16 +319,10 @@ AC_DEFUN_ONCE([FLAGS_PRE_TOOLCHAIN],
AC_DEFUN([FLAGS_SETUP_TOOLCHAIN_CONTROL],
[
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
- CC_OUT_OPTION=-Fo
if test "x$OPENJDK_TARGET_CPU" != xaarch64; then
AS_NON_ASM_EXTENSION_OPTION=-Ta
fi
- else
- # The option used to specify the target .o,.a or .so file.
- # When compiling, how to specify the to be created object file.
- CC_OUT_OPTION='-o$(SPACE)'
fi
- AC_SUBST(CC_OUT_OPTION)
AC_SUBST(AS_NON_ASM_EXTENSION_OPTION)
# Generate make dependency files
@@ -374,6 +368,7 @@ AC_DEFUN([FLAGS_SETUP_FLAGS],
FLAGS_SETUP_RCFLAGS
FLAGS_SETUP_NMFLAGS
+ FLAGS_SETUP_SVE
FLAGS_SETUP_ASFLAGS
FLAGS_SETUP_ASFLAGS_CPU_DEP([TARGET])
FLAGS_SETUP_ASFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_])
diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4
index d4299078abf..bb188778001 100644
--- a/make/autoconf/jdk-options.m4
+++ b/make/autoconf/jdk-options.m4
@@ -565,9 +565,14 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER],
# with an additional define LLVM_SYMBOLIZER, which we set here.
# To calculate the correct llvm_symbolizer path we can use the location of the compiler, because
# their relation is fixed.
+ # In the ubsan case we have to link every binary with the C++-compiler as linker, because inherently
+ # the C-Compiler and the C++-compiler used as linker provide a different set of ubsan exports.
+ # Linking an executable with the C-compiler and one of its shared libraries with the C++-compiler
+ # leeds to unresolved symbols.
if test "x$TOOLCHAIN_TYPE" = "xclang" && test "x$OPENJDK_TARGET_OS" = "xaix"; then
- UBSAN_CFLAGS="$UBSAN_CFLAGS -fno-sanitize=function,vptr -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer"
- UBSAN_LDFLAGS="$UBSAN_LDFLAGS -fno-sanitize=function,vptr -Wl,-bbigtoc"
+ UBSAN_CFLAGS="$UBSAN_CFLAGS -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer"
+ UBSAN_LDFLAGS="$UBSAN_LDFLAGS -Wl,-bbigtoc"
+ LD="$LDCXX"
fi
UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED,
DESC: [enable UndefinedBehaviorSanitizer],
diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4
index 9eb5ee5a046..31d48055984 100644
--- a/make/autoconf/lib-tests.m4
+++ b/make/autoconf/lib-tests.m4
@@ -28,7 +28,7 @@
################################################################################
# Minimum supported versions
-JTREG_MINIMUM_VERSION=7.5.2
+JTREG_MINIMUM_VERSION=8.1
GTEST_MINIMUM_VERSION=1.14.0
################################################################################
diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4
index bf697928f1b..8dc3d55ed0c 100644
--- a/make/autoconf/libraries.m4
+++ b/make/autoconf/libraries.m4
@@ -136,12 +136,8 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBPTHREAD"
fi
- # librt for legacy clock_gettime
+ # librt - for timers (timer_* functions)
if test "x$OPENJDK_TARGET_OS" = xlinux; then
- # Hotspot needs to link librt to get the clock_* functions.
- # But once our supported minimum build and runtime platform
- # has glibc 2.17, this can be removed as the functions are
- # in libc.
BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lrt"
fi
diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template
index ab6bb51c27e..0b336721d65 100644
--- a/make/autoconf/spec.gmk.template
+++ b/make/autoconf/spec.gmk.template
@@ -386,9 +386,22 @@ CAPSTONE_ARCH_AARCH64_NAME := @CAPSTONE_ARCH_AARCH64_NAME@
# it in sync.
BOOT_JDK := @BOOT_JDK@
-BUILD_JDK := @BUILD_JDK@
-CREATE_BUILDJDK := @CREATE_BUILDJDK@
-EXTERNAL_BUILDJDK := @EXTERNAL_BUILDJDK@
+EXTERNAL_BUILDJDK_PATH := @EXTERNAL_BUILDJDK_PATH@
+
+ifneq ($(EXTERNAL_BUILDJDK_PATH), )
+ EXTERNAL_BUILDJDK := true
+ CREATE_BUILDJDK := false
+ BUILD_JDK := $(EXTERNAL_BUILDJDK_PATH)
+else
+ EXTERNAL_BUILDJDK := false
+ ifeq ($(COMPILE_TYPE), cross)
+ CREATE_BUILDJDK := true
+ BUILD_JDK := $(BUILDJDK_OUTPUTDIR)/jdk
+ else
+ CREATE_BUILDJDK := false
+ BUILD_JDK := $(JDK_OUTPUTDIR)
+ endif
+endif
# Whether the boot jdk jar supports --date=TIMESTAMP
BOOT_JDK_JAR_SUPPORTS_DATE := @BOOT_JDK_JAR_SUPPORTS_DATE@
@@ -491,7 +504,6 @@ CXX_VERSION_NUMBER := @CXX_VERSION_NUMBER@
# Legacy support
HOTSPOT_TOOLCHAIN_TYPE := @HOTSPOT_TOOLCHAIN_TYPE@
-CC_OUT_OPTION := @CC_OUT_OPTION@
AS_NON_ASM_EXTENSION_OPTION := @AS_NON_ASM_EXTENSION_OPTION@
# Flags used for overriding the default opt setting for a C/C++ source file.
@@ -624,17 +636,8 @@ ASFLAGS_DEBUG_SYMBOLS := @ASFLAGS_DEBUG_SYMBOLS@
# Compress (or not) jars
COMPRESS_JARS := @COMPRESS_JARS@
-# Options to linker to specify the library name.
-# (Note absence of := assignment, because we do not want to evaluate the macro body here)
-SET_SHARED_LIBRARY_NAME = @SET_SHARED_LIBRARY_NAME@
-
SHARED_LIBRARY_FLAGS := @SHARED_LIBRARY_FLAGS@
-# Set origin using the linker, ie use the relative path to the dependent library to find the dependencies.
-# (Note absence of := assignment, because we do not want to evaluate the macro body here)
-SET_SHARED_LIBRARY_ORIGIN = @SET_SHARED_LIBRARY_ORIGIN@
-SET_EXECUTABLE_ORIGIN = @SET_EXECUTABLE_ORIGIN@
-
LIBRARY_PREFIX := @LIBRARY_PREFIX@
SHARED_LIBRARY_SUFFIX := @SHARED_LIBRARY_SUFFIX@
STATIC_LIBRARY_SUFFIX := @STATIC_LIBRARY_SUFFIX@
@@ -657,8 +660,8 @@ JAVA_CMD := @JAVA@
JAVAC_CMD := @JAVAC@
JAVADOC_CMD := @JAVADOC@
JAR_CMD := @JAR@
-JLINK_CMD := @JLINK@
-JMOD_CMD := @JMOD@
+JLINK_CMD := @FIXPATH@ $(BUILD_JDK)/bin/jlink
+JMOD_CMD := @FIXPATH@ $(BUILD_JDK)/bin/jmod
# These variables are meant to be used. They are defined with = instead of := to make
# it possible to override only the *_CMD variables.
JAVA = $(JAVA_CMD) $(JAVA_FLAGS_BIG) $(JAVA_FLAGS)
diff --git a/make/common/Execute.gmk b/make/common/Execute.gmk
index 4199e8f13b7..c195510151f 100644
--- a/make/common/Execute.gmk
+++ b/make/common/Execute.gmk
@@ -148,9 +148,12 @@ define SetupExecuteBody
$1_INFO := Running commands for $1
endif
+ $1_VARDEPS := $$($1_COMMAND) $$($1_PRE_COMMAND) $$($1_POST_COMMAND)
+ $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BASE)_exec.vardeps)
+
ifneq ($$($1_PRE_COMMAND), )
- $$($1_PRE_MARKER): $$($1_DEPS)
+ $$($1_PRE_MARKER): $$($1_DEPS) $$($1_VARDEPS_FILE)
ifneq ($$($1_WARN), )
$$(call LogWarn, $$($1_WARN))
endif
@@ -176,7 +179,7 @@ define SetupExecuteBody
$1 := $$($1_PRE_MARKER) $$($1_EXEC_RESULT)
else
- $$($1_EXEC_RESULT): $$($1_DEPS)
+ $$($1_EXEC_RESULT): $$($1_DEPS) $$($1_VARDEPS_FILE)
ifneq ($$($1_WARN), )
$$(call LogWarn, $$($1_WARN))
endif
diff --git a/make/common/JdkNativeCompilation.gmk b/make/common/JdkNativeCompilation.gmk
index 0285669ffd8..29001e09bd0 100644
--- a/make/common/JdkNativeCompilation.gmk
+++ b/make/common/JdkNativeCompilation.gmk
@@ -30,6 +30,47 @@ ifeq ($(INCLUDE), true)
include NativeCompilation.gmk
+ifeq ($(call isCompiler, gcc), true)
+ # --disable-new-dtags forces use of RPATH instead of RUNPATH for rpaths.
+ # This protects internal library dependencies within the JDK from being
+ # overridden using LD_LIBRARY_PATH. See JDK-8326891 for more information.
+ SetExecutableOrigin = \
+ -Wl,-rpath,\$(DOLLAR)ORIGIN$1 -Wl,--disable-new-dtags
+ SetSharedLibraryOrigin = \
+ -Wl,-z,origin -Wl,-rpath,\$(DOLLAR)ORIGIN$1 -Wl,--disable-new-dtags
+else ifeq ($(call isCompiler, clang), true)
+ ifeq ($(call isTargetOs, macosx), true)
+ SetExecutableOrigin = \
+ -Wl,-rpath,@loader_path$(or $1,/.)
+ SetSharedLibraryOrigin = \
+ -Wl,-rpath,@loader_path$(or $1,/.)
+ else ifeq ($(call isTargetOs, aix), true)
+ SetExecutableOrigin =
+ SetSharedLibraryOrigin =
+ else
+ ifeq ($(call isTargetOs, linux), true)
+ SetExecutableOrigin = \
+ -Wl,-rpath,\$(DOLLAR)ORIGIN$1 -Wl,--disable-new-dtags
+ else
+ SetExecutableOrigin = \
+ -Wl,-rpath,\$(DOLLAR)ORIGIN$1
+ endif
+
+ ifeq ($(call isTargetOs, arm), true)
+ SetSharedLibraryOrigin = \
+ -Wl,-rpath,\$(DOLLAR)ORIGIN$1
+ else
+ SetSharedLibraryOrigin = \
+ -Wl,-z,origin -Wl,-rpath,\$(DOLLAR)ORIGIN$1
+ endif
+ endif
+else ifeq ($(call isCompiler, microsoft), true)
+ SetExecutableOrigin =
+ SetSharedLibraryOrigin =
+else
+ $(error Unknown toolchain)
+endif
+
FindSrcDirsForComponent += \
$(call uniq, $(wildcard \
$(TOPDIR)/src/$(strip $1)/$(OPENJDK_TARGET_OS)/native/$(strip $2) \
@@ -444,9 +485,9 @@ define SetupJdkNativeCompilationBody
ifneq ($$($1_LD_SET_ORIGIN), false)
ifeq ($$($1_TYPE), EXECUTABLE)
- $1_LDFLAGS += $$(call SET_EXECUTABLE_ORIGIN)
+ $1_LDFLAGS += $$(call SetExecutableOrigin)
else
- $1_LDFLAGS += $$(call SET_SHARED_LIBRARY_ORIGIN)
+ $1_LDFLAGS += $$(call SetSharedLibraryOrigin)
endif
endif
# APPEND_LDFLAGS, if it exists, must be set after the origin flags
diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk
index 700c0de74d5..0b420df5684 100644
--- a/make/common/modules/LauncherCommon.gmk
+++ b/make/common/modules/LauncherCommon.gmk
@@ -156,8 +156,8 @@ define SetupBuildLauncherBody
DISABLED_WARNINGS_gcc := unused-function unused-variable, \
DISABLED_WARNINGS_clang := unused-function, \
LDFLAGS := $$($1_LDFLAGS), \
- LDFLAGS_linux := $$(call SET_EXECUTABLE_ORIGIN,/../lib), \
- LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN,/../lib), \
+ LDFLAGS_linux := $$(call SetExecutableOrigin,/../lib), \
+ LDFLAGS_macosx := $$(call SetExecutableOrigin,/../lib), \
LDFLAGS_FILTER_OUT := $$($1_LDFLAGS_FILTER_OUT), \
JDK_LIBS := $$($1_JDK_LIBS), \
JDK_LIBS_windows := $$($1_JDK_LIBS_windows), \
diff --git a/make/common/native/CompileFile.gmk b/make/common/native/CompileFile.gmk
index a8d46949788..10326d3066c 100644
--- a/make/common/native/CompileFile.gmk
+++ b/make/common/native/CompileFile.gmk
@@ -93,6 +93,14 @@ DEPENDENCY_TARGET_SED_PATTERN := \
-e 's/$$$$/ :/' \
#
+################################################################################
+# Setup compiler-specific argument to specify output file
+ifeq ($(call isCompiler, microsoft), true)
+ CC_OUT_OPTION := -Fo
+else
+ CC_OUT_OPTION := -o$(SPACE)
+endif
+
################################################################################
# Create the recipe needed to compile a single native source file.
#
@@ -334,7 +342,7 @@ define CreateWindowsResourceFile
$$(call LogInfo, Compiling resource $$(notdir $$($1_VERSIONINFO_RESOURCE)) (for $$($1_BASENAME)))
$$(call MakeDir, $$(@D) $$($1_OBJECT_DIR))
$$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \
- $$($1_RC) $$($1_RCFLAGS) $$($1_SYSROOT_CFLAGS) $(CC_OUT_OPTION)$$@ \
+ $$($1_RC) $$($1_RCFLAGS) $$($1_SYSROOT_CFLAGS) -Fo$$@ \
$$($1_VERSIONINFO_RESOURCE) 2>&1 ))
# Windows RC compiler does not support -showIncludes, so we mis-use CL
# for this. Filter out RC specific arguments that are unknown to CL.
@@ -344,7 +352,7 @@ define CreateWindowsResourceFile
$$(call ExecuteWithLog, $$($1_RES_DEPS_FILE)$(OBJ_SUFFIX), \
$$($1_CC) $$(filter-out -l%, $$($1_RCFLAGS)) \
$$($1_SYSROOT_CFLAGS) -showIncludes -nologo -TC \
- $(CC_OUT_OPTION)$$($1_RES_DEPS_FILE)$(OBJ_SUFFIX) -P -Fi$$($1_RES_DEPS_FILE).pp \
+ -Fo$$($1_RES_DEPS_FILE)$(OBJ_SUFFIX) -P -Fi$$($1_RES_DEPS_FILE).pp \
$$($1_VERSIONINFO_RESOURCE)) 2>&1 \
| $(TR) -d '\r' | $(GREP) -v -e "^Note: including file:" \
-e "^$$(notdir $$($1_VERSIONINFO_RESOURCE))$$$$" || test "$$$$?" = "1" ; \
diff --git a/make/common/native/Link.gmk b/make/common/native/Link.gmk
index e888edfcc4c..855e50bddfb 100644
--- a/make/common/native/Link.gmk
+++ b/make/common/native/Link.gmk
@@ -50,6 +50,26 @@ GetEntitlementsFile = \
$(if $(wildcard $f), $f, $(DEFAULT_ENTITLEMENTS_FILE)) \
)
+ifeq ($(call isCompiler, gcc), true)
+ SetSharedLibraryName = \
+ -Wl,-soname=$1
+else ifeq ($(call isCompiler, clang), true)
+ ifeq ($(call isTargetOs, macosx), true)
+ SetSharedLibraryName = \
+ -Wl,-install_name,@rpath/$1
+ else ifeq ($(call isTargetOs, aix), true)
+ SetSharedLibraryName =
+ else
+ # Default works for linux, might work on other platforms as well.
+ SetSharedLibraryName = \
+ -Wl,-soname=$1
+ endif
+else ifeq ($(call isCompiler, microsoft), true)
+ SetSharedLibraryName =
+else
+ $(error Unknown toolchain)
+endif
+
################################################################################
define SetupLinking
# Unless specifically set, stripping should only happen if symbols are also
@@ -131,7 +151,7 @@ define CreateDynamicLibraryOrExecutable
# A shared dynamic library or an executable binary has been specified
ifeq ($$($1_TYPE), LIBRARY)
# Generating a dynamic library.
- $1_EXTRA_LDFLAGS += $$(call SET_SHARED_LIBRARY_NAME,$$($1_BASENAME))
+ $1_EXTRA_LDFLAGS += $$(call SetSharedLibraryName,$$($1_BASENAME))
endif
ifeq ($(MACOSX_CODESIGN_MODE), hardened)
diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf
index d2b6cd23128..bd73e909062 100644
--- a/make/conf/github-actions.conf
+++ b/make/conf/github-actions.conf
@@ -26,24 +26,24 @@
# Versions and download locations for dependencies used by GitHub Actions (GHA)
GTEST_VERSION=1.14.0
-JTREG_VERSION=7.5.2+1
+JTREG_VERSION=8.1+1
LINUX_X64_BOOT_JDK_EXT=tar.gz
-LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_linux-x64_bin.tar.gz
-LINUX_X64_BOOT_JDK_SHA256=88b090fa80c6c1d084ec9a755233967458788e2c0777ae2e172230c5c692d7ef
+LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_linux-x64_bin.tar.gz
+LINUX_X64_BOOT_JDK_SHA256=59cdcaf255add4721de38eb411d4ecfe779356b61fb671aee63c7dec78054c2b
ALPINE_LINUX_X64_BOOT_JDK_EXT=tar.gz
-ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin24-binaries/releases/download/jdk-24%2B36/OpenJDK24U-jdk_x64_alpine-linux_hotspot_24_36.tar.gz
-ALPINE_LINUX_X64_BOOT_JDK_SHA256=a642608f0da78344ee6812fb1490b8bc1d7ad5a18064c70994d6f330568c51cb
+ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25%2B36/OpenJDK25U-jdk_x64_alpine-linux_hotspot_25_36.tar.gz
+ALPINE_LINUX_X64_BOOT_JDK_SHA256=637e47474d411ed86134f413af7d5fef4180ddb0bf556347b7e74a88cf8904c8
MACOS_AARCH64_BOOT_JDK_EXT=tar.gz
-MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_macos-aarch64_bin.tar.gz
-MACOS_AARCH64_BOOT_JDK_SHA256=f7133238a12714a62c5ad2bd4da6741130be1a82512065da9ca23dee26b2d3d3
+MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_macos-aarch64_bin.tar.gz
+MACOS_AARCH64_BOOT_JDK_SHA256=2006337bf326fdfdf6117081751ba38c1c8706d63419ecac7ff102ff7c776876
MACOS_X64_BOOT_JDK_EXT=tar.gz
-MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_macos-x64_bin.tar.gz
-MACOS_X64_BOOT_JDK_SHA256=6bbfb1d01741cbe55ab90299cb91464b695de9a3ace85c15131aa2f50292f321
+MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_macos-x64_bin.tar.gz
+MACOS_X64_BOOT_JDK_SHA256=47482ad9888991ecac9b2bcc131e2b53ff78aff275104cef85f66252308e8a09
WINDOWS_X64_BOOT_JDK_EXT=zip
-WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_windows-x64_bin.zip
-WINDOWS_X64_BOOT_JDK_SHA256=11d1d9f6ac272d5361c8a0bef01894364081c7fb1a6914c2ad2fc312ae83d63b
+WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_windows-x64_bin.zip
+WINDOWS_X64_BOOT_JDK_SHA256=85bcc178461e2cb3c549ab9ca9dfa73afd54c09a175d6510d0884071867137d3
diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index d4877604a90..795335d7c3c 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -387,8 +387,8 @@ var getJibProfilesCommon = function (input, data) {
};
};
- common.boot_jdk_version = "24";
- common.boot_jdk_build_number = "36";
+ common.boot_jdk_version = "25";
+ common.boot_jdk_build_number = "37";
common.boot_jdk_home = input.get("boot_jdk", "install_path") + "/jdk-"
+ common.boot_jdk_version
+ (input.build_os == "macosx" ? ".jdk/Contents/Home" : "");
@@ -1174,9 +1174,9 @@ var getJibProfilesDependencies = function (input, common) {
jtreg: {
server: "jpg",
product: "jtreg",
- version: "7.5.2",
+ version: "8.1",
build_number: "1",
- file: "bundles/jtreg-7.5.2+1.zip",
+ file: "bundles/jtreg-8.1+1.zip",
environment_name: "JT_HOME",
environment_path: input.get("jtreg", "home_path") + "/bin",
configure_args: "--with-jtreg=" + input.get("jtreg", "home_path"),
diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf
index 38d6e42dff9..977809535ba 100644
--- a/make/conf/version-numbers.conf
+++ b/make/conf/version-numbers.conf
@@ -37,6 +37,6 @@ DEFAULT_VERSION_DATE=2026-03-17
DEFAULT_VERSION_CLASSFILE_MAJOR=70 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
DEFAULT_VERSION_CLASSFILE_MINOR=0
DEFAULT_VERSION_DOCS_API_SINCE=11
-DEFAULT_ACCEPTABLE_BOOT_VERSIONS="24 25 26"
+DEFAULT_ACCEPTABLE_BOOT_VERSIONS="25 26"
DEFAULT_JDK_SOURCE_TARGET_VERSION=26
DEFAULT_PROMOTED_VERSION_PRE=ea
diff --git a/make/data/charsetmapping/IBM930.c2b b/make/data/charsetmapping/IBM930.c2b
index 88754763fe3..72107424104 100644
--- a/make/data/charsetmapping/IBM930.c2b
+++ b/make/data/charsetmapping/IBM930.c2b
@@ -32,11 +32,6 @@
547d 92ca
53da 9b7e
446e f86f
-#
-# we should use this one instead of the 4260<-ff0d
-#4260 2212
-4260 ff0d
-#
426A 00A6
43A1 301C
444A 2014
diff --git a/make/data/charsetmapping/IBM930.map b/make/data/charsetmapping/IBM930.map
index 4b9dad9526b..7939e795bdf 100644
--- a/make/data/charsetmapping/IBM930.map
+++ b/make/data/charsetmapping/IBM930.map
@@ -25,13 +25,6 @@
# 4260 <--> 2212
# 426A <--> 00A6
#
-# Warning:
-# "our old" implementation seems agree with above "new" mappings
-# except the entries 4260 <-> 2212. To keep the "compatbility"
-# with the "old" implementation, I changed the entries "temporarily"
-# 4260 <-> 2212
-# 4260 <- ff0d
-#
00 0000
01 0001
02 0002
@@ -407,8 +400,7 @@ FF 009F
425D FF09
425E FF1B
425F FFE2
-#4260 FF0D
-4260 2212
+4260 FF0D
4261 FF0F
426A FFE4
426B FF0C
diff --git a/make/devkit/Makefile b/make/devkit/Makefile
index d2167bf33fa..30e0dce0839 100644
--- a/make/devkit/Makefile
+++ b/make/devkit/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2025, 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
@@ -57,61 +57,61 @@
COMMA := ,
-os := $(shell uname -o)
-cpu := $(shell uname -p)
+OS := $(shell uname -o)
+CPU := $(shell uname -m)
# Figure out what platform this is building on.
-me := $(cpu)-$(if $(findstring Linux,$(os)),linux-gnu)
+ME := $(CPU)-$(if $(findstring Linux,$(OS)),linux-gnu)
-$(info Building on platform $(me))
+$(info Building on platform $(ME))
#
# By default just build for the current platform, which is assumed to be Linux
#
ifeq ($(TARGETS), )
- platforms := $(me)
- host_platforms := $(platforms)
+ PLATFORMS := $(ME)
+ HOST_PLATFORMS := $(PLATFORMS)
else
- platforms := $(subst $(COMMA), , $(TARGETS))
- host_platforms := $(me)
+ PLATFORMS := $(subst $(COMMA), , $(TARGETS))
+ HOST_PLATFORMS := $(ME)
endif
-target_platforms := $(platforms)
-$(info host_platforms $(host_platforms))
-$(info target_platforms $(target_platforms))
+TARGET_PLATFORMS := $(PLATFORMS)
+$(info HOST_PLATFORMS $(HOST_PLATFORMS))
+$(info TARGET_PLATFORMS $(TARGET_PLATFORMS))
-all compile : $(platforms)
+all compile : $(PLATFORMS)
ifeq ($(SKIP_ME), )
- $(foreach p,$(filter-out $(me),$(platforms)),$(eval $(p) : $$(me)))
+ $(foreach p,$(filter-out $(ME),$(PLATFORMS)),$(eval $(p) : $$(ME)))
endif
OUTPUT_ROOT = $(abspath ../../build/devkit)
RESULT = $(OUTPUT_ROOT)/result
-submakevars = HOST=$@ BUILD=$(me) RESULT=$(RESULT) OUTPUT_ROOT=$(OUTPUT_ROOT)
+SUBMAKEVARS = HOST=$@ BUILD=$(ME) RESULT=$(RESULT) OUTPUT_ROOT=$(OUTPUT_ROOT)
-$(host_platforms) :
+$(HOST_PLATFORMS) :
@echo 'Building compilers for $@'
- @echo 'Targets: $(target_platforms)'
- for p in $(filter $@, $(target_platforms)) $(filter-out $@, $(target_platforms)); do \
- $(MAKE) -f Tools.gmk download-rpms $(submakevars) \
+ @echo 'Targets: $(TARGET_PLATFORMS)'
+ for p in $(filter $@, $(TARGET_PLATFORMS)) $(filter-out $@, $(TARGET_PLATFORMS)); do \
+ $(MAKE) -f Tools.gmk download-rpms $(SUBMAKEVARS) \
TARGET=$$p PREFIX=$(RESULT)/$@-to-$$p && \
- $(MAKE) -f Tools.gmk all $(submakevars) \
+ $(MAKE) -f Tools.gmk all $(SUBMAKEVARS) \
TARGET=$$p PREFIX=$(RESULT)/$@-to-$$p && \
- $(MAKE) -f Tools.gmk ccache $(submakevars) \
+ $(MAKE) -f Tools.gmk ccache $(SUBMAKEVARS) \
TARGET=$@ PREFIX=$(RESULT)/$@-to-$$p || exit 1 ; \
done
@echo 'All done"'
-today := $(shell date +%Y%m%d)
+TODAY := $(shell date +%Y%m%d)
define Mktar
- $(1)-to-$(2)_tar = $$(RESULT)/sdk-$(1)-to-$(2)-$$(today).tar.gz
+ $(1)-to-$(2)_tar = $$(RESULT)/sdk-$(1)-to-$(2)-$$(TODAY).tar.gz
$$($(1)-to-$(2)_tar) : PLATFORM = $(1)-to-$(2)
TARFILES += $$($(1)-to-$(2)_tar)
endef
-$(foreach p,$(host_platforms),$(foreach t,$(target_platforms),$(eval $(call Mktar,$(p),$(t)))))
+$(foreach p,$(HOST_PLATFORMS),$(foreach t,$(TARGET_PLATFORMS),$(eval $(call Mktar,$(p),$(t)))))
tars : all $(TARFILES)
onlytars : $(TARFILES)
@@ -119,9 +119,9 @@ onlytars : $(TARFILES)
$(MAKE) -r -f Tars.gmk SRC_DIR=$(RESULT)/$(PLATFORM) TAR_FILE=$@
clean :
- rm -rf $(addprefix ../../build/devkit/, result $(host_platforms))
+ rm -rf $(addprefix ../../build/devkit/, result $(HOST_PLATFORMS))
dist-clean: clean
rm -rf $(addprefix ../../build/devkit/, src download)
FORCE :
-.PHONY : all compile tars $(configs) $(host_platforms) clean dist-clean
+.PHONY : all compile tars $(HOST_PLATFORMS) clean dist-clean
diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk
index f27d47b822c..db77f2f3f74 100644
--- a/make/devkit/Tools.gmk
+++ b/make/devkit/Tools.gmk
@@ -39,7 +39,7 @@
# Fix this...
#
-uppercase = $(shell echo $1 | tr a-z A-Z)
+lowercase = $(shell echo $1 | tr A-Z a-z)
$(info TARGET=$(TARGET))
$(info HOST=$(HOST))
@@ -104,26 +104,48 @@ endif
################################################################################
# Define external dependencies
-gcc_ver_only := 14.2.0
-binutils_ver_only := 2.43
-ccache_ver_only := 4.10.2
+GNU_BASE_URL := https://ftp.gnu.org/pub/gnu
+
+BINUTILS_VER_ONLY := 2.43
+BINUTILS_BASE_URL := $(GNU_BASE_URL)/binutils
+BINUTILS_SHA512 := 93e063163e54d6a6ee2bd48dc754270bf757a3635b49a702ed6b310e929e94063958512d191e66beaf44275f7ea60865dbde138b624626739679fcc306b133bb
+
+CCACHE_VER_ONLY := 4.10.2
+CCACHE_BASE_URL := https://github.com/ccache/ccache/releases/download
CCACHE_CMAKE_BASED := 1
-mpfr_ver_only := 4.2.1
-gmp_ver_only := 6.3.0
-mpc_ver_only := 1.3.1
-gdb_ver_only := 15.2
+CCACHE_SHA512 := 3815c71d7266c32839acb306763268018acc58b3bbbd9ec79fc101e4217c1720d2ad2f01645bf69168c1c61d27700b6f3bb755cfa82689cca69824f015653f3c
-dependencies := gcc binutils ccache mpfr gmp mpc gdb
+GCC_VER_ONLY := 14.2.0
+GCC_BASE_URL := $(GNU_BASE_URL)/gcc
+GCC_SHA512 := 932bdef0cda94bacedf452ab17f103c0cb511ff2cec55e9112fc0328cbf1d803b42595728ea7b200e0a057c03e85626f937012e49a7515bc5dd256b2bf4bc396
-$(foreach dep,$(dependencies),$(eval $(dep)_ver := $(dep)-$($(dep)_ver_only)))
+GDB_VER_ONLY := 15.2
+GDB_BASE_URL := $(GNU_BASE_URL)/gdb
+GDB_SHA512 := 624007deceb5b15ba89c0725883d1a699fa46714ef30887f3d0165e17c5d65d634671740a135aa69e437d916218abb08cfa2a38ed309ff19d48f51da56b2a8ba
-GCC := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz
-BINUTILS := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz
-CCACHE := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz
-MPFR := https://www.mpfr.org/$(mpfr_ver)/$(mpfr_ver).tar.bz2
-GMP := http://ftp.gnu.org/pub/gnu/gmp/$(gmp_ver).tar.bz2
-MPC := http://ftp.gnu.org/pub/gnu/mpc/$(mpc_ver).tar.gz
-GDB := http://ftp.gnu.org/gnu/gdb/$(gdb_ver).tar.xz
+GMP_VER_ONLY := 6.3.0
+GMP_BASE_URL := $(GNU_BASE_URL)/gmp
+GMP_SHA512 := e85a0dab5195889948a3462189f0e0598d331d3457612e2d3350799dba2e244316d256f8161df5219538eb003e4b5343f989aaa00f96321559063ed8c8f29fd2
+
+MPC_VER_ONLY := 1.3.1
+MPC_BASE_URL := $(GNU_BASE_URL)/mpc
+MPC_SHA512 := 4bab4ef6076f8c5dfdc99d810b51108ced61ea2942ba0c1c932d624360a5473df20d32b300fc76f2ba4aa2a97e1f275c9fd494a1ba9f07c4cb2ad7ceaeb1ae97
+
+MPFR_VER_ONLY := 4.2.1
+MPFR_BASE_URL := https://www.mpfr.org
+MPFR_SHA512 := bc68c0d755d5446403644833ecbb07e37360beca45f474297b5d5c40926df1efc3e2067eecffdf253f946288bcca39ca89b0613f545d46a9e767d1d4cf358475
+
+DEPENDENCIES := BINUTILS CCACHE GCC GDB GMP MPC MPFR
+
+$(foreach dep,$(DEPENDENCIES),$(eval $(dep)_VER := $(call lowercase,$(dep)-$($(dep)_VER_ONLY))))
+
+BINUTILS_URL := $(BINUTILS_BASE_URL)/$(BINUTILS_VER).tar.xz
+CCACHE_URL := $(CCACHE_BASE_URL)/v$(CCACHE_VER_ONLY)/$(CCACHE_VER).tar.xz
+GCC_URL := $(GCC_BASE_URL)/$(GCC_VER)/$(GCC_VER).tar.xz
+GDB_URL := $(GDB_BASE_URL)/$(GDB_VER).tar.xz
+GMP_URL := $(GMP_BASE_URL)/$(GMP_VER).tar.xz
+MPC_URL := $(MPC_BASE_URL)/$(MPC_VER).tar.gz
+MPFR_URL := $(MPFR_BASE_URL)/$(MPFR_VER)/$(MPFR_VER).tar.xz
REQUIRED_MIN_MAKE_MAJOR_VERSION := 4
ifneq ($(REQUIRED_MIN_MAKE_MAJOR_VERSION),)
@@ -180,10 +202,10 @@ DOWNLOAD_RPMS := $(DOWNLOAD)/rpms/$(TARGET)-$(LINUX_VERSION)
SRCDIR := $(OUTPUT_ROOT)/src
# Marker file for unpacking rpms
-rpms := $(SYSROOT)/rpms_unpacked
+RPMS := $(SYSROOT)/rpms_unpacked
# Need to patch libs that are linker scripts to use non-absolute paths
-libs := $(SYSROOT)/libs_patched
+LIBS := $(SYSROOT)/libs_patched
################################################################################
# Download RPMs
@@ -198,10 +220,10 @@ download-rpms:
################################################################################
# Unpack source packages
-# Generate downloading + unpacking of sources.
-define Download
+# Generate downloading + checksum verification of sources.
+define DownloadVerify
# Allow override
- $(1)_DIRNAME ?= $(basename $(basename $(notdir $($(1)))))
+ $(1)_DIRNAME ?= $(basename $(basename $(notdir $($(1)_URL))))
$(1)_DIR = $(abspath $(SRCDIR)/$$($(1)_DIRNAME))
ifeq ($$($(1)_CMAKE_BASED),)
$(1)_CFG = $$($(1)_DIR)/configure
@@ -212,7 +234,7 @@ define Download
$(1)_SRC_MARKER = $$($(1)_DIR)/CMakeLists.txt
$(1)_CONFIG = $$(CMAKE_CONFIG) $$($(1)_DIR)
endif
- $(1)_FILE = $(DOWNLOAD)/$(notdir $($(1)))
+ $(1)_FILE = $(DOWNLOAD)/$(notdir $($(1)_URL))
$$($(1)_SRC_MARKER) : $$($(1)_FILE)
mkdir -p $$(SRCDIR)
@@ -224,11 +246,20 @@ define Download
touch $$@
$$($(1)_FILE) :
- wget -P $(DOWNLOAD) $$($(1))
+ mkdir -p $$(@D)
+ wget -O - $$($(1)_URL) > $$@.tmp
+ sha512_actual="$$$$(sha512sum $$@.tmp | awk '{ print $$$$1; }')"; \
+ if [ x"$$$${sha512_actual}" != x"$$($(1)_SHA512)" ]; then \
+ echo "Checksum mismatch for $$@.tmp"; \
+ echo " Expected: $$($(1)_SHA512)"; \
+ echo " Actual: $$$${sha512_actual}"; \
+ exit 1; \
+ fi
+ mv $$@.tmp $$@
endef
# Download and unpack all source packages
-$(foreach dep,$(dependencies),$(eval $(call Download,$(call uppercase,$(dep)))))
+$(foreach dep,$(DEPENDENCIES),$(eval $(call DownloadVerify,$(dep))))
################################################################################
# Unpack RPMS
@@ -250,7 +281,7 @@ RPM_FILE_LIST := $(sort $(foreach a, $(RPM_ARCHS), \
# Note. For building linux you should install rpm2cpio.
define unrpm
$(SYSROOT)/$(notdir $(1)).unpacked : $(1)
- $$(rpms) : $(SYSROOT)/$(notdir $(1)).unpacked
+ $$(RPMS) : $(SYSROOT)/$(notdir $(1)).unpacked
endef
%.unpacked :
@@ -277,7 +308,7 @@ $(foreach p,$(RPM_FILE_LIST),$(eval $(call unrpm,$(p))))
# have it anyway, but just to make sure...
# Patch libc.so and libpthread.so to force linking against libraries in sysroot
# and not the ones installed on the build machine.
-$(libs) : $(rpms)
+$(LIBS) : $(RPMS)
@echo Patching libc and pthreads
@(for f in `find $(SYSROOT) -name libc.so -o -name libpthread.so`; do \
(cat $$f | sed -e 's|/usr/lib64/||g' \
@@ -293,10 +324,10 @@ $(libs) : $(rpms)
# Create links for ffi header files so that they become visible by default when using the
# devkit.
ifeq ($(ARCH), x86_64)
- $(SYSROOT)/usr/include/ffi.h: $(rpms)
+ $(SYSROOT)/usr/include/ffi.h: $(RPMS)
cd $(@D) && rm -f $(@F) && ln -s ../lib/libffi-*/include/$(@F) .
- $(SYSROOT)/usr/include/ffitarget.h: $(rpms)
+ $(SYSROOT)/usr/include/ffitarget.h: $(RPMS)
cd $(@D) && rm -f $(@F) && ln -s ../lib/libffi-*/include/$(@F) .
SYSROOT_LINKS += $(SYSROOT)/usr/include/ffi.h $(SYSROOT)/usr/include/ffitarget.h
@@ -305,7 +336,7 @@ endif
################################################################################
# Define marker files for each source package to be compiled
-$(foreach dep,$(dependencies),$(eval $(dep) = $(TARGETDIR)/$($(dep)_ver).done))
+$(foreach dep,$(DEPENDENCIES),$(eval $(dep) = $(TARGETDIR)/$($(dep)_VER).done))
################################################################################
@@ -345,48 +376,48 @@ TOOLS ?= $(call declare_tools,_FOR_TARGET,$(TARGET)-)
# CFLAG_ to most likely -m32.
define mk_bfd
$$(info Libs for $(1))
- $$(BUILDDIR)/$$(binutils_ver)-$(subst /,-,$(1))/Makefile \
+ $$(BUILDDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1))/Makefile \
: CFLAGS += $$(CFLAGS_$(1))
- $$(BUILDDIR)/$$(binutils_ver)-$(subst /,-,$(1))/Makefile \
+ $$(BUILDDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1))/Makefile \
: LIBDIRS = --libdir=$(TARGETDIR)/$(1)
- bfdlib += $$(TARGETDIR)/$$(binutils_ver)-$(subst /,-,$(1)).done
- bfdmakes += $$(BUILDDIR)/$$(binutils_ver)-$(subst /,-,$(1))/Makefile
+ BFDLIB += $$(TARGETDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1)).done
+ BFDMAKES += $$(BUILDDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1))/Makefile
endef
# Create one set of bfds etc for each multilib arch
$(foreach l,$(LIBDIRS),$(eval $(call mk_bfd,$(l))))
# Only build these two libs.
-$(bfdlib) : MAKECMD = all-libiberty all-bfd
-$(bfdlib) : INSTALLCMD = install-libiberty install-bfd
+$(BFDLIB) : MAKECMD = all-libiberty all-bfd
+$(BFDLIB) : INSTALLCMD = install-libiberty install-bfd
# Building targets libbfd + libiberty. HOST==TARGET, i.e not
# for a cross env.
-$(bfdmakes) : CONFIG = --target=$(TARGET) \
+$(BFDMAKES) : CONFIG = --target=$(TARGET) \
--host=$(TARGET) --build=$(BUILD) \
--prefix=$(TARGETDIR) \
--with-sysroot=$(SYSROOT) \
$(LIBDIRS)
-$(bfdmakes) : TOOLS = $(call declare_tools,_FOR_TARGET,$(TARGET)-) $(call declare_tools,,$(TARGET)-)
+$(BFDMAKES) : TOOLS = $(call declare_tools,_FOR_TARGET,$(TARGET)-) $(call declare_tools,,$(TARGET)-)
################################################################################
-$(gcc) \
- $(binutils) \
- $(gmp) \
- $(mpfr) \
- $(mpc) \
- $(bfdmakes) \
- $(ccache) : ENVS += $(TOOLS)
+$(GCC) \
+ $(BINUTILS) \
+ $(GMP) \
+ $(MPFR) \
+ $(MPC) \
+ $(BFDMAKES) \
+ $(CCACHE) : ENVS += $(TOOLS)
# libdir to work around hateful bfd stuff installing into wrong dirs...
# ensure we have 64 bit bfd support in the HOST library. I.e our
# compiler on i686 will know 64 bit symbols, BUT later
# we build just the libs again for TARGET, then with whatever the arch
# wants.
-$(BUILDDIR)/$(binutils_ver)/Makefile : CONFIG += --enable-64-bit-bfd --libdir=$(PREFIX)/$(word 1,$(LIBDIRS))
+$(BUILDDIR)/$(BINUTILS_VER)/Makefile : CONFIG += --enable-64-bit-bfd --libdir=$(PREFIX)/$(word 1,$(LIBDIRS))
ifeq ($(filter $(ARCH), s390x riscv64 ppc64le), )
# gold compiles but cannot link properly on s390x @ gcc 13.2 and Fedore 41
@@ -397,8 +428,8 @@ endif
# Makefile creation. Simply run configure in build dir.
# Setting CFLAGS to -O2 generates a much faster ld.
-$(bfdmakes) \
-$(BUILDDIR)/$(binutils_ver)/Makefile \
+$(BFDMAKES) \
+$(BUILDDIR)/$(BINUTILS_VER)/Makefile \
: $(BINUTILS_CFG)
$(info Configuring $@. Log in $(@D)/log.config)
@mkdir -p $(@D)
@@ -417,7 +448,7 @@ $(BUILDDIR)/$(binutils_ver)/Makefile \
) > $(@D)/log.config 2>&1
@echo 'done'
-$(BUILDDIR)/$(mpfr_ver)/Makefile \
+$(BUILDDIR)/$(MPFR_VER)/Makefile \
: $(MPFR_CFG)
$(info Configuring $@. Log in $(@D)/log.config)
@mkdir -p $(@D)
@@ -432,7 +463,7 @@ $(BUILDDIR)/$(mpfr_ver)/Makefile \
) > $(@D)/log.config 2>&1
@echo 'done'
-$(BUILDDIR)/$(gmp_ver)/Makefile \
+$(BUILDDIR)/$(GMP_VER)/Makefile \
: $(GMP_CFG)
$(info Configuring $@. Log in $(@D)/log.config)
@mkdir -p $(@D)
@@ -449,7 +480,7 @@ $(BUILDDIR)/$(gmp_ver)/Makefile \
) > $(@D)/log.config 2>&1
@echo 'done'
-$(BUILDDIR)/$(mpc_ver)/Makefile \
+$(BUILDDIR)/$(MPC_VER)/Makefile \
: $(MPC_CFG)
$(info Configuring $@. Log in $(@D)/log.config)
@mkdir -p $(@D)
@@ -468,11 +499,11 @@ $(BUILDDIR)/$(mpc_ver)/Makefile \
# Only valid if glibc target -> linux
# proper destructor handling for c++
ifneq (,$(findstring linux,$(TARGET)))
- $(BUILDDIR)/$(gcc_ver)/Makefile : CONFIG += --enable-__cxa_atexit
+ $(BUILDDIR)/$(GCC_VER)/Makefile : CONFIG += --enable-__cxa_atexit
endif
ifeq ($(ARCH), armhfp)
- $(BUILDDIR)/$(gcc_ver)/Makefile : CONFIG += --with-float=hard
+ $(BUILDDIR)/$(GCC_VER)/Makefile : CONFIG += --with-float=hard
endif
ifneq ($(filter riscv64 ppc64le s390x, $(ARCH)), )
@@ -487,7 +518,7 @@ endif
# skip native language.
# and link and assemble with the binutils we created
# earlier, so --with-gnu*
-$(BUILDDIR)/$(gcc_ver)/Makefile \
+$(BUILDDIR)/$(GCC_VER)/Makefile \
: $(GCC_CFG)
$(info Configuring $@. Log in $(@D)/log.config)
mkdir -p $(@D)
@@ -509,17 +540,17 @@ $(BUILDDIR)/$(gcc_ver)/Makefile \
@echo 'done'
# need binutils for gcc
-$(gcc) : $(binutils)
+$(GCC) : $(BINUTILS)
# as of 4.3 or so need these for doing config
-$(BUILDDIR)/$(gcc_ver)/Makefile : $(gmp) $(mpfr) $(mpc)
-$(mpfr) : $(gmp)
-$(mpc) : $(gmp) $(mpfr)
+$(BUILDDIR)/$(GCC_VER)/Makefile : $(GMP) $(MPFR) $(MPC)
+$(MPFR) : $(GMP)
+$(MPC) : $(GMP) $(MPFR)
################################################################################
# Build gdb but only where host and target match
ifeq ($(HOST), $(TARGET))
- $(BUILDDIR)/$(gdb_ver)/Makefile: $(GDB_CFG)
+ $(BUILDDIR)/$(GDB_VER)/Makefile: $(GDB_CFG)
$(info Configuring $@. Log in $(@D)/log.config)
mkdir -p $(@D)
( \
@@ -532,9 +563,9 @@ ifeq ($(HOST), $(TARGET))
) > $(@D)/log.config 2>&1
@echo 'done'
- $(gdb): $(gcc)
+ $(GDB): $(GCC)
else
- $(BUILDDIR)/$(gdb_ver)/Makefile:
+ $(BUILDDIR)/$(GDB_VER)/Makefile:
$(info Faking $@, not used when cross-compiling)
mkdir -p $(@D)
echo "install:" > $@
@@ -543,7 +574,7 @@ endif
################################################################################
# very straightforward. just build a ccache. it is only for host.
-$(BUILDDIR)/$(ccache_ver)/Makefile \
+$(BUILDDIR)/$(CCACHE_VER)/Makefile \
: $(CCACHE_SRC_MARKER)
$(info Configuring $@. Log in $(@D)/log.config)
@mkdir -p $(@D)
@@ -554,12 +585,12 @@ $(BUILDDIR)/$(ccache_ver)/Makefile \
) > $(@D)/log.config 2>&1
@echo 'done'
-gccpatch = $(TARGETDIR)/gcc-patched
+GCC_PATCHED = $(TARGETDIR)/gcc-patched
################################################################################
# For some reason cpp is not created as a target-compiler
ifeq ($(HOST),$(TARGET))
- $(gccpatch) : $(gcc) link_libs
+ $(GCC_PATCHED) : $(GCC) link_libs
@echo -n 'Creating compiler symlinks...'
@for f in cpp; do \
if [ ! -e $(PREFIX)/bin/$(TARGET)-$$f ]; \
@@ -587,7 +618,7 @@ ifeq ($(HOST),$(TARGET))
done;)
@echo 'done'
else
- $(gccpatch) :
+ $(GCC_PATCHED) :
@echo 'done'
endif
@@ -615,7 +646,7 @@ $(PREFIX)/devkit.info:
echo '# This file describes to configure how to interpret the contents of this' >> $@
echo '# devkit' >> $@
echo '' >> $@
- echo 'DEVKIT_NAME="$(gcc_ver) - $(LINUX_VERSION)"' >> $@
+ echo 'DEVKIT_NAME="$(GCC_VER) - $(LINUX_VERSION)"' >> $@
echo 'DEVKIT_TOOLCHAIN_PATH="$$DEVKIT_ROOT/bin"' >> $@
echo 'DEVKIT_SYSROOT="$$DEVKIT_ROOT/$(TARGET)/sysroot"' >> $@
echo 'DEVKIT_EXTRA_PATH="$$DEVKIT_ROOT/bin"' >> $@
@@ -651,32 +682,32 @@ ifeq ($(TARGET), $(HOST))
@echo 'Creating missing $* soft link'
ln -s $(TARGET)-$* $@
- missing-links := $(addprefix $(PREFIX)/bin/, \
- addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(gcc_ver_only) gprof ld ld.bfd \
+ MISSING_LINKS := $(addprefix $(PREFIX)/bin/, \
+ addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(GCC_VER_ONLY) gprof ld ld.bfd \
ld.gold nm objcopy objdump ranlib readelf size strings strip)
endif
# Add link to work around "plugin needed to handle lto object" (JDK-8344272)
-$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(gcc_ver_only)/liblto_plugin.so
+$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(GCC_VER_ONLY)/liblto_plugin.so
@echo 'Creating missing $(@F) soft link'
@mkdir -p $(@D)
ln -s $$(realpath -s --relative-to=$(@D) $<) $@
-missing-links += $(PREFIX)/lib/bfd-plugins/liblto_plugin.so
+MISSING_LINKS += $(PREFIX)/lib/bfd-plugins/liblto_plugin.so
################################################################################
-bfdlib : $(bfdlib)
-binutils : $(binutils)
-rpms : $(rpms)
-libs : $(libs)
+bfdlib : $(BFDLIB)
+binutils : $(BINUTILS)
+rpms : $(RPMS)
+libs : $(LIBS)
sysroot : rpms libs
-gcc : sysroot $(gcc) $(gccpatch)
-gdb : $(gdb)
-all : binutils gcc bfdlib $(PREFIX)/devkit.info $(missing-links) $(SYSROOT_LINKS) \
+gcc : sysroot $(GCC) $(GCC_PATCHED)
+gdb : $(GDB)
+all : binutils gcc bfdlib $(PREFIX)/devkit.info $(MISSING_LINKS) $(SYSROOT_LINKS) \
$(THESE_MAKEFILES) gdb
# this is only built for host. so separate.
-ccache : $(ccache)
+ccache : $(CCACHE)
.PHONY : gcc all binutils bfdlib link_libs rpms libs sysroot
diff --git a/make/devkit/createAutoconfBundle.sh b/make/devkit/createAutoconfBundle.sh
index ebe9c427f76..4697e4eb1e3 100644
--- a/make/devkit/createAutoconfBundle.sh
+++ b/make/devkit/createAutoconfBundle.sh
@@ -93,7 +93,7 @@ elif test "x$TARGET_PLATFORM" = xlinux_x64; then
rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.x86_64.rpm | cpio -d -i
elif test "x$TARGET_PLATFORM" = xlinux_x86; then
M4_VERSION=1.4.13-5
- wget http://yum.oracle.com/repo/OracleLinux/OL6/latest/i386/getPackage/m4-$M4_VERSION.el6.i686.rpm
+ wget https://yum.oracle.com/repo/OracleLinux/OL6/latest/i386/getPackage/m4-$M4_VERSION.el6.i686.rpm
cd $IMAGE_DIR
rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.i686.rpm | cpio -d -i
else
diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk
index 30d3e3b524c..d615e254f5a 100644
--- a/make/hotspot/lib/CompileGtest.gmk
+++ b/make/hotspot/lib/CompileGtest.gmk
@@ -152,7 +152,7 @@ $(eval $(call SetupJdkExecutable, BUILD_GTEST_LAUNCHER, \
-I$(GTEST_FRAMEWORK_SRC)/googlemock \
-I$(GTEST_FRAMEWORK_SRC)/googlemock/include, \
LD_SET_ORIGIN := false, \
- LDFLAGS_unix := $(call SET_SHARED_LIBRARY_ORIGIN), \
+ LDFLAGS_unix := $(call SetSharedLibraryOrigin), \
JDK_LIBS := gtest:libjvm, \
COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \
ZIP_EXTERNAL_DEBUG_SYMBOLS := false, \
diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk
index bf92c50576a..fd574b9e42d 100644
--- a/make/hotspot/lib/CompileJvm.gmk
+++ b/make/hotspot/lib/CompileJvm.gmk
@@ -158,6 +158,10 @@ ifeq ($(call isTargetOs, windows), true)
WIN_EXPORT_FILE := $(JVM_OUTPUTDIR)/win-exports.def
endif
+ ifeq ($(SHIP_DEBUG_SYMBOLS), public)
+ CFLAGS_STRIPPED_DEBUGINFO := -DHAS_STRIPPED_DEBUGINFO
+ endif
+
JVM_LDFLAGS += -def:$(WIN_EXPORT_FILE)
endif
@@ -183,13 +187,13 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \
CFLAGS := $(JVM_CFLAGS), \
abstract_vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
+ whitebox.cpp_CXXFLAGS := $(CFLAGS_STRIPPED_DEBUGINFO), \
DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc), \
DISABLED_WARNINGS_gcc_ad_$(HOTSPOT_TARGET_CPU_ARCH).cpp := nonnull, \
DISABLED_WARNINGS_gcc_bytecodeInterpreter.cpp := unused-label, \
DISABLED_WARNINGS_gcc_c1_Runtime1_aarch64.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_cgroupV1Subsystem_linux.cpp := address, \
DISABLED_WARNINGS_gcc_cgroupV2Subsystem_linux.cpp := address, \
- DISABLED_WARNINGS_gcc_g1FreeIdSet.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_handshake.cpp := stringop-overflow, \
DISABLED_WARNINGS_gcc_interp_masm_x86.cpp := uninitialized, \
DISABLED_WARNINGS_gcc_javaClasses.cpp := unused-const-variable, \
diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk
index 0fd1c752174..79bbd6a4106 100644
--- a/make/hotspot/lib/JvmFeatures.gmk
+++ b/make/hotspot/lib/JvmFeatures.gmk
@@ -57,7 +57,7 @@ ifeq ($(call check-jvm-feature, zero), true)
-DZERO_LIBARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' $(LIBFFI_CFLAGS)
JVM_LIBS_FEATURES += $(LIBFFI_LIBS)
ifeq ($(ENABLE_LIBFFI_BUNDLING), true)
- JVM_LDFLAGS_FEATURES += $(call SET_EXECUTABLE_ORIGIN,/..)
+ JVM_LDFLAGS_FEATURES += $(call SetExecutableOrigin,/..)
endif
else
JVM_EXCLUDE_PATTERNS += /zero/
diff --git a/make/ide/vscode/hotspot/template-workspace.jsonc b/make/ide/vscode/hotspot/template-workspace.jsonc
index c582c48047d..8a349b232ce 100644
--- a/make/ide/vscode/hotspot/template-workspace.jsonc
+++ b/make/ide/vscode/hotspot/template-workspace.jsonc
@@ -22,6 +22,7 @@
// Java extension
"jdk.project.jdkhome": "{{OUTPUTDIR}}/jdk",
"jdk.java.onSave.organizeImports": false, // prevents unnecessary changes
+ "jdk.serverVmOptions": ["-Xmx2G"], // prevent out of memory
// Additional conventions
"files.associations": {
diff --git a/make/langtools/tools/javacserver/server/CompilerThreadPool.java b/make/langtools/tools/javacserver/server/CompilerThreadPool.java
index 1f9e3a195b6..460adcfba28 100644
--- a/make/langtools/tools/javacserver/server/CompilerThreadPool.java
+++ b/make/langtools/tools/javacserver/server/CompilerThreadPool.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2025, 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
@@ -61,7 +61,7 @@ public class CompilerThreadPool {
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
- // Preserve interrupt status
+ // Preserve interrupted status
Thread.currentThread().interrupt();
}
}
diff --git a/make/modules/java.base/Gensrc.gmk b/make/modules/java.base/Gensrc.gmk
index 2750a6c8791..79db438934e 100644
--- a/make/modules/java.base/Gensrc.gmk
+++ b/make/modules/java.base/Gensrc.gmk
@@ -33,7 +33,6 @@ include gensrc/GensrcBuffer.gmk
include gensrc/GensrcCharacterData.gmk
include gensrc/GensrcCharsetCoder.gmk
include gensrc/GensrcCharsetMapping.gmk
-include gensrc/GensrcExceptions.gmk
include gensrc/GensrcMisc.gmk
include gensrc/GensrcModuleLoaderMap.gmk
include gensrc/GensrcRegex.gmk
diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk
index 51d323a0344..41da22f8cb2 100644
--- a/make/modules/java.base/Lib.gmk
+++ b/make/modules/java.base/Lib.gmk
@@ -154,6 +154,8 @@ endif
################################################################################
## Build libsyslookup
+## The LIBDL dependency on Linux is needed to dynamically access libdl symbols,
+## which may be needed as part of resolving some standard symbols
################################################################################
$(eval $(call SetupJdkLibrary, BUILD_LIBSYSLOOKUP, \
@@ -196,7 +198,7 @@ ifeq ($(call isTargetOs, linux)+$(call isTargetCpu, x86_64)+$(INCLUDE_COMPILER2)
OPTIMIZATION := HIGH, \
CXXFLAGS := -std=c++17, \
DISABLED_WARNINGS_gcc := unused-variable, \
- LIBS_linux := $(LIBDL) $(LIBM), \
+ LIBS_linux := $(LIBM), \
))
TARGETS += $(BUILD_LIBSIMD_SORT)
diff --git a/make/modules/java.base/gensrc/GensrcExceptions.gmk b/make/modules/java.base/gensrc/GensrcExceptions.gmk
deleted file mode 100644
index baa61596d6b..00000000000
--- a/make/modules/java.base/gensrc/GensrcExceptions.gmk
+++ /dev/null
@@ -1,57 +0,0 @@
-#
-# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include MakeIncludeStart.gmk
-ifeq ($(INCLUDE), true)
-
-################################################################################
-
-GENSRC_EXCEPTIONS :=
-
-GENSRC_EXCEPTIONS_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio
-
-GENSRC_EXCEPTIONS_SRC := $(MODULE_SRC)/share/classes/java/nio
-GENSRC_EXCEPTIONS_CMD := $(TOPDIR)/make/scripts/genExceptions.sh
-
-GENSRC_EXCEPTIONS_SRC_DIRS := . charset channels
-
-$(GENSRC_EXCEPTIONS_DST)/_the.%.marker: $(GENSRC_EXCEPTIONS_SRC)/%/exceptions \
- $(GENSRC_EXCEPTIONS_CMD)
- $(call LogInfo, Generating exceptions java.nio $*)
- $(call MakeDir, $(@D)/$*)
- SCRIPTS="$(TOPDIR)/make/scripts" AWK="$(AWK)" SH="$(SH)" $(SH) \
- $(GENSRC_EXCEPTIONS_CMD) $< $(@D)/$* $(LOG_DEBUG)
- $(TOUCH) $@
-
-GENSRC_EXCEPTIONS += $(foreach D, $(GENSRC_EXCEPTIONS_SRC_DIRS), $(GENSRC_EXCEPTIONS_DST)/_the.$(D).marker)
-
-$(GENSRC_EXCEPTIONS): $(BUILD_TOOLS_JDK)
-
-TARGETS += $(GENSRC_EXCEPTIONS)
-
-################################################################################
-
-endif # include guard
-include MakeIncludeEnd.gmk
diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk
index a69b65180d7..2c29092cdd6 100644
--- a/make/modules/java.desktop/lib/ClientLibraries.gmk
+++ b/make/modules/java.desktop/lib/ClientLibraries.gmk
@@ -51,7 +51,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBMLIB_IMAGE, \
$(LIBMLIB_IMAGE_CFLAGS), \
DISABLED_WARNINGS_gcc := unused-function, \
DISABLED_WARNINGS_clang_mlib_ImageCreate.c := unused-function, \
- LIBS_unix := $(LIBDL) $(LIBM), \
+ LIBS_unix := $(LIBM), \
))
TARGETS += $(BUILD_LIBMLIB_IMAGE)
@@ -264,7 +264,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
JDK_LIBS_macosx := libosxapp, \
LIBS := $(GIFLIB_LIBS) $(LIBJPEG_LIBS) $(LIBZ_LIBS) $(PNG_LIBS) $(ICONV_LIBS), \
LIBS_unix := $(LIBM) $(LIBPTHREAD), \
- LIBS_linux := $(LIBDL) $(X_LIBS) -lX11 -lXext, \
+ LIBS_linux := $(X_LIBS) -lX11 -lXext, \
LIBS_macosx := \
-framework ApplicationServices \
-framework Cocoa \
diff --git a/make/modules/java.instrument/Lib.gmk b/make/modules/java.instrument/Lib.gmk
index 609814c86ed..4181cdf81c9 100644
--- a/make/modules/java.instrument/Lib.gmk
+++ b/make/modules/java.instrument/Lib.gmk
@@ -43,8 +43,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBINSTRUMENT, \
JDK_LIBS := java.base:libjava java.base:libjli java.base:libjvm, \
LIBS := $(ICONV_LIBS), \
LIBS_unix := $(LIBZ_LIBS), \
- LIBS_linux := $(LIBDL), \
- LIBS_aix := $(LIBDL), \
LIBS_macosx := \
-framework ApplicationServices \
-framework Cocoa \
diff --git a/make/modules/java.scripting/Java.gmk b/make/modules/java.scripting/Java.gmk
index 1909ec1a2df..6e5ea0e2c73 100644
--- a/make/modules/java.scripting/Java.gmk
+++ b/make/modules/java.scripting/Java.gmk
@@ -27,7 +27,5 @@
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'
-COPY += .js
-CLEAN += .properties
################################################################################
diff --git a/make/modules/java.scripting/Launcher.gmk b/make/modules/java.scripting/Launcher.gmk
deleted file mode 100644
index ee6b93fbf2c..00000000000
--- a/make/modules/java.scripting/Launcher.gmk
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-################################################################################
-
-include LauncherCommon.gmk
-
-################################################################################
-## Build jrunscript
-################################################################################
-
-$(eval $(call SetupBuildLauncher, jrunscript, \
- MAIN_CLASS := com.sun.tools.script.shell.Main, \
- JAVA_ARGS := --add-modules ALL-DEFAULT, \
-))
-
-################################################################################
diff --git a/make/modules/jdk.sctp/Lib.gmk b/make/modules/jdk.sctp/Lib.gmk
index 327f4fa6104..9a70996d9cb 100644
--- a/make/modules/jdk.sctp/Lib.gmk
+++ b/make/modules/jdk.sctp/Lib.gmk
@@ -41,7 +41,7 @@ ifeq ($(call isTargetOs, linux), true)
java.base:libnio \
java.base:libnio/ch, \
JDK_LIBS := java.base:libjava java.base:libnet, \
- LIBS_linux := $(LIBDL) $(LIBPTHREAD), \
+ LIBS_linux := $(LIBDL), \
))
TARGETS += $(BUILD_LIBSCTP)
diff --git a/make/scripts/addNotices.sh b/make/scripts/addNotices.sh
deleted file mode 100644
index d9864818a14..00000000000
--- a/make/scripts/addNotices.sh
+++ /dev/null
@@ -1,45 +0,0 @@
-#! /bin/sh
-#
-# Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# Parse the first contiguous comment block in this script and generate
-# a java comment block. If this script is invoked with a copyright
-# year/year range, the java comment block will contain a Sun copyright.
-
-COPYRIGHT_YEARS="$1"
-
-cat <<__END__
-/*
-__END__
-
-if [ "x$COPYRIGHT_YEARS" != x ]; then
- cat <<__END__
- * Copyright (c) $COPYRIGHT_YEARS Oracle and/or its affiliates. All rights reserved.
-__END__
-fi
-
-$AWK ' /^#.*Copyright.*Oracle/ { next }
- /^#([^!]|$)/ { sub(/^#/, " *"); print }
- /^$/ { print " */"; exit } ' $0
diff --git a/make/scripts/genExceptions.sh b/make/scripts/genExceptions.sh
deleted file mode 100644
index 7c191189827..00000000000
--- a/make/scripts/genExceptions.sh
+++ /dev/null
@@ -1,116 +0,0 @@
-#! /bin/sh
-#
-# Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# Generate exception classes
-
-SPEC=$1
-DST=$2
-
-gen() {
- ID=$1
- WHAT=$2
- SVUID=$3
- ARG_TYPE=$4
- ARG_ID=$5
- ARG_PROP=$6
- ARG_PHRASE=$7
- ARG_PARAM="$ARG_TYPE$ $ARG_ID"
- echo '-->' $DST/$ID.java
- out=$DST/${ID}.java
-
- $SH ${SCRIPTS}/addNotices.sh "$COPYRIGHT_YEARS" > $out
-
- cat >>$out <<__END__
-
-// -- This file was mechanically generated: Do not edit! -- //
-
-package $PACKAGE;
-
-
-/**$WHAT
- *
- * @since $SINCE
- */
-
-public `if [ ${ABSTRACT:-0} = 1 ];
- then echo 'abstract '; fi`class $ID
- extends ${SUPER}
-{
-
- @java.io.Serial
- private static final long serialVersionUID = $SVUID;
-__END__
-
- if [ $ARG_ID ]; then
-
- cat >>$out <<__END__
-
- /**
- * The $ARG_PHRASE.
- *
- * @serial
- */
- private $ARG_TYPE $ARG_ID;
-
- /**
- * Constructs an instance of this class.
- *
- * @param $ARG_ID
- * The $ARG_PHRASE
- */
- public $ID($ARG_TYPE $ARG_ID) {
- super(String.valueOf($ARG_ID));
- this.$ARG_ID = $ARG_ID;
- }
-
- /**
- * Retrieves the $ARG_PHRASE.
- *
- * @return The $ARG_PHRASE
- */
- public $ARG_TYPE get$ARG_PROP() {
- return $ARG_ID;
- }
-
-}
-__END__
-
- else
-
- cat >>$out <<__END__
-
- /**
- * Constructs an instance of this class.
- */
- public $ID() { }
-
-}
-__END__
-
- fi
-}
-
-. $SPEC
diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
index 393de3f0f0d..a01f83fc658 100644
--- a/src/hotspot/cpu/aarch64/aarch64.ad
+++ b/src/hotspot/cpu/aarch64/aarch64.ad
@@ -1266,39 +1266,39 @@ source %{
// adlc register classes to make AArch64 rheapbase (r27) and rfp (r29)
// registers conditionally reserved.
- _ANY_REG32_mask = _ALL_REG32_mask;
- _ANY_REG32_mask.Remove(OptoReg::as_OptoReg(r31_sp->as_VMReg()));
+ _ANY_REG32_mask.assignFrom(_ALL_REG32_mask);
+ _ANY_REG32_mask.remove(OptoReg::as_OptoReg(r31_sp->as_VMReg()));
- _ANY_REG_mask = _ALL_REG_mask;
+ _ANY_REG_mask.assignFrom(_ALL_REG_mask);
- _PTR_REG_mask = _ALL_REG_mask;
+ _PTR_REG_mask.assignFrom(_ALL_REG_mask);
- _NO_SPECIAL_REG32_mask = _ALL_REG32_mask;
- _NO_SPECIAL_REG32_mask.SUBTRACT(_NON_ALLOCATABLE_REG32_mask);
+ _NO_SPECIAL_REG32_mask.assignFrom(_ALL_REG32_mask);
+ _NO_SPECIAL_REG32_mask.subtract(_NON_ALLOCATABLE_REG32_mask);
- _NO_SPECIAL_REG_mask = _ALL_REG_mask;
- _NO_SPECIAL_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask);
+ _NO_SPECIAL_REG_mask.assignFrom(_ALL_REG_mask);
+ _NO_SPECIAL_REG_mask.subtract(_NON_ALLOCATABLE_REG_mask);
- _NO_SPECIAL_PTR_REG_mask = _ALL_REG_mask;
- _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask);
+ _NO_SPECIAL_PTR_REG_mask.assignFrom(_ALL_REG_mask);
+ _NO_SPECIAL_PTR_REG_mask.subtract(_NON_ALLOCATABLE_REG_mask);
// r27 is not allocatable when compressed oops is on and heapbase is not
// zero, compressed klass pointers doesn't use r27 after JDK-8234794
if (UseCompressedOops && (CompressedOops::base() != nullptr)) {
- _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg()));
- _NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg()));
- _NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg()));
+ _NO_SPECIAL_REG32_mask.remove(OptoReg::as_OptoReg(r27->as_VMReg()));
+ _NO_SPECIAL_REG_mask.remove(OptoReg::as_OptoReg(r27->as_VMReg()));
+ _NO_SPECIAL_PTR_REG_mask.remove(OptoReg::as_OptoReg(r27->as_VMReg()));
}
// r29 is not allocatable when PreserveFramePointer is on
if (PreserveFramePointer) {
- _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg()));
- _NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg()));
- _NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg()));
+ _NO_SPECIAL_REG32_mask.remove(OptoReg::as_OptoReg(r29->as_VMReg()));
+ _NO_SPECIAL_REG_mask.remove(OptoReg::as_OptoReg(r29->as_VMReg()));
+ _NO_SPECIAL_PTR_REG_mask.remove(OptoReg::as_OptoReg(r29->as_VMReg()));
}
- _NO_SPECIAL_NO_RFP_PTR_REG_mask = _NO_SPECIAL_PTR_REG_mask;
- _NO_SPECIAL_NO_RFP_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg()));
+ _NO_SPECIAL_NO_RFP_PTR_REG_mask.assignFrom(_NO_SPECIAL_PTR_REG_mask);
+ _NO_SPECIAL_NO_RFP_PTR_REG_mask.remove(OptoReg::as_OptoReg(r29->as_VMReg()));
}
// Optimizaton of volatile gets and puts
@@ -1734,7 +1734,7 @@ uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
}
//=============================================================================
-const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
+const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::EMPTY;
int ConstantTable::calculate_table_base_offset() const {
return 0; // absolute addressing, no offset
@@ -2520,10 +2520,10 @@ uint Matcher::int_pressure_limit()
// as a spilled LRG. Spilling heuristics(Spill-USE) explicitly skip
// derived pointers and lastly fail to spill after reaching maximum
// number of iterations. Lowering the default pressure threshold to
- // (_NO_SPECIAL_REG32_mask.Size() minus 1) forces CallNode to become
+ // (_NO_SPECIAL_REG32_mask.size() minus 1) forces CallNode to become
// a high register pressure area of the code so that split_DEF can
// generate DefinitionSpillCopy for the derived pointer.
- uint default_int_pressure_threshold = _NO_SPECIAL_REG32_mask.Size() - 1;
+ uint default_int_pressure_threshold = _NO_SPECIAL_REG32_mask.size() - 1;
if (!PreserveFramePointer) {
// When PreserveFramePointer is off, frame pointer is allocatable,
// but different from other SOC registers, it is excluded from
@@ -2538,38 +2538,34 @@ uint Matcher::int_pressure_limit()
uint Matcher::float_pressure_limit()
{
// _FLOAT_REG_mask is generated by adlc from the float_reg register class.
- return (FLOATPRESSURE == -1) ? _FLOAT_REG_mask.Size() : FLOATPRESSURE;
+ return (FLOATPRESSURE == -1) ? _FLOAT_REG_mask.size() : FLOATPRESSURE;
}
bool Matcher::use_asm_for_ldiv_by_con(jlong divisor) {
return false;
}
-RegMask Matcher::divI_proj_mask() {
+const RegMask& Matcher::divI_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for MODI projection of divmodI.
-RegMask Matcher::modI_proj_mask() {
+const RegMask& Matcher::modI_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for DIVL projection of divmodL.
-RegMask Matcher::divL_proj_mask() {
+const RegMask& Matcher::divL_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for MODL projection of divmodL.
-RegMask Matcher::modL_proj_mask() {
+const RegMask& Matcher::modL_proj_mask() {
ShouldNotReachHere();
- return RegMask();
-}
-
-const RegMask Matcher::method_handle_invoke_SP_save_mask() {
- return FP_REG_mask();
+ return RegMask::EMPTY;
}
bool size_fits_all_mem_uses(AddPNode* addp, int shift) {
diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad
index a7f879613fc..54c2441587e 100644
--- a/src/hotspot/cpu/aarch64/aarch64_vector.ad
+++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad
@@ -215,11 +215,6 @@ source %{
return false;
}
break;
- case Op_ExpandV:
- if (UseSVE < 2 || is_subword_type(bt)) {
- return false;
- }
- break;
case Op_VectorMaskToLong:
if (UseSVE > 0 && vlen > 64) {
return false;
@@ -7183,37 +7178,68 @@ instruct vcompress(vReg dst, vReg src, pRegGov pg) %{
%}
instruct vcompressB(vReg dst, vReg src, pReg pg, vReg tmp1, vReg tmp2,
- vReg tmp3, vReg tmp4, pReg ptmp, pRegGov pgtmp) %{
+ vReg tmp3, pReg ptmp, pRegGov pgtmp) %{
predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_BYTE);
- effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP ptmp, TEMP pgtmp);
+ effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP ptmp, TEMP pgtmp);
match(Set dst (CompressV src pg));
- format %{ "vcompressB $dst, $src, $pg\t# KILL $tmp1, $tmp2, $tmp3, tmp4, $ptmp, $pgtmp" %}
+ format %{ "vcompressB $dst, $src, $pg\t# KILL $tmp1, $tmp2, $tmp3, $ptmp, $pgtmp" %}
ins_encode %{
+ uint length_in_bytes = Matcher::vector_length_in_bytes(this);
__ sve_compress_byte($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
- $tmp1$$FloatRegister,$tmp2$$FloatRegister,
- $tmp3$$FloatRegister,$tmp4$$FloatRegister,
- $ptmp$$PRegister, $pgtmp$$PRegister);
+ $tmp1$$FloatRegister, $tmp2$$FloatRegister, $tmp3$$FloatRegister,
+ $ptmp$$PRegister, $pgtmp$$PRegister, length_in_bytes);
%}
ins_pipe(pipe_slow);
%}
-instruct vcompressS(vReg dst, vReg src, pReg pg,
- vReg tmp1, vReg tmp2, pRegGov pgtmp) %{
+instruct vcompressS(vReg dst, vReg src, pReg pg, vReg tmp1, vReg tmp2, pRegGov pgtmp) %{
predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_SHORT);
effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP pgtmp);
match(Set dst (CompressV src pg));
format %{ "vcompressS $dst, $src, $pg\t# KILL $tmp1, $tmp2, $pgtmp" %}
ins_encode %{
+ uint length_in_bytes = Matcher::vector_length_in_bytes(this);
+ __ sve_dup($tmp1$$FloatRegister, __ H, 0);
__ sve_compress_short($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
- $tmp1$$FloatRegister,$tmp2$$FloatRegister, $pgtmp$$PRegister);
+ $tmp1$$FloatRegister, $tmp2$$FloatRegister, $pgtmp$$PRegister,
+ length_in_bytes);
%}
ins_pipe(pipe_slow);
%}
-instruct vexpand(vReg dst, vReg src, pRegGov pg) %{
+instruct vexpand_neon(vReg dst, vReg src, vReg mask, vReg tmp1, vReg tmp2) %{
+ predicate(UseSVE == 0);
+ match(Set dst (ExpandV src mask));
+ effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
+ format %{ "vexpand_neon $dst, $src, $mask\t# KILL $tmp1, $tmp2" %}
+ ins_encode %{
+ BasicType bt = Matcher::vector_element_basic_type(this);
+ int length_in_bytes = (int) Matcher::vector_length_in_bytes(this);
+ __ vector_expand_neon($dst$$FloatRegister, $src$$FloatRegister, $mask$$FloatRegister,
+ $tmp1$$FloatRegister, $tmp2$$FloatRegister, bt, length_in_bytes);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct vexpand_sve(vReg dst, vReg src, pRegGov pg, vReg tmp1, vReg tmp2) %{
+ predicate(UseSVE == 1 || (UseSVE == 2 && type2aelembytes(Matcher::vector_element_basic_type(n)) < 4));
+ match(Set dst (ExpandV src pg));
+ effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
+ format %{ "vexpand_sve $dst, $src, $pg\t# KILL $tmp1, $tmp2" %}
+ ins_encode %{
+ BasicType bt = Matcher::vector_element_basic_type(this);
+ int length_in_bytes = (int) Matcher::vector_length_in_bytes(this);
+ __ vector_expand_sve($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
+ $tmp1$$FloatRegister, $tmp2$$FloatRegister, bt, length_in_bytes);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct vexpand_sve2_SD(vReg dst, vReg src, pRegGov pg) %{
+ predicate(UseSVE == 2 && type2aelembytes(Matcher::vector_element_basic_type(n)) >= 4);
match(Set dst (ExpandV src pg));
effect(TEMP_DEF dst);
- format %{ "vexpand $dst, $pg, $src" %}
+ format %{ "vexpand_sve2_SD $dst, $src, $pg" %}
ins_encode %{
// Example input: src = 1 2 3 4 5 6 7 8
// pg = 1 0 0 1 1 0 1 1
@@ -7224,7 +7250,6 @@ instruct vexpand(vReg dst, vReg src, pRegGov pg) %{
// for TBL whose value is used to select the indexed element from src vector.
BasicType bt = Matcher::vector_element_basic_type(this);
- assert(UseSVE == 2 && !is_subword_type(bt), "unsupported");
Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
// dst = 0 0 0 0 0 0 0 0
__ sve_dup($dst$$FloatRegister, size, 0);
diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4
index 7719ff7765b..6be660b571a 100644
--- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4
+++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4
@@ -205,11 +205,6 @@ source %{
return false;
}
break;
- case Op_ExpandV:
- if (UseSVE < 2 || is_subword_type(bt)) {
- return false;
- }
- break;
case Op_VectorMaskToLong:
if (UseSVE > 0 && vlen > 64) {
return false;
@@ -5129,37 +5124,68 @@ instruct vcompress(vReg dst, vReg src, pRegGov pg) %{
%}
instruct vcompressB(vReg dst, vReg src, pReg pg, vReg tmp1, vReg tmp2,
- vReg tmp3, vReg tmp4, pReg ptmp, pRegGov pgtmp) %{
+ vReg tmp3, pReg ptmp, pRegGov pgtmp) %{
predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_BYTE);
- effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP ptmp, TEMP pgtmp);
+ effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP ptmp, TEMP pgtmp);
match(Set dst (CompressV src pg));
- format %{ "vcompressB $dst, $src, $pg\t# KILL $tmp1, $tmp2, $tmp3, tmp4, $ptmp, $pgtmp" %}
+ format %{ "vcompressB $dst, $src, $pg\t# KILL $tmp1, $tmp2, $tmp3, $ptmp, $pgtmp" %}
ins_encode %{
+ uint length_in_bytes = Matcher::vector_length_in_bytes(this);
__ sve_compress_byte($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
- $tmp1$$FloatRegister,$tmp2$$FloatRegister,
- $tmp3$$FloatRegister,$tmp4$$FloatRegister,
- $ptmp$$PRegister, $pgtmp$$PRegister);
+ $tmp1$$FloatRegister, $tmp2$$FloatRegister, $tmp3$$FloatRegister,
+ $ptmp$$PRegister, $pgtmp$$PRegister, length_in_bytes);
%}
ins_pipe(pipe_slow);
%}
-instruct vcompressS(vReg dst, vReg src, pReg pg,
- vReg tmp1, vReg tmp2, pRegGov pgtmp) %{
+instruct vcompressS(vReg dst, vReg src, pReg pg, vReg tmp1, vReg tmp2, pRegGov pgtmp) %{
predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_SHORT);
effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP pgtmp);
match(Set dst (CompressV src pg));
format %{ "vcompressS $dst, $src, $pg\t# KILL $tmp1, $tmp2, $pgtmp" %}
ins_encode %{
+ uint length_in_bytes = Matcher::vector_length_in_bytes(this);
+ __ sve_dup($tmp1$$FloatRegister, __ H, 0);
__ sve_compress_short($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
- $tmp1$$FloatRegister,$tmp2$$FloatRegister, $pgtmp$$PRegister);
+ $tmp1$$FloatRegister, $tmp2$$FloatRegister, $pgtmp$$PRegister,
+ length_in_bytes);
%}
ins_pipe(pipe_slow);
%}
-instruct vexpand(vReg dst, vReg src, pRegGov pg) %{
+instruct vexpand_neon(vReg dst, vReg src, vReg mask, vReg tmp1, vReg tmp2) %{
+ predicate(UseSVE == 0);
+ match(Set dst (ExpandV src mask));
+ effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
+ format %{ "vexpand_neon $dst, $src, $mask\t# KILL $tmp1, $tmp2" %}
+ ins_encode %{
+ BasicType bt = Matcher::vector_element_basic_type(this);
+ int length_in_bytes = (int) Matcher::vector_length_in_bytes(this);
+ __ vector_expand_neon($dst$$FloatRegister, $src$$FloatRegister, $mask$$FloatRegister,
+ $tmp1$$FloatRegister, $tmp2$$FloatRegister, bt, length_in_bytes);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct vexpand_sve(vReg dst, vReg src, pRegGov pg, vReg tmp1, vReg tmp2) %{
+ predicate(UseSVE == 1 || (UseSVE == 2 && type2aelembytes(Matcher::vector_element_basic_type(n)) < 4));
+ match(Set dst (ExpandV src pg));
+ effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
+ format %{ "vexpand_sve $dst, $src, $pg\t# KILL $tmp1, $tmp2" %}
+ ins_encode %{
+ BasicType bt = Matcher::vector_element_basic_type(this);
+ int length_in_bytes = (int) Matcher::vector_length_in_bytes(this);
+ __ vector_expand_sve($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
+ $tmp1$$FloatRegister, $tmp2$$FloatRegister, bt, length_in_bytes);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct vexpand_sve2_SD(vReg dst, vReg src, pRegGov pg) %{
+ predicate(UseSVE == 2 && type2aelembytes(Matcher::vector_element_basic_type(n)) >= 4);
match(Set dst (ExpandV src pg));
effect(TEMP_DEF dst);
- format %{ "vexpand $dst, $pg, $src" %}
+ format %{ "vexpand_sve2_SD $dst, $src, $pg" %}
ins_encode %{
// Example input: src = 1 2 3 4 5 6 7 8
// pg = 1 0 0 1 1 0 1 1
@@ -5170,7 +5196,6 @@ instruct vexpand(vReg dst, vReg src, pRegGov pg) %{
// for TBL whose value is used to select the indexed element from src vector.
BasicType bt = Matcher::vector_element_basic_type(this);
- assert(UseSVE == 2 && !is_subword_type(bt), "unsupported");
Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
// dst = 0 0 0 0 0 0 0 0
__ sve_dup($dst$$FloatRegister, size, 0);
diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp
index 1e35af1ed73..6444fa21215 100644
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp
@@ -3486,6 +3486,7 @@ public:
INSN(sve_smaxv, 0b00000100, 0b001000001); // signed maximum reduction to scalar
INSN(sve_smin, 0b00000100, 0b001010000); // signed minimum vectors
INSN(sve_sminv, 0b00000100, 0b001010001); // signed minimum reduction to scalar
+ INSN(sve_splice,0b00000101, 0b101100100); // splice two vectors under predicate control, destructive
INSN(sve_sub, 0b00000100, 0b000001000); // vector sub
INSN(sve_uaddv, 0b00000100, 0b000001001); // unsigned add reduction to scalar
INSN(sve_umax, 0b00000100, 0b001001000); // unsigned maximum vectors
@@ -4072,6 +4073,13 @@ public:
INSN(sve_brkb, 0b10); // Break before first true condition
#undef INSN
+ // SVE move prefix (unpredicated)
+ void sve_movprfx(FloatRegister Zd, FloatRegister Zn) {
+ starti;
+ f(0b00000100, 31, 24), f(0b00, 23, 22), f(0b1, 21), f(0b00000, 20, 16);
+ f(0b101111, 15, 10), rf(Zn, 5), rf(Zd, 0);
+ }
+
// Element count and increment scalar (SVE)
#define INSN(NAME, TYPE) \
void NAME(Register Xdn, unsigned imm4 = 1, int pattern = 0b11111) { \
diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.inline.hpp
index e7efe472b82..fb14d588f04 100644
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.inline.hpp
+++ b/src/hotspot/cpu/aarch64/assembler_aarch64.inline.hpp
@@ -26,7 +26,7 @@
#ifndef CPU_AARCH64_ASSEMBLER_AARCH64_INLINE_HPP
#define CPU_AARCH64_ASSEMBLER_AARCH64_INLINE_HPP
-#include "asm/assembler.inline.hpp"
+#include "asm/assembler.hpp"
#include "asm/codeBuffer.hpp"
#include "code/codeCache.hpp"
diff --git a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
index 954e4abee14..9bf46678535 100644
--- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
@@ -216,10 +216,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- if (_compute_lock) {
- // lock_reg was destroyed by fast unlocking attempt => recompute it
- ce->monitor_address(_monitor_ix, _lock_reg);
- }
+
+ // lock_reg was destroyed by fast unlocking attempt => recompute it
+ ce->monitor_address(_monitor_ix, _lock_reg);
+
ce->store_parameter(_lock_reg->as_register(), 0);
// note: non-blocking leaf routine => no call info needed
StubId exit_id;
diff --git a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp
index 9d30092b45a..83d0952dcb4 100644
--- a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp
@@ -383,13 +383,6 @@ LIR_Opr FrameMap::stack_pointer() {
return FrameMap::sp_opr;
}
-
-// JSR 292
-LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
- return LIR_OprFact::illegalOpr; // Not needed on aarch64
-}
-
-
bool FrameMap::validate_frame() {
return true;
}
diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
index d788c0c201a..9ab463125fe 100644
--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
@@ -409,7 +409,7 @@ int LIR_Assembler::emit_unwind_handler() {
MonitorExitStub* stub = nullptr;
if (method()->is_synchronized()) {
monitor_address(0, FrameMap::r0_opr);
- stub = new MonitorExitStub(FrameMap::r0_opr, true, 0);
+ stub = new MonitorExitStub(FrameMap::r0_opr, 0);
__ unlock_object(r5, r4, r0, r6, *stub->entry());
__ bind(*stub->continuation());
}
@@ -2481,7 +2481,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
Register lock = op->lock_opr()->as_register();
Register temp = op->scratch_opr()->as_register();
if (op->code() == lir_lock) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
// add debug info for NullPointerException only if one is possible
int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry());
if (op->info() != nullptr) {
@@ -2489,7 +2488,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
}
// done
} else if (op->code() == lir_unlock) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
__ unlock_object(hdr, obj, lock, temp, *op->stub()->entry());
} else {
Unimplemented();
diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
index 8a79274b2ff..31c36e749c5 100644
--- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
@@ -59,28 +59,28 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result,
}
}
-int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) {
- assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2);
+int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) {
+ assert_different_registers(hdr, obj, basic_lock, temp, rscratch2);
int null_check_offset = -1;
verify_oop(obj);
// save object being locked into the BasicObjectLock
- str(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
+ str(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
null_check_offset = offset();
- lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case);
+ lightweight_lock(basic_lock, obj, hdr, temp, rscratch2, slow_case);
return null_check_offset;
}
-void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) {
- assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2);
+void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) {
+ assert_different_registers(hdr, obj, basic_lock, temp, rscratch2);
// load object
- ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
+ ldr(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
verify_oop(obj);
lightweight_unlock(obj, hdr, temp, rscratch2, slow_case);
diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp
index fc8e83d706b..7b181b104c1 100644
--- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -55,19 +55,19 @@ using MacroAssembler::null_check;
Register result);
// locking
- // hdr : must be r0, contents destroyed
- // obj : must point to the object to lock, contents preserved
- // disp_hdr: must point to the displaced header location, contents preserved
- // temp : temporary register, must not be rscratch1 or rscratch2
+ // hdr : must be r0, contents destroyed
+ // obj : must point to the object to lock, contents preserved
+ // basic_lock: must point to the basic lock, contents preserved
+ // temp : temporary register, must not be rscratch1 or rscratch2
// returns code offset at which to add null check debug information
- int lock_object (Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case);
+ int lock_object (Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case);
// unlocking
- // hdr : contents destroyed
- // obj : must point to the object to lock, contents preserved
- // disp_hdr: must be r0 & must point to the displaced header location, contents destroyed
- // temp : temporary register, must not be rscratch1 or rscratch2
- void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case);
+ // hdr : contents destroyed
+ // obj : must point to the object to lock, contents preserved
+ // basic_lock: must be r0 & must point to the basic lock, contents destroyed
+ // temp : temporary register, must not be rscratch1 or rscratch2
+ void unlock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case);
void initialize_object(
Register obj, // result: pointer to object after successful allocation
diff --git a/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp
index a8a2fa8b2ee..938a64dd399 100644
--- a/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp
@@ -53,7 +53,6 @@ define_pd_global(size_t, CodeCacheExpansionSize, 32*K );
define_pd_global(size_t, CodeCacheMinBlockLength, 1);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, NeverActAsServerClassMachine, true );
-define_pd_global(uint64_t,MaxRAM, 1ULL*G);
define_pd_global(bool, CICompileOSR, true );
#endif // !COMPILER2
define_pd_global(bool, UseTypeProfile, false);
diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
index b1562c54f4e..328ef0c53e6 100644
--- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
@@ -2203,114 +2203,117 @@ void C2_MacroAssembler::sve_gen_mask_imm(PRegister dst, BasicType bt, uint32_t l
// Pack active elements of src, under the control of mask, into the lowest-numbered elements of dst.
// Any remaining elements of dst will be filled with zero.
// Clobbers: rscratch1
-// Preserves: src, mask
+// Preserves: mask, vzr
void C2_MacroAssembler::sve_compress_short(FloatRegister dst, FloatRegister src, PRegister mask,
- FloatRegister vtmp1, FloatRegister vtmp2,
- PRegister pgtmp) {
+ FloatRegister vzr, FloatRegister vtmp,
+ PRegister pgtmp, unsigned vector_length_in_bytes) {
assert(pgtmp->is_governing(), "This register has to be a governing predicate register");
- assert_different_registers(dst, src, vtmp1, vtmp2);
+ // When called by sve_compress_byte, src and vtmp may be the same register.
+ assert_different_registers(dst, src, vzr);
+ assert_different_registers(dst, vtmp, vzr);
assert_different_registers(mask, pgtmp);
-
- // Example input: src = 8888 7777 6666 5555 4444 3333 2222 1111
- // mask = 0001 0000 0000 0001 0001 0000 0001 0001
- // Expected result: dst = 0000 0000 0000 8888 5555 4444 2222 1111
- sve_dup(vtmp2, H, 0);
+ // high <-- low
+ // Example input: src = hh gg ff ee dd cc bb aa, one character is 8 bits.
+ // mask = 01 00 00 01 01 00 01 01, one character is 1 bit.
+ // Expected result: dst = 00 00 00 hh ee dd bb aa
// Extend lowest half to type INT.
- // dst = 00004444 00003333 00002222 00001111
+ // dst = 00dd 00cc 00bb 00aa
sve_uunpklo(dst, S, src);
- // pgtmp = 00000001 00000000 00000001 00000001
+ // pgtmp = 0001 0000 0001 0001
sve_punpklo(pgtmp, mask);
// Pack the active elements in size of type INT to the right,
// and fill the remainings with zero.
- // dst = 00000000 00004444 00002222 00001111
+ // dst = 0000 00dd 00bb 00aa
sve_compact(dst, S, dst, pgtmp);
// Narrow the result back to type SHORT.
- // dst = 0000 0000 0000 0000 0000 4444 2222 1111
- sve_uzp1(dst, H, dst, vtmp2);
+ // dst = 00 00 00 00 00 dd bb aa
+ sve_uzp1(dst, H, dst, vzr);
+
+ // Return if the vector length is no more than MaxVectorSize/2, since the
+ // highest half is invalid.
+ if (vector_length_in_bytes <= (MaxVectorSize >> 1)) {
+ return;
+ }
+
// Count the active elements of lowest half.
// rscratch1 = 3
sve_cntp(rscratch1, S, ptrue, pgtmp);
// Repeat to the highest half.
- // pgtmp = 00000001 00000000 00000000 00000001
+ // pgtmp = 0001 0000 0000 0001
sve_punpkhi(pgtmp, mask);
- // vtmp1 = 00008888 00007777 00006666 00005555
- sve_uunpkhi(vtmp1, S, src);
- // vtmp1 = 00000000 00000000 00008888 00005555
- sve_compact(vtmp1, S, vtmp1, pgtmp);
- // vtmp1 = 0000 0000 0000 0000 0000 0000 8888 5555
- sve_uzp1(vtmp1, H, vtmp1, vtmp2);
+ // vtmp = 00hh 00gg 00ff 00ee
+ sve_uunpkhi(vtmp, S, src);
+ // vtmp = 0000 0000 00hh 00ee
+ sve_compact(vtmp, S, vtmp, pgtmp);
+ // vtmp = 00 00 00 00 00 00 hh ee
+ sve_uzp1(vtmp, H, vtmp, vzr);
- // Compressed low: dst = 0000 0000 0000 0000 0000 4444 2222 1111
- // Compressed high: vtmp1 = 0000 0000 0000 0000 0000 0000 8888 5555
- // Left shift(cross lane) compressed high with TRUE_CNT lanes,
- // TRUE_CNT is the number of active elements in the compressed low.
- neg(rscratch1, rscratch1);
- // vtmp2 = {4 3 2 1 0 -1 -2 -3}
- sve_index(vtmp2, H, rscratch1, 1);
- // vtmp1 = 0000 0000 0000 8888 5555 0000 0000 0000
- sve_tbl(vtmp1, H, vtmp1, vtmp2);
-
- // Combine the compressed high(after shifted) with the compressed low.
- // dst = 0000 0000 0000 8888 5555 4444 2222 1111
- sve_orr(dst, dst, vtmp1);
+ // pgtmp = 00 00 00 00 00 01 01 01
+ sve_whilelt(pgtmp, H, zr, rscratch1);
+ // Compressed low: dst = 00 00 00 00 00 dd bb aa
+ // Compressed high: vtmp = 00 00 00 00 00 00 hh ee
+ // Combine the compressed low with the compressed high:
+ // dst = 00 00 00 hh ee dd bb aa
+ sve_splice(dst, H, pgtmp, vtmp);
}
// Clobbers: rscratch1, rscratch2
// Preserves: src, mask
void C2_MacroAssembler::sve_compress_byte(FloatRegister dst, FloatRegister src, PRegister mask,
- FloatRegister vtmp1, FloatRegister vtmp2,
- FloatRegister vtmp3, FloatRegister vtmp4,
- PRegister ptmp, PRegister pgtmp) {
+ FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3,
+ PRegister ptmp, PRegister pgtmp, unsigned vector_length_in_bytes) {
assert(pgtmp->is_governing(), "This register has to be a governing predicate register");
- assert_different_registers(dst, src, vtmp1, vtmp2, vtmp3, vtmp4);
+ assert_different_registers(dst, src, vtmp1, vtmp2, vtmp3);
assert_different_registers(mask, ptmp, pgtmp);
- // Example input: src = 88 77 66 55 44 33 22 11
- // mask = 01 00 00 01 01 00 01 01
- // Expected result: dst = 00 00 00 88 55 44 22 11
+ // high <-- low
+ // Example input: src = q p n m l k j i h g f e d c b a, one character is 8 bits.
+ // mask = 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 1, one character is 1 bit.
+ // Expected result: dst = 0 0 0 0 0 0 0 0 0 0 0 p i g c a
+ FloatRegister vzr = vtmp3;
+ sve_dup(vzr, B, 0);
- sve_dup(vtmp4, B, 0);
// Extend lowest half to type SHORT.
- // vtmp1 = 0044 0033 0022 0011
+ // vtmp1 = 0h 0g 0f 0e 0d 0c 0b 0a
sve_uunpklo(vtmp1, H, src);
- // ptmp = 0001 0000 0001 0001
+ // ptmp = 00 01 00 00 00 01 00 01
sve_punpklo(ptmp, mask);
+ // Pack the active elements in size of type SHORT to the right,
+ // and fill the remainings with zero.
+ // dst = 00 00 00 00 00 0g 0c 0a
+ unsigned extended_size = vector_length_in_bytes << 1;
+ sve_compress_short(dst, vtmp1, ptmp, vzr, vtmp2, pgtmp, extended_size > MaxVectorSize ? MaxVectorSize : extended_size);
+ // Narrow the result back to type BYTE.
+ // dst = 0 0 0 0 0 0 0 0 0 0 0 0 0 g c a
+ sve_uzp1(dst, B, dst, vzr);
+
+ // Return if the vector length is no more than MaxVectorSize/2, since the
+ // highest half is invalid.
+ if (vector_length_in_bytes <= (MaxVectorSize >> 1)) {
+ return;
+ }
// Count the active elements of lowest half.
// rscratch2 = 3
sve_cntp(rscratch2, H, ptrue, ptmp);
- // Pack the active elements in size of type SHORT to the right,
- // and fill the remainings with zero.
- // dst = 0000 0044 0022 0011
- sve_compress_short(dst, vtmp1, ptmp, vtmp2, vtmp3, pgtmp);
- // Narrow the result back to type BYTE.
- // dst = 00 00 00 00 00 44 22 11
- sve_uzp1(dst, B, dst, vtmp4);
// Repeat to the highest half.
- // ptmp = 0001 0000 0000 0001
+ // ptmp = 00 01 00 00 00 00 00 01
sve_punpkhi(ptmp, mask);
- // vtmp1 = 0088 0077 0066 0055
+ // vtmp2 = 0q 0p 0n 0m 0l 0k 0j 0i
sve_uunpkhi(vtmp2, H, src);
- // vtmp1 = 0000 0000 0088 0055
- sve_compress_short(vtmp1, vtmp2, ptmp, vtmp3, vtmp4, pgtmp);
+ // vtmp1 = 00 00 00 00 00 00 0p 0i
+ sve_compress_short(vtmp1, vtmp2, ptmp, vzr, vtmp2, pgtmp, extended_size - MaxVectorSize);
+ // vtmp1 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 p i
+ sve_uzp1(vtmp1, B, vtmp1, vzr);
- sve_dup(vtmp4, B, 0);
- // vtmp1 = 00 00 00 00 00 00 88 55
- sve_uzp1(vtmp1, B, vtmp1, vtmp4);
-
- // Compressed low: dst = 00 00 00 00 00 44 22 11
- // Compressed high: vtmp1 = 00 00 00 00 00 00 88 55
- // Left shift(cross lane) compressed high with TRUE_CNT lanes,
- // TRUE_CNT is the number of active elements in the compressed low.
- neg(rscratch2, rscratch2);
- // vtmp2 = {4 3 2 1 0 -1 -2 -3}
- sve_index(vtmp2, B, rscratch2, 1);
- // vtmp1 = 00 00 00 88 55 00 00 00
- sve_tbl(vtmp1, B, vtmp1, vtmp2);
- // Combine the compressed high(after shifted) with the compressed low.
- // dst = 00 00 00 88 55 44 22 11
- sve_orr(dst, dst, vtmp1);
+ // ptmp = 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
+ sve_whilelt(ptmp, B, zr, rscratch2);
+ // Compressed low: dst = 0 0 0 0 0 0 0 0 0 0 0 0 0 g c a
+ // Compressed high: vtmp1 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 p i
+ // Combine the compressed low with the compressed high:
+ // dst = 0 0 0 0 0 0 0 0 0 0 0 p i g c a
+ sve_splice(dst, B, ptmp, vtmp1);
}
void C2_MacroAssembler::neon_reverse_bits(FloatRegister dst, FloatRegister src, BasicType bt, bool isQ) {
@@ -2771,3 +2774,90 @@ void C2_MacroAssembler::select_from_two_vectors(FloatRegister dst, FloatRegister
select_from_two_vectors_neon(dst, src1, src2, dst, tmp, vector_length_in_bytes);
}
}
+
+// Vector expand implementation. Elements from the src vector are expanded into
+// the dst vector under the control of the vector mask.
+// Since there are no native instructions directly corresponding to expand before
+// SVE2p2, the following implementations mainly leverages the TBL instruction to
+// implement expand. To compute the index input for TBL, the prefix sum algorithm
+// (https://en.wikipedia.org/wiki/Prefix_sum) is used. The same algorithm is used
+// for NEON and SVE, but with different instructions where appropriate.
+
+// Vector expand implementation for NEON.
+//
+// An example of 128-bit Byte vector:
+// Data direction: high <== low
+// Input:
+// src = g f e d c b a 9 8 7 6 5 4 3 2 1
+// mask = 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1
+// Expected result:
+// dst = 0 0 8 7 0 0 6 5 0 0 4 3 0 0 2 1
+void C2_MacroAssembler::vector_expand_neon(FloatRegister dst, FloatRegister src, FloatRegister mask,
+ FloatRegister tmp1, FloatRegister tmp2, BasicType bt,
+ int vector_length_in_bytes) {
+ assert(vector_length_in_bytes <= 16, "the vector length in bytes for NEON must be <= 16");
+ assert_different_registers(dst, src, mask, tmp1, tmp2);
+ // Since the TBL instruction only supports byte table, we need to
+ // compute indices in byte type for all types.
+ SIMD_Arrangement size = vector_length_in_bytes == 16 ? T16B : T8B;
+ // tmp1 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ dup(tmp1, size, zr);
+ // dst = 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
+ negr(dst, size, mask);
+ // Calculate vector index for TBL with prefix sum algorithm.
+ // dst = 8 8 8 7 6 6 6 5 4 4 4 3 2 2 2 1
+ for (int i = 1; i < vector_length_in_bytes; i <<= 1) {
+ ext(tmp2, size, tmp1, dst, vector_length_in_bytes - i);
+ addv(dst, size, tmp2, dst);
+ }
+ // tmp2 = 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1
+ orr(tmp2, size, mask, mask);
+ // tmp2 = 0 0 8 7 0 0 6 5 0 0 4 3 0 0 2 1
+ bsl(tmp2, size, dst, tmp1);
+ // tmp1 = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ movi(tmp1, size, 1);
+ // dst = -1 -1 7 6 -1 -1 5 4 -1 -1 3 2 -1 -1 1 0
+ subv(dst, size, tmp2, tmp1);
+ // dst = 0 0 8 7 0 0 6 5 0 0 4 3 0 0 2 1
+ tbl(dst, size, src, 1, dst);
+}
+
+// Vector expand implementation for SVE.
+//
+// An example of 128-bit Short vector:
+// Data direction: high <== low
+// Input:
+// src = gf ed cb a9 87 65 43 21
+// pg = 00 01 00 01 00 01 00 01
+// Expected result:
+// dst = 00 87 00 65 00 43 00 21
+void C2_MacroAssembler::vector_expand_sve(FloatRegister dst, FloatRegister src, PRegister pg,
+ FloatRegister tmp1, FloatRegister tmp2, BasicType bt,
+ int vector_length_in_bytes) {
+ assert(UseSVE > 0, "expand implementation only for SVE");
+ assert_different_registers(dst, src, tmp1, tmp2);
+ SIMD_RegVariant size = elemType_to_regVariant(bt);
+
+ // tmp1 = 00 00 00 00 00 00 00 00
+ sve_dup(tmp1, size, 0);
+ sve_movprfx(tmp2, tmp1);
+ // tmp2 = 00 01 00 01 00 01 00 01
+ sve_cpy(tmp2, size, pg, 1, true);
+ // Calculate vector index for TBL with prefix sum algorithm.
+ // tmp2 = 04 04 03 03 02 02 01 01
+ for (int i = type2aelembytes(bt); i < vector_length_in_bytes; i <<= 1) {
+ sve_movprfx(dst, tmp1);
+ // The EXT instruction operates on the full-width sve register. The correct
+ // index calculation method is:
+ // vector_length_in_bytes - i + MaxVectorSize - vector_length_in_bytes =>
+ // MaxVectorSize - i.
+ sve_ext(dst, tmp2, MaxVectorSize - i);
+ sve_add(tmp2, size, dst, tmp2);
+ }
+ // dst = 00 04 00 03 00 02 00 01
+ sve_sel(dst, size, pg, tmp2, tmp1);
+ // dst = -1 03 -1 02 -1 01 -1 00
+ sve_sub(dst, size, 1);
+ // dst = 00 87 00 65 00 43 00 21
+ sve_tbl(dst, size, src, dst);
+}
\ No newline at end of file
diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
index 0403a27910f..09850a60c64 100644
--- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
@@ -173,13 +173,12 @@
// lowest-numbered elements of dst. Any remaining elements of dst will
// be filled with zero.
void sve_compress_byte(FloatRegister dst, FloatRegister src, PRegister mask,
- FloatRegister vtmp1, FloatRegister vtmp2,
- FloatRegister vtmp3, FloatRegister vtmp4,
- PRegister ptmp, PRegister pgtmp);
+ FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3,
+ PRegister ptmp, PRegister pgtmp, unsigned vector_length_in_bytes);
void sve_compress_short(FloatRegister dst, FloatRegister src, PRegister mask,
- FloatRegister vtmp1, FloatRegister vtmp2,
- PRegister pgtmp);
+ FloatRegister vzr, FloatRegister vtmp,
+ PRegister pgtmp, unsigned vector_length_in_bytes);
void neon_reverse_bits(FloatRegister dst, FloatRegister src, BasicType bt, bool isQ);
@@ -204,4 +203,10 @@
FloatRegister index, FloatRegister tmp, BasicType bt,
unsigned vector_length_in_bytes);
+ void vector_expand_neon(FloatRegister dst, FloatRegister src, FloatRegister mask,
+ FloatRegister tmp1, FloatRegister tmp2, BasicType bt,
+ int vector_length_in_bytes);
+ void vector_expand_sve(FloatRegister dst, FloatRegister src, PRegister pg,
+ FloatRegister tmp1, FloatRegister tmp2, BasicType bt,
+ int vector_length_in_bytes);
#endif // CPU_AARCH64_C2_MACROASSEMBLER_AARCH64_HPP
diff --git a/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp
index 94a80dec3ea..a0dea3643a1 100644
--- a/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp
@@ -55,7 +55,6 @@ define_pd_global(size_t, InitialCodeCacheSize, 2496*K); // Integral multip
define_pd_global(size_t, CodeCacheExpansionSize, 64*K);
// Ergonomics related flags
-define_pd_global(uint64_t,MaxRAM, 128ULL*G);
define_pd_global(intx, RegisterCostAreaRatio, 16000);
// Peephole and CISC spilling both break the graph, and so makes the
diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp
index aff50b9cf2f..bdbef53bfdb 100644
--- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp
@@ -228,8 +228,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
nmethod* nm = sender_blob->as_nmethod_or_null();
if (nm != nullptr) {
- if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) ||
- nm->method()->is_method_handle_intrinsic()) {
+ if (nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) {
return false;
}
}
@@ -454,48 +453,6 @@ JavaThread** frame::saved_thread_address(const frame& f) {
return thread_addr;
}
-//------------------------------------------------------------------------------
-// frame::verify_deopt_original_pc
-//
-// Verifies the calculated original PC of a deoptimization PC for the
-// given unextended SP.
-#ifdef ASSERT
-void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) {
- frame fr;
-
- // This is ugly but it's better than to change {get,set}_original_pc
- // to take an SP value as argument. And it's only a debugging
- // method anyway.
- fr._unextended_sp = unextended_sp;
-
- address original_pc = nm->get_original_pc(&fr);
- assert(nm->insts_contains_inclusive(original_pc),
- "original PC must be in the main code section of the compiled method (or must be immediately following it)");
-}
-#endif
-
-//------------------------------------------------------------------------------
-// frame::adjust_unextended_sp
-#ifdef ASSERT
-void frame::adjust_unextended_sp() {
- // On aarch64, sites calling method handle intrinsics and lambda forms are treated
- // as any other call site. Therefore, no special action is needed when we are
- // returning to any of these call sites.
-
- if (_cb != nullptr) {
- nmethod* sender_nm = _cb->as_nmethod_or_null();
- if (sender_nm != nullptr) {
- // If the sender PC is a deoptimization point, get the original PC.
- if (sender_nm->is_deopt_entry(_pc) ||
- sender_nm->is_deopt_mh_entry(_pc)) {
- verify_deopt_original_pc(sender_nm, _unextended_sp);
- }
- }
- }
-}
-#endif
-
-
//------------------------------------------------------------------------------
// frame::sender_for_interpreter_frame
frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.hpp
index da020b4234d..231710df7d7 100644
--- a/src/hotspot/cpu/aarch64/frame_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/frame_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -141,8 +141,6 @@
int _offset_unextended_sp; // for use in stack-chunk frames
};
- void adjust_unextended_sp() NOT_DEBUG_RETURN;
-
// true means _sp value is correct and we can use it to get the sender's sp
// of the compiled frame, otherwise, _sp value may be invalid and we can use
// _fp to get the sender's sp if PreserveFramePointer is enabled.
@@ -152,11 +150,6 @@
return (intptr_t*) addr_at(offset);
}
-#ifdef ASSERT
- // Used in frame::sender_for_{interpreter,compiled}_frame
- static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
-#endif
-
public:
// Constructors
diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp
index 47ae93a4932..cb53d8663ad 100644
--- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp
+++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp
@@ -116,8 +116,6 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
}
inline void frame::setup(address pc) {
- adjust_unextended_sp();
-
address original_pc = get_deopt_original_pc();
if (original_pc != nullptr) {
_pc = original_pc;
@@ -223,7 +221,6 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
// assert(_pc != nullptr, "no pc?");
_cb = CodeCache::find_blob(_pc);
- adjust_unextended_sp();
address original_pc = get_deopt_original_pc();
if (original_pc != nullptr) {
diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
index 42f3c4a015a..974527f30e9 100644
--- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
@@ -86,15 +86,48 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm
}
}
-void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register start, Register count, Register scratch, RegSet saved_regs) {
- __ push(saved_regs, sp);
- assert_different_registers(start, count, scratch);
- assert_different_registers(c_rarg0, count);
- __ mov(c_rarg0, start);
- __ mov(c_rarg1, count);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);
- __ pop(saved_regs, sp);
+void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm,
+ DecoratorSet decorators,
+ Register start,
+ Register count,
+ Register scratch,
+ RegSet saved_regs) {
+
+ Label done;
+ Label loop;
+ Label next;
+
+ __ cbz(count, done);
+
+ // Calculate the number of card marks to set. Since the object might start and
+ // end within a card, we need to calculate this via the card table indexes of
+ // the actual start and last addresses covered by the object.
+ // Temporarily use the count register for the last element address.
+ __ lea(count, Address(start, count, Address::lsl(LogBytesPerHeapOop))); // end = start + count << LogBytesPerHeapOop
+ __ sub(count, count, BytesPerHeapOop); // Use last element address for end.
+
+ __ lsr(start, start, CardTable::card_shift());
+ __ lsr(count, count, CardTable::card_shift());
+ __ sub(count, count, start); // Number of bytes to mark - 1.
+
+ // Add card table base offset to start.
+ __ ldr(scratch, Address(rthread, in_bytes(G1ThreadLocalData::card_table_base_offset())));
+ __ add(start, start, scratch);
+
+ __ bind(loop);
+ if (UseCondCardMark) {
+ __ ldrb(scratch, Address(start, count));
+ // Instead of loading clean_card_val and comparing, we exploit the fact that
+ // the LSB of non-clean cards is always 0, and the LSB of clean cards 1.
+ __ tbz(scratch, 0, next);
+ }
+ static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
+ __ strb(zr, Address(start, count));
+ __ bind(next);
+ __ subs(count, count, 1);
+ __ br(Assembler::GE, loop);
+
+ __ bind(done);
}
static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
@@ -199,13 +232,17 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
}
-static void generate_post_barrier_fast_path(MacroAssembler* masm,
- const Register store_addr,
- const Register new_val,
- const Register tmp1,
- const Register tmp2,
- Label& done,
- bool new_val_may_be_null) {
+static void generate_post_barrier(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
+ assert(thread == rthread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg, rscratch1);
+
// Does store cross heap regions?
__ eor(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
__ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
@@ -214,33 +251,19 @@ static void generate_post_barrier_fast_path(MacroAssembler* masm,
if (new_val_may_be_null) {
__ cbz(new_val, done);
}
- // Storing region crossing non-null, is card young?
+ // Storing region crossing non-null.
__ lsr(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base
- __ load_byte_map_base(tmp2); // tmp2 := card table base address
- __ add(tmp1, tmp1, tmp2); // tmp1 := card address
- __ ldrb(tmp2, Address(tmp1)); // tmp2 := card
- __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val()); // tmp2 := card == young_card_val?
-}
-static void generate_post_barrier_slow_path(MacroAssembler* masm,
- const Register thread,
- const Register tmp1,
- const Register tmp2,
- Label& done,
- Label& runtime) {
- __ membar(Assembler::StoreLoad); // StoreLoad membar
- __ ldrb(tmp2, Address(tmp1)); // tmp2 := card
- __ cbzw(tmp2, done);
- // Storing a region crossing, non-null oop, card is clean.
- // Dirty card and log.
- STATIC_ASSERT(CardTable::dirty_card_val() == 0);
- __ strb(zr, Address(tmp1)); // *(card address) := dirty_card_val
- generate_queue_test_and_insertion(masm,
- G1ThreadLocalData::dirty_card_queue_index_offset(),
- G1ThreadLocalData::dirty_card_queue_buffer_offset(),
- runtime,
- thread, tmp1, tmp2, rscratch1);
- __ b(done);
+ Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
+ __ ldr(tmp2, card_table_addr); // tmp2 := card table base address
+ if (UseCondCardMark) {
+ __ ldrb(rscratch1, Address(tmp1, tmp2)); // rscratch1 := card
+ // Instead of loading clean_card_val and comparing, we exploit the fact that
+ // the LSB of non-clean cards is always 0, and the LSB of clean cards 1.
+ __ tbz(rscratch1, 0, done);
+ }
+ static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
+ __ strb(zr, Address(tmp1, tmp2)); // *(card address) := dirty_card_val
}
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
@@ -249,27 +272,8 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
Register thread,
Register tmp1,
Register tmp2) {
- assert(thread == rthread, "must be");
- assert_different_registers(store_addr, new_val, thread, tmp1, tmp2,
- rscratch1);
- assert(store_addr != noreg && new_val != noreg && tmp1 != noreg
- && tmp2 != noreg, "expecting a register");
-
Label done;
- Label runtime;
-
- generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
- // If card is young, jump to done
- __ br(Assembler::EQ, done);
- generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime);
-
- __ bind(runtime);
- // save the live input values
- RegSet saved = RegSet::of(store_addr);
- __ push(saved, sp);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread);
- __ pop(saved, sp);
-
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, false /* new_val_may_be_null */);
__ bind(done);
}
@@ -329,38 +333,10 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
Register thread,
Register tmp1,
Register tmp2,
- G1PostBarrierStubC2* stub) {
- assert(thread == rthread, "must be");
- assert_different_registers(store_addr, new_val, thread, tmp1, tmp2,
- rscratch1);
- assert(store_addr != noreg && new_val != noreg && tmp1 != noreg
- && tmp2 != noreg, "expecting a register");
-
- stub->initialize_registers(thread, tmp1, tmp2);
-
- bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
- generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null);
- // If card is not young, jump to stub (slow path)
- __ br(Assembler::NE, *stub->entry());
-
- __ bind(*stub->continuation());
-}
-
-void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const {
- Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
- Label runtime;
- Register thread = stub->thread();
- Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
- Register tmp2 = stub->tmp2();
- assert(stub->tmp3() == noreg, "not needed in this platform");
-
- __ bind(*stub->entry());
- generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime);
-
- __ bind(runtime);
- generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
- __ b(*stub->continuation());
+ bool new_val_may_be_null) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, new_val_may_be_null);
+ __ bind(done);
}
#endif // COMPILER2
@@ -456,20 +432,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
__ b(*stub->continuation());
}
-void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
- G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
- __ bind(*stub->entry());
- assert(stub->addr()->is_register(), "Precondition.");
- assert(stub->new_val()->is_register(), "Precondition.");
- Register new_val_reg = stub->new_val()->as_register();
- __ cbz(new_val_reg, *stub->continuation());
- ce->store_parameter(stub->addr()->as_pointer_register(), 0);
- __ far_call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));
- __ b(*stub->continuation());
-}
-
#undef __
+void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
+ masm->bind(done);
+}
+
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
@@ -521,74 +496,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ epilogue();
}
-void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
- __ prologue("g1_post_barrier", false);
-
- // arg0: store_address
- Address store_addr(rfp, 2*BytesPerWord);
-
- BarrierSet* bs = BarrierSet::barrier_set();
- CardTableBarrierSet* ctbs = barrier_set_cast(bs);
- CardTable* ct = ctbs->card_table();
-
- Label done;
- Label runtime;
-
- // At this point we know new_value is non-null and the new_value crosses regions.
- // Must check to see if card is already dirty
-
- const Register thread = rthread;
-
- Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
- Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
-
- const Register card_offset = rscratch2;
- // LR is free here, so we can use it to hold the byte_map_base.
- const Register byte_map_base = lr;
-
- assert_different_registers(card_offset, byte_map_base, rscratch1);
-
- __ load_parameter(0, card_offset);
- __ lsr(card_offset, card_offset, CardTable::card_shift());
- __ load_byte_map_base(byte_map_base);
- __ ldrb(rscratch1, Address(byte_map_base, card_offset));
- __ cmpw(rscratch1, (int)G1CardTable::g1_young_card_val());
- __ br(Assembler::EQ, done);
-
- assert((int)CardTable::dirty_card_val() == 0, "must be 0");
-
- __ membar(Assembler::StoreLoad);
- __ ldrb(rscratch1, Address(byte_map_base, card_offset));
- __ cbzw(rscratch1, done);
-
- // storing region crossing non-null, card is clean.
- // dirty card and log.
- __ strb(zr, Address(byte_map_base, card_offset));
-
- // Convert card offset into an address in card_addr
- Register card_addr = card_offset;
- __ add(card_addr, byte_map_base, card_addr);
-
- __ ldr(rscratch1, queue_index);
- __ cbz(rscratch1, runtime);
- __ sub(rscratch1, rscratch1, wordSize);
- __ str(rscratch1, queue_index);
-
- // Reuse LR to hold buffer_addr
- const Register buffer_addr = lr;
-
- __ ldr(buffer_addr, buffer);
- __ str(card_addr, Address(buffer_addr, rscratch1));
- __ b(done);
-
- __ bind(runtime);
- __ push_call_clobbered_registers();
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);
- __ pop_call_clobbered_registers();
- __ bind(done);
- __ epilogue();
-}
-
#undef __
#endif // COMPILER1
diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp
index 04ac2096096..72040cd7ad2 100644
--- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,9 +32,7 @@
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
-class G1PostBarrierStub;
class G1PreBarrierStubC2;
-class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -65,10 +63,15 @@ protected:
public:
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
- void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
- void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
+
+ void g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2);
#endif
#ifdef COMPILER2
@@ -87,9 +90,7 @@ public:
Register thread,
Register tmp1,
Register tmp2,
- G1PostBarrierStubC2* c2_stub);
- void generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const;
+ bool new_val_may_be_null);
#endif
void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad
index 081a67d6880..18fc27a4af4 100644
--- a/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2024, 2025, 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
@@ -62,13 +62,13 @@ static void write_barrier_post(MacroAssembler* masm,
Register new_val,
Register tmp1,
Register tmp2) {
- if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ if (!G1BarrierStubC2::needs_post_barrier(node)) {
return;
}
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
- G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
- g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, rthread, tmp1, tmp2, stub);
+ bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, rthread, tmp1, tmp2, new_val_may_be_null);
}
%}
diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp
index a2b43d80746..021af3e5698 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp
@@ -398,14 +398,18 @@ void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register
OptoReg::Name BarrierSetAssembler::encode_float_vector_register_size(const Node* node, OptoReg::Name opto_reg) {
switch (node->ideal_reg()) {
case Op_RegF:
+ case Op_RegI: // RA may place scalar values (Op_RegI/N/L/P) in FP registers when UseFPUForSpilling is enabled
+ case Op_RegN:
// No need to refine. The original encoding is already fine to distinguish.
- assert(opto_reg % 4 == 0, "Float register should only occupy a single slot");
+ assert(opto_reg % 4 == 0, "32-bit register should only occupy a single slot");
break;
// Use different encoding values of the same fp/vector register to help distinguish different sizes.
// Such as V16. The OptoReg::name and its corresponding slot value are
// "V16": 64, "V16_H": 65, "V16_J": 66, "V16_K": 67.
case Op_RegD:
case Op_VecD:
+ case Op_RegL:
+ case Op_RegP:
opto_reg &= ~3;
opto_reg |= 1;
break;
diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp
index ad3a171c103..ae2819e78ca 100644
--- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp
@@ -275,7 +275,6 @@ public:
Label* entry();
};
-
class ZStoreBarrierStubC2Aarch64 : public ZStoreBarrierStubC2 {
private:
bool _deferred_emit;
diff --git a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad
index 78dc5d56bbd..8149c7e4c97 100644
--- a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad
+++ b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad
@@ -239,7 +239,6 @@ instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne
ins_pipe(pipe_slow);
%}
-
instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{
match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
predicate(UseZGC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp
index 948ba97aa22..1e788590b64 100644
--- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp
@@ -35,8 +35,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
#define SUPPORTS_NATIVE_CX8
-#define SUPPORT_MONITOR_COUNT
-
// Aarch64 was not originally defined to be multi-copy-atomic, but now
// is. See: "Simplifying ARM Concurrency: Multicopy-atomic Axiomatic
// and Operational Models for ARMv8"
diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp
index 607912e6e49..6f8795494a2 100644
--- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp
@@ -1704,3 +1704,14 @@ void InterpreterMacroAssembler::load_method_entry(Register cache, Register index
add(cache, cache, Array::base_offset_in_bytes());
lea(cache, Address(cache, index));
}
+
+#ifdef ASSERT
+void InterpreterMacroAssembler::verify_field_offset(Register reg) {
+ // Verify the field offset is not in the header, implicitly checks for 0
+ Label L;
+ subs(zr, reg, oopDesc::base_offset_in_bytes());
+ br(Assembler::GE, L);
+ stop("bad field offset");
+ bind(L);
+}
+#endif
diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp
index e896a2a9430..e07e6e49f53 100644
--- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp
@@ -319,6 +319,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
void load_resolved_indy_entry(Register cache, Register index);
void load_field_entry(Register cache, Register index, int bcp_offset = 1);
void load_method_entry(Register cache, Register index, int bcp_offset = 1);
+
+ void verify_field_offset(Register reg) NOT_DEBUG_RETURN;
};
#endif // CPU_AARCH64_INTERP_MASM_AARCH64_HPP
diff --git a/src/hotspot/cpu/aarch64/javaFrameAnchor_aarch64.hpp b/src/hotspot/cpu/aarch64/javaFrameAnchor_aarch64.hpp
index 8d125d3c027..a6e7d74f528 100644
--- a/src/hotspot/cpu/aarch64/javaFrameAnchor_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/javaFrameAnchor_aarch64.hpp
@@ -39,24 +39,22 @@ public:
// 3 - restoring an old state (javaCalls)
void clear(void) {
+ // No hardware barriers are necessary. All members are volatile and the profiler
+ // is run from a signal handler and only observers the thread its running on.
+
// clearing _last_Java_sp must be first
_last_Java_sp = nullptr;
- OrderAccess::release();
_last_Java_fp = nullptr;
_last_Java_pc = nullptr;
}
void copy(JavaFrameAnchor* src) {
- // In order to make sure the transition state is valid for "this"
+ // No hardware barriers are necessary. All members are volatile and the profiler
+ // is run from a signal handler and only observers the thread its running on.
+
// We must clear _last_Java_sp before copying the rest of the new data
- //
- // Hack Alert: Temporary bugfix for 4717480/4721647
- // To act like previous version (pd_cache_state) don't null _last_Java_sp
- // unless the value is changing
- //
if (_last_Java_sp != src->_last_Java_sp) {
_last_Java_sp = nullptr;
- OrderAccess::release();
}
_last_Java_fp = src->_last_Java_fp;
_last_Java_pc = src->_last_Java_pc;
diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
index 3999beeec2b..14009789319 100644
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
@@ -148,56 +148,34 @@ extern "C" void disnm(intptr_t p);
// strictly should be 64 bit movz #imm16<<0
// 110___10100 (i.e. requires insn[31:21] == 11010010100)
//
-class RelocActions {
-protected:
- typedef int (*reloc_insn)(address insn_addr, address &target);
- virtual reloc_insn adrpMem() = 0;
- virtual reloc_insn adrpAdd() = 0;
- virtual reloc_insn adrpMovk() = 0;
+static uint32_t insn_at(address insn_addr, int n) {
+ return ((uint32_t*)insn_addr)[n];
+}
- const address _insn_addr;
- const uint32_t _insn;
-
- static uint32_t insn_at(address insn_addr, int n) {
- return ((uint32_t*)insn_addr)[n];
- }
- uint32_t insn_at(int n) const {
- return insn_at(_insn_addr, n);
- }
+template
+class RelocActions : public AllStatic {
public:
- RelocActions(address insn_addr) : _insn_addr(insn_addr), _insn(insn_at(insn_addr, 0)) {}
- RelocActions(address insn_addr, uint32_t insn)
- : _insn_addr(insn_addr), _insn(insn) {}
-
- virtual int unconditionalBranch(address insn_addr, address &target) = 0;
- virtual int conditionalBranch(address insn_addr, address &target) = 0;
- virtual int testAndBranch(address insn_addr, address &target) = 0;
- virtual int loadStore(address insn_addr, address &target) = 0;
- virtual int adr(address insn_addr, address &target) = 0;
- virtual int adrp(address insn_addr, address &target, reloc_insn inner) = 0;
- virtual int immediate(address insn_addr, address &target) = 0;
- virtual void verify(address insn_addr, address &target) = 0;
-
- int ALWAYSINLINE run(address insn_addr, address &target) {
+ static int ALWAYSINLINE run(address insn_addr, address &target) {
int instructions = 1;
+ uint32_t insn = insn_at(insn_addr, 0);
- uint32_t dispatch = Instruction_aarch64::extract(_insn, 30, 25);
+ uint32_t dispatch = Instruction_aarch64::extract(insn, 30, 25);
switch(dispatch) {
case 0b001010:
case 0b001011: {
- instructions = unconditionalBranch(insn_addr, target);
+ instructions = T::unconditionalBranch(insn_addr, target);
break;
}
case 0b101010: // Conditional branch (immediate)
case 0b011010: { // Compare & branch (immediate)
- instructions = conditionalBranch(insn_addr, target);
- break;
+ instructions = T::conditionalBranch(insn_addr, target);
+ break;
}
case 0b011011: {
- instructions = testAndBranch(insn_addr, target);
+ instructions = T::testAndBranch(insn_addr, target);
break;
}
case 0b001100:
@@ -209,9 +187,9 @@ public:
case 0b111100:
case 0b111110: {
// load/store
- if ((Instruction_aarch64::extract(_insn, 29, 24) & 0b111011) == 0b011000) {
+ if ((Instruction_aarch64::extract(insn, 29, 24) & 0b111011) == 0b011000) {
// Load register (literal)
- instructions = loadStore(insn_addr, target);
+ instructions = T::loadStore(insn_addr, target);
break;
} else {
// nothing to do
@@ -224,27 +202,27 @@ public:
case 0b101000:
case 0b111000: {
// adr/adrp
- assert(Instruction_aarch64::extract(_insn, 28, 24) == 0b10000, "must be");
- int shift = Instruction_aarch64::extract(_insn, 31, 31);
+ assert(Instruction_aarch64::extract(insn, 28, 24) == 0b10000, "must be");
+ int shift = Instruction_aarch64::extract(insn, 31, 31);
if (shift) {
- uint32_t insn2 = insn_at(1);
+ uint32_t insn2 = insn_at(insn_addr, 1);
if (Instruction_aarch64::extract(insn2, 29, 24) == 0b111001 &&
- Instruction_aarch64::extract(_insn, 4, 0) ==
+ Instruction_aarch64::extract(insn, 4, 0) ==
Instruction_aarch64::extract(insn2, 9, 5)) {
- instructions = adrp(insn_addr, target, adrpMem());
+ instructions = T::adrp(insn_addr, target, T::adrpMem);
} else if (Instruction_aarch64::extract(insn2, 31, 22) == 0b1001000100 &&
- Instruction_aarch64::extract(_insn, 4, 0) ==
+ Instruction_aarch64::extract(insn, 4, 0) ==
Instruction_aarch64::extract(insn2, 4, 0)) {
- instructions = adrp(insn_addr, target, adrpAdd());
+ instructions = T::adrp(insn_addr, target, T::adrpAdd);
} else if (Instruction_aarch64::extract(insn2, 31, 21) == 0b11110010110 &&
- Instruction_aarch64::extract(_insn, 4, 0) ==
+ Instruction_aarch64::extract(insn, 4, 0) ==
Instruction_aarch64::extract(insn2, 4, 0)) {
- instructions = adrp(insn_addr, target, adrpMovk());
+ instructions = T::adrp(insn_addr, target, T::adrpMovk);
} else {
ShouldNotReachHere();
}
} else {
- instructions = adr(insn_addr, target);
+ instructions = T::adr(insn_addr, target);
}
break;
}
@@ -252,7 +230,7 @@ public:
case 0b011001:
case 0b101001:
case 0b111001: {
- instructions = immediate(insn_addr, target);
+ instructions = T::immediate(insn_addr, target);
break;
}
default: {
@@ -260,42 +238,36 @@ public:
}
}
- verify(insn_addr, target);
+ T::verify(insn_addr, target);
return instructions * NativeInstruction::instruction_size;
}
};
-class Patcher : public RelocActions {
- virtual reloc_insn adrpMem() { return &Patcher::adrpMem_impl; }
- virtual reloc_insn adrpAdd() { return &Patcher::adrpAdd_impl; }
- virtual reloc_insn adrpMovk() { return &Patcher::adrpMovk_impl; }
-
+class Patcher : public AllStatic {
public:
- Patcher(address insn_addr) : RelocActions(insn_addr) {}
-
- virtual int unconditionalBranch(address insn_addr, address &target) {
+ static int unconditionalBranch(address insn_addr, address &target) {
intptr_t offset = (target - insn_addr) >> 2;
Instruction_aarch64::spatch(insn_addr, 25, 0, offset);
return 1;
}
- virtual int conditionalBranch(address insn_addr, address &target) {
+ static int conditionalBranch(address insn_addr, address &target) {
intptr_t offset = (target - insn_addr) >> 2;
Instruction_aarch64::spatch(insn_addr, 23, 5, offset);
return 1;
}
- virtual int testAndBranch(address insn_addr, address &target) {
+ static int testAndBranch(address insn_addr, address &target) {
intptr_t offset = (target - insn_addr) >> 2;
Instruction_aarch64::spatch(insn_addr, 18, 5, offset);
return 1;
}
- virtual int loadStore(address insn_addr, address &target) {
+ static int loadStore(address insn_addr, address &target) {
intptr_t offset = (target - insn_addr) >> 2;
Instruction_aarch64::spatch(insn_addr, 23, 5, offset);
return 1;
}
- virtual int adr(address insn_addr, address &target) {
+ static int adr(address insn_addr, address &target) {
#ifdef ASSERT
- assert(Instruction_aarch64::extract(_insn, 28, 24) == 0b10000, "must be");
+ assert(Instruction_aarch64::extract(insn_at(insn_addr, 0), 28, 24) == 0b10000, "must be");
#endif
// PC-rel. addressing
ptrdiff_t offset = target - insn_addr;
@@ -305,17 +277,18 @@ public:
Instruction_aarch64::patch(insn_addr, 30, 29, offset_lo);
return 1;
}
- virtual int adrp(address insn_addr, address &target, reloc_insn inner) {
+ template
+ static int adrp(address insn_addr, address &target, U inner) {
int instructions = 1;
#ifdef ASSERT
- assert(Instruction_aarch64::extract(_insn, 28, 24) == 0b10000, "must be");
+ assert(Instruction_aarch64::extract(insn_at(insn_addr, 0), 28, 24) == 0b10000, "must be");
#endif
ptrdiff_t offset = target - insn_addr;
instructions = 2;
precond(inner != nullptr);
// Give the inner reloc a chance to modify the target.
address adjusted_target = target;
- instructions = (*inner)(insn_addr, adjusted_target);
+ instructions = inner(insn_addr, adjusted_target);
uintptr_t pc_page = (uintptr_t)insn_addr >> 12;
uintptr_t adr_page = (uintptr_t)adjusted_target >> 12;
offset = adr_page - pc_page;
@@ -325,7 +298,7 @@ public:
Instruction_aarch64::patch(insn_addr, 30, 29, offset_lo);
return instructions;
}
- static int adrpMem_impl(address insn_addr, address &target) {
+ static int adrpMem(address insn_addr, address &target) {
uintptr_t dest = (uintptr_t)target;
int offset_lo = dest & 0xfff;
uint32_t insn2 = insn_at(insn_addr, 1);
@@ -334,21 +307,21 @@ public:
guarantee(((dest >> size) << size) == dest, "misaligned target");
return 2;
}
- static int adrpAdd_impl(address insn_addr, address &target) {
+ static int adrpAdd(address insn_addr, address &target) {
uintptr_t dest = (uintptr_t)target;
int offset_lo = dest & 0xfff;
Instruction_aarch64::patch(insn_addr + sizeof (uint32_t), 21, 10, offset_lo);
return 2;
}
- static int adrpMovk_impl(address insn_addr, address &target) {
+ static int adrpMovk(address insn_addr, address &target) {
uintptr_t dest = uintptr_t(target);
Instruction_aarch64::patch(insn_addr + sizeof (uint32_t), 20, 5, (uintptr_t)target >> 32);
dest = (dest & 0xffffffffULL) | (uintptr_t(insn_addr) & 0xffff00000000ULL);
target = address(dest);
return 2;
}
- virtual int immediate(address insn_addr, address &target) {
- assert(Instruction_aarch64::extract(_insn, 31, 21) == 0b11010010100, "must be");
+ static int immediate(address insn_addr, address &target) {
+ assert(Instruction_aarch64::extract(insn_at(insn_addr, 0), 31, 21) == 0b11010010100, "must be");
uint64_t dest = (uint64_t)target;
// Move wide constant
assert(nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch");
@@ -358,7 +331,7 @@ public:
Instruction_aarch64::patch(insn_addr+8, 20, 5, (dest >>= 16) & 0xffff);
return 3;
}
- virtual void verify(address insn_addr, address &target) {
+ static void verify(address insn_addr, address &target) {
#ifdef ASSERT
address address_is = MacroAssembler::target_addr_for_insn(insn_addr);
if (!(address_is == target)) {
@@ -392,56 +365,54 @@ static bool offset_for(uint32_t insn1, uint32_t insn2, ptrdiff_t &byte_offset) {
return false;
}
-class AArch64Decoder : public RelocActions {
- virtual reloc_insn adrpMem() { return &AArch64Decoder::adrpMem_impl; }
- virtual reloc_insn adrpAdd() { return &AArch64Decoder::adrpAdd_impl; }
- virtual reloc_insn adrpMovk() { return &AArch64Decoder::adrpMovk_impl; }
-
+class AArch64Decoder : public AllStatic {
public:
- AArch64Decoder(address insn_addr, uint32_t insn) : RelocActions(insn_addr, insn) {}
- virtual int loadStore(address insn_addr, address &target) {
- intptr_t offset = Instruction_aarch64::sextract(_insn, 23, 5);
+ static int loadStore(address insn_addr, address &target) {
+ intptr_t offset = Instruction_aarch64::sextract(insn_at(insn_addr, 0), 23, 5);
target = insn_addr + (offset << 2);
return 1;
}
- virtual int unconditionalBranch(address insn_addr, address &target) {
- intptr_t offset = Instruction_aarch64::sextract(_insn, 25, 0);
+ static int unconditionalBranch(address insn_addr, address &target) {
+ intptr_t offset = Instruction_aarch64::sextract(insn_at(insn_addr, 0), 25, 0);
target = insn_addr + (offset << 2);
return 1;
}
- virtual int conditionalBranch(address insn_addr, address &target) {
- intptr_t offset = Instruction_aarch64::sextract(_insn, 23, 5);
+ static int conditionalBranch(address insn_addr, address &target) {
+ intptr_t offset = Instruction_aarch64::sextract(insn_at(insn_addr, 0), 23, 5);
target = address(((uint64_t)insn_addr + (offset << 2)));
return 1;
}
- virtual int testAndBranch(address insn_addr, address &target) {
- intptr_t offset = Instruction_aarch64::sextract(_insn, 18, 5);
+ static int testAndBranch(address insn_addr, address &target) {
+ intptr_t offset = Instruction_aarch64::sextract(insn_at(insn_addr, 0), 18, 5);
target = address(((uint64_t)insn_addr + (offset << 2)));
return 1;
}
- virtual int adr(address insn_addr, address &target) {
+ static int adr(address insn_addr, address &target) {
// PC-rel. addressing
- intptr_t offset = Instruction_aarch64::extract(_insn, 30, 29);
- offset |= Instruction_aarch64::sextract(_insn, 23, 5) << 2;
+ uint32_t insn = insn_at(insn_addr, 0);
+ intptr_t offset = Instruction_aarch64::extract(insn, 30, 29);
+ offset |= Instruction_aarch64::sextract(insn, 23, 5) << 2;
target = address((uint64_t)insn_addr + offset);
return 1;
}
- virtual int adrp(address insn_addr, address &target, reloc_insn inner) {
- assert(Instruction_aarch64::extract(_insn, 28, 24) == 0b10000, "must be");
- intptr_t offset = Instruction_aarch64::extract(_insn, 30, 29);
- offset |= Instruction_aarch64::sextract(_insn, 23, 5) << 2;
+ template
+ static int adrp(address insn_addr, address &target, U inner) {
+ uint32_t insn = insn_at(insn_addr, 0);
+ assert(Instruction_aarch64::extract(insn, 28, 24) == 0b10000, "must be");
+ intptr_t offset = Instruction_aarch64::extract(insn, 30, 29);
+ offset |= Instruction_aarch64::sextract(insn, 23, 5) << 2;
int shift = 12;
offset <<= shift;
uint64_t target_page = ((uint64_t)insn_addr) + offset;
target_page &= ((uint64_t)-1) << shift;
- uint32_t insn2 = insn_at(1);
+ uint32_t insn2 = insn_at(insn_addr, 1);
target = address(target_page);
precond(inner != nullptr);
- (*inner)(insn_addr, target);
+ inner(insn_addr, target);
return 2;
}
- static int adrpMem_impl(address insn_addr, address &target) {
+ static int adrpMem(address insn_addr, address &target) {
uint32_t insn2 = insn_at(insn_addr, 1);
// Load/store register (unsigned immediate)
ptrdiff_t byte_offset = Instruction_aarch64::extract(insn2, 21, 10);
@@ -450,14 +421,14 @@ public:
target += byte_offset;
return 2;
}
- static int adrpAdd_impl(address insn_addr, address &target) {
+ static int adrpAdd(address insn_addr, address &target) {
uint32_t insn2 = insn_at(insn_addr, 1);
// add (immediate)
ptrdiff_t byte_offset = Instruction_aarch64::extract(insn2, 21, 10);
target += byte_offset;
return 2;
}
- static int adrpMovk_impl(address insn_addr, address &target) {
+ static int adrpMovk(address insn_addr, address &target) {
uint32_t insn2 = insn_at(insn_addr, 1);
uint64_t dest = uint64_t(target);
dest = (dest & 0xffff0000ffffffff) |
@@ -476,35 +447,33 @@ public:
return 2;
}
}
- virtual int immediate(address insn_addr, address &target) {
+ static int immediate(address insn_addr, address &target) {
uint32_t *insns = (uint32_t *)insn_addr;
- assert(Instruction_aarch64::extract(_insn, 31, 21) == 0b11010010100, "must be");
+ assert(Instruction_aarch64::extract(insns[0], 31, 21) == 0b11010010100, "must be");
// Move wide constant: movz, movk, movk. See movptr().
assert(nativeInstruction_at(insns+1)->is_movk(), "wrong insns in patch");
assert(nativeInstruction_at(insns+2)->is_movk(), "wrong insns in patch");
- target = address(uint64_t(Instruction_aarch64::extract(_insn, 20, 5))
- + (uint64_t(Instruction_aarch64::extract(insns[1], 20, 5)) << 16)
- + (uint64_t(Instruction_aarch64::extract(insns[2], 20, 5)) << 32));
+ target = address(uint64_t(Instruction_aarch64::extract(insns[0], 20, 5))
+ + (uint64_t(Instruction_aarch64::extract(insns[1], 20, 5)) << 16)
+ + (uint64_t(Instruction_aarch64::extract(insns[2], 20, 5)) << 32));
assert(nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch");
assert(nativeInstruction_at(insn_addr+8)->is_movk(), "wrong insns in patch");
return 3;
}
- virtual void verify(address insn_addr, address &target) {
+ static void verify(address insn_addr, address &target) {
}
};
-address MacroAssembler::target_addr_for_insn(address insn_addr, uint32_t insn) {
- AArch64Decoder decoder(insn_addr, insn);
+address MacroAssembler::target_addr_for_insn(address insn_addr) {
address target;
- decoder.run(insn_addr, target);
+ RelocActions::run(insn_addr, target);
return target;
}
// Patch any kind of instruction; there may be several instructions.
// Return the total length (in bytes) of the instructions.
int MacroAssembler::pd_patch_instruction_size(address insn_addr, address target) {
- Patcher patcher(insn_addr);
- return patcher.run(insn_addr, target);
+ return RelocActions::run(insn_addr, target);
}
int MacroAssembler::patch_oop(address insn_addr, address o) {
@@ -546,11 +515,11 @@ int MacroAssembler::patch_narrow_klass(address insn_addr, narrowKlass n) {
return 2 * NativeInstruction::instruction_size;
}
-address MacroAssembler::target_addr_for_insn_or_null(address insn_addr, unsigned insn) {
- if (NativeInstruction::is_ldrw_to_zr(address(&insn))) {
+address MacroAssembler::target_addr_for_insn_or_null(address insn_addr) {
+ if (NativeInstruction::is_ldrw_to_zr(insn_addr)) {
return nullptr;
}
- return MacroAssembler::target_addr_for_insn(insn_addr, insn);
+ return MacroAssembler::target_addr_for_insn(insn_addr);
}
void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool in_nmethod, Register tmp) {
@@ -634,12 +603,13 @@ void MacroAssembler::set_last_Java_frame(Register last_java_sp,
last_java_sp = esp;
}
- str(last_java_sp, Address(rthread, JavaThread::last_Java_sp_offset()));
-
// last_java_fp is optional
if (last_java_fp->is_valid()) {
str(last_java_fp, Address(rthread, JavaThread::last_Java_fp_offset()));
}
+
+ // We must set sp last.
+ str(last_java_sp, Address(rthread, JavaThread::last_Java_sp_offset()));
}
void MacroAssembler::set_last_Java_frame(Register last_java_sp,
@@ -5630,38 +5600,6 @@ void MacroAssembler::tlab_allocate(Register obj,
bs->tlab_allocate(this, obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case);
}
-void MacroAssembler::inc_held_monitor_count(Register tmp) {
- Address dst(rthread, JavaThread::held_monitor_count_offset());
-#ifdef ASSERT
- ldr(tmp, dst);
- increment(tmp);
- str(tmp, dst);
- Label ok;
- tbz(tmp, 63, ok);
- STOP("assert(held monitor count underflow)");
- should_not_reach_here();
- bind(ok);
-#else
- increment(dst);
-#endif
-}
-
-void MacroAssembler::dec_held_monitor_count(Register tmp) {
- Address dst(rthread, JavaThread::held_monitor_count_offset());
-#ifdef ASSERT
- ldr(tmp, dst);
- decrement(tmp);
- str(tmp, dst);
- Label ok;
- tbz(tmp, 63, ok);
- STOP("assert(held monitor count underflow)");
- should_not_reach_here();
- bind(ok);
-#else
- decrement(dst);
-#endif
-}
-
void MacroAssembler::verify_tlab() {
#ifdef ASSERT
if (UseTLAB && VerifyOops) {
diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
index fe2440fd3fd..d5a16e424e4 100644
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
@@ -676,16 +676,8 @@ public:
static bool needs_explicit_null_check(intptr_t offset);
static bool uses_implicit_null_check(void* address);
- static address target_addr_for_insn(address insn_addr, unsigned insn);
- static address target_addr_for_insn_or_null(address insn_addr, unsigned insn);
- static address target_addr_for_insn(address insn_addr) {
- unsigned insn = *(unsigned*)insn_addr;
- return target_addr_for_insn(insn_addr, insn);
- }
- static address target_addr_for_insn_or_null(address insn_addr) {
- unsigned insn = *(unsigned*)insn_addr;
- return target_addr_for_insn_or_null(insn_addr, insn);
- }
+ static address target_addr_for_insn(address insn_addr);
+ static address target_addr_for_insn_or_null(address insn_addr);
// Required platform-specific helpers for Label::patch_instructions.
// They _shadow_ the declarations in AbstractAssembler, which are undefined.
@@ -983,9 +975,6 @@ public:
void push_cont_fastpath(Register java_thread = rthread);
void pop_cont_fastpath(Register java_thread = rthread);
- void inc_held_monitor_count(Register tmp);
- void dec_held_monitor_count(Register tmp);
-
// Round up to a power of two
void round_to(Register reg, int modulus);
@@ -1623,7 +1612,7 @@ public:
FloatRegister p, FloatRegister z, FloatRegister t1);
void ghash_reduce_wide(int index, FloatRegister result, FloatRegister lo, FloatRegister hi,
FloatRegister p, FloatRegister z, FloatRegister t1);
- void ghash_processBlocks_wide(address p, Register state, Register subkeyH,
+ void ghash_processBlocks_wide(Label& p, Register state, Register subkeyH,
Register data, Register blocks, int unrolls);
diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp
index 84b85b7b445..25ec9cf9bdd 100644
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp
@@ -507,7 +507,7 @@ void MacroAssembler::ghash_modmul(FloatRegister result,
//
// Clobbers all vector registers.
//
-void MacroAssembler::ghash_processBlocks_wide(address field_polynomial, Register state,
+void MacroAssembler::ghash_processBlocks_wide(Label& field_polynomial, Register state,
Register subkeyH,
Register data, Register blocks, int unrolls) {
int register_stride = 7;
@@ -531,7 +531,10 @@ void MacroAssembler::ghash_processBlocks_wide(address field_polynomial, Register
FloatRegister p = v31;
eor(vzr, T16B, vzr, vzr); // zero register
- ldrq(p, field_polynomial); // The field polynomial
+ // load polynomial via label which must identify local data in the
+ // same code stub
+ adr(rscratch1, field_polynomial);
+ ldrq(p, rscratch1); // The field polynomial
ldrq(v0, Address(state));
ldrq(Hprime, Address(subkeyH));
diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp
index f5d7d9e4387..94694b58d2f 100644
--- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp
@@ -90,7 +90,6 @@ void Relocation::pd_set_call_destination(address x) {
void trampoline_stub_Relocation::pd_fix_owner_after_move() {
NativeCall* call = nativeCall_at(owner());
- assert(call->raw_destination() == owner(), "destination should be empty");
address trampoline = addr();
address dest = nativeCallTrampolineStub_at(trampoline)->destination();
if (!Assembler::reachable_from_branch_at(owner(), dest)) {
diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
index 748c3e8fb11..39609cbe0ac 100644
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
@@ -683,12 +683,12 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs,
- AdapterHandlerEntry* handler) {
- address i2c_entry = __ pc();
+ address entry_address[AdapterBlob::ENTRY_COUNT]) {
+ entry_address[AdapterBlob::I2C] = __ pc();
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
- address c2i_unverified_entry = __ pc();
+ entry_address[AdapterBlob::C2I_Unverified] = __ pc();
Label skip_fixup;
Register data = rscratch2;
@@ -718,10 +718,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ block_comment("} c2i_unverified_entry");
}
- address c2i_entry = __ pc();
+ entry_address[AdapterBlob::C2I] = __ pc();
// Class initialization barrier for static methods
- address c2i_no_clinit_check_entry = nullptr;
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
if (VM_Version::supports_fast_class_init_checks()) {
Label L_skip_barrier;
@@ -736,15 +736,13 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub()));
__ bind(L_skip_barrier);
- c2i_no_clinit_check_entry = __ pc();
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
}
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->c2i_entry_barrier(masm);
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
-
- handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
return;
}
@@ -987,11 +985,8 @@ static void fill_continuation_entry(MacroAssembler* masm) {
__ ldr(rscratch1, Address(rthread, JavaThread::cont_fastpath_offset()));
__ str(rscratch1, Address(sp, ContinuationEntry::parent_cont_fastpath_offset()));
- __ ldr(rscratch1, Address(rthread, JavaThread::held_monitor_count_offset()));
- __ str(rscratch1, Address(sp, ContinuationEntry::parent_held_monitor_count_offset()));
__ str(zr, Address(rthread, JavaThread::cont_fastpath_offset()));
- __ str(zr, Address(rthread, JavaThread::held_monitor_count_offset()));
}
// on entry, sp points to the ContinuationEntry
@@ -1007,50 +1002,6 @@ static void continuation_enter_cleanup(MacroAssembler* masm) {
#endif
__ ldr(rscratch1, Address(sp, ContinuationEntry::parent_cont_fastpath_offset()));
__ str(rscratch1, Address(rthread, JavaThread::cont_fastpath_offset()));
-
- if (CheckJNICalls) {
- // Check if this is a virtual thread continuation
- Label L_skip_vthread_code;
- __ ldrw(rscratch1, Address(sp, ContinuationEntry::flags_offset()));
- __ cbzw(rscratch1, L_skip_vthread_code);
-
- // If the held monitor count is > 0 and this vthread is terminating then
- // it failed to release a JNI monitor. So we issue the same log message
- // that JavaThread::exit does.
- __ ldr(rscratch1, Address(rthread, JavaThread::jni_monitor_count_offset()));
- __ cbz(rscratch1, L_skip_vthread_code);
-
- // Save return value potentially containing the exception oop in callee-saved R19.
- __ mov(r19, r0);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held));
- // Restore potential return value.
- __ mov(r0, r19);
-
- // For vthreads we have to explicitly zero the JNI monitor count of the carrier
- // on termination. The held count is implicitly zeroed below when we restore from
- // the parent held count (which has to be zero).
- __ str(zr, Address(rthread, JavaThread::jni_monitor_count_offset()));
-
- __ bind(L_skip_vthread_code);
- }
-#ifdef ASSERT
- else {
- // Check if this is a virtual thread continuation
- Label L_skip_vthread_code;
- __ ldrw(rscratch1, Address(sp, ContinuationEntry::flags_offset()));
- __ cbzw(rscratch1, L_skip_vthread_code);
-
- // See comment just above. If not checking JNI calls the JNI count is only
- // needed for assertion checking.
- __ str(zr, Address(rthread, JavaThread::jni_monitor_count_offset()));
-
- __ bind(L_skip_vthread_code);
- }
-#endif
-
- __ ldr(rscratch1, Address(sp, ContinuationEntry::parent_held_monitor_count_offset()));
- __ str(rscratch1, Address(rthread, JavaThread::held_monitor_count_offset()));
-
__ ldr(rscratch2, Address(sp, ContinuationEntry::parent_offset()));
__ str(rscratch2, Address(rthread, JavaThread::cont_entry_offset()));
__ add(rfp, sp, (int)ContinuationEntry::size());
@@ -1763,9 +1714,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
Label lock_done;
if (method->is_synchronized()) {
- Label count;
- const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes();
-
// Get the handle (the 2nd argument)
__ mov(oop_handle_reg, c_rarg1);
diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
index 3f1a9f7daaa..ffe5afd93cb 100644
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
@@ -802,7 +802,7 @@ class StubGenerator: public StubCodeGenerator {
//
// s and d are adjusted to point to the remaining words to copy
//
- void generate_copy_longs(StubId stub_id, DecoratorSet decorators, Label &start, Register s, Register d, Register count) {
+ address generate_copy_longs(StubId stub_id, DecoratorSet decorators, Register s, Register d, Register count) {
BasicType type;
copy_direction direction;
@@ -854,7 +854,7 @@ class StubGenerator: public StubCodeGenerator {
StubCodeMark mark(this, stub_id);
- __ bind(start);
+ address start = __ pc();
Label unaligned_copy_long;
if (AvoidUnalignedAccesses) {
@@ -894,9 +894,9 @@ class StubGenerator: public StubCodeGenerator {
int prefetch = PrefetchCopyIntervalInBytes;
bool use_stride = false;
if (direction == copy_backwards) {
- use_stride = prefetch > 256;
- prefetch = -prefetch;
- if (use_stride) __ mov(stride, prefetch);
+ use_stride = prefetch > 256;
+ prefetch = -prefetch;
+ if (use_stride) __ mov(stride, prefetch);
}
__ bind(again);
@@ -1026,9 +1026,9 @@ class StubGenerator: public StubCodeGenerator {
int prefetch = PrefetchCopyIntervalInBytes;
bool use_stride = false;
if (direction == copy_backwards) {
- use_stride = prefetch > 256;
- prefetch = -prefetch;
- if (use_stride) __ mov(stride, prefetch);
+ use_stride = prefetch > 256;
+ prefetch = -prefetch;
+ if (use_stride) __ mov(stride, prefetch);
}
__ bind(again);
@@ -1037,15 +1037,15 @@ class StubGenerator: public StubCodeGenerator {
__ prfm(use_stride ? Address(s, stride) : Address(s, prefetch), PLDL1KEEP);
if (direction == copy_forwards) {
- // allowing for the offset of -8 the store instructions place
- // registers into the target 64 bit block at the following
- // offsets
- //
- // t0 at offset 0
- // t1 at offset 8, t2 at offset 16
- // t3 at offset 24, t4 at offset 32
- // t5 at offset 40, t6 at offset 48
- // t7 at offset 56
+ // allowing for the offset of -8 the store instructions place
+ // registers into the target 64 bit block at the following
+ // offsets
+ //
+ // t0 at offset 0
+ // t1 at offset 8, t2 at offset 16
+ // t3 at offset 24, t4 at offset 32
+ // t5 at offset 40, t6 at offset 48
+ // t7 at offset 56
bs.copy_store_at_8(Address(d, 1 * unit), t0);
bs.copy_store_at_16(Address(d, 2 * unit), t1, t2);
@@ -1057,18 +1057,18 @@ class StubGenerator: public StubCodeGenerator {
bs.copy_store_at_8(Address(__ pre(d, 8 * unit)), t7);
bs.copy_load_at_16(t6, t7, Address(__ pre(s, 8 * unit)));
} else {
- // d was not offset when we started so the registers are
- // written into the 64 bit block preceding d with the following
- // offsets
- //
- // t1 at offset -8
- // t3 at offset -24, t0 at offset -16
- // t5 at offset -48, t2 at offset -32
- // t7 at offset -56, t4 at offset -48
- // t6 at offset -64
- //
- // note that this matches the offsets previously noted for the
- // loads
+ // d was not offset when we started so the registers are
+ // written into the 64 bit block preceding d with the following
+ // offsets
+ //
+ // t1 at offset -8
+ // t3 at offset -24, t0 at offset -16
+ // t5 at offset -48, t2 at offset -32
+ // t7 at offset -56, t4 at offset -48
+ // t6 at offset -64
+ //
+ // note that this matches the offsets previously noted for the
+ // loads
bs.copy_store_at_8(Address(d, 1 * unit), t1);
bs.copy_store_at_16(Address(d, 3 * unit), t3, t0);
@@ -1109,10 +1109,10 @@ class StubGenerator: public StubCodeGenerator {
{
Label L1, L2;
__ tbz(count, exact_log2(4), L1);
- // this is the same as above but copying only 4 longs hence
- // with only one intervening stp between the str instructions
- // but note that the offsets and registers still follow the
- // same pattern
+ // this is the same as above but copying only 4 longs hence
+ // with only one intervening stp between the str instructions
+ // but note that the offsets and registers still follow the
+ // same pattern
bs.copy_load_at_16(t0, t1, Address(s, 2 * unit));
bs.copy_load_at_16(t2, t3, Address(__ pre(s, 4 * unit)));
if (direction == copy_forwards) {
@@ -1127,10 +1127,10 @@ class StubGenerator: public StubCodeGenerator {
__ bind(L1);
__ tbz(count, 1, L2);
- // this is the same as above but copying only 2 longs hence
- // there is no intervening stp between the str instructions
- // but note that the offset and register patterns are still
- // the same
+ // this is the same as above but copying only 2 longs hence
+ // there is no intervening stp between the str instructions
+ // but note that the offset and register patterns are still
+ // the same
bs.copy_load_at_16(t0, t1, Address(__ pre(s, 2 * unit)));
if (direction == copy_forwards) {
bs.copy_store_at_8(Address(d, 1 * unit), t0);
@@ -1141,18 +1141,20 @@ class StubGenerator: public StubCodeGenerator {
}
__ bind(L2);
- // for forwards copy we need to re-adjust the offsets we
- // applied so that s and d are follow the last words written
+ // for forwards copy we need to re-adjust the offsets we
+ // applied so that s and d are follow the last words written
- if (direction == copy_forwards) {
- __ add(s, s, 16);
- __ add(d, d, 8);
- }
+ if (direction == copy_forwards) {
+ __ add(s, s, 16);
+ __ add(d, d, 8);
+ }
}
__ ret(lr);
- }
+ }
+
+ return start;
}
// Small copy: less than 16 bytes.
@@ -1206,10 +1208,6 @@ class StubGenerator: public StubCodeGenerator {
}
}
- Label copy_f, copy_b;
- Label copy_obj_f, copy_obj_b;
- Label copy_obj_uninit_f, copy_obj_uninit_b;
-
// All-singing all-dancing memory copy.
//
// Copy count units of memory from s to d. The size of a unit is
@@ -1447,19 +1445,19 @@ class StubGenerator: public StubCodeGenerator {
}
if (direction == copy_forwards) {
if (type != T_OBJECT) {
- __ bl(copy_f);
+ __ bl(StubRoutines::aarch64::copy_byte_f());
} else if ((decorators & IS_DEST_UNINITIALIZED) != 0) {
- __ bl(copy_obj_uninit_f);
+ __ bl(StubRoutines::aarch64::copy_oop_uninit_f());
} else {
- __ bl(copy_obj_f);
+ __ bl(StubRoutines::aarch64::copy_oop_f());
}
} else {
if (type != T_OBJECT) {
- __ bl(copy_b);
+ __ bl(StubRoutines::aarch64::copy_byte_b());
} else if ((decorators & IS_DEST_UNINITIALIZED) != 0) {
- __ bl(copy_obj_uninit_b);
+ __ bl(StubRoutines::aarch64::copy_oop_uninit_b());
} else {
- __ bl(copy_obj_b);
+ __ bl(StubRoutines::aarch64::copy_oop_b());
}
}
@@ -1522,11 +1520,11 @@ class StubGenerator: public StubCodeGenerator {
// the hardware handle it. The two dwords within qwords that span
// cache line boundaries will still be loaded and stored atomically.
//
- // Side Effects: entry is set to the (post push) entry point so it
- // can be used by the corresponding conjoint copy
- // method
+ // Side Effects: nopush_entry is set to the (post push) entry point
+ // so it can be used by the corresponding conjoint
+ // copy method
//
- address generate_disjoint_copy(StubId stub_id, address *entry) {
+ address generate_disjoint_copy(StubId stub_id, address *nopush_entry) {
Register s = c_rarg0, d = c_rarg1, count = c_rarg2;
RegSet saved_reg = RegSet::of(s, d, count);
int size;
@@ -1615,8 +1613,8 @@ class StubGenerator: public StubCodeGenerator {
address start = __ pc();
__ enter();
- if (entry != nullptr) {
- *entry = __ pc();
+ if (nopush_entry != nullptr) {
+ *nopush_entry = __ pc();
// caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
BLOCK_COMMENT("Entry:");
}
@@ -1679,10 +1677,10 @@ class StubGenerator: public StubCodeGenerator {
// cache line boundaries will still be loaded and stored atomically.
//
// Side Effects:
- // entry is set to the no-overlap entry point so it can be used by
- // some other conjoint copy method
+ // nopush_entry is set to the no-overlap entry point so it can be
+ // used by some other conjoint copy method
//
- address generate_conjoint_copy(StubId stub_id, address nooverlap_target, address *entry) {
+ address generate_conjoint_copy(StubId stub_id, address nooverlap_target, address *nopush_entry) {
Register s = c_rarg0, d = c_rarg1, count = c_rarg2;
RegSet saved_regs = RegSet::of(s, d, count);
int size;
@@ -1769,16 +1767,19 @@ class StubGenerator: public StubCodeGenerator {
address start = __ pc();
__ enter();
- if (entry != nullptr) {
- *entry = __ pc();
+ if (nopush_entry != nullptr) {
+ *nopush_entry = __ pc();
// caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
BLOCK_COMMENT("Entry:");
}
// use fwd copy when (d-s) above_equal (count*size)
+ Label L_overlapping;
__ sub(rscratch1, d, s);
__ cmp(rscratch1, count, Assembler::LSL, exact_log2(size));
- __ br(Assembler::HS, nooverlap_target);
+ __ br(Assembler::LO, L_overlapping);
+ __ b(RuntimeAddress(nooverlap_target));
+ __ bind(L_overlapping);
DecoratorSet decorators = IN_HEAP | IS_ARRAY;
if (dest_uninitialized) {
@@ -1850,7 +1851,7 @@ class StubGenerator: public StubCodeGenerator {
// r0 == 0 - success
// r0 == -1^K - failure, where K is partial transfer count
//
- address generate_checkcast_copy(StubId stub_id, address *entry) {
+ address generate_checkcast_copy(StubId stub_id, address *nopush_entry) {
bool dest_uninitialized;
switch (stub_id) {
case StubId::stubgen_checkcast_arraycopy_id:
@@ -1911,8 +1912,8 @@ class StubGenerator: public StubCodeGenerator {
#endif //ASSERT
// Caller of this entry point must set up the argument registers.
- if (entry != nullptr) {
- *entry = __ pc();
+ if (nopush_entry != nullptr) {
+ *nopush_entry = __ pc();
BLOCK_COMMENT("Entry:");
}
@@ -2724,13 +2725,21 @@ class StubGenerator: public StubCodeGenerator {
}
void generate_arraycopy_stubs() {
- address entry;
- address entry_jbyte_arraycopy;
- address entry_jshort_arraycopy;
- address entry_jint_arraycopy;
- address entry_oop_arraycopy;
- address entry_jlong_arraycopy;
- address entry_checkcast_arraycopy;
+ // Some copy stubs publish a normal entry and then a 2nd 'fallback'
+ // entry immediately following their stack push. This can be used
+ // as a post-push branch target for compatible stubs when they
+ // identify a special case that can be handled by the fallback
+ // stub e.g a disjoint copy stub may be use as a special case
+ // fallback for its compatible conjoint copy stub.
+ //
+ // A no push entry is always returned in the following local and
+ // then published by assigning to the appropriate entry field in
+ // class StubRoutines. The entry value is then passed to the
+ // generator for the compatible stub. That means the entry must be
+ // listed when saving to/restoring from the AOT cache, ensuring
+ // that the inter-stub jumps are noted at AOT-cache save and
+ // relocated at AOT cache load.
+ address nopush_entry;
// generate the common exit first so later stubs can rely on it if
// they want an UnsafeMemoryAccess exit non-local to the stub
@@ -2738,83 +2747,123 @@ class StubGenerator: public StubCodeGenerator {
// register the stub as the default exit with class UnsafeMemoryAccess
UnsafeMemoryAccess::set_common_exit_stub_pc(StubRoutines::_unsafecopy_common_exit);
- generate_copy_longs(StubId::stubgen_copy_byte_f_id, IN_HEAP | IS_ARRAY, copy_f, r0, r1, r15);
- generate_copy_longs(StubId::stubgen_copy_byte_b_id, IN_HEAP | IS_ARRAY, copy_b, r0, r1, r15);
+ // generate and publish arch64-specific bulk copy routines first
+ // so we can call them from other copy stubs
+ StubRoutines::aarch64::_copy_byte_f = generate_copy_longs(StubId::stubgen_copy_byte_f_id, IN_HEAP | IS_ARRAY, r0, r1, r15);
+ StubRoutines::aarch64::_copy_byte_b = generate_copy_longs(StubId::stubgen_copy_byte_b_id, IN_HEAP | IS_ARRAY, r0, r1, r15);
- generate_copy_longs(StubId::stubgen_copy_oop_f_id, IN_HEAP | IS_ARRAY, copy_obj_f, r0, r1, r15);
- generate_copy_longs(StubId::stubgen_copy_oop_b_id, IN_HEAP | IS_ARRAY, copy_obj_b, r0, r1, r15);
+ StubRoutines::aarch64::_copy_oop_f = generate_copy_longs(StubId::stubgen_copy_oop_f_id, IN_HEAP | IS_ARRAY, r0, r1, r15);
+ StubRoutines::aarch64::_copy_oop_b = generate_copy_longs(StubId::stubgen_copy_oop_b_id, IN_HEAP | IS_ARRAY, r0, r1, r15);
- generate_copy_longs(StubId::stubgen_copy_oop_uninit_f_id, IN_HEAP | IS_ARRAY | IS_DEST_UNINITIALIZED, copy_obj_uninit_f, r0, r1, r15);
- generate_copy_longs(StubId::stubgen_copy_oop_uninit_b_id, IN_HEAP | IS_ARRAY | IS_DEST_UNINITIALIZED, copy_obj_uninit_b, r0, r1, r15);
+ StubRoutines::aarch64::_copy_oop_uninit_f = generate_copy_longs(StubId::stubgen_copy_oop_uninit_f_id, IN_HEAP | IS_ARRAY | IS_DEST_UNINITIALIZED, r0, r1, r15);
+ StubRoutines::aarch64::_copy_oop_uninit_b = generate_copy_longs(StubId::stubgen_copy_oop_uninit_b_id, IN_HEAP | IS_ARRAY | IS_DEST_UNINITIALIZED, r0, r1, r15);
StubRoutines::aarch64::_zero_blocks = generate_zero_blocks();
//*** jbyte
// Always need aligned and unaligned versions
- StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id, &entry);
- StubRoutines::_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_jbyte_arraycopy_id, entry, &entry_jbyte_arraycopy);
- StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jbyte_disjoint_arraycopy_id, &entry);
- StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jbyte_arraycopy_id, entry, nullptr);
+ StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jbyte_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_jbyte_arraycopy_id, StubRoutines::_jbyte_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jbyte_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jbyte_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_jbyte_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jbyte_arraycopy_id, StubRoutines::_arrayof_jbyte_disjoint_arraycopy_nopush, nullptr);
//*** jshort
// Always need aligned and unaligned versions
- StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jshort_disjoint_arraycopy_id, &entry);
- StubRoutines::_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_jshort_arraycopy_id, entry, &entry_jshort_arraycopy);
- StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jshort_disjoint_arraycopy_id, &entry);
- StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jshort_arraycopy_id, entry, nullptr);
+ StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jshort_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jshort_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_jshort_arraycopy_id, StubRoutines::_jshort_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is used by generic/unsafe copy
+ StubRoutines::_jshort_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jshort_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_jshort_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jshort_arraycopy_id, StubRoutines::_arrayof_jshort_disjoint_arraycopy_nopush, nullptr);
//*** jint
// Aligned versions
- StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jint_disjoint_arraycopy_id, &entry);
- StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jint_arraycopy_id, entry, &entry_jint_arraycopy);
+ StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jint_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_jint_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jint_arraycopy_id, StubRoutines::_arrayof_jint_disjoint_arraycopy_nopush, nullptr);
// In 64 bit we need both aligned and unaligned versions of jint arraycopy.
- // entry_jint_arraycopy always points to the unaligned version
- StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &entry);
- StubRoutines::_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_jint_arraycopy_id, entry, &entry_jint_arraycopy);
+ // jint_arraycopy_nopush always points to the unaligned version
+ StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jint_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_jint_arraycopy_id, StubRoutines::_jint_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jint_arraycopy_nopush = nopush_entry;
//*** jlong
// It is always aligned
- StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id, &entry);
- StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jlong_arraycopy_id, entry, &entry_jlong_arraycopy);
+ StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jlong_arraycopy_id, StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jlong_arraycopy_nopush = nopush_entry;
+ // disjoint normal/nopush and conjoint normal entries are not
+ // generated since the arrayof versions are the same
StubRoutines::_jlong_disjoint_arraycopy = StubRoutines::_arrayof_jlong_disjoint_arraycopy;
+ StubRoutines::_jlong_disjoint_arraycopy_nopush = StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush;
StubRoutines::_jlong_arraycopy = StubRoutines::_arrayof_jlong_arraycopy;
//*** oops
{
- // With compressed oops we need unaligned versions; notice that
- // we overwrite entry_oop_arraycopy.
- bool aligned = !UseCompressedOops;
-
StubRoutines::_arrayof_oop_disjoint_arraycopy
- = generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_id, &entry);
+ = generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush = nopush_entry;
StubRoutines::_arrayof_oop_arraycopy
- = generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_id, entry, &entry_oop_arraycopy);
+ = generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_id, StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint arrayof nopush entry is needed by generic/unsafe copy
+ StubRoutines::_oop_arraycopy_nopush = nopush_entry;
// Aligned versions without pre-barriers
StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit
- = generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_uninit_id, &entry);
+ = generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_uninit_id, &nopush_entry);
+ // disjoint arrayof+uninit nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush = nopush_entry;
+ // note that we don't need a returned nopush entry because the
+ // generic/unsafe copy does not cater for uninit arrays.
StubRoutines::_arrayof_oop_arraycopy_uninit
- = generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_uninit_id, entry, nullptr);
+ = generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_uninit_id, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush, nullptr);
}
+ // for oop copies reuse arrayof entries for non-arrayof cases
StubRoutines::_oop_disjoint_arraycopy = StubRoutines::_arrayof_oop_disjoint_arraycopy;
+ StubRoutines::_oop_disjoint_arraycopy_nopush = StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush;
StubRoutines::_oop_arraycopy = StubRoutines::_arrayof_oop_arraycopy;
StubRoutines::_oop_disjoint_arraycopy_uninit = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit;
+ StubRoutines::_oop_disjoint_arraycopy_uninit_nopush = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush;
StubRoutines::_oop_arraycopy_uninit = StubRoutines::_arrayof_oop_arraycopy_uninit;
- StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &entry_checkcast_arraycopy);
+ StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &nopush_entry);
+ // checkcast nopush entry is needed by generic copy
+ StubRoutines::_checkcast_arraycopy_nopush = nopush_entry;
+ // note that we don't need a returned nopush entry because the
+ // generic copy does not cater for uninit arrays.
StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_uninit_id, nullptr);
- StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(entry_jbyte_arraycopy,
- entry_jshort_arraycopy,
- entry_jint_arraycopy,
- entry_jlong_arraycopy);
+ // unsafe arraycopy may fallback on conjoint stubs
+ StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(StubRoutines::_jbyte_arraycopy_nopush,
+ StubRoutines::_jshort_arraycopy_nopush,
+ StubRoutines::_jint_arraycopy_nopush,
+ StubRoutines::_jlong_arraycopy_nopush);
- StubRoutines::_generic_arraycopy = generate_generic_copy(entry_jbyte_arraycopy,
- entry_jshort_arraycopy,
- entry_jint_arraycopy,
- entry_oop_arraycopy,
- entry_jlong_arraycopy,
- entry_checkcast_arraycopy);
+ // generic arraycopy may fallback on conjoint stubs
+ StubRoutines::_generic_arraycopy = generate_generic_copy(StubRoutines::_jbyte_arraycopy_nopush,
+ StubRoutines::_jshort_arraycopy_nopush,
+ StubRoutines::_jint_arraycopy_nopush,
+ StubRoutines::_oop_arraycopy_nopush,
+ StubRoutines::_jlong_arraycopy_nopush,
+ StubRoutines::_checkcast_arraycopy_nopush);
StubRoutines::_jbyte_fill = generate_fill(StubId::stubgen_jbyte_fill_id);
StubRoutines::_jshort_fill = generate_fill(StubId::stubgen_jshort_fill_id);
@@ -3402,14 +3451,9 @@ class StubGenerator: public StubCodeGenerator {
// counter = c_rarg7 - 16 bytes of CTR
// return - number of processed bytes
address generate_galoisCounterMode_AESCrypt() {
- address ghash_polynomial = __ pc();
- __ emit_int64(0x87); // The low-order bits of the field
- // polynomial (i.e. p = z^7+z^2+z+1)
- // repeated in the low and high parts of a
- // 128-bit vector
- __ emit_int64(0x87);
+ Label ghash_polynomial; // local data generated after code
- __ align(CodeEntryAlignment);
+ __ align(CodeEntryAlignment);
StubId stub_id = StubId::stubgen_galoisCounterMode_AESCrypt_id;
StubCodeMark mark(this, stub_id);
address start = __ pc();
@@ -3514,7 +3558,17 @@ class StubGenerator: public StubCodeGenerator {
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(lr);
- return start;
+
+ // bind label and generate polynomial data
+ __ align(wordSize * 2);
+ __ bind(ghash_polynomial);
+ __ emit_int64(0x87); // The low-order bits of the field
+ // polynomial (i.e. p = z^7+z^2+z+1)
+ // repeated in the low and high parts of a
+ // 128-bit vector
+ __ emit_int64(0x87);
+
+ return start;
}
class Cached64Bytes {
@@ -4559,16 +4613,6 @@ class StubGenerator: public StubCodeGenerator {
// by the second lane from all vectors and so on.
address generate_chacha20Block_blockpar() {
Label L_twoRounds, L_cc20_const;
- // The constant data is broken into two 128-bit segments to be loaded
- // onto FloatRegisters. The first 128 bits are a counter add overlay
- // that adds +0/+1/+2/+3 to the vector holding replicated state[12].
- // The second 128-bits is a table constant used for 8-bit left rotations.
- __ BIND(L_cc20_const);
- __ emit_int64(0x0000000100000000UL);
- __ emit_int64(0x0000000300000002UL);
- __ emit_int64(0x0605040702010003UL);
- __ emit_int64(0x0E0D0C0F0A09080BUL);
-
__ align(CodeEntryAlignment);
StubId stub_id = StubId::stubgen_chacha20Block_id;
StubCodeMark mark(this, stub_id);
@@ -4716,6 +4760,17 @@ class StubGenerator: public StubCodeGenerator {
__ leave();
__ ret(lr);
+ // bind label and generate local constant data used by this stub
+ // The constant data is broken into two 128-bit segments to be loaded
+ // onto FloatRegisters. The first 128 bits are a counter add overlay
+ // that adds +0/+1/+2/+3 to the vector holding replicated state[12].
+ // The second 128-bits is a table constant used for 8-bit left rotations.
+ __ BIND(L_cc20_const);
+ __ emit_int64(0x0000000100000000UL);
+ __ emit_int64(0x0000000300000002UL);
+ __ emit_int64(0x0605040702010003UL);
+ __ emit_int64(0x0E0D0C0F0A09080BUL);
+
return start;
}
@@ -6036,10 +6091,6 @@ class StubGenerator: public StubCodeGenerator {
address generate_kyber12To16() {
Label L_F00, L_loop, L_end;
- __ BIND(L_F00);
- __ emit_int64(0x0f000f000f000f00);
- __ emit_int64(0x0f000f000f000f00);
-
__ align(CodeEntryAlignment);
StubId stub_id = StubId::stubgen_kyber12To16_id;
StubCodeMark mark(this, stub_id);
@@ -6233,6 +6284,11 @@ class StubGenerator: public StubCodeGenerator {
__ mov(r0, zr); // return 0
__ ret(lr);
+ // bind label and generate constant data used by this stub
+ __ BIND(L_F00);
+ __ emit_int64(0x0f000f000f000f00);
+ __ emit_int64(0x0f000f000f000f00);
+
return start;
}
@@ -9642,14 +9698,7 @@ class StubGenerator: public StubCodeGenerator {
StubId stub_id = StubId::stubgen_ghash_processBlocks_id;
StubCodeMark mark(this, stub_id);
- __ align(wordSize * 2);
- address p = __ pc();
- __ emit_int64(0x87); // The low-order bits of the field
- // polynomial (i.e. p = z^7+z^2+z+1)
- // repeated in the low and high parts of a
- // 128-bit vector
- __ emit_int64(0x87);
-
+ Label polynomial; // local data generated at end of stub
__ align(CodeEntryAlignment);
address start = __ pc();
@@ -9661,7 +9710,8 @@ class StubGenerator: public StubCodeGenerator {
FloatRegister vzr = v30;
__ eor(vzr, __ T16B, vzr, vzr); // zero register
- __ ldrq(v24, p); // The field polynomial
+ __ adr(rscratch1, polynomial);
+ __ ldrq(v24, rscratch1); // The field polynomial
__ ldrq(v0, Address(state));
__ ldrq(v1, Address(subkeyH));
@@ -9701,6 +9751,15 @@ class StubGenerator: public StubCodeGenerator {
__ st1(v0, __ T16B, state);
__ ret(lr);
+ // bind label and generate local polynomial data
+ __ align(wordSize * 2);
+ __ bind(polynomial);
+ __ emit_int64(0x87); // The low-order bits of the field
+ // polynomial (i.e. p = z^7+z^2+z+1)
+ // repeated in the low and high parts of a
+ // 128-bit vector
+ __ emit_int64(0x87);
+
return start;
}
@@ -9709,14 +9768,7 @@ class StubGenerator: public StubCodeGenerator {
StubId stub_id = StubId::stubgen_ghash_processBlocks_wide_id;
StubCodeMark mark(this, stub_id);
- __ align(wordSize * 2);
- address p = __ pc();
- __ emit_int64(0x87); // The low-order bits of the field
- // polynomial (i.e. p = z^7+z^2+z+1)
- // repeated in the low and high parts of a
- // 128-bit vector
- __ emit_int64(0x87);
-
+ Label polynomial; // local data generated after stub
__ align(CodeEntryAlignment);
address start = __ pc();
@@ -9738,7 +9790,7 @@ class StubGenerator: public StubCodeGenerator {
__ st1(v8, v9, v10, v11, __ T16B, Address(sp));
}
- __ ghash_processBlocks_wide(p, state, subkeyH, data, blocks, unroll);
+ __ ghash_processBlocks_wide(polynomial, state, subkeyH, data, blocks, unroll);
if (unroll > 1) {
// And restore state
@@ -9751,7 +9803,17 @@ class StubGenerator: public StubCodeGenerator {
__ ret(lr);
+ // bind label and generate polynomial data
+ __ align(wordSize * 2);
+ __ bind(polynomial);
+ __ emit_int64(0x87); // The low-order bits of the field
+ // polynomial (i.e. p = z^7+z^2+z+1)
+ // repeated in the low and high parts of a
+ // 128-bit vector
+ __ emit_int64(0x87);
+
return start;
+
}
void generate_base64_encode_simdround(Register src, Register dst,
diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
index 2ccde98d98d..f4774f31bbd 100644
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
@@ -168,6 +168,7 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
Register temp_reg, bool load_bc_into_bc_reg/*=true*/,
int byte_no)
{
+ assert_different_registers(bc_reg, temp_reg);
if (!RewriteBytecodes) return;
Label L_patch_done;
@@ -231,9 +232,12 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
__ stop("patching the wrong bytecode");
__ bind(L_okay);
#endif
-
- // patch bytecode
- __ strb(bc_reg, at_bcp(0));
+ // Patch bytecode with release store to coordinate with ResolvedFieldEntry loads
+ // in fast bytecode codelets. load_field_entry has a memory barrier that gains
+ // the needed ordering, together with control dependency on entering the fast codelet
+ // itself.
+ __ lea(temp_reg, at_bcp(0));
+ __ stlrb(bc_reg, temp_reg);
__ bind(L_patch_done);
}
@@ -2269,7 +2273,7 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
assert_different_registers(Rcache, index, temp);
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
- Label resolved, clinit_barrier_slow;
+ Label L_clinit_barrier_slow, L_done;
Bytecodes::Code code = bytecode();
__ load_method_entry(Rcache, index);
@@ -2284,11 +2288,20 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
// Load-acquire the bytecode to match store-release in InterpreterRuntime
__ ldarb(temp, temp);
__ subs(zr, temp, (int) code); // have we resolved this bytecode?
- __ br(Assembler::EQ, resolved);
+
+ // Class initialization barrier for static methods
+ if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
+ __ br(Assembler::NE, L_clinit_barrier_slow);
+ __ ldr(temp, Address(Rcache, in_bytes(ResolvedMethodEntry::method_offset())));
+ __ load_method_holder(temp, temp);
+ __ clinit_barrier(temp, rscratch1, &L_done, /*L_slow_path*/ nullptr);
+ __ bind(L_clinit_barrier_slow);
+ } else {
+ __ br(Assembler::EQ, L_done);
+ }
// resolve first time through
// Class initialization barrier slow path lands here as well.
- __ bind(clinit_barrier_slow);
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ mov(temp, (int) code);
__ call_VM(noreg, entry, temp);
@@ -2297,14 +2310,7 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
__ load_method_entry(Rcache, index);
// n.b. unlike x86 Rcache is now rcpool plus the indexed offset
// so all clients ofthis method must be modified accordingly
- __ bind(resolved);
-
- // Class initialization barrier for static methods
- if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
- __ ldr(temp, Address(Rcache, in_bytes(ResolvedMethodEntry::method_offset())));
- __ load_method_holder(temp, temp);
- __ clinit_barrier(temp, rscratch1, nullptr, &clinit_barrier_slow);
- }
+ __ bind(L_done);
}
void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
@@ -2313,7 +2319,7 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
const Register temp = r19;
assert_different_registers(Rcache, index, temp);
- Label resolved;
+ Label L_clinit_barrier_slow, L_done;
Bytecodes::Code code = bytecode();
switch (code) {
@@ -2332,16 +2338,29 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
// Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in()
__ ldarb(temp, temp);
__ subs(zr, temp, (int) code); // have we resolved this bytecode?
- __ br(Assembler::EQ, resolved);
+
+ // Class initialization barrier for static fields
+ if (VM_Version::supports_fast_class_init_checks() &&
+ (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) {
+ const Register field_holder = temp;
+
+ __ br(Assembler::NE, L_clinit_barrier_slow);
+ __ ldr(field_holder, Address(Rcache, in_bytes(ResolvedFieldEntry::field_holder_offset())));
+ __ clinit_barrier(field_holder, rscratch1, &L_done, /*L_slow_path*/ nullptr);
+ __ bind(L_clinit_barrier_slow);
+ } else {
+ __ br(Assembler::EQ, L_done);
+ }
// resolve first time through
+ // Class initialization barrier slow path lands here as well.
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ mov(temp, (int) code);
__ call_VM(noreg, entry, temp);
// Update registers with resolved info
__ load_field_entry(Rcache, index);
- __ bind(resolved);
+ __ bind(L_done);
}
void TemplateTable::load_resolved_field_entry(Register obj,
@@ -3079,6 +3098,7 @@ void TemplateTable::fast_storefield(TosState state)
// R1: field offset, R2: field holder, R5: flags
load_resolved_field_entry(r2, r2, noreg, r1, r5);
+ __ verify_field_offset(r1);
{
Label notVolatile;
@@ -3168,6 +3188,8 @@ void TemplateTable::fast_accessfield(TosState state)
__ load_field_entry(r2, r1);
__ load_sized_value(r1, Address(r2, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/);
+ __ verify_field_offset(r1);
+
__ load_unsigned_byte(r3, Address(r2, in_bytes(ResolvedFieldEntry::flags_offset())));
// r0: object
@@ -3234,7 +3256,9 @@ void TemplateTable::fast_xaccess(TosState state)
__ ldr(r0, aaddress(0));
// access constant pool cache
__ load_field_entry(r2, r3, 2);
+
__ load_sized_value(r1, Address(r2, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/);
+ __ verify_field_offset(r1);
// 8179954: We need to make sure that the code generated for
// volatile accesses forms a sequentially-consistent set of
diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
index 308deeaf5e2..a04e9defa4b 100644
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, Red Hat Inc. All rights reserved.
+ * Copyright 2025 Arm Limited and/or its affiliates.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -222,10 +223,13 @@ void VM_Version::initialize() {
// Neoverse
// N1: 0xd0c
// N2: 0xd49
+ // N3: 0xd8e
// V1: 0xd40
// V2: 0xd4f
+ // V3: 0xd84
if (_cpu == CPU_ARM && (model_is(0xd0c) || model_is(0xd49) ||
- model_is(0xd40) || model_is(0xd4f))) {
+ model_is(0xd40) || model_is(0xd4f) ||
+ model_is(0xd8e) || model_is(0xd84))) {
if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) {
FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true);
}
@@ -260,7 +264,9 @@ void VM_Version::initialize() {
// Neoverse
// V1: 0xd40
// V2: 0xd4f
- if (_cpu == CPU_ARM && (model_is(0xd40) || model_is(0xd4f))) {
+ // V3: 0xd84
+ if (_cpu == CPU_ARM &&
+ (model_is(0xd40) || model_is(0xd4f) || model_is(0xd84))) {
if (FLAG_IS_DEFAULT(UseCryptoPmullForCRC32)) {
FLAG_SET_DEFAULT(UseCryptoPmullForCRC32, true);
}
diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad
index 2835a256153..31a442be624 100644
--- a/src/hotspot/cpu/arm/arm.ad
+++ b/src/hotspot/cpu/arm/arm.ad
@@ -1131,31 +1131,27 @@ bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
}
// Register for DIVI projection of divmodI
-RegMask Matcher::divI_proj_mask() {
+const RegMask& Matcher::divI_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for MODI projection of divmodI
-RegMask Matcher::modI_proj_mask() {
+const RegMask& Matcher::modI_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for DIVL projection of divmodL
-RegMask Matcher::divL_proj_mask() {
+const RegMask& Matcher::divL_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for MODL projection of divmodL
-RegMask Matcher::modL_proj_mask() {
+const RegMask& Matcher::modL_proj_mask() {
ShouldNotReachHere();
- return RegMask();
-}
-
-const RegMask Matcher::method_handle_invoke_SP_save_mask() {
- return FP_REGP_mask();
+ return RegMask::EMPTY;
}
bool maybe_far_call(const CallNode *n) {
@@ -1248,23 +1244,6 @@ encode %{
__ set_inst_mark(mark);
%}
- enc_class preserve_SP %{
- // preserve mark
- address mark = __ inst_mark();
- DEBUG_ONLY(int off0 = __ offset());
- // FP is preserved across all calls, even compiled calls.
- // Use it to preserve SP in places where the callee might change the SP.
- __ mov(Rmh_SP_save, SP);
- DEBUG_ONLY(int off1 = __ offset());
- assert(off1 - off0 == 4, "correct size prediction");
- // restore mark
- __ set_inst_mark(mark);
- %}
-
- enc_class restore_SP %{
- __ mov(SP, Rmh_SP_save);
- %}
-
enc_class Java_Dynamic_Call (method meth) %{
Register R8_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode());
assert(R8_ic_reg == Ricklass, "should be");
@@ -8799,7 +8778,6 @@ instruct safePoint_poll(iRegP poll, R12RegI tmp, flagsReg icc) %{
// Call Java Static Instruction
instruct CallStaticJavaDirect( method meth ) %{
match(CallStaticJava);
- predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke());
effect(USE meth);
ins_cost(CALL_COST);
@@ -8808,20 +8786,6 @@ instruct CallStaticJavaDirect( method meth ) %{
ins_pipe(simple_call);
%}
-// Call Java Static Instruction (method handle version)
-instruct CallStaticJavaHandle( method meth ) %{
- match(CallStaticJava);
- predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke());
- effect(USE meth);
- // FP is saved by all callees (for interpreter stack correction).
- // We use it here for a similar purpose, in {preserve,restore}_FP.
-
- ins_cost(CALL_COST);
- format %{ "CALL,static/MethodHandle ==> " %}
- ins_encode( SetInstMark, preserve_SP, Java_Static_Call( meth ), restore_SP, call_epilog, ClearInstMark );
- ins_pipe(simple_call);
-%}
-
// Call Java Dynamic Instruction
instruct CallDynamicJavaDirect( method meth ) %{
match(CallDynamicJava);
diff --git a/src/hotspot/cpu/arm/arm_32.ad b/src/hotspot/cpu/arm/arm_32.ad
index 1c15d55fbc3..00bf3bd61e4 100644
--- a/src/hotspot/cpu/arm/arm_32.ad
+++ b/src/hotspot/cpu/arm/arm_32.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2008, 2025, 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
@@ -432,8 +432,7 @@ OptoRegPair c2::return_value(int ideal_reg) {
int MachCallStaticJavaNode::ret_addr_offset() {
bool far = (_method == nullptr) ? maybe_far_call(this) : !cache_reachable();
- return ((far ? 3 : 1) + (_method_handle_invoke ? 1 : 0)) *
- NativeInstruction::instruction_size;
+ return (far ? 3 : 1) * NativeInstruction::instruction_size;
}
int MachCallDynamicJavaNode::ret_addr_offset() {
diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp
index efdc190f09a..8e49cfcbcaa 100644
--- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp
@@ -200,9 +200,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- if (_compute_lock) {
- ce->monitor_address(_monitor_ix, _lock_reg);
- }
+
+ // lock_reg was destroyed by fast unlocking attempt => recompute it
+ ce->monitor_address(_monitor_ix, _lock_reg);
+
const Register lock_reg = _lock_reg->as_pointer_register();
ce->verify_reserved_argument_area_size(1);
diff --git a/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp b/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp
index 0fd113c8ceb..a820da4d283 100644
--- a/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp
@@ -174,11 +174,6 @@ LIR_Opr FrameMap::stack_pointer() {
return FrameMap::SP_opr;
}
-LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
- assert(Rmh_SP_save == FP, "Fix register used for saving SP for MethodHandle calls");
- return FP_opr;
-}
-
bool FrameMap::validate_frame() {
int max_offset = in_bytes(framesize_in_bytes());
int java_index = 0;
diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
index d6ed82dcdb2..219c49d1f14 100644
--- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
@@ -245,7 +245,7 @@ int LIR_Assembler::emit_unwind_handler() {
MonitorExitStub* stub = nullptr;
if (method()->is_synchronized()) {
monitor_address(0, FrameMap::R0_opr);
- stub = new MonitorExitStub(FrameMap::R0_opr, true, 0);
+ stub = new MonitorExitStub(FrameMap::R0_opr, 0);
__ unlock_object(R2, R1, R0, *stub->entry());
__ bind(*stub->continuation());
}
@@ -2427,7 +2427,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
Register lock = op->lock_opr()->as_pointer_register();
if (op->code() == lir_lock) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
int null_check_offset = __ lock_object(hdr, obj, lock, *op->stub()->entry());
if (op->info() != nullptr) {
add_debug_info_for_null_check(null_check_offset, op->info());
diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
index f2b08269750..ca7711353d2 100644
--- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
@@ -176,17 +176,17 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len,
initialize_object(obj, tmp1, klass, len, tmp2, tmp3, header_size_in_bytes, -1, /* is_tlab_allocated */ UseTLAB);
}
-int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
+int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) {
int null_check_offset = 0;
const Register tmp2 = Rtemp; // Rtemp should be free at c1 LIR level
- assert_different_registers(hdr, obj, disp_hdr, tmp2);
+ assert_different_registers(hdr, obj, basic_lock, tmp2);
assert(BasicObjectLock::lock_offset() == 0, "adjust this code");
assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
// save object being locked into the BasicObjectLock
- str(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
+ str(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
null_check_offset = offset();
@@ -197,26 +197,26 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
b(slow_case, ne);
}
- Register t1 = disp_hdr; // Needs saving, probably
- Register t2 = hdr; // blow
- Register t3 = Rtemp; // blow
+ Register t1 = basic_lock; // Needs saving, probably
+ Register t2 = hdr; // blow
+ Register t3 = Rtemp; // blow
lightweight_lock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
// Success: fall through
return null_check_offset;
}
-void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
- assert_different_registers(hdr, obj, disp_hdr, Rtemp);
+void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) {
+ assert_different_registers(hdr, obj, basic_lock, Rtemp);
assert(BasicObjectLock::lock_offset() == 0, "adjust this code");
assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
- ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
+ ldr(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
- Register t1 = disp_hdr; // Needs saving, probably
- Register t2 = hdr; // blow
- Register t3 = Rtemp; // blow
+ Register t1 = basic_lock; // Needs saving, probably
+ Register t2 = hdr; // blow
+ Register t3 = Rtemp; // blow
lightweight_unlock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
// Success: fall through
diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp
index 0a626822a9b..fd88b6c4fe9 100644
--- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp
+++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2025, 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,9 +59,9 @@
max_array_allocation_length = 0x01000000
};
- int lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case);
+ int lock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case);
- void unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case);
+ void unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case);
// This platform only uses signal-based null checks. The Label is not needed.
void null_check(Register r, Label *Lnull = nullptr) { MacroAssembler::null_check(r); }
diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp
index 32da2c24d26..9983f2ce7a2 100644
--- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp
@@ -275,14 +275,6 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe
}
-static void restore_sp_for_method_handle(StubAssembler* sasm) {
- // Restore SP from its saved reg (FP) if the exception PC is a MethodHandle call site.
- __ ldr_s32(Rtemp, Address(Rthread, JavaThread::is_method_handle_return_offset()));
- __ cmp(Rtemp, 0);
- __ mov(SP, Rmh_SP_save, ne);
-}
-
-
OopMapSet* Runtime1::generate_handle_exception(StubId id, StubAssembler* sasm) {
__ block_comment("generate_handle_exception");
@@ -339,7 +331,6 @@ OopMapSet* Runtime1::generate_handle_exception(StubId id, StubAssembler* sasm) {
break;
case StubId::c1_handle_exception_from_callee_id:
restore_live_registers_without_return(sasm); // must not jump immediately to handler
- restore_sp_for_method_handle(sasm);
__ ret();
break;
default: ShouldNotReachHere();
@@ -372,9 +363,6 @@ void Runtime1::generate_unwind_exception(StubAssembler* sasm) {
// Jump to handler
__ verify_not_null_oop(Rexception_obj);
- // JSR292 extension
- restore_sp_for_method_handle(sasm);
-
__ jump(R0);
}
diff --git a/src/hotspot/cpu/arm/c1_globals_arm.hpp b/src/hotspot/cpu/arm/c1_globals_arm.hpp
index 396f206975b..1fe5f1a23ee 100644
--- a/src/hotspot/cpu/arm/c1_globals_arm.hpp
+++ b/src/hotspot/cpu/arm/c1_globals_arm.hpp
@@ -54,7 +54,6 @@ define_pd_global(size_t, CodeCacheExpansionSize, 32*K );
define_pd_global(size_t, CodeCacheMinBlockLength, 1);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, NeverActAsServerClassMachine, true);
-define_pd_global(uint64_t, MaxRAM, 1ULL*G);
define_pd_global(bool, CICompileOSR, true );
#endif // COMPILER2
define_pd_global(bool, UseTypeProfile, false);
diff --git a/src/hotspot/cpu/arm/c2_globals_arm.hpp b/src/hotspot/cpu/arm/c2_globals_arm.hpp
index d739e67360a..0849bd594f0 100644
--- a/src/hotspot/cpu/arm/c2_globals_arm.hpp
+++ b/src/hotspot/cpu/arm/c2_globals_arm.hpp
@@ -80,9 +80,6 @@ define_pd_global(size_t, NonProfiledCodeHeapSize, 21*M);
define_pd_global(size_t, ProfiledCodeHeapSize, 22*M);
define_pd_global(size_t, NonNMethodCodeHeapSize, 5*M );
define_pd_global(size_t, CodeCacheExpansionSize, 64*K);
-
-// Ergonomics related flags
-define_pd_global(uint64_t, MaxRAM, 128ULL*G);
#else
// InitialCodeCacheSize derived from specjbb2000 run.
define_pd_global(size_t, InitialCodeCacheSize, 1536*K); // Integral multiple of CodeCacheExpansionSize
@@ -91,8 +88,6 @@ define_pd_global(size_t, NonProfiledCodeHeapSize, 13*M);
define_pd_global(size_t, ProfiledCodeHeapSize, 14*M);
define_pd_global(size_t, NonNMethodCodeHeapSize, 5*M );
define_pd_global(size_t, CodeCacheExpansionSize, 32*K);
-// Ergonomics related flags
-define_pd_global(uint64_t, MaxRAM, 4ULL*G);
#endif
define_pd_global(size_t, CodeCacheMinBlockLength, 6);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp
index 2722f93edec..7a23296a3d4 100644
--- a/src/hotspot/cpu/arm/frame_arm.cpp
+++ b/src/hotspot/cpu/arm/frame_arm.cpp
@@ -329,56 +329,6 @@ JavaThread** frame::saved_thread_address(const frame& f) {
return nullptr;
}
-//------------------------------------------------------------------------------
-// frame::verify_deopt_original_pc
-//
-// Verifies the calculated original PC of a deoptimization PC for the
-// given unextended SP. The unextended SP might also be the saved SP
-// for MethodHandle call sites.
-#ifdef ASSERT
-void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) {
- frame fr;
-
- // This is ugly but it's better than to change {get,set}_original_pc
- // to take an SP value as argument. And it's only a debugging
- // method anyway.
- fr._unextended_sp = unextended_sp;
-
- address original_pc = nm->get_original_pc(&fr);
- assert(nm->insts_contains_inclusive(original_pc),
- "original PC must be in the main code section of the compiled method (or must be immediately following it)");
- assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be");
-}
-#endif
-
-//------------------------------------------------------------------------------
-// frame::adjust_unextended_sp
-void frame::adjust_unextended_sp() {
- // same as on x86
-
- // If we are returning to a compiled MethodHandle call site, the
- // saved_fp will in fact be a saved value of the unextended SP. The
- // simplest way to tell whether we are returning to such a call site
- // is as follows:
-
- nmethod* sender_nm = (_cb == nullptr) ? nullptr : _cb->as_nmethod_or_null();
- if (sender_nm != nullptr) {
- // If the sender PC is a deoptimization point, get the original
- // PC. For MethodHandle call site the unextended_sp is stored in
- // saved_fp.
- if (sender_nm->is_deopt_mh_entry(_pc)) {
- DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp));
- _unextended_sp = _fp;
- }
- else if (sender_nm->is_deopt_entry(_pc)) {
- DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp));
- }
- else if (sender_nm->is_method_handle_return(_pc)) {
- _unextended_sp = _fp;
- }
- }
-}
-
//------------------------------------------------------------------------------
// frame::update_map_with_saved_link
void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) {
diff --git a/src/hotspot/cpu/arm/frame_arm.hpp b/src/hotspot/cpu/arm/frame_arm.hpp
index dec27554a47..6d4ac042831 100644
--- a/src/hotspot/cpu/arm/frame_arm.hpp
+++ b/src/hotspot/cpu/arm/frame_arm.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2025, 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
@@ -85,20 +85,11 @@
// original sp.
intptr_t* _unextended_sp;
- void adjust_unextended_sp();
intptr_t* ptr_at_addr(int offset) const {
return (intptr_t*) addr_at(offset);
}
-#ifdef ASSERT
- // Used in frame::sender_for_{interpreter,compiled}_frame
- static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false);
- static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) {
- verify_deopt_original_pc(nm, unextended_sp, true);
- }
-#endif
-
public:
// Constructors
diff --git a/src/hotspot/cpu/arm/frame_arm.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp
index 4be190f0504..42e034cfdc7 100644
--- a/src/hotspot/cpu/arm/frame_arm.inline.hpp
+++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2025, 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
@@ -112,8 +112,6 @@ inline void frame::init(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, add
}
inline void frame::setup(address pc) {
- adjust_unextended_sp();
-
address original_pc = get_deopt_original_pc();
if (original_pc != nullptr) {
_pc = original_pc;
diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp
index 049477cda76..74a9f273a43 100644
--- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp
@@ -198,15 +198,18 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
__ bind(done);
}
-static void generate_post_barrier_fast_path(MacroAssembler* masm,
- const Register store_addr,
- const Register new_val,
- const Register tmp1,
- const Register tmp2,
- Label& done,
- bool new_val_may_be_null) {
- // Does store cross heap regions?
+static void generate_post_barrier(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
+ assert(thread == Rthread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
+ // Does store cross heap regions?
__ eor(tmp1, store_addr, new_val);
__ movs(tmp1, AsmOperand(tmp1, lsr, G1HeapRegion::LogOfHRGrainBytes));
__ b(done, eq);
@@ -215,76 +218,34 @@ static void generate_post_barrier_fast_path(MacroAssembler* masm,
if (new_val_may_be_null) {
__ cbz(new_val, done);
}
- // storing region crossing non-null, is card already dirty?
- const Register card_addr = tmp1;
- CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
- __ mov_address(tmp2, (address)ct->card_table()->byte_map_base());
- __ add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift()));
+ // storing region crossing non-null, is card already non-clean?
+ Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
+ __ ldr(tmp2, card_table_addr);
+ __ add(tmp1, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift()));
- __ ldrb(tmp2, Address(card_addr));
- __ cmp(tmp2, (int)G1CardTable::g1_young_card_val());
+ if (UseCondCardMark) {
+ __ ldrb(tmp2, Address(tmp1));
+ // Instead of loading clean_card_val and comparing, we exploit the fact that
+ // the LSB of non-clean cards is always 0, and the LSB of clean cards 1.
+ __ tbz(tmp2, 0, done);
+ }
+
+ static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zero_register()");
+ __ zero_register(tmp2);
+ __ strb(tmp2, Address(tmp1)); // *(card address) := dirty_card_val
}
-static void generate_post_barrier_slow_path(MacroAssembler* masm,
- const Register thread,
- const Register tmp1,
- const Register tmp2,
- const Register tmp3,
- Label& done,
- Label& runtime) {
- __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2);
- assert(CardTable::dirty_card_val() == 0, "adjust this code");
- // card_addr is loaded by generate_post_barrier_fast_path
- const Register card_addr = tmp1;
- __ ldrb(tmp2, Address(card_addr));
- __ cbz(tmp2, done);
-
- // storing a region crossing, non-null oop, card is clean.
- // dirty card and log.
-
- __ strb(__ zero_register(tmp2), Address(card_addr));
- generate_queue_test_and_insertion(masm,
- G1ThreadLocalData::dirty_card_queue_index_offset(),
- G1ThreadLocalData::dirty_card_queue_buffer_offset(),
- runtime,
- thread, card_addr, tmp2, tmp3);
- __ b(done);
-}
-
-
// G1 post-barrier.
// Blows all volatile registers R0-R3, LR).
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
- Register store_addr,
- Register new_val,
- Register tmp1,
- Register tmp2,
- Register tmp3) {
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2,
+ Register tmp3) {
Label done;
- Label runtime;
-
- generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
- // If card is young, jump to done
- // card_addr and card are loaded by generate_post_barrier_fast_path
- const Register card = tmp2;
- const Register card_addr = tmp1;
- __ b(done, eq);
- generate_post_barrier_slow_path(masm, Rthread, card_addr, tmp2, tmp3, done, runtime);
-
- __ bind(runtime);
-
- RegisterSet set = RegisterSet(store_addr) | RegisterSet(R0, R3) | RegisterSet(R12);
- __ push(set);
-
- if (card_addr != R0) {
- __ mov(R0, card_addr);
- }
- __ mov(R1, Rthread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), R0, R1);
-
- __ pop(set);
-
+ generate_post_barrier(masm, store_addr, new_val, Rthread, tmp1, tmp2, done, true /* new_val_may_be_null */);
__ bind(done);
}
@@ -344,35 +305,10 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
Register tmp1,
Register tmp2,
Register tmp3,
- G1PostBarrierStubC2* stub) {
- assert(thread == Rthread, "must be");
- assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
-
- stub->initialize_registers(thread, tmp1, tmp2, tmp3);
-
- bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
- generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null);
- // If card is not young, jump to stub (slow path)
- __ b(*stub->entry(), ne);
-
- __ bind(*stub->continuation());
-}
-
-void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const {
- Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
- Label runtime;
- Register thread = stub->thread();
- Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
- Register tmp2 = stub->tmp2();
- Register tmp3 = stub->tmp3();
-
- __ bind(*stub->entry());
- generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, tmp3, *stub->continuation(), runtime);
-
- __ bind(runtime);
- generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp2);
- __ b(*stub->continuation());
+ bool new_val_may_be_null) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, new_val_may_be_null);
+ __ bind(done);
}
#endif // COMPILER2
@@ -463,20 +399,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
__ b(*stub->continuation());
}
-void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
- G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
- __ bind(*stub->entry());
- assert(stub->addr()->is_register(), "Precondition.");
- assert(stub->new_val()->is_register(), "Precondition.");
- Register new_val_reg = stub->new_val()->as_register();
- __ cbz(new_val_reg, *stub->continuation());
- ce->verify_reserved_argument_area_size(1);
- __ str(stub->addr()->as_pointer_register(), Address(SP));
- __ call(bs->post_barrier_c1_runtime_code_blob()->code_begin(), relocInfo::runtime_call_type);
- __ b(*stub->continuation());
+#undef __
+
+void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
+ masm->bind(done);
}
-#undef __
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
@@ -536,102 +471,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ b(done);
}
-void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
- // Input:
- // - store_addr, pushed on the stack
-
- __ set_info("g1_post_barrier_slow_id", false);
-
- Label done;
- Label recheck;
- Label runtime;
-
- Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
- Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
-
- AddressLiteral cardtable(ci_card_table_address_as(), relocInfo::none);
-
- // save at least the registers that need saving if the runtime is called
- const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR);
- const int nb_saved_regs = 6;
- assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs");
- __ push(saved_regs);
-
- const Register r_card_addr_0 = R0; // must be R0 for the slow case
- const Register r_obj_0 = R0;
- const Register r_card_base_1 = R1;
- const Register r_tmp2 = R2;
- const Register r_index_2 = R2;
- const Register r_buffer_3 = R3;
- const Register tmp1 = Rtemp;
-
- __ ldr(r_obj_0, Address(SP, nb_saved_regs*wordSize));
- // Note: there is a comment in x86 code about not using
- // ExternalAddress / lea, due to relocation not working
- // properly for that address. Should be OK for arm, where we
- // explicitly specify that 'cardtable' has a relocInfo::none
- // type.
- __ lea(r_card_base_1, cardtable);
- __ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTable::card_shift()));
-
- // first quick check without barrier
- __ ldrb(r_tmp2, Address(r_card_addr_0));
-
- __ cmp(r_tmp2, (int)G1CardTable::g1_young_card_val());
- __ b(recheck, ne);
-
- __ bind(done);
-
- __ pop(saved_regs);
-
- __ ret();
-
- __ bind(recheck);
-
- __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp1);
-
- // reload card state after the barrier that ensures the stored oop was visible
- __ ldrb(r_tmp2, Address(r_card_addr_0));
-
- assert(CardTable::dirty_card_val() == 0, "adjust this code");
- __ cbz(r_tmp2, done);
-
- // storing region crossing non-null, card is clean.
- // dirty card and log.
-
- assert(0 == (int)CardTable::dirty_card_val(), "adjust this code");
- if ((ci_card_table_address_as() & 0xff) == 0) {
- // Card table is aligned so the lowest byte of the table address base is zero.
- __ strb(r_card_base_1, Address(r_card_addr_0));
- } else {
- __ strb(__ zero_register(r_tmp2), Address(r_card_addr_0));
- }
-
- __ ldr(r_index_2, queue_index);
- __ ldr(r_buffer_3, buffer);
-
- __ subs(r_index_2, r_index_2, wordSize);
- __ b(runtime, lt); // go to runtime if now negative
-
- __ str(r_index_2, queue_index);
-
- __ str(r_card_addr_0, Address(r_buffer_3, r_index_2));
-
- __ b(done);
-
- __ bind(runtime);
-
- __ save_live_registers();
-
- assert(r_card_addr_0 == c_rarg0, "card_addr should be in R0");
- __ mov(c_rarg1, Rthread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), c_rarg0, c_rarg1);
-
- __ restore_live_registers_without_return();
-
- __ b(done);
-}
-
#undef __
#endif // COMPILER1
diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp
index 4e49e655e3e..9e0eff4601b 100644
--- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp
+++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,9 +32,7 @@
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
-class G1PostBarrierStub;
class G1PreBarrierStubC2;
-class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -66,10 +64,15 @@ public:
#ifdef COMPILER1
public:
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
- void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
- void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
+
+ void g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2);
#endif
#ifdef COMPILER2
@@ -89,9 +92,7 @@ public:
Register tmp1,
Register tmp2,
Register tmp3,
- G1PostBarrierStubC2* c2_stub);
- void generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const;
+ bool new_val_may_be_null);
#endif
};
diff --git a/src/hotspot/cpu/arm/gc/g1/g1_arm.ad b/src/hotspot/cpu/arm/gc/g1/g1_arm.ad
index 8a0a9e1aa53..e905ba9ff67 100644
--- a/src/hotspot/cpu/arm/gc/g1/g1_arm.ad
+++ b/src/hotspot/cpu/arm/gc/g1/g1_arm.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2024, 2025, 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
@@ -63,13 +63,13 @@ static void write_barrier_post(MacroAssembler* masm,
Register tmp1,
Register tmp2,
Register tmp3) {
- if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ if (!G1BarrierStubC2::needs_post_barrier(node)) {
return;
}
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
- G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
- g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Rthread, tmp1, tmp2, tmp3, stub);
+ bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Rthread, tmp1, tmp2, tmp3, new_val_may_be_null);
}
%}
diff --git a/src/hotspot/cpu/arm/register_arm.hpp b/src/hotspot/cpu/arm/register_arm.hpp
index fca23d07fee..e0688af0d36 100644
--- a/src/hotspot/cpu/arm/register_arm.hpp
+++ b/src/hotspot/cpu/arm/register_arm.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -364,7 +364,6 @@ class VFPSystemRegisterImpl : public AbstractRegisterImpl {
// This does not seem to conflict with Rexception_pc
// In case of issues, R3 might be OK but adapters calling the runtime would have to save it
#define R5_mh R5 // MethodHandle register, used during the call setup
-#define Rmh_SP_save FP // for C1
/*
* C++ Interpreter Register Defines
diff --git a/src/hotspot/cpu/arm/runtime_arm.cpp b/src/hotspot/cpu/arm/runtime_arm.cpp
index ea4c9a76381..8d48de5795a 100644
--- a/src/hotspot/cpu/arm/runtime_arm.cpp
+++ b/src/hotspot/cpu/arm/runtime_arm.cpp
@@ -264,11 +264,6 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
__ raw_pop(FP, LR);
- // Restore SP from its saved reg (FP) if the exception PC is a MethodHandle call site.
- __ ldr(Rtemp, Address(Rthread, JavaThread::is_method_handle_return_offset()));
- __ cmp(Rtemp, 0);
- __ mov(SP, Rmh_SP_save, ne);
-
// R0 contains handler address
// Since this may be the deopt blob we must set R5 to look like we returned
// from the original pc that threw the exception
diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
index dcf631525ab..99d8773368d 100644
--- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
+++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
@@ -617,11 +617,11 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs,
- AdapterHandlerEntry* handler) {
- address i2c_entry = __ pc();
+ address entry_address[AdapterBlob::ENTRY_COUNT]) {
+ entry_address[AdapterBlob::I2C] = __ pc();
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
- address c2i_unverified_entry = __ pc();
+ entry_address[AdapterBlob::C2I_Unverified] = __ pc();
Label skip_fixup;
const Register receiver = R0;
const Register holder_klass = Rtemp; // XXX should be OK for C2 but not 100% sure
@@ -634,10 +634,9 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ b(skip_fixup, eq);
__ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, noreg, ne);
- address c2i_entry = __ pc();
+ entry_address[AdapterBlob::C2I] = __ pc();
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
-
- handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, nullptr);
return;
}
@@ -1129,7 +1128,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
const Register sync_handle = R5;
const Register sync_obj = R6;
- const Register disp_hdr = altFP_7_11;
+ const Register basic_lock = altFP_7_11;
const Register tmp = R8;
Label slow_lock, lock_done, fast_lock;
@@ -1140,7 +1139,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ mov(sync_handle, R1);
log_trace(fastlock)("SharedRuntime lock fast");
- __ lightweight_lock(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
+ __ lightweight_lock(sync_obj /* object */, basic_lock /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
0x7 /* savemask */, slow_lock);
// Fall through to lock_done
__ bind(lock_done);
@@ -1255,7 +1254,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
// last_Java_frame is already set, so do call_VM manually; no exception can occur
__ mov(R0, sync_obj);
- __ mov(R1, disp_hdr);
+ __ mov(R1, basic_lock);
__ mov(R2, Rthread);
__ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_locking_C));
@@ -1270,12 +1269,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
// Clear pending exception before reentering VM.
// Can store the oop in register since it is a leaf call.
- assert_different_registers(Rtmp_save1, sync_obj, disp_hdr);
+ assert_different_registers(Rtmp_save1, sync_obj, basic_lock);
__ ldr(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset()));
Register zero = __ zero_register(Rtemp);
__ str(zero, Address(Rthread, Thread::pending_exception_offset()));
__ mov(R0, sync_obj);
- __ mov(R1, disp_hdr);
+ __ mov(R1, basic_lock);
__ mov(R2, Rthread);
__ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C));
__ str(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset()));
diff --git a/src/hotspot/cpu/arm/stubGenerator_arm.cpp b/src/hotspot/cpu/arm/stubGenerator_arm.cpp
index 2e2e0f7a4b9..a36ad3a0c47 100644
--- a/src/hotspot/cpu/arm/stubGenerator_arm.cpp
+++ b/src/hotspot/cpu/arm/stubGenerator_arm.cpp
@@ -3011,6 +3011,10 @@ class StubGenerator: public StubCodeGenerator {
// Note: the disjoint stubs must be generated first, some of
// the conjoint stubs use them.
+ // Note: chaining of stubs does not rely on branching to an
+ // auxiliary post-push entry because none of the stubs
+ // push/pop a frame.
+
// these need always status in case they are called from generic_arraycopy
StubRoutines::_jbyte_disjoint_arraycopy = generate_primitive_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id);
StubRoutines::_jshort_disjoint_arraycopy = generate_primitive_copy(StubId::stubgen_jshort_disjoint_arraycopy_id);
@@ -3024,6 +3028,7 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_primitive_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id);
StubRoutines::_arrayof_oop_disjoint_arraycopy = generate_oop_copy (StubId::stubgen_arrayof_oop_disjoint_arraycopy_id);
+ // disjoint copy entry is needed by conjoint copy
// these need always status in case they are called from generic_arraycopy
StubRoutines::_jbyte_arraycopy = generate_primitive_copy(StubId::stubgen_jbyte_arraycopy_id, StubRoutines::_jbyte_disjoint_arraycopy);
StubRoutines::_jshort_arraycopy = generate_primitive_copy(StubId::stubgen_jshort_arraycopy_id, StubRoutines::_jshort_disjoint_arraycopy);
diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp
index aa330bfa1a7..15e38411482 100644
--- a/src/hotspot/cpu/ppc/assembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp
@@ -2059,12 +2059,12 @@ class Assembler : public AbstractAssembler {
protected:
inline void tdi_unchecked(int tobits, Register a, int si16);
inline void twi_unchecked(int tobits, Register a, int si16);
+ public:
inline void tdi( int tobits, Register a, int si16); // asserts UseSIGTRAP
inline void twi( int tobits, Register a, int si16); // asserts UseSIGTRAP
inline void td( int tobits, Register a, Register b); // asserts UseSIGTRAP
inline void tw( int tobits, Register a, Register b); // asserts UseSIGTRAP
- public:
static bool is_tdi(int x, int tobits, int ra, int si16) {
return (TDI_OPCODE == (x & TDI_OPCODE_MASK))
&& (tobits == inv_to_field(x))
diff --git a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp
index 24601c5d3b0..7e49ec7455d 100644
--- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp
+++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp
@@ -26,7 +26,7 @@
#ifndef CPU_PPC_ASSEMBLER_PPC_INLINE_HPP
#define CPU_PPC_ASSEMBLER_PPC_INLINE_HPP
-#include "asm/assembler.inline.hpp"
+#include "asm/assembler.hpp"
#include "asm/codeBuffer.hpp"
#include "code/codeCache.hpp"
#include "runtime/vm_version.hpp"
diff --git a/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp b/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp
similarity index 51%
rename from src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp
rename to src/hotspot/cpu/ppc/atomicAccess_ppc.hpp
index d32f7c93ecf..a0ff19e6171 100644
--- a/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp
+++ b/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2019 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 2025 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,17 +23,17 @@
*
*/
-#ifndef OS_CPU_AIX_PPC_ATOMIC_AIX_PPC_HPP
-#define OS_CPU_AIX_PPC_ATOMIC_AIX_PPC_HPP
+#ifndef CPU_PPC_ATOMICACCESS_PPC_HPP
+#define CPU_PPC_ATOMICACCESS_PPC_HPP
#ifndef PPC64
#error "Atomic currently only implemented for PPC64"
#endif
-#include "orderAccess_aix_ppc.hpp"
+#include "orderAccess_ppc.hpp"
#include "utilities/debug.hpp"
-// Implementation of class atomic
+// Implementation of class AtomicAccess
//
// machine barrier instructions:
@@ -92,6 +92,7 @@ inline void post_membar(atomic_memory_order order) {
}
+
template
struct AtomicAccess::PlatformAdd {
template
@@ -115,12 +116,13 @@ inline D AtomicAccess::PlatformAdd<4>::add_then_fetch(D volatile* dest, I add_va
pre_membar(order);
__asm__ __volatile__ (
- "1: lwarx %0, 0, %2 \n"
- " add %0, %0, %1 \n"
- " stwcx. %0, 0, %2 \n"
- " bne- 1b \n"
- : /*%0*/"=&r" (result)
- : /*%1*/"r" (add_value), /*%2*/"r" (dest)
+ "1: lwarx %[result], 0, %[dest] \n"
+ " add %[result], %[result], %[add_value] \n"
+ " stwcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [result] "=&r" (result)
+ : [add_value] "r" (add_value),
+ [dest] "b" (dest)
: "cc", "memory" );
post_membar(order);
@@ -141,12 +143,13 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va
pre_membar(order);
__asm__ __volatile__ (
- "1: ldarx %0, 0, %2 \n"
- " add %0, %0, %1 \n"
- " stdcx. %0, 0, %2 \n"
- " bne- 1b \n"
- : /*%0*/"=&r" (result)
- : /*%1*/"r" (add_value), /*%2*/"r" (dest)
+ "1: ldarx %[result], 0, %[dest] \n"
+ " add %[result], %[result], %[add_value] \n"
+ " stdcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [result] "=&r" (result)
+ : [add_value] "r" (add_value),
+ [dest] "b" (dest)
: "cc", "memory" );
post_membar(order);
@@ -159,30 +162,27 @@ template
inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,
T exchange_value,
atomic_memory_order order) const {
+ STATIC_ASSERT(4 == sizeof(T));
// Note that xchg doesn't necessarily do an acquire
// (see synchronizer.cpp).
T old_value;
- const uint64_t zero = 0;
pre_membar(order);
__asm__ __volatile__ (
/* atomic loop */
"1: \n"
- " lwarx %[old_value], %[dest], %[zero] \n"
- " stwcx. %[exchange_value], %[dest], %[zero] \n"
+ " lwarx %[old_value], 0, %[dest] \n"
+ " stwcx. %[exchange_value], 0, %[dest] \n"
" bne- 1b \n"
/* exit */
"2: \n"
/* out */
- : [old_value] "=&r" (old_value),
- "=m" (*dest)
+ : [old_value] "=&r" (old_value)
/* in */
: [dest] "b" (dest),
- [zero] "r" (zero),
- [exchange_value] "r" (exchange_value),
- "m" (*dest)
+ [exchange_value] "r" (exchange_value)
/* clobber */
: "cc",
"memory"
@@ -203,26 +203,22 @@ inline T AtomicAccess::PlatformXchg<8>::operator()(T volatile* dest,
// (see synchronizer.cpp).
T old_value;
- const uint64_t zero = 0;
pre_membar(order);
__asm__ __volatile__ (
/* atomic loop */
"1: \n"
- " ldarx %[old_value], %[dest], %[zero] \n"
- " stdcx. %[exchange_value], %[dest], %[zero] \n"
+ " ldarx %[old_value], 0, %[dest] \n"
+ " stdcx. %[exchange_value], 0, %[dest] \n"
" bne- 1b \n"
/* exit */
"2: \n"
/* out */
- : [old_value] "=&r" (old_value),
- "=m" (*dest)
+ : [old_value] "=&r" (old_value)
/* in */
: [dest] "b" (dest),
- [zero] "r" (zero),
- [exchange_value] "r" (exchange_value),
- "m" (*dest)
+ [exchange_value] "r" (exchange_value)
/* clobber */
: "cc",
"memory"
@@ -245,19 +241,9 @@ inline T AtomicAccess::PlatformCmpxchg<1>::operator()(T volatile* dest,
// the cmpxchg, so it's really a 'fence_cmpxchg_fence' if not
// specified otherwise (see atomicAccess.hpp).
- // Using 32 bit internally.
- volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3);
+ const unsigned int masked_compare_val = (unsigned int)(unsigned char)compare_value;
-#ifdef VM_LITTLE_ENDIAN
- const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8;
-#else
- const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8;
-#endif
- const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value),
- masked_exchange_val = ((unsigned int)(unsigned char)exchange_value),
- xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount;
-
- unsigned int old_value, value32;
+ unsigned int old_value;
pre_membar(order);
@@ -268,31 +254,19 @@ inline T AtomicAccess::PlatformCmpxchg<1>::operator()(T volatile* dest,
" bne- 2f \n"
/* atomic loop */
"1: \n"
- " lwarx %[value32], 0, %[dest_base] \n"
- /* extract byte and compare */
- " srd %[old_value], %[value32], %[shift_amount] \n"
- " clrldi %[old_value], %[old_value], 56 \n"
+ " lbarx %[old_value], 0, %[dest] \n"
" cmpw %[masked_compare_val], %[old_value] \n"
" bne- 2f \n"
- /* replace byte and try to store */
- " xor %[value32], %[xor_value], %[value32] \n"
- " stwcx. %[value32], 0, %[dest_base] \n"
+ " stbcx. %[exchange_value], 0, %[dest] \n"
" bne- 1b \n"
/* exit */
"2: \n"
/* out */
- : [old_value] "=&r" (old_value),
- [value32] "=&r" (value32),
- "=m" (*dest),
- "=m" (*dest_base)
+ : [old_value] "=&r" (old_value)
/* in */
- : [dest] "b" (dest),
- [dest_base] "b" (dest_base),
- [shift_amount] "r" (shift_amount),
- [masked_compare_val] "r" (masked_compare_val),
- [xor_value] "r" (xor_value),
- "m" (*dest),
- "m" (*dest_base)
+ : [dest] "b" (dest),
+ [masked_compare_val] "r" (masked_compare_val),
+ [exchange_value] "r" (exchange_value)
/* clobber */
: "cc",
"memory"
@@ -316,7 +290,6 @@ inline T AtomicAccess::PlatformCmpxchg<4>::operator()(T volatile* dest,
// specified otherwise (see atomicAccess.hpp).
T old_value;
- const uint64_t zero = 0;
pre_membar(order);
@@ -327,22 +300,19 @@ inline T AtomicAccess::PlatformCmpxchg<4>::operator()(T volatile* dest,
" bne- 2f \n"
/* atomic loop */
"1: \n"
- " lwarx %[old_value], %[dest], %[zero] \n"
+ " lwarx %[old_value], 0, %[dest] \n"
" cmpw %[compare_value], %[old_value] \n"
" bne- 2f \n"
- " stwcx. %[exchange_value], %[dest], %[zero] \n"
+ " stwcx. %[exchange_value], 0, %[dest] \n"
" bne- 1b \n"
/* exit */
"2: \n"
/* out */
- : [old_value] "=&r" (old_value),
- "=m" (*dest)
+ : [old_value] "=&r" (old_value)
/* in */
: [dest] "b" (dest),
- [zero] "r" (zero),
[compare_value] "r" (compare_value),
- [exchange_value] "r" (exchange_value),
- "m" (*dest)
+ [exchange_value] "r" (exchange_value)
/* clobber */
: "cc",
"memory"
@@ -366,7 +336,6 @@ inline T AtomicAccess::PlatformCmpxchg<8>::operator()(T volatile* dest,
// specified otherwise (see atomicAccess.hpp).
T old_value;
- const uint64_t zero = 0;
pre_membar(order);
@@ -377,22 +346,19 @@ inline T AtomicAccess::PlatformCmpxchg<8>::operator()(T volatile* dest,
" bne- 2f \n"
/* atomic loop */
"1: \n"
- " ldarx %[old_value], %[dest], %[zero] \n"
+ " ldarx %[old_value], 0, %[dest] \n"
" cmpd %[compare_value], %[old_value] \n"
" bne- 2f \n"
- " stdcx. %[exchange_value], %[dest], %[zero] \n"
+ " stdcx. %[exchange_value], 0, %[dest] \n"
" bne- 1b \n"
/* exit */
"2: \n"
/* out */
- : [old_value] "=&r" (old_value),
- "=m" (*dest)
+ : [old_value] "=&r" (old_value)
/* in */
: [dest] "b" (dest),
- [zero] "r" (zero),
[compare_value] "r" (compare_value),
- [exchange_value] "r" (exchange_value),
- "m" (*dest)
+ [exchange_value] "r" (exchange_value)
/* clobber */
: "cc",
"memory"
@@ -404,7 +370,8 @@ inline T AtomicAccess::PlatformCmpxchg<8>::operator()(T volatile* dest,
}
template
-struct AtomicAccess::PlatformOrderedLoad {
+struct AtomicAccess::PlatformOrderedLoad
+{
template
T operator()(const volatile T* p) const {
T t = AtomicAccess::load(p);
@@ -414,4 +381,269 @@ struct AtomicAccess::PlatformOrderedLoad {
}
};
-#endif // OS_CPU_AIX_PPC_ATOMIC_AIX_PPC_HPP
+template<>
+class AtomicAccess::PlatformBitops<4, true> {
+public:
+ template
+ T fetch_then_and(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T old_value, result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: lwarx %[old_value], 0, %[dest] \n"
+ " and %[result], %[old_value], %[bits] \n"
+ " stwcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [old_value] "=&r" (old_value),
+ [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return old_value;
+ }
+
+ template
+ T fetch_then_or(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T old_value, result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: lwarx %[old_value], 0, %[dest] \n"
+ " or %[result], %[old_value], %[bits] \n"
+ " stwcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [old_value] "=&r" (old_value),
+ [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return old_value;
+ }
+
+ template
+ T fetch_then_xor(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T old_value, result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: lwarx %[old_value], 0, %[dest] \n"
+ " xor %[result], %[old_value], %[bits] \n"
+ " stwcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [old_value] "=&r" (old_value),
+ [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return old_value;
+ }
+
+ template
+ T and_then_fetch(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: lwarx %[result], 0, %[dest] \n"
+ " and %[result], %[result], %[bits] \n"
+ " stwcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return result;
+ }
+
+ template
+ T or_then_fetch(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: lwarx %[result], 0, %[dest] \n"
+ " or %[result], %[result], %[bits] \n"
+ " stwcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return result;
+ }
+
+ template
+ T xor_then_fetch(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: lwarx %[result], 0, %[dest] \n"
+ " xor %[result], %[result], %[bits] \n"
+ " stwcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return result;
+ }
+};
+
+template<>
+class AtomicAccess::PlatformBitops<8, true> {
+public:
+ template
+ T fetch_then_and(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T old_value, result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: ldarx %[old_value], 0, %[dest] \n"
+ " and %[result], %[old_value], %[bits] \n"
+ " stdcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [old_value] "=&r" (old_value),
+ [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return old_value;
+ }
+
+ template
+ T fetch_then_or(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T old_value, result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: ldarx %[old_value], 0, %[dest] \n"
+ " or %[result], %[old_value], %[bits] \n"
+ " stdcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [old_value] "=&r" (old_value),
+ [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return old_value;
+ }
+
+ template
+ T fetch_then_xor(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T old_value, result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: ldarx %[old_value], 0, %[dest] \n"
+ " xor %[result], %[old_value], %[bits] \n"
+ " stdcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [old_value] "=&r" (old_value),
+ [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return old_value;
+ }
+
+ template
+ T and_then_fetch(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: ldarx %[result], 0, %[dest] \n"
+ " and %[result], %[result], %[bits] \n"
+ " stdcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return result;
+ }
+
+ template
+ T or_then_fetch(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: ldarx %[result], 0, %[dest] \n"
+ " or %[result], %[result], %[bits] \n"
+ " stdcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return result;
+ }
+
+ template
+ T xor_then_fetch(T volatile* dest, T bits, atomic_memory_order order) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T result;
+
+ pre_membar(order);
+
+ __asm__ __volatile__ (
+ "1: ldarx %[result], 0, %[dest] \n"
+ " xor %[result], %[result], %[bits] \n"
+ " stdcx. %[result], 0, %[dest] \n"
+ " bne- 1b \n"
+ : [result] "=&r" (result)
+ : [dest] "b" (dest),
+ [bits] "r" (bits)
+ : "cc", "memory" );
+
+ post_membar(order);
+ return result;
+ }
+};
+#endif // CPU_PPC_ATOMICACCESS_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp
index 438521b0a9b..61780a73969 100644
--- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp
@@ -268,9 +268,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- if (_compute_lock) {
- ce->monitor_address(_monitor_ix, _lock_reg);
- }
+
+ // lock_reg was destroyed by fast unlocking attempt => recompute it
+ ce->monitor_address(_monitor_ix, _lock_reg);
+
address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? StubId::c1_monitorexit_id : StubId::c1_monitorexit_nofpu_id);
//__ load_const_optimized(R0, stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
diff --git a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp
index 8ce324a570b..cb9368f2ce9 100644
--- a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp
@@ -374,15 +374,6 @@ LIR_Opr FrameMap::stack_pointer() {
return SP_opr;
}
-
-// JSR 292
-// On PPC64, there is no need to save the SP, because neither
-// method handle intrinsics, nor compiled lambda forms modify it.
-LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
- return LIR_OprFact::illegalOpr;
-}
-
-
bool FrameMap::validate_frame() {
int max_offset = in_bytes(framesize_in_bytes());
int java_index = 0;
diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
index 3ca75305eca..108da2039f6 100644
--- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
@@ -227,7 +227,7 @@ int LIR_Assembler::emit_unwind_handler() {
MonitorExitStub* stub = nullptr;
if (method()->is_synchronized()) {
monitor_address(0, FrameMap::R4_opr);
- stub = new MonitorExitStub(FrameMap::R4_opr, true, 0);
+ stub = new MonitorExitStub(FrameMap::R4_opr, 0);
__ unlock_object(R5, R6, R4, *stub->entry());
__ bind(*stub->continuation());
}
@@ -2614,7 +2614,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
// Obj may not be an oop.
if (op->code() == lir_lock) {
MonitorEnterStub* stub = (MonitorEnterStub*)op->stub();
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
// Add debug info for NullPointerException only if one is possible.
if (op->info() != nullptr) {
if (!os::zero_page_read_protected() || !ImplicitNullChecks) {
@@ -2626,7 +2625,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
__ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry());
} else {
assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock");
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
__ unlock_object(hdr, obj, lock, *op->stub()->entry());
}
__ bind(*op->stub()->continuation());
diff --git a/src/hotspot/cpu/ppc/c1_globals_ppc.hpp b/src/hotspot/cpu/ppc/c1_globals_ppc.hpp
index ab014287250..77d9acd1cd1 100644
--- a/src/hotspot/cpu/ppc/c1_globals_ppc.hpp
+++ b/src/hotspot/cpu/ppc/c1_globals_ppc.hpp
@@ -53,7 +53,6 @@ define_pd_global(size_t, CodeCacheMinBlockLength, 1);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, NeverActAsServerClassMachine, true);
define_pd_global(size_t, NewSizeThreadIncrease, 16*K);
-define_pd_global(uint64_t, MaxRAM, 1ULL*G);
define_pd_global(size_t, InitialCodeCacheSize, 160*K);
#endif // !COMPILER2
diff --git a/src/hotspot/cpu/ppc/c2_globals_ppc.hpp b/src/hotspot/cpu/ppc/c2_globals_ppc.hpp
index 706255d035a..d5a0ff10994 100644
--- a/src/hotspot/cpu/ppc/c2_globals_ppc.hpp
+++ b/src/hotspot/cpu/ppc/c2_globals_ppc.hpp
@@ -86,7 +86,6 @@ define_pd_global(size_t, NonNMethodCodeHeapSize, 5*M );
define_pd_global(size_t, CodeCacheExpansionSize, 64*K);
// Ergonomics related flags
-define_pd_global(uint64_t, MaxRAM, 128ULL*G);
define_pd_global(size_t, CodeCacheMinBlockLength, 6);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp
index 4fb13422f59..65bfd683abd 100644
--- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp
@@ -28,7 +28,6 @@
#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1BarrierSetRuntime.hpp"
#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1DirtyCardQueue.hpp"
#include "gc/g1/g1HeapRegion.hpp"
#include "gc/g1/g1SATBMarkQueueSet.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
@@ -230,78 +229,52 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator
__ bind(filtered);
}
-static void generate_region_crossing_test(MacroAssembler* masm, const Register store_addr, const Register new_val) {
- __ xorr(R0, store_addr, new_val); // tmp1 := store address ^ new value
- __ srdi_(R0, R0, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
-}
+static void generate_post_barrier(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
+ assert_different_registers(store_addr, new_val, tmp1, R0);
+ assert_different_registers(store_addr, tmp1, tmp2, R0);
-static Address generate_card_young_test(MacroAssembler* masm, const Register store_addr, const Register tmp1, const Register tmp2) {
- CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
- __ load_const_optimized(tmp1, (address)(ct->card_table()->byte_map_base()), tmp2);
- __ srdi(tmp2, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base
- __ lbzx(R0, tmp1, tmp2); // tmp1 := card address
- __ cmpwi(CR0, R0, (int)G1CardTable::g1_young_card_val());
- return Address(tmp1, tmp2); // return card address
-}
+ __ xorr(R0, store_addr, new_val); // R0 := store address ^ new value
+ __ srdi_(R0, R0, G1HeapRegion::LogOfHRGrainBytes); // R0 := ((store address ^ new value) >> LogOfHRGrainBytes)
+ __ beq(CR0, done);
-static void generate_card_dirty_test(MacroAssembler* masm, Address card_addr) {
- __ membar(Assembler::StoreLoad); // Must reload after StoreLoad membar due to concurrent refinement
- __ lbzx(R0, card_addr.base(), card_addr.index()); // tmp2 := card
- __ cmpwi(CR0, R0, (int)G1CardTable::dirty_card_val()); // tmp2 := card == dirty_card_val?
+ // Crosses regions, storing null?
+ if (!new_val_may_be_null) {
+#ifdef ASSERT
+ __ cmpdi(CR0, new_val, 0);
+ __ asm_assert_ne("null oop not allowed (G1 post)"); // Checked by caller.
+#endif
+ } else {
+ __ cmpdi(CR0, new_val, 0);
+ __ beq(CR0, done);
+ }
+
+ __ ld(tmp1, G1ThreadLocalData::card_table_base_offset(), thread);
+ __ srdi(tmp2, store_addr, CardTable::card_shift()); // tmp2 := card address relative to card table base
+ if (UseCondCardMark) {
+ __ lbzx(R0, tmp1, tmp2);
+ __ cmpwi(CR0, R0, (int)G1CardTable::clean_card_val());
+ __ bne(CR0, done);
+ }
+
+ __ li(R0, G1CardTable::dirty_card_val());
+ __ stbx(R0, tmp1, tmp2);
}
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators,
Register store_addr, Register new_val,
- Register tmp1, Register tmp2, Register tmp3,
- MacroAssembler::PreservationLevel preservation_level) {
+ Register tmp1, Register tmp2) {
bool not_null = (decorators & IS_NOT_NULL) != 0;
- Label runtime, filtered;
- assert_different_registers(store_addr, new_val, tmp1, tmp2);
-
- CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
-
- generate_region_crossing_test(masm, store_addr, new_val);
- __ beq(CR0, filtered);
-
- // Crosses regions, storing null?
- if (not_null) {
-#ifdef ASSERT
- __ cmpdi(CR0, new_val, 0);
- __ asm_assert_ne("null oop not allowed (G1 post)"); // Checked by caller.
-#endif
- } else {
- __ cmpdi(CR0, new_val, 0);
- __ beq(CR0, filtered);
- }
-
- Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2);
- __ beq(CR0, filtered);
-
- generate_card_dirty_test(masm, card_addr);
- __ beq(CR0, filtered);
-
- __ li(R0, (int)G1CardTable::dirty_card_val());
- __ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val
-
- Register Rcard_addr = tmp3;
- __ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued.
-
- generate_queue_insertion(masm,
- G1ThreadLocalData::dirty_card_queue_index_offset(),
- G1ThreadLocalData::dirty_card_queue_buffer_offset(),
- runtime, Rcard_addr, tmp1);
- __ b(filtered);
-
- __ bind(runtime);
-
- assert(preservation_level == MacroAssembler::PRESERVATION_NONE,
- "g1_write_barrier_post doesn't support preservation levels higher than PRESERVATION_NONE");
-
- // Save the live input values.
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), Rcard_addr, R16_thread);
-
- __ bind(filtered);
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, R16_thread, tmp1, tmp2, done, !not_null);
+ __ bind(done);
}
void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
@@ -333,8 +306,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco
}
g1_write_barrier_post(masm, decorators,
base, val,
- tmp1, tmp2, tmp3,
- preservation_level);
+ tmp1, tmp2);
}
}
@@ -457,70 +429,29 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
Register new_val,
Register tmp1,
Register tmp2,
- G1PostBarrierStubC2* stub,
+ bool new_val_may_be_null,
bool decode_new_val) {
assert_different_registers(store_addr, new_val, tmp1, R0);
assert_different_registers(store_addr, tmp1, tmp2, R0);
- stub->initialize_registers(R16_thread, tmp1, tmp2);
+ Label done;
- bool null_check_required = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
Register new_val_decoded = new_val;
if (decode_new_val) {
assert(UseCompressedOops, "or should not be here");
- if (null_check_required && CompressedOops::base() != nullptr) {
+ if (new_val_may_be_null && CompressedOops::base() != nullptr) {
// We prefer doing the null check after the region crossing check.
// Only compressed oop modes with base != null require a null check here.
__ cmpwi(CR0, new_val, 0);
- __ beq(CR0, *stub->continuation());
- null_check_required = false;
+ __ beq(CR0, done);
+ new_val_may_be_null = false;
}
new_val_decoded = __ decode_heap_oop_not_null(tmp2, new_val);
}
- generate_region_crossing_test(masm, store_addr, new_val_decoded);
- __ beq(CR0, *stub->continuation());
-
- // crosses regions, storing null?
- if (null_check_required) {
- __ cmpdi(CR0, new_val_decoded, 0);
- __ beq(CR0, *stub->continuation());
- }
-
- Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2);
- assert(card_addr.base() == tmp1 && card_addr.index() == tmp2, "needed by post barrier stub");
- __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CR0, Assembler::equal), *stub->entry());
-
- __ bind(*stub->continuation());
-}
-
-void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const {
- Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
- Label runtime;
- Address card_addr(stub->tmp1(), stub->tmp2()); // See above.
-
- __ bind(*stub->entry());
-
- generate_card_dirty_test(masm, card_addr);
- __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *stub->continuation());
-
- __ li(R0, (int)G1CardTable::dirty_card_val());
- __ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val
-
- Register Rcard_addr = stub->tmp1();
- __ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued.
-
- generate_queue_insertion(masm,
- G1ThreadLocalData::dirty_card_queue_index_offset(),
- G1ThreadLocalData::dirty_card_queue_buffer_offset(),
- runtime, Rcard_addr, stub->tmp2());
- __ b(*stub->continuation());
-
- __ bind(runtime);
- generate_c2_barrier_runtime_call(masm, stub, Rcard_addr, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
- __ b(*stub->continuation());
+ generate_post_barrier(masm, store_addr, new_val_decoded, R16_thread, tmp1, tmp2, done, new_val_may_be_null);
+ __ bind(done);
}
#endif // COMPILER2
@@ -558,28 +489,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
__ b(*stub->continuation());
}
-void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
- G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
- __ bind(*stub->entry());
+#undef __
- assert(stub->addr()->is_register(), "Precondition.");
- assert(stub->new_val()->is_register(), "Precondition.");
- Register addr_reg = stub->addr()->as_pointer_register();
- Register new_val_reg = stub->new_val()->as_register();
-
- __ cmpdi(CR0, new_val_reg, 0);
- __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *stub->continuation());
-
- address c_code = bs->post_barrier_c1_runtime_code_blob()->code_begin();
- //__ load_const_optimized(R0, c_code);
- __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(c_code));
- __ mtctr(R0);
- __ mr(R0, addr_reg); // Pass addr in R0.
- __ bctrl();
- __ b(*stub->continuation());
+void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
+ masm->bind(done);
}
-#undef __
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
@@ -642,86 +564,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ b(restart);
}
-void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
- G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set());
-
- __ set_info("g1_post_barrier_slow_id", false);
-
- // Using stack slots: spill addr, spill tmp2
- const int stack_slots = 2;
- Register tmp = R0;
- Register addr = R14;
- Register tmp2 = R15;
- CardTable::CardValue* byte_map_base = bs->card_table()->byte_map_base();
-
- Label restart, refill, ret;
-
- // Spill
- __ std(addr, -8, R1_SP);
- __ std(tmp2, -16, R1_SP);
-
- __ srdi(addr, R0, CardTable::card_shift()); // Addr is passed in R0.
- __ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp);
- __ add(addr, tmp2, addr);
- __ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
-
- // Return if young card.
- __ cmpwi(CR0, tmp, G1CardTable::g1_young_card_val());
- __ beq(CR0, ret);
-
- // Return if sequential consistent value is already dirty.
- __ membar(Assembler::StoreLoad);
- __ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
-
- __ cmpwi(CR0, tmp, G1CardTable::dirty_card_val());
- __ beq(CR0, ret);
-
- // Not dirty.
-
- // First, dirty it.
- __ li(tmp, G1CardTable::dirty_card_val());
- __ stb(tmp, 0, addr);
-
- int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
- int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
-
- __ bind(restart);
-
- // Get the index into the update buffer. G1DirtyCardQueue::_index is
- // a size_t so ld_ptr is appropriate here.
- __ ld(tmp2, dirty_card_q_index_byte_offset, R16_thread);
-
- // index == 0?
- __ cmpdi(CR0, tmp2, 0);
- __ beq(CR0, refill);
-
- __ ld(tmp, dirty_card_q_buf_byte_offset, R16_thread);
- __ addi(tmp2, tmp2, -oopSize);
-
- __ std(tmp2, dirty_card_q_index_byte_offset, R16_thread);
- __ add(tmp2, tmp, tmp2);
- __ std(addr, 0, tmp2); // [_buf + index] :=
-
- // Restore temp registers and return-from-leaf.
- __ bind(ret);
- __ ld(tmp2, -16, R1_SP);
- __ ld(addr, -8, R1_SP);
- __ blr();
-
- __ bind(refill);
- const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord;
- __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
- __ mflr(R0);
- __ std(R0, _abi0(lr), R1_SP);
- __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1DirtyCardQueueSet::handle_zero_index_for_thread), R16_thread);
- __ pop_frame();
- __ ld(R0, _abi0(lr), R1_SP);
- __ mtlr(R0);
- __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0
- __ b(restart);
-}
-
#undef __
#endif // COMPILER1
diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp
index 33cb89dacc6..e059cc661af 100644
--- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -37,9 +37,7 @@
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
-class G1PostBarrierStub;
class G1PreBarrierStubC2;
-class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -56,8 +54,7 @@ protected:
MacroAssembler::PreservationLevel preservation_level);
void g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators,
Register store_addr, Register new_val,
- Register tmp1, Register tmp2, Register tmp3,
- MacroAssembler::PreservationLevel preservation_level);
+ Register tmp1, Register tmp2);
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register base, RegisterOrConstant ind_or_offs, Register val,
@@ -79,17 +76,21 @@ public:
Register new_val,
Register tmp1,
Register tmp2,
- G1PostBarrierStubC2* c2_stub,
+ bool new_val_may_be_null,
bool decode_new_val);
- void generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const;
#endif
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
- void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
- void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
+
+ void g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2);
+
#endif
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
diff --git a/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad
index 4f24efe872b..0a4a9442855 100644
--- a/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad
+++ b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2025 SAP SE. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
@@ -64,13 +64,13 @@ static void post_write_barrier(MacroAssembler* masm,
Register tmp1,
Register tmp2,
bool decode_new_val = false) {
- if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ if (!G1BarrierStubC2::needs_post_barrier(node)) {
return;
}
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
- G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
- g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, stub, decode_new_val);
+ bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, new_val_may_be_null, decode_new_val);
}
%}
diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
index b2e830bcdb8..8712c75711d 100644
--- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
@@ -193,14 +193,19 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t
// Low order half of 64 bit value is currently used.
__ ld(R0, in_bytes(bs_nm->thread_disarmed_guard_value_offset()), R16_thread);
- __ cmpw(CR0, R0, tmp);
- // Load stub address using toc (fixed instruction size, unlike load_const_optimized)
- __ calculate_address_from_global_toc(tmp, StubRoutines::method_entry_barrier(),
- true, true, false); // 2 instructions
- __ mtctr(tmp);
+ if (TrapBasedNMethodEntryBarriers) {
+ __ tw(Assembler::traptoLessThanUnsigned | Assembler::traptoGreaterThanUnsigned, R0, tmp);
+ } else {
+ __ cmpw(CR0, R0, tmp);
- __ bnectrl(CR0);
+ // Load stub address using toc (fixed instruction size, unlike load_const_optimized)
+ __ calculate_address_from_global_toc(tmp, StubRoutines::method_entry_barrier(),
+ true, true, false); // 2 instructions
+ __ mtctr(tmp);
+
+ __ bnectrl(CR0);
+ }
// Oops may have been changed. Make those updates observable.
// "isync" can serve both, data and instruction patching.
diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp
index 7aca2c9db45..96fa03df519 100644
--- a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp
@@ -100,17 +100,21 @@ public:
verify_op_code(current_instruction, Assembler::LD_OPCODE);
- // cmpw (mnemonic)
- verify_op_code(current_instruction, Assembler::CMP_OPCODE);
+ if (TrapBasedNMethodEntryBarriers) {
+ verify_op_code(current_instruction, Assembler::TW_OPCODE);
+ } else {
+ // cmpw (mnemonic)
+ verify_op_code(current_instruction, Assembler::CMP_OPCODE);
- // calculate_address_from_global_toc (compound instruction)
- verify_op_code_manually(current_instruction, MacroAssembler::is_addis(*current_instruction));
- verify_op_code_manually(current_instruction, MacroAssembler::is_addi(*current_instruction));
+ // calculate_address_from_global_toc (compound instruction)
+ verify_op_code_manually(current_instruction, MacroAssembler::is_addis(*current_instruction));
+ verify_op_code_manually(current_instruction, MacroAssembler::is_addi(*current_instruction));
- verify_op_code_manually(current_instruction, MacroAssembler::is_mtctr(*current_instruction));
+ verify_op_code_manually(current_instruction, MacroAssembler::is_mtctr(*current_instruction));
- // bnectrl (mnemonic) (weak check; not checking the exact type)
- verify_op_code(current_instruction, Assembler::BCCTR_OPCODE);
+ // bnectrl (mnemonic) (weak check; not checking the exact type)
+ verify_op_code(current_instruction, Assembler::BCCTR_OPCODE);
+ }
// isync is optional
}
@@ -131,9 +135,10 @@ private:
static NativeNMethodBarrier* get_nmethod_barrier(nmethod* nm) {
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
- address barrier_address = nm->code_begin() + nm->frame_complete_offset() + (-8 * 4);
+ address barrier_address = nm->code_begin() + nm->frame_complete_offset() -
+ (TrapBasedNMethodEntryBarriers ? 4 : 8) * BytesPerInstWord;
if (bs_asm->nmethod_patching_type() != NMethodPatchingType::stw_instruction_and_data_patch) {
- barrier_address -= 4; // isync (see nmethod_entry_barrier)
+ barrier_address -= BytesPerInstWord; // isync (see nmethod_entry_barrier)
}
auto barrier = reinterpret_cast(barrier_address);
diff --git a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp
index e30e8c82d23..0aa5858c8e6 100644
--- a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp
@@ -114,7 +114,6 @@ public:
}
};
-
void ZBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register base, RegisterOrConstant ind_or_offs, Register dst,
Register tmp1, Register tmp2,
@@ -561,7 +560,6 @@ void ZBarrierSetAssembler::generate_conjoint_oop_copy(MacroAssembler* masm, bool
copy_store_at_slow(masm, R4_ARG2, tmp, store_bad, store_good, dest_uninitialized);
}
-
// Verify a colored pointer.
void ZBarrierSetAssembler::check_oop(MacroAssembler *masm, Register obj, const char* msg) {
if (!VerifyOops) {
@@ -583,7 +581,6 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler *masm, Register obj, const c
__ bind(done);
}
-
void ZBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env,
Register obj, Register tmp, Label& slowpath) {
__ block_comment("try_resolve_jobject_in_native (zgc) {");
diff --git a/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp b/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp
index f8f15741301..6c41e56b20b 100644
--- a/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp
+++ b/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -43,8 +43,6 @@ const bool CCallingConventionRequiresIntsAsLongs = true;
#define SUPPORTS_NATIVE_CX8
-#define SUPPORT_MONITOR_COUNT
-
// PPC64 is not specified as multi-copy-atomic
// So we must not #define CPU_MULTI_COPY_ATOMIC
diff --git a/src/hotspot/cpu/ppc/globals_ppc.hpp b/src/hotspot/cpu/ppc/globals_ppc.hpp
index 65334bf0389..41a8e821ada 100644
--- a/src/hotspot/cpu/ppc/globals_ppc.hpp
+++ b/src/hotspot/cpu/ppc/globals_ppc.hpp
@@ -145,6 +145,8 @@ define_pd_global(intx, InitArrayShortSize, 9*BytesPerLong);
"switch off all optimizations requiring SIGTRAP.") \
product(bool, TrapBasedICMissChecks, true, DIAGNOSTIC, \
"Raise and handle SIGTRAP if inline cache miss detected.") \
+ product(bool, TrapBasedNMethodEntryBarriers, true, DIAGNOSTIC, \
+ "Raise and handle SIGTRAP if nmethod entry barrier armed.") \
\
product(bool, TraceTraps, false, DIAGNOSTIC, \
"Trace all traps the signal handler handles.") \
diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp
index d3969427db3..9140dd7ca4e 100644
--- a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp
+++ b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp
@@ -133,8 +133,13 @@ class InterpreterMacroAssembler: public MacroAssembler {
void get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size);
void load_resolved_indy_entry(Register cache, Register index);
- void load_field_entry(Register cache, Register index, int bcp_offset = 1);
- void load_method_entry(Register cache, Register index, int bcp_offset = 1);
+ void load_field_or_method_entry(bool is_method, Register cache, Register index, int bcp_offset, bool for_fast_bytecode);
+ void load_field_entry(Register cache, Register index, int bcp_offset = 1, bool for_fast_bytecode = false) {
+ load_field_or_method_entry(false, cache, index, bcp_offset, for_fast_bytecode);
+ }
+ void load_method_entry(Register cache, Register index, int bcp_offset = 1, bool for_fast_bytecode = false) {
+ load_field_or_method_entry(true, cache, index, bcp_offset, for_fast_bytecode);
+ }
void get_u4(Register Rdst, Register Rsrc, int offset, signedOrNot is_signed);
diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
index 8df2cc5d273..503cc259432 100644
--- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
@@ -468,33 +468,33 @@ void InterpreterMacroAssembler::load_resolved_indy_entry(Register cache, Registe
add(cache, cache, index);
}
-void InterpreterMacroAssembler::load_field_entry(Register cache, Register index, int bcp_offset) {
+void InterpreterMacroAssembler::load_field_or_method_entry(bool is_method, Register cache, Register index, int bcp_offset, bool for_fast_bytecode) {
+ const int entry_size = is_method ? sizeof(ResolvedMethodEntry) : sizeof(ResolvedFieldEntry),
+ base_offset = is_method ? Array::base_offset_in_bytes() : Array::base_offset_in_bytes(),
+ entries_offset = is_method ? in_bytes(ConstantPoolCache::method_entries_offset()) : in_bytes(ConstantPoolCache::field_entries_offset());
+
// Get index out of bytecode pointer
get_cache_index_at_bcp(index, bcp_offset, sizeof(u2));
// Take shortcut if the size is a power of 2
- if (is_power_of_2(sizeof(ResolvedFieldEntry))) {
+ if (is_power_of_2(entry_size)) {
// Scale index by power of 2
- sldi(index, index, log2i_exact(sizeof(ResolvedFieldEntry)));
+ sldi(index, index, log2i_exact(entry_size));
} else {
// Scale the index to be the entry index * sizeof(ResolvedFieldEntry)
- mulli(index, index, sizeof(ResolvedFieldEntry));
+ mulli(index, index, entry_size);
}
// Get address of field entries array
- ld_ptr(cache, in_bytes(ConstantPoolCache::field_entries_offset()), R27_constPoolCache);
- addi(cache, cache, Array::base_offset_in_bytes());
+ ld_ptr(cache, entries_offset, R27_constPoolCache);
+ addi(cache, cache, base_offset);
add(cache, cache, index);
-}
-void InterpreterMacroAssembler::load_method_entry(Register cache, Register index, int bcp_offset) {
- // Get index out of bytecode pointer
- get_cache_index_at_bcp(index, bcp_offset, sizeof(u2));
- // Scale the index to be the entry index * sizeof(ResolvedMethodEntry)
- mulli(index, index, sizeof(ResolvedMethodEntry));
-
- // Get address of field entries array
- ld_ptr(cache, ConstantPoolCache::method_entries_offset(), R27_constPoolCache);
- addi(cache, cache, Array::base_offset_in_bytes());
- add(cache, cache, index); // method_entries + base_offset + scaled index
+ if (for_fast_bytecode) {
+ // Prevent speculative loading from ResolvedFieldEntry/ResolvedMethodEntry as it can miss the info written by another thread.
+ // TemplateTable::patch_bytecode uses release-store.
+ // We reached here via control dependency (Bytecode dispatch has used the rewritten Bytecode).
+ // So, we can use control-isync based ordering.
+ isync();
+ }
}
// Load object from cpool->resolved_references(index).
diff --git a/src/hotspot/cpu/ppc/javaFrameAnchor_ppc.hpp b/src/hotspot/cpu/ppc/javaFrameAnchor_ppc.hpp
index 00a6b4cbf95..431166e9d66 100644
--- a/src/hotspot/cpu/ppc/javaFrameAnchor_ppc.hpp
+++ b/src/hotspot/cpu/ppc/javaFrameAnchor_ppc.hpp
@@ -33,17 +33,17 @@ public:
// 2 - saving a current state (javaCalls)
// 3 - restoring an old state (javaCalls)
+ // No hardware barriers are necessary. All members are volatile and the profiler
+ // is run from a signal handler and only observers the thread its running on.
+
inline void clear(void) {
// clearing _last_Java_sp must be first
_last_Java_sp = nullptr;
- // fence?
- OrderAccess::release();
_last_Java_pc = nullptr;
}
inline void set(intptr_t* sp, address pc) {
_last_Java_pc = pc;
- OrderAccess::release();
_last_Java_sp = sp;
}
@@ -56,11 +56,9 @@ public:
// unless the value is changing.
if (_last_Java_sp != src->_last_Java_sp) {
_last_Java_sp = nullptr;
- OrderAccess::release();
}
_last_Java_pc = src->_last_Java_pc;
// Must be last so profiler will always see valid frame if has_last_frame() is true.
- OrderAccess::release();
_last_Java_sp = src->_last_Java_sp;
}
@@ -75,6 +73,6 @@ public:
intptr_t* last_Java_fp() const { return *(intptr_t**)_last_Java_sp; }
- void set_last_Java_sp(intptr_t* sp) { OrderAccess::release(); _last_Java_sp = sp; }
+ void set_last_Java_sp(intptr_t* sp) { _last_Java_sp = sp; }
#endif // CPU_PPC_JAVAFRAMEANCHOR_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
index 4e93992f413..ebdfd9a57d6 100644
--- a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
+++ b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
@@ -402,7 +402,7 @@ void NativePostCallNop::make_deopt() {
bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) {
int32_t i2, i1;
assert(is_aligned(cb_offset, 4), "cb offset alignment does not match instruction alignment");
- assert(!decode(i1, i2), "already patched");
+ assert(!decode(i1, i2) || NMethodRelocation, "already patched");
cb_offset = cb_offset >> 2;
if (((oopmap_slot & ppc_oopmap_slot_mask) != oopmap_slot) || ((cb_offset & ppc_cb_offset_mask) != cb_offset)) {
diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp
index d5dec3f4b1f..dcb5c2bb3cb 100644
--- a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp
+++ b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp
@@ -77,6 +77,12 @@ class NativeInstruction {
}
#endif
+ bool is_sigtrap_nmethod_entry_barrier() {
+ assert(UseSIGTRAP && TrapBasedNMethodEntryBarriers, "precondition");
+ return Assembler::is_tw(long_at(0), Assembler::traptoLessThanUnsigned | Assembler::traptoGreaterThanUnsigned,
+ 0, -1);
+ }
+
bool is_safepoint_poll() {
// The current arguments of the instruction are not checked!
if (USE_POLL_BIT_ONLY) {
diff --git a/src/hotspot/cpu/ppc/orderAccess_ppc.hpp b/src/hotspot/cpu/ppc/orderAccess_ppc.hpp
new file mode 100644
index 00000000000..f5fa8da755f
--- /dev/null
+++ b/src/hotspot/cpu/ppc/orderAccess_ppc.hpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 SAP SE. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_PPC_ORDERACCESS_PPC_HPP
+#define CPU_PPC_ORDERACCESS_PPC_HPP
+
+#ifndef PPC64
+#error "OrderAccess currently only implemented for PPC64"
+#endif
+
+// Compiler version last used for testing: gcc 4.1.2
+// Please update this information when this file changes
+
+// Implementation of class OrderAccess.
+
+//
+// Machine barrier instructions:
+//
+// - sync Two-way memory barrier, aka fence.
+// - lwsync orders Store|Store,
+// Load|Store,
+// Load|Load,
+// but not Store|Load
+// - eieio orders Store|Store
+// - isync Invalidates speculatively executed instructions,
+// but isync may complete before storage accesses
+// associated with instructions preceding isync have
+// been performed.
+//
+// Semantic barrier instructions:
+// (as defined in orderAccess.hpp)
+//
+// - release orders Store|Store, (maps to lwsync)
+// Load|Store
+// - acquire orders Load|Store, (maps to lwsync)
+// Load|Load
+// - fence orders Store|Store, (maps to sync)
+// Load|Store,
+// Load|Load,
+// Store|Load
+//
+
+#define inlasm_sync() __asm__ __volatile__ ("sync" : : : "memory");
+#define inlasm_lwsync() __asm__ __volatile__ ("lwsync" : : : "memory");
+#define inlasm_eieio() __asm__ __volatile__ ("eieio" : : : "memory");
+#define inlasm_isync() __asm__ __volatile__ ("isync" : : : "memory");
+
+inline void OrderAccess::loadload() { inlasm_lwsync(); }
+inline void OrderAccess::storestore() { inlasm_lwsync(); }
+inline void OrderAccess::loadstore() { inlasm_lwsync(); }
+inline void OrderAccess::storeload() { inlasm_sync(); }
+
+inline void OrderAccess::acquire() { inlasm_lwsync(); }
+inline void OrderAccess::release() { inlasm_lwsync(); }
+inline void OrderAccess::fence() { inlasm_sync(); }
+inline void OrderAccess::cross_modify_fence_impl()
+ { inlasm_isync(); }
+
+#undef inlasm_sync
+#undef inlasm_lwsync
+#undef inlasm_eieio
+#undef inlasm_isync
+
+#endif // CPU_PPC_ORDERACCESS_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad
index 290369360fc..75566b2dd80 100644
--- a/src/hotspot/cpu/ppc/ppc.ad
+++ b/src/hotspot/cpu/ppc/ppc.ad
@@ -2450,31 +2450,27 @@ bool Matcher::use_asm_for_ldiv_by_con(jlong divisor) {
}
// Register for DIVI projection of divmodI.
-RegMask Matcher::divI_proj_mask() {
+const RegMask& Matcher::divI_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for MODI projection of divmodI.
-RegMask Matcher::modI_proj_mask() {
+const RegMask& Matcher::modI_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for DIVL projection of divmodL.
-RegMask Matcher::divL_proj_mask() {
+const RegMask& Matcher::divL_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for MODL projection of divmodL.
-RegMask Matcher::modL_proj_mask() {
+const RegMask& Matcher::modL_proj_mask() {
ShouldNotReachHere();
- return RegMask();
-}
-
-const RegMask Matcher::method_handle_invoke_SP_save_mask() {
- return RegMask();
+ return RegMask::EMPTY;
}
%}
@@ -3434,7 +3430,6 @@ encode %{
// Create the call node.
CallDynamicJavaDirectSchedNode *call = new CallDynamicJavaDirectSchedNode();
- call->_method_handle_invoke = _method_handle_invoke;
call->_vtable_index = _vtable_index;
call->_method = _method;
call->_optimized_virtual = _optimized_virtual;
@@ -12386,27 +12381,27 @@ instruct countTrailingZerosL_cnttzd(iRegIdst dst, iRegLsrc src) %{
%}
// Expand nodes for byte_reverse_int.
-instruct insrwi_a(iRegIdst dst, iRegIsrc src, immI16 pos, immI16 shift) %{
- effect(DEF dst, USE src, USE pos, USE shift);
+instruct insrwi_a(iRegIdst dst, iRegIsrc src, immI16 n, immI16 b) %{
+ effect(DEF dst, USE src, USE n, USE b);
predicate(false);
- format %{ "INSRWI $dst, $src, $pos, $shift" %}
+ format %{ "INSRWI $dst, $src, $n, $b" %}
size(4);
ins_encode %{
- __ insrwi($dst$$Register, $src$$Register, $shift$$constant, $pos$$constant);
+ __ insrwi($dst$$Register, $src$$Register, $n$$constant, $b$$constant);
%}
ins_pipe(pipe_class_default);
%}
// As insrwi_a, but with USE_DEF.
-instruct insrwi(iRegIdst dst, iRegIsrc src, immI16 pos, immI16 shift) %{
- effect(USE_DEF dst, USE src, USE pos, USE shift);
+instruct insrwi(iRegIdst dst, iRegIsrc src, immI16 n, immI16 b) %{
+ effect(USE_DEF dst, USE src, USE n, USE b);
predicate(false);
- format %{ "INSRWI $dst, $src, $pos, $shift" %}
+ format %{ "INSRWI $dst, $src, $n, $b" %}
size(4);
ins_encode %{
- __ insrwi($dst$$Register, $src$$Register, $shift$$constant, $pos$$constant);
+ __ insrwi($dst$$Register, $src$$Register, $n$$constant, $b$$constant);
%}
ins_pipe(pipe_class_default);
%}
@@ -12428,12 +12423,12 @@ instruct bytes_reverse_int_Ex(iRegIdst dst, iRegIsrc src) %{
iRegLdst tmpI3;
urShiftI_reg_imm(tmpI1, src, imm24);
- insrwi_a(dst, tmpI1, imm24, imm8);
+ insrwi_a(dst, tmpI1, imm8, imm24);
urShiftI_reg_imm(tmpI2, src, imm16);
- insrwi(dst, tmpI2, imm8, imm16);
+ insrwi(dst, tmpI2, imm16, imm8);
urShiftI_reg_imm(tmpI3, src, imm8);
insrwi(dst, tmpI3, imm8, imm8);
- insrwi(dst, src, imm0, imm8);
+ insrwi(dst, src, imm8, imm0);
%}
%}
@@ -12551,7 +12546,7 @@ instruct bytes_reverse_ushort_Ex(iRegIdst dst, iRegIsrc src) %{
immI16 imm8 %{ (int) 8 %}
urShiftI_reg_imm(dst, src, imm8);
- insrwi(dst, src, imm16, imm8);
+ insrwi(dst, src, imm8, imm16);
%}
%}
@@ -12580,7 +12575,7 @@ instruct bytes_reverse_short_Ex(iRegIdst dst, iRegIsrc src) %{
iRegLdst tmpI1;
urShiftI_reg_imm(tmpI1, src, imm8);
- insrwi(tmpI1, src, imm16, imm8);
+ insrwi(tmpI1, src, imm8, imm16);
extsh(dst, tmpI1);
%}
%}
diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
index 2a9bad059ba..9fe7e1f22ff 100644
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
@@ -1199,16 +1199,11 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs,
- AdapterHandlerEntry* handler) {
- address i2c_entry;
- address c2i_unverified_entry;
- address c2i_entry;
-
-
+ address entry_address[AdapterBlob::ENTRY_COUNT]) {
// entry: i2c
__ align(CodeEntryAlignment);
- i2c_entry = __ pc();
+ entry_address[AdapterBlob::I2C] = __ pc();
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
@@ -1216,7 +1211,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ align(CodeEntryAlignment);
BLOCK_COMMENT("c2i unverified entry");
- c2i_unverified_entry = __ pc();
+ entry_address[AdapterBlob::C2I_Unverified] = __ pc();
// inline_cache contains a CompiledICData
const Register ic = R19_inline_cache_reg;
@@ -1244,10 +1239,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
// entry: c2i
- c2i_entry = __ pc();
+ entry_address[AdapterBlob::C2I] = __ pc();
// Class initialization barrier for static methods
- address c2i_no_clinit_check_entry = nullptr;
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
if (VM_Version::supports_fast_class_init_checks()) {
Label L_skip_barrier;
@@ -1266,15 +1261,13 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ bctr();
__ bind(L_skip_barrier);
- c2i_no_clinit_check_entry = __ pc();
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
}
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->c2i_entry_barrier(masm, /* tmp register*/ ic_klass, /* tmp register*/ receiver_klass, /* tmp register*/ code);
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, call_interpreter, ientry);
-
- handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
return;
}
@@ -1646,7 +1639,6 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj,
assert_different_registers(reg_cont_obj, reg_flags);
Register zero = R8_ARG6;
Register tmp2 = R9_ARG7;
- Register tmp3 = R10_ARG8;
DEBUG_ONLY(__ block_comment("fill {"));
#ifdef ASSERT
@@ -1662,12 +1654,9 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj,
__ stw(zero, in_bytes(ContinuationEntry::pin_count_offset()), R1_SP);
__ ld_ptr(tmp2, JavaThread::cont_fastpath_offset(), R16_thread);
- __ ld(tmp3, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread);
__ st_ptr(tmp2, ContinuationEntry::parent_cont_fastpath_offset(), R1_SP);
- __ std(tmp3, in_bytes(ContinuationEntry::parent_held_monitor_count_offset()), R1_SP);
__ st_ptr(zero, JavaThread::cont_fastpath_offset(), R16_thread);
- __ std(zero, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread);
DEBUG_ONLY(__ block_comment("} fill"));
}
@@ -1688,7 +1677,6 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj,
static void continuation_enter_cleanup(MacroAssembler* masm) {
Register tmp1 = R8_ARG6;
Register tmp2 = R9_ARG7;
- Register tmp3 = R10_ARG8;
#ifdef ASSERT
__ block_comment("clean {");
@@ -1699,57 +1687,8 @@ static void continuation_enter_cleanup(MacroAssembler* masm) {
__ ld_ptr(tmp1, ContinuationEntry::parent_cont_fastpath_offset(), R1_SP);
__ st_ptr(tmp1, JavaThread::cont_fastpath_offset(), R16_thread);
-
- if (CheckJNICalls) {
- // Check if this is a virtual thread continuation
- Label L_skip_vthread_code;
- __ lwz(R0, in_bytes(ContinuationEntry::flags_offset()), R1_SP);
- __ cmpwi(CR0, R0, 0);
- __ beq(CR0, L_skip_vthread_code);
-
- // If the held monitor count is > 0 and this vthread is terminating then
- // it failed to release a JNI monitor. So we issue the same log message
- // that JavaThread::exit does.
- __ ld(R0, in_bytes(JavaThread::jni_monitor_count_offset()), R16_thread);
- __ cmpdi(CR0, R0, 0);
- __ beq(CR0, L_skip_vthread_code);
-
- // Save return value potentially containing the exception oop
- Register ex_oop = R15_esp; // nonvolatile register
- __ mr(ex_oop, R3_RET);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held));
- // Restore potental return value
- __ mr(R3_RET, ex_oop);
-
- // For vthreads we have to explicitly zero the JNI monitor count of the carrier
- // on termination. The held count is implicitly zeroed below when we restore from
- // the parent held count (which has to be zero).
- __ li(tmp1, 0);
- __ std(tmp1, in_bytes(JavaThread::jni_monitor_count_offset()), R16_thread);
-
- __ bind(L_skip_vthread_code);
- }
-#ifdef ASSERT
- else {
- // Check if this is a virtual thread continuation
- Label L_skip_vthread_code;
- __ lwz(R0, in_bytes(ContinuationEntry::flags_offset()), R1_SP);
- __ cmpwi(CR0, R0, 0);
- __ beq(CR0, L_skip_vthread_code);
-
- // See comment just above. If not checking JNI calls the JNI count is only
- // needed for assertion checking.
- __ li(tmp1, 0);
- __ std(tmp1, in_bytes(JavaThread::jni_monitor_count_offset()), R16_thread);
-
- __ bind(L_skip_vthread_code);
- }
-#endif
-
- __ ld(tmp2, in_bytes(ContinuationEntry::parent_held_monitor_count_offset()), R1_SP);
- __ ld_ptr(tmp3, ContinuationEntry::parent_offset(), R1_SP);
- __ std(tmp2, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread);
- __ st_ptr(tmp3, JavaThread::cont_entry_offset(), R16_thread);
+ __ ld_ptr(tmp2, ContinuationEntry::parent_offset(), R1_SP);
+ __ st_ptr(tmp2, JavaThread::cont_entry_offset(), R16_thread);
DEBUG_ONLY(__ block_comment("} clean"));
}
diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp
index f9f43ade501..948092bbb9a 100644
--- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp
+++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp
@@ -3277,8 +3277,12 @@ class StubGenerator: public StubCodeGenerator {
// register the stub as the default exit with class UnsafeMemoryAccess
UnsafeMemoryAccess::set_common_exit_stub_pc(StubRoutines::_unsafecopy_common_exit);
- // Note: the disjoint stubs must be generated first, some of
- // the conjoint stubs use them.
+ // Note: the disjoint stubs must be generated first, some of the
+ // conjoint stubs use them.
+
+ // Note: chaining of stubs does not rely on branching to an
+ // auxiliary post-push entry because none of the stubs
+ // push/pop a frame.
// non-aligned disjoint versions
StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id);
diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
index 7431f77aeff..09acd1c067d 100644
--- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
@@ -148,7 +148,9 @@ void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Reg
__ bind(L_fast_patch);
}
- // Patch bytecode.
+ // Patch bytecode with release store to coordinate with ResolvedFieldEntry
+ // and ResolvedMethodEntry loads in fast bytecode codelets.
+ __ release();
__ stb(Rnew_bc, 0, R14_bcp);
__ bind(L_patch_done);
@@ -312,6 +314,7 @@ void TemplateTable::fast_aldc(LdcType type) {
// We are resolved if the resolved reference cache entry contains a
// non-null object (CallSite, etc.)
__ get_cache_index_at_bcp(R31, 1, index_size); // Load index.
+ // Only rewritten during link time. So, no need for memory barriers for accessing resolved info.
__ load_resolved_reference_at_index(R17_tos, R31, R11_scratch1, R12_scratch2, &is_null);
// Convert null sentinel to null
@@ -2179,17 +2182,11 @@ void TemplateTable::_return(TosState state) {
// - Rscratch
void TemplateTable::resolve_cache_and_index_for_method(int byte_no, Register Rcache, Register Rscratch) {
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
- Label Lresolved, Ldone, L_clinit_barrier_slow;
+
+ Label L_clinit_barrier_slow, L_done;
Register Rindex = Rscratch;
Bytecodes::Code code = bytecode();
- switch (code) {
- case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
- case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
- default:
- break;
- }
-
const int bytecode_offset = (byte_no == f1_byte) ? in_bytes(ResolvedMethodEntry::bytecode1_offset())
: in_bytes(ResolvedMethodEntry::bytecode2_offset());
__ load_method_entry(Rcache, Rindex);
@@ -2197,20 +2194,8 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no, Register Rca
__ lbz(Rscratch, bytecode_offset, Rcache);
// Acquire by cmp-br-isync (see below).
__ cmpdi(CR0, Rscratch, (int)code);
- __ beq(CR0, Lresolved);
+ __ bne(CR0, L_clinit_barrier_slow);
- // Class initialization barrier slow path lands here as well.
- __ bind(L_clinit_barrier_slow);
-
- address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
- __ li(R4_ARG2, code);
- __ call_VM(noreg, entry, R4_ARG2, true);
-
- // Update registers with resolved info.
- __ load_method_entry(Rcache, Rindex);
- __ b(Ldone);
-
- __ bind(Lresolved);
__ isync(); // Order load wrt. succeeding loads.
// Class initialization barrier for static methods
@@ -2220,18 +2205,26 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no, Register Rca
__ ld(method, in_bytes(ResolvedMethodEntry::method_offset()), Rcache);
__ load_method_holder(klass, method);
- __ clinit_barrier(klass, R16_thread, nullptr /*L_fast_path*/, &L_clinit_barrier_slow);
+ __ clinit_barrier(klass, R16_thread, &L_done, /*L_slow_path*/ nullptr);
+ } else {
+ __ b(L_done);
}
- __ bind(Ldone);
+ // Class initialization barrier slow path lands here as well.
+ __ bind(L_clinit_barrier_slow);
+ address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
+ __ li(R4_ARG2, code);
+ __ call_VM(noreg, entry, R4_ARG2);
+
+ // Update registers with resolved info.
+ __ load_method_entry(Rcache, Rindex);
+ __ bind(L_done);
}
-void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
- Register Rcache,
- Register index) {
+void TemplateTable::resolve_cache_and_index_for_field(int byte_no, Register Rcache, Register index) {
assert_different_registers(Rcache, index);
- Label resolved;
+ Label L_clinit_barrier_slow, L_done;
Bytecodes::Code code = bytecode();
switch (code) {
@@ -2246,19 +2239,34 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
: in_bytes(ResolvedFieldEntry::put_code_offset());
__ lbz(R0, code_offset, Rcache);
__ cmpwi(CR0, R0, (int)code); // have we resolved this bytecode?
- __ beq(CR0, resolved);
+ __ bne(CR0, L_clinit_barrier_slow);
+
+ __ isync(); // Order load wrt. succeeding loads.
+
+ // Class initialization barrier for static fields
+ if (VM_Version::supports_fast_class_init_checks() &&
+ (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) {
+ const Register field_holder = R4_ARG2;
+
+ // InterpreterRuntime::resolve_get_put sets field_holder and finally release-stores put_code.
+ // We have seen the released put_code above and will read the corresponding field_holder and init_state
+ // (ordered by compare-branch-isync).
+ __ ld(field_holder, ResolvedFieldEntry::field_holder_offset(), Rcache);
+ __ clinit_barrier(field_holder, R16_thread, &L_done, /*L_slow_path*/ nullptr);
+ } else {
+ __ b(L_done);
+ }
// resolve first time through
+ // Class initialization barrier slow path lands here as well.
+ __ bind(L_clinit_barrier_slow);
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
- __ li(R4_ARG2, (int)code);
+ __ li(R4_ARG2, code);
__ call_VM(noreg, entry, R4_ARG2);
// Update registers with resolved info
__ load_field_entry(Rcache, index);
- __ bind(resolved);
-
- // Use acquire semantics for the bytecode (see ResolvedFieldEntry::fill_in()).
- __ isync(); // Order load wrt. succeeding loads.
+ __ bind(L_done);
}
void TemplateTable::load_resolved_field_entry(Register obj,
@@ -3109,7 +3117,7 @@ void TemplateTable::fast_storefield(TosState state) {
const ConditionRegister CR_is_vol = CR2; // Non-volatile condition register (survives runtime call in do_oop_store).
// Constant pool already resolved => Load flags and offset of field.
- __ load_field_entry(Rcache, Rscratch);
+ __ load_field_entry(Rcache, Rscratch, 1, /* for_fast_bytecode */ true);
jvmti_post_field_mod(Rcache, Rscratch, false /* not static */);
load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12
@@ -3190,7 +3198,7 @@ void TemplateTable::fast_accessfield(TosState state) {
// R12_scratch2 used by load_field_cp_cache_entry
// Constant pool already resolved. Get the field offset.
- __ load_field_entry(Rcache, Rscratch);
+ __ load_field_entry(Rcache, Rscratch, 1, /* for_fast_bytecode */ true);
load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12
// JVMTI support
@@ -3329,7 +3337,7 @@ void TemplateTable::fast_xaccess(TosState state) {
__ ld(Rclass_or_obj, 0, R18_locals);
// Constant pool already resolved. Get the field offset.
- __ load_field_entry(Rcache, Rscratch, 2);
+ __ load_field_entry(Rcache, Rscratch, 2, /* for_fast_bytecode */ true);
load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12
// JVMTI support not needed, since we switch back to single bytecode as soon as debugger attaches.
@@ -3490,7 +3498,7 @@ void TemplateTable::fast_invokevfinal(int byte_no) {
assert(byte_no == f2_byte, "use this argument");
Register Rcache = R31;
- __ load_method_entry(Rcache, R11_scratch1);
+ __ load_method_entry(Rcache, R11_scratch1, 1, /* for_fast_bytecode */ true);
invokevfinal_helper(Rcache, R11_scratch1, R12_scratch2, R22_tmp2, R23_tmp3);
}
diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp
index 1d2b8d3ca04..8b1de754650 100644
--- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp
+++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp
@@ -87,8 +87,10 @@ void VM_Version::initialize() {
if (!UseSIGTRAP) {
MSG(TrapBasedICMissChecks);
MSG(TrapBasedNullChecks);
- FLAG_SET_ERGO(TrapBasedNullChecks, false);
- FLAG_SET_ERGO(TrapBasedICMissChecks, false);
+ MSG(TrapBasedNMethodEntryBarriers);
+ FLAG_SET_ERGO(TrapBasedNullChecks, false);
+ FLAG_SET_ERGO(TrapBasedICMissChecks, false);
+ FLAG_SET_ERGO(TrapBasedNMethodEntryBarriers, false);
}
#ifdef COMPILER2
@@ -97,6 +99,10 @@ void VM_Version::initialize() {
FLAG_SET_ERGO(TrapBasedRangeChecks, false);
}
+ if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
+ FLAG_SET_ERGO(UsePopCountInstruction, true);
+ }
+
if (PowerArchitecturePPC64 >= 9) {
// Performance is good since Power9.
if (FLAG_IS_DEFAULT(SuperwordUseVSX)) {
diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp
index 0828342ee65..0712b60fb2a 100644
--- a/src/hotspot/cpu/riscv/assembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp
@@ -914,6 +914,17 @@ protected:
public:
+ static uint32_t encode_csrrw(Register Rd, const uint32_t csr, Register Rs1) {
+ guarantee(is_uimm12(csr), "csr is invalid");
+ uint32_t insn = 0;
+ patch((address)&insn, 6, 0, 0b1110011);
+ patch((address)&insn, 14, 12, 0b001);
+ patch_reg((address)&insn, 7, Rd);
+ patch_reg((address)&insn, 15, Rs1);
+ patch((address)&insn, 31, 20, csr);
+ return insn;
+ }
+
static uint32_t encode_jal(Register Rd, const int32_t offset) {
guarantee(is_simm21(offset) && ((offset % 2) == 0), "offset is invalid.");
uint32_t insn = 0;
@@ -3693,19 +3704,15 @@ public:
// --------------------------
// Upper Immediate Instruction
// --------------------------
-#define INSN(NAME) \
- void NAME(Register Rd, int32_t imm) { \
- /* lui -> c.lui */ \
- if (do_compress() && (Rd != x0 && Rd != x2 && imm != 0 && is_simm18(imm))) { \
- c_lui(Rd, imm); \
- return; \
- } \
- _lui(Rd, imm); \
+ void lui(Register Rd, int32_t imm) {
+ /* lui -> c.lui */
+ if (do_compress() && (Rd != x0 && Rd != x2 && imm != 0 && is_simm18(imm))) {
+ c_lui(Rd, imm);
+ return;
+ }
+ _lui(Rd, imm);
}
- INSN(lui);
-
-#undef INSN
// Cache Management Operations
// These instruction may be turned off for user space.
diff --git a/src/hotspot/cpu/riscv/assembler_riscv.inline.hpp b/src/hotspot/cpu/riscv/assembler_riscv.inline.hpp
index 1f9e6df2172..e85b64bd6ba 100644
--- a/src/hotspot/cpu/riscv/assembler_riscv.inline.hpp
+++ b/src/hotspot/cpu/riscv/assembler_riscv.inline.hpp
@@ -27,7 +27,7 @@
#ifndef CPU_RISCV_ASSEMBLER_RISCV_INLINE_HPP
#define CPU_RISCV_ASSEMBLER_RISCV_INLINE_HPP
-#include "asm/assembler.inline.hpp"
+#include "asm/assembler.hpp"
#include "asm/codeBuffer.hpp"
#include "code/codeCache.hpp"
diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp
index 0c16e632e5a..a8a21342248 100644
--- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp
@@ -204,10 +204,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- if (_compute_lock) {
- // lock_reg was destroyed by fast unlocking attempt => recompute it
- ce->monitor_address(_monitor_ix, _lock_reg);
- }
+
+ // lock_reg was destroyed by fast unlocking attempt => recompute it
+ ce->monitor_address(_monitor_ix, _lock_reg);
+
ce->store_parameter(_lock_reg->as_register(), 0);
// note: non-blocking leaf routine => no call info needed
StubId exit_id;
diff --git a/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp
index d3ccd46048b..b3a0b261f54 100644
--- a/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp
@@ -377,11 +377,6 @@ LIR_Opr FrameMap::stack_pointer() {
return FrameMap::sp_opr;
}
-// JSR 292
-LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
- return LIR_OprFact::illegalOpr; // Not needed on riscv
-}
-
bool FrameMap::validate_frame() {
return true;
}
diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp
index c3fe72870cf..9d8ae770ccf 100644
--- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp
@@ -338,7 +338,7 @@ int LIR_Assembler::emit_unwind_handler() {
MonitorExitStub* stub = nullptr;
if (method()->is_synchronized()) {
monitor_address(0, FrameMap::r10_opr);
- stub = new MonitorExitStub(FrameMap::r10_opr, true, 0);
+ stub = new MonitorExitStub(FrameMap::r10_opr, 0);
__ unlock_object(x15, x14, x10, x16, *stub->entry());
__ bind(*stub->continuation());
}
@@ -1350,6 +1350,7 @@ void LIR_Assembler::align_call(LIR_Code code) {
}
void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
+ Assembler::IncompressibleScope scope(_masm);
address call = __ reloc_call(Address(op->addr(), rtype));
if (call == nullptr) {
bailout("reloc call address stub overflow");
@@ -1360,6 +1361,7 @@ void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
}
void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
+ Assembler::IncompressibleScope scope(_masm);
address call = __ ic_call(op->addr());
if (call == nullptr) {
bailout("reloc call address stub overflow");
@@ -1494,14 +1496,12 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
Register lock = op->lock_opr()->as_register();
Register temp = op->scratch_opr()->as_register();
if (op->code() == lir_lock) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
// add debug info for NullPointerException only if one is possible
int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry());
if (op->info() != nullptr) {
add_debug_info_for_null_check(null_check_offset, op->info());
}
} else if (op->code() == lir_unlock) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
__ unlock_object(hdr, obj, lock, temp, *op->stub()->entry());
} else {
Unimplemented();
@@ -1844,6 +1844,10 @@ void LIR_Assembler::leal(LIR_Opr addr, LIR_Opr dest, LIR_PatchCode patch_code, C
void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) {
assert(!tmp->is_valid(), "don't need temporary");
+ Assembler::IncompressibleScope scope(_masm);
+ // Post call nops must be natural aligned due to cmodx rules.
+ align_call(lir_rtcall);
+
__ rt_call(dest);
if (info != nullptr) {
diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp
index 8198192f506..8e989de2665 100644
--- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp
@@ -48,27 +48,27 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result,
}
}
-int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) {
- assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1);
+int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) {
+ assert_different_registers(hdr, obj, basic_lock, temp, t0, t1);
int null_check_offset = -1;
verify_oop(obj);
// save object being locked into the BasicObjectLock
- sd(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
+ sd(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
null_check_offset = offset();
- lightweight_lock(disp_hdr, obj, hdr, temp, t1, slow_case);
+ lightweight_lock(basic_lock, obj, hdr, temp, t1, slow_case);
return null_check_offset;
}
-void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) {
- assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1);
+void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) {
+ assert_different_registers(hdr, obj, basic_lock, temp, t0, t1);
// load object
- ld(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
+ ld(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
verify_oop(obj);
lightweight_unlock(obj, hdr, temp, t1, slow_case);
diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp
index 561053045ec..16e76884049 100644
--- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -56,19 +56,19 @@ using MacroAssembler::null_check;
Register result);
// locking
- // hdr : must be x10, contents destroyed
- // obj : must point to the object to lock, contents preserved
- // disp_hdr: must point to the displaced header location, contents preserved
- // temp : temporary register, must not be scratch register t0 or t1
+ // hdr : must be x10, contents destroyed
+ // obj : must point to the object to lock, contents preserved
+ // basic_lock: must point to the basic_lock, contents preserved
+ // temp : temporary register, must not be scratch register t0 or t1
// returns code offset at which to add null check debug information
- int lock_object(Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case);
+ int lock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case);
// unlocking
- // hdr : contents destroyed
- // obj : must point to the object to lock, contents preserved
- // disp_hdr: must be x10 & must point to the displaced header location, contents destroyed
- // temp : temporary register, must not be scratch register t0 or t1
- void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case);
+ // hdr : contents destroyed
+ // obj : must point to the object to lock, contents preserved
+ // basic_lock: must be x10 & must point to the basic lock, contents destroyed
+ // temp : temporary register, must not be scratch register t0 or t1
+ void unlock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case);
void initialize_object(
Register obj, // result: pointer to object after successful allocation
diff --git a/src/hotspot/cpu/riscv/c1_globals_riscv.hpp b/src/hotspot/cpu/riscv/c1_globals_riscv.hpp
index d64b3b66fa2..b15bb5c23c3 100644
--- a/src/hotspot/cpu/riscv/c1_globals_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c1_globals_riscv.hpp
@@ -53,7 +53,6 @@ define_pd_global(size_t, CodeCacheExpansionSize, 32*K );
define_pd_global(size_t, CodeCacheMinBlockLength, 1);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, NeverActAsServerClassMachine, true );
-define_pd_global(uint64_t, MaxRAM, 1ULL*G);
define_pd_global(bool, CICompileOSR, true );
#endif // !COMPILER2
define_pd_global(bool, UseTypeProfile, false);
diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
index 1bdb7bc2f7c..154b62db47f 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
@@ -1687,6 +1687,7 @@ void C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register res
Register tmp4, Register tmp5, Register tmp6,
BasicType eltype)
{
+ assert(!UseRVV, "sanity");
assert_different_registers(ary, cnt, result, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, t0, t1);
const int elsize = arrays_hashcode_elsize(eltype);
@@ -1759,29 +1760,143 @@ void C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register res
BLOCK_COMMENT("} // arrays_hashcode");
}
+void C2_MacroAssembler::arrays_hashcode_v(Register ary, Register cnt, Register result,
+ Register tmp1, Register tmp2, Register tmp3,
+ BasicType eltype)
+{
+ assert(UseRVV, "sanity");
+ assert(StubRoutines::riscv::arrays_hashcode_powers_of_31() != nullptr, "sanity");
+ assert_different_registers(ary, cnt, result, tmp1, tmp2, tmp3, t0, t1);
+
+ // The MaxVectorSize should have been set by detecting RVV max vector register
+ // size when check UseRVV (i.e. MaxVectorSize == VM_Version::_initial_vector_length).
+ // Let's use T_INT as all hashCode calculations eventually deal with ints.
+ const int lmul = 2;
+ const int stride = MaxVectorSize / sizeof(jint) * lmul;
+
+ const int elsize_bytes = arrays_hashcode_elsize(eltype);
+ const int elsize_shift = exact_log2(elsize_bytes);
+
+ switch (eltype) {
+ case T_BOOLEAN: BLOCK_COMMENT("arrays_hashcode_v(unsigned byte) {"); break;
+ case T_CHAR: BLOCK_COMMENT("arrays_hashcode_v(char) {"); break;
+ case T_BYTE: BLOCK_COMMENT("arrays_hashcode_v(byte) {"); break;
+ case T_SHORT: BLOCK_COMMENT("arrays_hashcode_v(short) {"); break;
+ case T_INT: BLOCK_COMMENT("arrays_hashcode_v(int) {"); break;
+ default:
+ ShouldNotReachHere();
+ }
+
+ const Register pow31_highest = tmp1;
+ const Register ary_end = tmp2;
+ const Register consumed = tmp3;
+
+ const VectorRegister v_sum = v2;
+ const VectorRegister v_src = v4;
+ const VectorRegister v_coeffs = v6;
+ const VectorRegister v_tmp = v8;
+
+ const address adr_pows31 = StubRoutines::riscv::arrays_hashcode_powers_of_31()
+ + sizeof(jint);
+ Label VEC_LOOP, DONE, SCALAR_TAIL, SCALAR_TAIL_LOOP;
+
+ // NB: at this point (a) 'result' already has some value,
+ // (b) 'cnt' is not 0 or 1, see java code for details.
+
+ andi(t0, cnt, ~(stride - 1));
+ beqz(t0, SCALAR_TAIL);
+
+ la(t1, ExternalAddress(adr_pows31));
+ lw(pow31_highest, Address(t1, -1 * sizeof(jint)));
+
+ vsetvli(consumed, cnt, Assembler::e32, Assembler::m2);
+ vle32_v(v_coeffs, t1); // 31^^(stride - 1) ... 31^^0
+ vmv_v_x(v_sum, x0);
+
+ bind(VEC_LOOP);
+ arrays_hashcode_elload_v(v_src, v_tmp, ary, eltype);
+ vmul_vv(v_src, v_src, v_coeffs);
+ vmadd_vx(v_sum, pow31_highest, v_src);
+ mulw(result, result, pow31_highest);
+ shadd(ary, consumed, ary, t0, elsize_shift);
+ subw(cnt, cnt, consumed);
+ andi(t1, cnt, ~(stride - 1));
+ bnez(t1, VEC_LOOP);
+
+ vmv_s_x(v_tmp, x0);
+ vredsum_vs(v_sum, v_sum, v_tmp);
+ vmv_x_s(t0, v_sum);
+ addw(result, result, t0);
+ beqz(cnt, DONE);
+
+ bind(SCALAR_TAIL);
+ shadd(ary_end, cnt, ary, t0, elsize_shift);
+
+ bind(SCALAR_TAIL_LOOP);
+ arrays_hashcode_elload(t0, Address(ary), eltype);
+ slli(t1, result, 5); // optimize 31 * result
+ subw(result, t1, result); // with result<<5 - result
+ addw(result, result, t0);
+ addi(ary, ary, elsize_bytes);
+ bne(ary, ary_end, SCALAR_TAIL_LOOP);
+
+ bind(DONE);
+ BLOCK_COMMENT("} // arrays_hashcode_v");
+}
+
int C2_MacroAssembler::arrays_hashcode_elsize(BasicType eltype) {
switch (eltype) {
- case T_BOOLEAN: return sizeof(jboolean);
- case T_BYTE: return sizeof(jbyte);
- case T_SHORT: return sizeof(jshort);
- case T_CHAR: return sizeof(jchar);
- case T_INT: return sizeof(jint);
- default:
- ShouldNotReachHere();
- return -1;
+ case T_BOOLEAN: return sizeof(jboolean);
+ case T_BYTE: return sizeof(jbyte);
+ case T_SHORT: return sizeof(jshort);
+ case T_CHAR: return sizeof(jchar);
+ case T_INT: return sizeof(jint);
+ default:
+ ShouldNotReachHere();
+ return -1;
}
}
void C2_MacroAssembler::arrays_hashcode_elload(Register dst, Address src, BasicType eltype) {
switch (eltype) {
- // T_BOOLEAN used as surrogate for unsigned byte
- case T_BOOLEAN: lbu(dst, src); break;
- case T_BYTE: lb(dst, src); break;
- case T_SHORT: lh(dst, src); break;
- case T_CHAR: lhu(dst, src); break;
- case T_INT: lw(dst, src); break;
- default:
- ShouldNotReachHere();
+ // T_BOOLEAN used as surrogate for unsigned byte
+ case T_BOOLEAN: lbu(dst, src); break;
+ case T_BYTE: lb(dst, src); break;
+ case T_SHORT: lh(dst, src); break;
+ case T_CHAR: lhu(dst, src); break;
+ case T_INT: lw(dst, src); break;
+ default:
+ ShouldNotReachHere();
+ }
+}
+
+void C2_MacroAssembler::arrays_hashcode_elload_v(VectorRegister vdst,
+ VectorRegister vtmp,
+ Register src,
+ BasicType eltype) {
+ assert_different_registers(vdst, vtmp);
+ switch (eltype) {
+ case T_BOOLEAN:
+ vle8_v(vtmp, src);
+ vzext_vf4(vdst, vtmp);
+ break;
+ case T_BYTE:
+ vle8_v(vtmp, src);
+ vsext_vf4(vdst, vtmp);
+ break;
+ case T_CHAR:
+ vle16_v(vtmp, src);
+ vzext_vf2(vdst, vtmp);
+ break;
+ case T_SHORT:
+ vle16_v(vtmp, src);
+ vsext_vf2(vdst, vtmp);
+ break;
+ case T_INT:
+ vle32_v(vdst, src);
+ break;
+ default:
+ ShouldNotReachHere();
}
}
diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
index 309ef8d9d5e..2d5339dc153 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
@@ -92,11 +92,15 @@
Register tmp3, Register tmp4,
Register tmp5, Register tmp6,
BasicType eltype);
-
- // helper function for arrays_hashcode
int arrays_hashcode_elsize(BasicType eltype);
void arrays_hashcode_elload(Register dst, Address src, BasicType eltype);
+ void arrays_hashcode_v(Register ary, Register cnt, Register result,
+ Register tmp1, Register tmp2, Register tmp3,
+ BasicType eltype);
+ void arrays_hashcode_elload_v(VectorRegister vdst, VectorRegister vtmp,
+ Register src, BasicType eltype);
+
void string_equals(Register r1, Register r2,
Register result, Register cnt1);
diff --git a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp
index 372865fc291..648c24ee98b 100644
--- a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp
@@ -55,7 +55,6 @@ define_pd_global(size_t, InitialCodeCacheSize, 2496*K); // Integral multip
define_pd_global(size_t, CodeCacheExpansionSize, 64*K);
// Ergonomics related flags
-define_pd_global(uint64_t,MaxRAM, 128ULL*G);
define_pd_global(intx, RegisterCostAreaRatio, 16000);
// Peephole and CISC spilling both break the graph, and so makes the
diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp
index b677c980c78..19dbdd6aeae 100644
--- a/src/hotspot/cpu/riscv/frame_riscv.cpp
+++ b/src/hotspot/cpu/riscv/frame_riscv.cpp
@@ -217,8 +217,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
nmethod* nm = sender_blob->as_nmethod_or_null();
if (nm != nullptr) {
- if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) ||
- nm->method()->is_method_handle_intrinsic()) {
+ if (nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) {
return false;
}
}
@@ -427,49 +426,6 @@ JavaThread** frame::saved_thread_address(const frame& f) {
return thread_addr;
}
-//------------------------------------------------------------------------------
-// frame::verify_deopt_original_pc
-//
-// Verifies the calculated original PC of a deoptimization PC for the
-// given unextended SP.
-#ifdef ASSERT
-void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) {
- frame fr;
-
- // This is ugly but it's better than to change {get,set}_original_pc
- // to take an SP value as argument. And it's only a debugging
- // method anyway.
- fr._unextended_sp = unextended_sp;
-
- assert_cond(nm != nullptr);
- address original_pc = nm->get_original_pc(&fr);
- assert(nm->insts_contains_inclusive(original_pc),
- "original PC must be in the main code section of the compiled method (or must be immediately following it)");
-}
-#endif
-
-//------------------------------------------------------------------------------
-// frame::adjust_unextended_sp
-#ifdef ASSERT
-void frame::adjust_unextended_sp() {
- // On riscv, sites calling method handle intrinsics and lambda forms are treated
- // as any other call site. Therefore, no special action is needed when we are
- // returning to any of these call sites.
-
- if (_cb != nullptr) {
- nmethod* sender_nm = _cb->as_nmethod_or_null();
- if (sender_nm != nullptr) {
- // If the sender PC is a deoptimization point, get the original PC.
- if (sender_nm->is_deopt_entry(_pc) ||
- sender_nm->is_deopt_mh_entry(_pc)) {
- verify_deopt_original_pc(sender_nm, _unextended_sp);
- }
- }
- }
-}
-#endif
-
-
//------------------------------------------------------------------------------
// frame::sender_for_interpreter_frame
frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
diff --git a/src/hotspot/cpu/riscv/frame_riscv.hpp b/src/hotspot/cpu/riscv/frame_riscv.hpp
index b4540c45ab8..ce5a8dde230 100644
--- a/src/hotspot/cpu/riscv/frame_riscv.hpp
+++ b/src/hotspot/cpu/riscv/frame_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -179,17 +179,10 @@
int _offset_unextended_sp; // for use in stack-chunk frames
};
- void adjust_unextended_sp() NOT_DEBUG_RETURN;
-
intptr_t* ptr_at_addr(int offset) const {
return (intptr_t*) addr_at(offset);
}
-#ifdef ASSERT
- // Used in frame::sender_for_{interpreter,compiled}_frame
- static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
-#endif
-
public:
// Constructors
diff --git a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp
index fb31760e20b..51a203c548c 100644
--- a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp
+++ b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -114,8 +114,6 @@ inline void frame::init(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc) {
}
inline void frame::setup(address pc) {
- adjust_unextended_sp();
-
address original_pc = get_deopt_original_pc();
if (original_pc != nullptr) {
_pc = original_pc;
@@ -215,7 +213,6 @@ inline frame::frame(intptr_t* ptr_sp, intptr_t* ptr_fp) {
// value.
_cb = CodeCache::find_blob(_pc);
- adjust_unextended_sp();
address original_pc = get_deopt_original_pc();
if (original_pc != nullptr) {
diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
index ef5dcdd8074..64e9cbe1f47 100644
--- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
@@ -87,15 +87,54 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm
}
}
-void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register start, Register count, Register tmp, RegSet saved_regs) {
- __ push_reg(saved_regs, sp);
+void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm,
+ DecoratorSet decorators,
+ Register start,
+ Register count,
+ Register tmp,
+ RegSet saved_regs) {
assert_different_registers(start, count, tmp);
- assert_different_registers(c_rarg0, count);
- __ mv(c_rarg0, start);
- __ mv(c_rarg1, count);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);
- __ pop_reg(saved_regs, sp);
+
+ Label loop, next, done;
+
+ // Zero count? Nothing to do.
+ __ beqz(count, done);
+
+ // Calculate the number of card marks to set. Since the object might start and
+ // end within a card, we need to calculate this via the card table indexes of
+ // the actual start and last addresses covered by the object.
+ // Temporarily use the count register for the last element address.
+ __ shadd(count, count, start, tmp, LogBytesPerHeapOop); // end = start + count << LogBytesPerHeapOop
+ __ subi(count, count, BytesPerHeapOop); // Use last element address for end.
+
+ __ srli(start, start, CardTable::card_shift());
+ __ srli(count, count, CardTable::card_shift());
+ __ sub(count, count, start); // Number of bytes to mark - 1.
+
+ // Add card table base offset to start.
+ Address card_table_address(xthread, G1ThreadLocalData::card_table_base_offset());
+ __ ld(tmp, card_table_address);
+ __ add(start, start, tmp);
+
+ __ bind(loop);
+ if (UseCondCardMark) {
+ __ add(tmp, start, count);
+ __ lbu(tmp, Address(tmp, 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);
+ }
+
+ __ add(tmp, start, count);
+ static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
+ __ sb(zr, Address(tmp, 0));
+
+ __ bind(next);
+ __ subi(count, count, 1);
+ __ bgez(count, loop);
+
+ __ bind(done);
}
static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
@@ -189,47 +228,40 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
}
-static void generate_post_barrier_fast_path(MacroAssembler* masm,
- const Register store_addr,
- const Register new_val,
- const Register tmp1,
- const Register tmp2,
- Label& done,
- bool new_val_may_be_null) {
+static void generate_post_barrier(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
+ assert(thread == xthread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
// Does store cross heap regions?
__ xorr(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
__ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
__ beqz(tmp1, done);
+
// Crosses regions, storing null?
if (new_val_may_be_null) {
__ beqz(new_val, done);
}
- // Storing region crossing non-null, is card young?
+ // Storing region crossing non-null, is card clean?
__ srli(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base
- __ load_byte_map_base(tmp2); // tmp2 := card table base address
- __ add(tmp1, tmp1, tmp2); // tmp1 := card address
- __ lbu(tmp2, Address(tmp1)); // tmp2 := card
-}
-static void generate_post_barrier_slow_path(MacroAssembler* masm,
- const Register thread,
- const Register tmp1,
- const Register tmp2,
- Label& done,
- Label& runtime) {
- __ membar(MacroAssembler::StoreLoad); // StoreLoad membar
- __ lbu(tmp2, Address(tmp1)); // tmp2 := card
- __ beqz(tmp2, done, true);
- // Storing a region crossing, non-null oop, card is clean.
- // Dirty card and log.
- STATIC_ASSERT(CardTable::dirty_card_val() == 0);
- __ sb(zr, Address(tmp1)); // *(card address) := dirty_card_val
- generate_queue_test_and_insertion(masm,
- G1ThreadLocalData::dirty_card_queue_index_offset(),
- G1ThreadLocalData::dirty_card_queue_buffer_offset(),
- runtime,
- thread, tmp1, tmp2, t0);
- __ j(done);
+ 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");
+ __ 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);
+ }
+ static_assert((uint)G1CardTable::dirty_card_val() == 0, "must be to use zr");
+ __ sb(zr, Address(tmp1, 0));
}
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
@@ -238,27 +270,8 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
Register thread,
Register tmp1,
Register tmp2) {
- assert(thread == xthread, "must be");
- assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0);
- assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg,
- "expecting a register");
-
Label done;
- Label runtime;
-
- generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
- // If card is young, jump to done (tmp2 holds the card value)
- __ mv(t0, (int)G1CardTable::g1_young_card_val());
- __ beq(tmp2, t0, done); // card == young_card_val?
- generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime);
-
- __ bind(runtime);
- // save the live input values
- RegSet saved = RegSet::of(store_addr);
- __ push_reg(saved, sp);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread);
- __ pop_reg(saved, sp);
-
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
__ bind(done);
}
@@ -318,37 +331,10 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
Register thread,
Register tmp1,
Register tmp2,
- G1PostBarrierStubC2* stub) {
- assert(thread == xthread, "must be");
- assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0);
- assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg,
- "expecting a register");
-
- stub->initialize_registers(thread, tmp1, tmp2);
-
- bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
- generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null);
- // If card is not young, jump to stub (slow path) (tmp2 holds the card value)
- __ mv(t0, (int)G1CardTable::g1_young_card_val());
- __ bne(tmp2, t0, *stub->entry(), true);
-
- __ bind(*stub->continuation());
-}
-
-void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const {
- Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
- Label runtime;
- Register thread = stub->thread();
- Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
- Register tmp2 = stub->tmp2();
-
- __ bind(*stub->entry());
- generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime);
-
- __ bind(runtime);
- generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
- __ j(*stub->continuation());
+ bool new_val_may_be_null) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, new_val_may_be_null);
+ __ bind(done);
}
#endif // COMPILER2
@@ -443,20 +429,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
__ j(*stub->continuation());
}
-void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
- G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
- __ bind(*stub->entry());
- assert(stub->addr()->is_register(), "Precondition");
- assert(stub->new_val()->is_register(), "Precondition");
- Register new_val_reg = stub->new_val()->as_register();
- __ beqz(new_val_reg, *stub->continuation(), /* is_far */ true);
- ce->store_parameter(stub->addr()->as_pointer_register(), 0);
- __ far_call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));
- __ j(*stub->continuation());
-}
-
#undef __
+void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
+ masm->bind(done);
+}
+
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
@@ -507,74 +492,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ epilogue();
}
-void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
- __ prologue("g1_post_barrier", false);
-
- // arg0 : store_address
- Address store_addr(fp, 2 * BytesPerWord); // 2 BytesPerWord from fp
-
- BarrierSet* bs = BarrierSet::barrier_set();
- CardTableBarrierSet* ctbs = barrier_set_cast(bs);
-
- Label done;
- Label runtime;
-
- // At this point we know new_value is non-null and the new_value crosses regions.
- // Must check to see if card is already dirty
- const Register thread = xthread;
-
- Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
- Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
-
- const Register card_offset = t1;
- // RA is free here, so we can use it to hold the byte_map_base.
- const Register byte_map_base = ra;
-
- assert_different_registers(card_offset, byte_map_base, t0);
-
- __ load_parameter(0, card_offset);
- __ srli(card_offset, card_offset, CardTable::card_shift());
- __ load_byte_map_base(byte_map_base);
-
- // Convert card offset into an address in card_addr
- Register card_addr = card_offset;
- __ add(card_addr, byte_map_base, card_addr);
-
- __ lbu(t0, Address(card_addr, 0));
- __ sub(t0, t0, (int)G1CardTable::g1_young_card_val());
- __ beqz(t0, done);
-
- assert((int)CardTable::dirty_card_val() == 0, "must be 0");
-
- __ membar(MacroAssembler::StoreLoad);
- __ lbu(t0, Address(card_addr, 0));
- __ beqz(t0, done);
-
- // storing region crossing non-null, card is clean.
- // dirty card and log.
- __ sb(zr, Address(card_addr, 0));
-
- __ ld(t0, queue_index);
- __ beqz(t0, runtime);
- __ subi(t0, t0, wordSize);
- __ sd(t0, queue_index);
-
- // Reuse RA to hold buffer_addr
- const Register buffer_addr = ra;
-
- __ ld(buffer_addr, buffer);
- __ add(t0, buffer_addr, t0);
- __ sd(card_addr, Address(t0, 0));
- __ j(done);
-
- __ bind(runtime);
- __ push_call_clobbered_registers();
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);
- __ pop_call_clobbered_registers();
- __ bind(done);
- __ epilogue();
-}
-
#undef __
#endif // COMPILER1
diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp
index 26310231362..654ba934242 100644
--- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -35,9 +35,7 @@ class LIR_Assembler;
#endif
class StubAssembler;
class G1PreBarrierStub;
-class G1PostBarrierStub;
class G1PreBarrierStubC2;
-class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -68,10 +66,16 @@ protected:
public:
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
- void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
- void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
+
+ void g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2);
+
#endif
#ifdef COMPILER2
@@ -90,9 +94,7 @@ public:
Register thread,
Register tmp1,
Register tmp2,
- G1PostBarrierStubC2* c2_stub);
- void generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const;
+ bool new_val_may_be_null);
#endif
void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
diff --git a/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad
index 7a525323021..8461a36e68c 100644
--- a/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad
+++ b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2024, Huawei Technologies Co., Ltd. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
@@ -63,13 +63,13 @@ static void write_barrier_post(MacroAssembler* masm,
Register new_val,
Register tmp1,
Register tmp2) {
- if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ if (!G1BarrierStubC2::needs_post_barrier(node)) {
return;
}
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
- G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
- g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, xthread, tmp1, tmp2, stub);
+ bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, xthread, tmp1, tmp2, new_val_may_be_null);
}
%}
diff --git a/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp
index 407017ee1c0..57223cf4390 100644
--- a/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp
+++ b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -44,8 +44,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
#define SUPPORTS_NATIVE_CX8
-#define SUPPORT_MONITOR_COUNT
-
#define SUPPORT_RESERVED_STACK_AREA
#define USE_POINTERS_TO_REGISTER_IMPL_ARRAY
diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp
index 7c4b8444407..549c9cda7b6 100644
--- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp
+++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp
@@ -1841,6 +1841,15 @@ void InterpreterMacroAssembler::load_method_entry(Register cache, Register index
}
#ifdef ASSERT
+void InterpreterMacroAssembler::verify_field_offset(Register reg) {
+ // Verify the field offset is not in the header, implicitly checks for 0
+ Label L;
+ mv(t0, oopDesc::base_offset_in_bytes());
+ bge(reg, t0, L);
+ stop("bad field offset");
+ bind(L);
+}
+
void InterpreterMacroAssembler::verify_access_flags(Register access_flags, uint32_t flag,
const char* msg, bool stop_by_hit) {
Label L;
diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp
index 0732191ea83..295f1b22191 100644
--- a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp
+++ b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp
@@ -300,11 +300,10 @@ class InterpreterMacroAssembler: public MacroAssembler {
void load_field_entry(Register cache, Register index, int bcp_offset = 1);
void load_method_entry(Register cache, Register index, int bcp_offset = 1);
-#ifdef ASSERT
+ void verify_field_offset(Register reg) NOT_DEBUG_RETURN;
void verify_access_flags(Register access_flags, uint32_t flag,
- const char* msg, bool stop_by_hit = true);
- void verify_frame_setup();
-#endif
+ const char* msg, bool stop_by_hit = true) NOT_DEBUG_RETURN;
+ void verify_frame_setup() NOT_DEBUG_RETURN;
};
#endif // CPU_RISCV_INTERP_MASM_RISCV_HPP
diff --git a/src/hotspot/cpu/riscv/javaFrameAnchor_riscv.hpp b/src/hotspot/cpu/riscv/javaFrameAnchor_riscv.hpp
index 1293fae0c0b..6bf1230914a 100644
--- a/src/hotspot/cpu/riscv/javaFrameAnchor_riscv.hpp
+++ b/src/hotspot/cpu/riscv/javaFrameAnchor_riscv.hpp
@@ -39,25 +39,23 @@ public:
// 3 - restoring an old state (javaCalls)
void clear(void) {
+ // No hardware barriers are necessary. All members are volatile and the profiler
+ // is run from a signal handler and the only observer is the thread its running on.
+
// clearing _last_Java_sp must be first
_last_Java_sp = nullptr;
- OrderAccess::release();
_last_Java_fp = nullptr;
_last_Java_pc = nullptr;
}
void copy(JavaFrameAnchor* src) {
- // In order to make sure the transition state is valid for "this"
+ // No hardware barriers are necessary. All members are volatile and the profiler
+ // is run from a signal handler and the only observer is the thread its running on.
+
// We must clear _last_Java_sp before copying the rest of the new data
- //
- // Hack Alert: Temporary bugfix for 4717480/4721647
- // To act like previous version (pd_cache_state) don't null _last_Java_sp
- // unless the value is changing
- //
assert(src != nullptr, "Src should not be null.");
if (_last_Java_sp != src->_last_Java_sp) {
_last_Java_sp = nullptr;
- OrderAccess::release();
}
_last_Java_fp = src->_last_Java_fp;
_last_Java_pc = src->_last_Java_pc;
diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
index c9de1db0308..700e42e6194 100644
--- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
@@ -225,36 +225,6 @@ void MacroAssembler::pop_cont_fastpath(Register java_thread) {
bind(done);
}
-void MacroAssembler::inc_held_monitor_count(Register tmp) {
- Address dst(xthread, JavaThread::held_monitor_count_offset());
- ld(tmp, dst);
- addi(tmp, tmp, 1);
- sd(tmp, dst);
-#ifdef ASSERT
- Label ok;
- test_bit(tmp, tmp, 63);
- beqz(tmp, ok);
- STOP("assert(held monitor count overflow)");
- should_not_reach_here();
- bind(ok);
-#endif
-}
-
-void MacroAssembler::dec_held_monitor_count(Register tmp) {
- Address dst(xthread, JavaThread::held_monitor_count_offset());
- ld(tmp, dst);
- subi(tmp, tmp, 1);
- sd(tmp, dst);
-#ifdef ASSERT
- Label ok;
- test_bit(tmp, tmp, 63);
- beqz(tmp, ok);
- STOP("assert(held monitor count underflow)");
- should_not_reach_here();
- bind(ok);
-#endif
-}
-
int MacroAssembler::align(int modulus, int extra_offset) {
CompressibleScope scope(this);
intptr_t before = offset();
@@ -355,14 +325,15 @@ void MacroAssembler::call_VM(Register oop_result,
}
void MacroAssembler::post_call_nop() {
+ assert(!in_compressible_scope(), "Must be");
+ assert_alignment(pc());
if (!Continuations::enabled()) {
return;
}
- relocate(post_call_nop_Relocation::spec(), [&] {
- InlineSkippedInstructionsCounter skipCounter(this);
- nop();
- li32(zr, 0);
- });
+ relocate(post_call_nop_Relocation::spec());
+ InlineSkippedInstructionsCounter skipCounter(this);
+ nop();
+ li32(zr, 0);
}
// these are no-ops overridden by InterpreterMacroAssembler
@@ -389,12 +360,14 @@ void MacroAssembler::set_last_Java_frame(Register last_java_sp,
last_java_sp = esp;
}
- sd(last_java_sp, Address(xthread, JavaThread::last_Java_sp_offset()));
-
// last_java_fp is optional
if (last_java_fp->is_valid()) {
sd(last_java_fp, Address(xthread, JavaThread::last_Java_fp_offset()));
}
+
+ // We must set sp last.
+ sd(last_java_sp, Address(xthread, JavaThread::last_Java_sp_offset()));
+
}
void MacroAssembler::set_last_Java_frame(Register last_java_sp,
@@ -5013,7 +4986,7 @@ address MacroAssembler::reloc_call(Address entry, Register tmp) {
address MacroAssembler::ic_call(address entry, jint method_index) {
RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
- IncompressibleScope scope(this); // relocations
+ assert(!in_compressible_scope(), "Must be");
movptr(t0, (address)Universe::non_oop_word(), t1);
assert_cond(entry != nullptr);
return reloc_call(Address(entry, rh));
diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
index 13b70d5dbd7..9e713e90270 100644
--- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -849,9 +849,6 @@ public:
void push_cont_fastpath(Register java_thread = xthread);
void pop_cont_fastpath(Register java_thread = xthread);
- void inc_held_monitor_count(Register tmp);
- void dec_held_monitor_count(Register tmp);
-
// if heap base register is used - reinit it with the correct value
void reinit_heapbase();
diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
index 72cc95a595d..5d1cac72ade 100644
--- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
+++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
@@ -331,13 +331,10 @@ bool NativeInstruction::is_safepoint_poll() {
return MacroAssembler::is_lwu_to_zr(address(this));
}
-void NativeIllegalInstruction::insert(address code_pos) {
- assert_cond(code_pos != nullptr);
- Assembler::sd_instr(code_pos, 0xffffffff); // all bits ones is permanently reserved as an illegal instruction
-}
-
bool NativeInstruction::is_stop() {
- return uint_at(0) == 0xc0101073; // an illegal instruction, 'csrrw x0, time, x0'
+ // an illegal instruction, 'csrrw x0, time, x0'
+ uint32_t encoded = Assembler::encode_csrrw(x0, Assembler::time, x0);
+ return uint_at(0) == encoded;
}
//-------------------------------------------------------------------
@@ -347,6 +344,8 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
MacroAssembler a(&cb);
Assembler::IncompressibleScope scope(&a); // Fixed length: see NativeGeneralJump::get_instruction_size()
+ MacroAssembler::assert_alignment(code_pos);
+
int32_t offset = 0;
a.movptr(t1, entry, offset, t0); // lui, lui, slli, add
a.jr(t1, offset); // jalr
@@ -378,6 +377,7 @@ bool NativePostCallNop::decode(int32_t& oopmap_slot, int32_t& cb_offset) const {
}
bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) {
+ MacroAssembler::assert_alignment(addr_at(4));
if (((oopmap_slot & 0xff) != oopmap_slot) || ((cb_offset & 0xffffff) != cb_offset)) {
return false; // cannot encode
}
@@ -389,14 +389,17 @@ bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) {
return true; // successfully encoded
}
-void NativeDeoptInstruction::verify() {
+bool NativeDeoptInstruction::is_deopt_at(address instr) {
+ assert(instr != nullptr, "Must be");
+ uint32_t value = Assembler::ld_instr(instr);
+ uint32_t encoded = Assembler::encode_csrrw(x0, Assembler::instret, x0);
+ return value == encoded;
}
// Inserts an undefined instruction at a given pc
void NativeDeoptInstruction::insert(address code_pos) {
- // 0xc0201073 encodes CSRRW x0, instret, x0
- uint32_t insn = 0xc0201073;
- uint32_t *pos = (uint32_t *) code_pos;
- *pos = insn;
+ MacroAssembler::assert_alignment(code_pos);
+ uint32_t encoded = Assembler::encode_csrrw(x0, Assembler::instret, x0);
+ Assembler::sd_instr(code_pos, encoded);
ICache::invalidate_range(code_pos, 4);
}
diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp
index 4235e23d421..d990cfbc50d 100644
--- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp
+++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp
@@ -294,12 +294,6 @@ inline NativeGeneralJump* nativeGeneralJump_at(address addr) {
return jump;
}
-class NativeIllegalInstruction: public NativeInstruction {
- public:
- // Insert illegal opcode as specific address
- static void insert(address code_pos);
-};
-
inline bool NativeInstruction::is_nop() const {
uint32_t insn = Assembler::ld_instr(addr_at(0));
return insn == 0x13;
@@ -353,14 +347,7 @@ class NativeDeoptInstruction: public NativeInstruction {
address instruction_address() const { return addr_at(instruction_offset); }
address next_instruction_address() const { return addr_at(instruction_size); }
- void verify();
-
- static bool is_deopt_at(address instr) {
- assert(instr != nullptr, "");
- uint32_t value = Assembler::ld_instr(instr);
- // 0xc0201073 encodes CSRRW x0, instret, x0
- return value == 0xc0201073;
- }
+ static bool is_deopt_at(address instr);
// MT-safe patching
static void insert(address code_pos);
diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad
index 739a525c9a4..83c59af9113 100644
--- a/src/hotspot/cpu/riscv/riscv.ad
+++ b/src/hotspot/cpu/riscv/riscv.ad
@@ -1092,40 +1092,40 @@ RegMask _NO_SPECIAL_NO_FP_PTR_REG_mask;
void reg_mask_init() {
- _ANY_REG32_mask = _ALL_REG32_mask;
- _ANY_REG32_mask.Remove(OptoReg::as_OptoReg(x0->as_VMReg()));
+ _ANY_REG32_mask.assignFrom(_ALL_REG32_mask);
+ _ANY_REG32_mask.remove(OptoReg::as_OptoReg(x0->as_VMReg()));
- _ANY_REG_mask = _ALL_REG_mask;
- _ANY_REG_mask.SUBTRACT(_ZR_REG_mask);
+ _ANY_REG_mask.assignFrom(_ALL_REG_mask);
+ _ANY_REG_mask.subtract(_ZR_REG_mask);
- _PTR_REG_mask = _ALL_REG_mask;
- _PTR_REG_mask.SUBTRACT(_ZR_REG_mask);
+ _PTR_REG_mask.assignFrom(_ALL_REG_mask);
+ _PTR_REG_mask.subtract(_ZR_REG_mask);
- _NO_SPECIAL_REG32_mask = _ALL_REG32_mask;
- _NO_SPECIAL_REG32_mask.SUBTRACT(_NON_ALLOCATABLE_REG32_mask);
+ _NO_SPECIAL_REG32_mask.assignFrom(_ALL_REG32_mask);
+ _NO_SPECIAL_REG32_mask.subtract(_NON_ALLOCATABLE_REG32_mask);
- _NO_SPECIAL_REG_mask = _ALL_REG_mask;
- _NO_SPECIAL_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask);
+ _NO_SPECIAL_REG_mask.assignFrom(_ALL_REG_mask);
+ _NO_SPECIAL_REG_mask.subtract(_NON_ALLOCATABLE_REG_mask);
- _NO_SPECIAL_PTR_REG_mask = _ALL_REG_mask;
- _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask);
+ _NO_SPECIAL_PTR_REG_mask.assignFrom(_ALL_REG_mask);
+ _NO_SPECIAL_PTR_REG_mask.subtract(_NON_ALLOCATABLE_REG_mask);
// x27 is not allocatable when compressed oops is on
if (UseCompressedOops) {
- _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(x27->as_VMReg()));
- _NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(x27->as_VMReg()));
- _NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(x27->as_VMReg()));
+ _NO_SPECIAL_REG32_mask.remove(OptoReg::as_OptoReg(x27->as_VMReg()));
+ _NO_SPECIAL_REG_mask.remove(OptoReg::as_OptoReg(x27->as_VMReg()));
+ _NO_SPECIAL_PTR_REG_mask.remove(OptoReg::as_OptoReg(x27->as_VMReg()));
}
// x8 is not allocatable when PreserveFramePointer is on
if (PreserveFramePointer) {
- _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg()));
- _NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg()));
- _NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg()));
+ _NO_SPECIAL_REG32_mask.remove(OptoReg::as_OptoReg(x8->as_VMReg()));
+ _NO_SPECIAL_REG_mask.remove(OptoReg::as_OptoReg(x8->as_VMReg()));
+ _NO_SPECIAL_PTR_REG_mask.remove(OptoReg::as_OptoReg(x8->as_VMReg()));
}
- _NO_SPECIAL_NO_FP_PTR_REG_mask = _NO_SPECIAL_PTR_REG_mask;
- _NO_SPECIAL_NO_FP_PTR_REG_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg()));
+ _NO_SPECIAL_NO_FP_PTR_REG_mask.assignFrom(_NO_SPECIAL_PTR_REG_mask);
+ _NO_SPECIAL_NO_FP_PTR_REG_mask.remove(OptoReg::as_OptoReg(x8->as_VMReg()));
}
void PhaseOutput::pd_perform_mach_node_analysis() {
@@ -1269,6 +1269,26 @@ int CallDynamicJavaDirectNode::compute_padding(int current_offset) const
return align_up(current_offset, alignment_required()) - current_offset;
}
+int CallRuntimeDirectNode::compute_padding(int current_offset) const
+{
+ return align_up(current_offset, alignment_required()) - current_offset;
+}
+
+int CallLeafDirectNode::compute_padding(int current_offset) const
+{
+ return align_up(current_offset, alignment_required()) - current_offset;
+}
+
+int CallLeafDirectVectorNode::compute_padding(int current_offset) const
+{
+ return align_up(current_offset, alignment_required()) - current_offset;
+}
+
+int CallLeafNoFPDirectNode::compute_padding(int current_offset) const
+{
+ return align_up(current_offset, alignment_required()) - current_offset;
+}
+
//=============================================================================
#ifndef PRODUCT
@@ -1306,7 +1326,7 @@ uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
}
//=============================================================================
-const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
+const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::EMPTY;
int ConstantTable::calculate_table_base_offset() const {
return 0; // absolute addressing, no offset
@@ -2084,10 +2104,10 @@ uint Matcher::int_pressure_limit()
// as a spilled LRG. Spilling heuristics(Spill-USE) explicitly skip
// derived pointers and lastly fail to spill after reaching maximum
// number of iterations. Lowering the default pressure threshold to
- // (_NO_SPECIAL_REG32_mask.Size() minus 1) forces CallNode to become
+ // (_NO_SPECIAL_REG32_mask.size() minus 1) forces CallNode to become
// a high register pressure area of the code so that split_DEF can
// generate DefinitionSpillCopy for the derived pointer.
- uint default_int_pressure_threshold = _NO_SPECIAL_REG32_mask.Size() - 1;
+ uint default_int_pressure_threshold = _NO_SPECIAL_REG32_mask.size() - 1;
if (!PreserveFramePointer) {
// When PreserveFramePointer is off, frame pointer is allocatable,
// but different from other SOC registers, it is excluded from
@@ -2102,38 +2122,34 @@ uint Matcher::int_pressure_limit()
uint Matcher::float_pressure_limit()
{
// _FLOAT_REG_mask is generated by adlc from the float_reg register class.
- return (FLOATPRESSURE == -1) ? _FLOAT_REG_mask.Size() : FLOATPRESSURE;
+ return (FLOATPRESSURE == -1) ? _FLOAT_REG_mask.size() : FLOATPRESSURE;
}
bool Matcher::use_asm_for_ldiv_by_con(jlong divisor) {
return false;
}
-RegMask Matcher::divI_proj_mask() {
+const RegMask& Matcher::divI_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for MODI projection of divmodI.
-RegMask Matcher::modI_proj_mask() {
+const RegMask& Matcher::modI_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for DIVL projection of divmodL.
-RegMask Matcher::divL_proj_mask() {
+const RegMask& Matcher::divL_proj_mask() {
ShouldNotReachHere();
- return RegMask();
+ return RegMask::EMPTY;
}
// Register for MODL projection of divmodL.
-RegMask Matcher::modL_proj_mask() {
+const RegMask& Matcher::modL_proj_mask() {
ShouldNotReachHere();
- return RegMask();
-}
-
-const RegMask Matcher::method_handle_invoke_SP_save_mask() {
- return FP_REG_mask();
+ return RegMask::EMPTY;
}
bool size_fits_all_mem_uses(AddPNode* addp, int shift) {
@@ -8175,7 +8191,7 @@ instruct unnecessary_membar_volatile_rvtso() %{
ins_cost(0);
size(0);
-
+
format %{ "#@unnecessary_membar_volatile_rvtso (unnecessary so empty encoding)" %}
ins_encode %{
__ block_comment("unnecessary_membar_volatile_rvtso");
@@ -10509,6 +10525,7 @@ instruct CallRuntimeDirect(method meth)
ins_encode(riscv_enc_java_to_runtime(meth));
ins_pipe(pipe_class_call);
+ ins_alignment(4);
%}
// Call Runtime Instruction
@@ -10526,6 +10543,7 @@ instruct CallLeafDirect(method meth)
ins_encode(riscv_enc_java_to_runtime(meth));
ins_pipe(pipe_class_call);
+ ins_alignment(4);
%}
// Call Runtime Instruction without safepoint and with vector arguments
@@ -10543,6 +10561,7 @@ instruct CallLeafDirectVector(method meth)
ins_encode(riscv_enc_java_to_runtime(meth));
ins_pipe(pipe_class_call);
+ ins_alignment(4);
%}
// Call Runtime Instruction
@@ -10560,6 +10579,7 @@ instruct CallLeafNoFPDirect(method meth)
ins_encode(riscv_enc_java_to_runtime(meth));
ins_pipe(pipe_class_call);
+ ins_alignment(4);
%}
// ============================================================================
@@ -10971,6 +10991,7 @@ instruct arrays_hashcode(iRegP_R11 ary, iRegI_R12 cnt, iRegI_R10 result, immI ba
iRegLNoSp tmp3, iRegLNoSp tmp4,
iRegLNoSp tmp5, iRegLNoSp tmp6, rFlagsReg cr)
%{
+ predicate(!UseRVV);
match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type)));
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6,
USE_KILL ary, USE_KILL cnt, USE basic_type, KILL cr);
diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad
index f2845ee2a6c..fe323474d60 100644
--- a/src/hotspot/cpu/riscv/riscv_v.ad
+++ b/src/hotspot/cpu/riscv/riscv_v.ad
@@ -4080,6 +4080,28 @@ instruct varray_equalsC(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result,
ins_pipe(pipe_class_memory);
%}
+// fast ArraysSupport.vectorizedHashCode
+instruct varrays_hashcode(iRegP_R11 ary, iRegI_R12 cnt, iRegI_R10 result, immI basic_type,
+ vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5,
+ vReg_V6 v6, vReg_V7 v7, vReg_V8 v8, vReg_V9 v9,
+ iRegLNoSp tmp1, iRegLNoSp tmp2, iRegLNoSp tmp3,
+ rFlagsReg cr)
+%{
+ predicate(UseRVV);
+ match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type)));
+ effect(USE_KILL ary, USE_KILL cnt, USE basic_type,
+ TEMP v2, TEMP v3, TEMP v4, TEMP v5, TEMP v6, TEMP v7, TEMP v8, TEMP v9,
+ TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+
+ format %{ "Array HashCode array[] $ary,$cnt,$result,$basic_type -> $result // KILL all" %}
+ ins_encode %{
+ __ arrays_hashcode_v($ary$$Register, $cnt$$Register, $result$$Register,
+ $tmp1$$Register, $tmp2$$Register, $tmp3$$Register,
+ (BasicType)$basic_type$$constant);
+ %}
+ ins_pipe(pipe_class_memory);
+%}
+
instruct vstring_compareU_128b(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2,
iRegI_R10 result, vReg_V4 v4, vReg_V5 v5, vReg_V6 v6, vReg_V7 v7,
vReg_V8 v8, vReg_V9 v9, vReg_V10 v10, vReg_V11 v11,
diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
index 2cc1fb8eeff..b303178a666 100644
--- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
+++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
@@ -602,11 +602,11 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs,
- AdapterHandlerEntry* handler) {
- address i2c_entry = __ pc();
+ address entry_address[AdapterBlob::ENTRY_COUNT]) {
+ entry_address[AdapterBlob::I2C] = __ pc();
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
- address c2i_unverified_entry = __ pc();
+ entry_address[AdapterBlob::C2I_Unverified] = __ pc();
Label skip_fixup;
const Register receiver = j_rarg0;
@@ -633,10 +633,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ block_comment("} c2i_unverified_entry");
}
- address c2i_entry = __ pc();
+ entry_address[AdapterBlob::C2I] = __ pc();
// Class initialization barrier for static methods
- address c2i_no_clinit_check_entry = nullptr;
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
if (VM_Version::supports_fast_class_init_checks()) {
Label L_skip_barrier;
@@ -651,15 +651,13 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub()));
__ bind(L_skip_barrier);
- c2i_no_clinit_check_entry = __ pc();
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
}
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->c2i_entry_barrier(masm);
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
-
- handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
return;
}
@@ -887,11 +885,8 @@ static void fill_continuation_entry(MacroAssembler* masm) {
__ ld(t0, Address(xthread, JavaThread::cont_fastpath_offset()));
__ sd(t0, Address(sp, ContinuationEntry::parent_cont_fastpath_offset()));
- __ ld(t0, Address(xthread, JavaThread::held_monitor_count_offset()));
- __ sd(t0, Address(sp, ContinuationEntry::parent_held_monitor_count_offset()));
__ sd(zr, Address(xthread, JavaThread::cont_fastpath_offset()));
- __ sd(zr, Address(xthread, JavaThread::held_monitor_count_offset()));
}
// on entry, sp points to the ContinuationEntry
@@ -907,50 +902,6 @@ static void continuation_enter_cleanup(MacroAssembler* masm) {
__ ld(t0, Address(sp, ContinuationEntry::parent_cont_fastpath_offset()));
__ sd(t0, Address(xthread, JavaThread::cont_fastpath_offset()));
-
- if (CheckJNICalls) {
- // Check if this is a virtual thread continuation
- Label L_skip_vthread_code;
- __ lwu(t0, Address(sp, ContinuationEntry::flags_offset()));
- __ beqz(t0, L_skip_vthread_code);
-
- // If the held monitor count is > 0 and this vthread is terminating then
- // it failed to release a JNI monitor. So we issue the same log message
- // that JavaThread::exit does.
- __ ld(t0, Address(xthread, JavaThread::jni_monitor_count_offset()));
- __ beqz(t0, L_skip_vthread_code);
-
- // Save return value potentially containing the exception oop in callee-saved x9
- __ mv(x9, x10);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held));
- // Restore potential return value
- __ mv(x10, x9);
-
- // For vthreads we have to explicitly zero the JNI monitor count of the carrier
- // on termination. The held count is implicitly zeroed below when we restore from
- // the parent held count (which has to be zero).
- __ sd(zr, Address(xthread, JavaThread::jni_monitor_count_offset()));
-
- __ bind(L_skip_vthread_code);
- }
-#ifdef ASSERT
- else {
- // Check if this is a virtual thread continuation
- Label L_skip_vthread_code;
- __ lwu(t0, Address(sp, ContinuationEntry::flags_offset()));
- __ beqz(t0, L_skip_vthread_code);
-
- // See comment just above. If not checking JNI calls the JNI count is only
- // needed for assertion checking.
- __ sd(zr, Address(xthread, JavaThread::jni_monitor_count_offset()));
-
- __ bind(L_skip_vthread_code);
- }
-#endif
-
- __ ld(t0, Address(sp, ContinuationEntry::parent_held_monitor_count_offset()));
- __ sd(t0, Address(xthread, JavaThread::held_monitor_count_offset()));
-
__ ld(t0, Address(sp, ContinuationEntry::parent_offset()));
__ sd(t0, Address(xthread, JavaThread::cont_entry_offset()));
__ add(fp, sp, (int)ContinuationEntry::size() + 2 * wordSize /* 2 extra words to match up with leave() */);
@@ -1004,20 +955,23 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ bnez(c_rarg2, call_thaw);
- // Make sure the call is patchable
- __ align(NativeInstruction::instruction_size);
+ address call_pc;
+ {
+ Assembler::IncompressibleScope scope(masm);
+ // Make sure the call is patchable
+ __ align(NativeInstruction::instruction_size);
- const address tr_call = __ reloc_call(resolve);
- if (tr_call == nullptr) {
- fatal("CodeCache is full at gen_continuation_enter");
+ call_pc = __ reloc_call(resolve);
+ if (call_pc == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
+
+ oop_maps->add_gc_map(__ pc() - start, map);
+ __ post_call_nop();
}
-
- oop_maps->add_gc_map(__ pc() - start, map);
- __ post_call_nop();
-
__ j(exit);
- address stub = CompiledDirectCall::emit_to_interp_stub(masm, tr_call);
+ address stub = CompiledDirectCall::emit_to_interp_stub(masm, call_pc);
if (stub == nullptr) {
fatal("CodeCache is full at gen_continuation_enter");
}
@@ -1036,26 +990,36 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ bnez(c_rarg2, call_thaw);
- // Make sure the call is patchable
- __ align(NativeInstruction::instruction_size);
+ address call_pc;
+ {
+ Assembler::IncompressibleScope scope(masm);
+ // Make sure the call is patchable
+ __ align(NativeInstruction::instruction_size);
- const address tr_call = __ reloc_call(resolve);
- if (tr_call == nullptr) {
- fatal("CodeCache is full at gen_continuation_enter");
+ call_pc = __ reloc_call(resolve);
+ if (call_pc == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
+
+ oop_maps->add_gc_map(__ pc() - start, map);
+ __ post_call_nop();
}
- oop_maps->add_gc_map(__ pc() - start, map);
- __ post_call_nop();
-
__ j(exit);
__ bind(call_thaw);
- ContinuationEntry::_thaw_call_pc_offset = __ pc() - start;
- __ rt_call(CAST_FROM_FN_PTR(address, StubRoutines::cont_thaw()));
- oop_maps->add_gc_map(__ pc() - start, map->deep_copy());
- ContinuationEntry::_return_pc_offset = __ pc() - start;
- __ post_call_nop();
+ // Post call nops must be natural aligned due to cmodx rules.
+ {
+ Assembler::IncompressibleScope scope(masm);
+ __ align(NativeInstruction::instruction_size);
+
+ ContinuationEntry::_thaw_call_pc_offset = __ pc() - start;
+ __ rt_call(CAST_FROM_FN_PTR(address, StubRoutines::cont_thaw()));
+ oop_maps->add_gc_map(__ pc() - start, map->deep_copy());
+ ContinuationEntry::_return_pc_offset = __ pc() - start;
+ __ post_call_nop();
+ }
__ bind(exit);
ContinuationEntry::_cleanup_offset = __ pc() - start;
@@ -1084,7 +1048,7 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ jr(x11); // the exception handler
}
- address stub = CompiledDirectCall::emit_to_interp_stub(masm, tr_call);
+ address stub = CompiledDirectCall::emit_to_interp_stub(masm, call_pc);
if (stub == nullptr) {
fatal("CodeCache is full at gen_continuation_enter");
}
@@ -1117,10 +1081,16 @@ static void gen_continuation_yield(MacroAssembler* masm,
__ mv(c_rarg1, sp);
+ // Post call nops must be natural aligned due to cmodx rules.
+ __ align(NativeInstruction::instruction_size);
+
frame_complete = __ pc() - start;
address the_pc = __ pc();
- __ post_call_nop(); // this must be exactly after the pc value that is pushed into the frame info, we use this nop for fast CodeBlob lookup
+ {
+ Assembler::IncompressibleScope scope(masm);
+ __ post_call_nop(); // this must be exactly after the pc value that is pushed into the frame info, we use this nop for fast CodeBlob lookup
+ }
__ mv(c_rarg0, xthread);
__ set_last_Java_frame(sp, fp, the_pc, t0);
@@ -1679,8 +1649,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
Label lock_done;
if (method->is_synchronized()) {
- const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes();
-
// Get the handle (the 2nd argument)
__ mv(oop_handle_reg, c_rarg1);
diff --git a/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp b/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp
index fe7f52884fa..f977d759d20 100644
--- a/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp
+++ b/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp
@@ -73,6 +73,9 @@
do_stub(compiler, string_indexof_linear_ul) \
do_arch_entry(riscv, compiler, string_indexof_linear_ul, \
string_indexof_linear_ul, string_indexof_linear_ul) \
+ do_stub(compiler, arrays_hashcode_powers_of_31) \
+ do_arch_entry(riscv, compiler, arrays_hashcode_powers_of_31, \
+ arrays_hashcode_powers_of_31, arrays_hashcode_powers_of_31) \
#define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \
diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
index 385c839879c..ec268d9bb65 100644
--- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
@@ -732,8 +732,7 @@ class StubGenerator: public StubCodeGenerator {
//
// s and d are adjusted to point to the remaining words to copy
//
- void generate_copy_longs(StubId stub_id, Label &start,
- Register s, Register d, Register count) {
+ address generate_copy_longs(StubId stub_id, Register s, Register d, Register count) {
BasicType type;
copy_direction direction;
switch (stub_id) {
@@ -763,7 +762,7 @@ class StubGenerator: public StubCodeGenerator {
Label again, drain;
StubCodeMark mark(this, stub_id);
__ align(CodeEntryAlignment);
- __ bind(start);
+ address start = __ pc();
if (direction == copy_forwards) {
__ sub(s, s, bias);
@@ -879,9 +878,9 @@ class StubGenerator: public StubCodeGenerator {
}
__ ret();
- }
- Label copy_f, copy_b;
+ return start;
+ }
typedef void (MacroAssembler::*copy_insn)(Register Rd, const Address &adr, Register temp);
@@ -1099,8 +1098,8 @@ class StubGenerator: public StubCodeGenerator {
// stub_id - is used to name the stub and identify all details of
// how to perform the copy.
//
- // entry - is assigned to the stub's post push entry point unless
- // it is null
+ // nopush_entry - is assigned to the stub's post push entry point
+ // unless it is null
//
// Inputs:
// c_rarg0 - source array address
@@ -1111,11 +1110,11 @@ class StubGenerator: public StubCodeGenerator {
// the hardware handle it. The two dwords within qwords that span
// cache line boundaries will still be loaded and stored atomically.
//
- // Side Effects: entry is set to the (post push) entry point so it
- // can be used by the corresponding conjoint copy
- // method
+ // Side Effects: nopush_entry is set to the (post push) entry point
+ // so it can be used by the corresponding conjoint
+ // copy method
//
- address generate_disjoint_copy(StubId stub_id, address* entry) {
+ address generate_disjoint_copy(StubId stub_id, address* nopush_entry) {
size_t size;
bool aligned;
bool is_oop;
@@ -1204,8 +1203,8 @@ class StubGenerator: public StubCodeGenerator {
address start = __ pc();
__ enter();
- if (entry != nullptr) {
- *entry = __ pc();
+ if (nopush_entry != nullptr) {
+ *nopush_entry = __ pc();
// caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
BLOCK_COMMENT("Entry:");
}
@@ -1256,8 +1255,8 @@ class StubGenerator: public StubCodeGenerator {
// corresponding disjoint copy routine which can be
// jumped to if the ranges do not actually overlap
//
- // entry - is assigned to the stub's post push entry point unless
- // it is null
+ // nopush_entry - is assigned to the stub's post push entry point
+ // unless it is null
//
// Inputs:
// c_rarg0 - source array address
@@ -1269,10 +1268,10 @@ class StubGenerator: public StubCodeGenerator {
// cache line boundaries will still be loaded and stored atomically.
//
// Side Effects:
- // entry is set to the no-overlap entry point so it can be used by
- // some other conjoint copy method
+ // nopush_entry is set to the no-overlap entry point so it can be
+ // used by some other conjoint copy method
//
- address generate_conjoint_copy(StubId stub_id, address nooverlap_target, address *entry) {
+ address generate_conjoint_copy(StubId stub_id, address nooverlap_target, address *nopush_entry) {
const Register s = c_rarg0, d = c_rarg1, count = c_rarg2;
RegSet saved_regs = RegSet::of(s, d, count);
int size;
@@ -1359,8 +1358,8 @@ class StubGenerator: public StubCodeGenerator {
address start = __ pc();
__ enter();
- if (entry != nullptr) {
- *entry = __ pc();
+ if (nopush_entry != nullptr) {
+ *nopush_entry = __ pc();
// caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
BLOCK_COMMENT("Entry:");
}
@@ -1370,7 +1369,7 @@ class StubGenerator: public StubCodeGenerator {
__ slli(t1, count, exact_log2(size));
Label L_continue;
__ bltu(t0, t1, L_continue);
- __ j(nooverlap_target);
+ __ j(RuntimeAddress(nooverlap_target));
__ bind(L_continue);
DecoratorSet decorators = IN_HEAP | IS_ARRAY;
@@ -1445,7 +1444,7 @@ class StubGenerator: public StubCodeGenerator {
// x10 == 0 - success
// x10 == -1^K - failure, where K is partial transfer count
//
- address generate_checkcast_copy(StubId stub_id, address* entry) {
+ address generate_checkcast_copy(StubId stub_id, address* nopush_entry) {
bool dest_uninitialized;
switch (stub_id) {
case StubId::stubgen_checkcast_arraycopy_id:
@@ -1496,8 +1495,8 @@ class StubGenerator: public StubCodeGenerator {
__ enter(); // required for proper stackwalking of RuntimeStub frame
// Caller of this entry point must set up the argument registers.
- if (entry != nullptr) {
- *entry = __ pc();
+ if (nopush_entry != nullptr) {
+ *nopush_entry = __ pc();
BLOCK_COMMENT("Entry:");
}
@@ -2294,13 +2293,21 @@ class StubGenerator: public StubCodeGenerator {
}
void generate_arraycopy_stubs() {
- address entry = nullptr;
- address entry_jbyte_arraycopy = nullptr;
- address entry_jshort_arraycopy = nullptr;
- address entry_jint_arraycopy = nullptr;
- address entry_oop_arraycopy = nullptr;
- address entry_jlong_arraycopy = nullptr;
- address entry_checkcast_arraycopy = nullptr;
+ // Some copy stubs publish a normal entry and then a 2nd 'fallback'
+ // entry immediately following their stack push. This can be used
+ // as a post-push branch target for compatible stubs when they
+ // identify a special case that can be handled by the fallback
+ // stub e.g a disjoint copy stub may be use as a special case
+ // fallback for its compatible conjoint copy stub.
+ //
+ // A no push entry is always returned in the following local and
+ // then published by assigning to the appropriate entry field in
+ // class StubRoutines. The entry value is then passed to the
+ // generator for the compatible stub. That means the entry must be
+ // listed when saving to/restoring from the AOT cache, ensuring
+ // that the inter-stub jumps are noted at AOT-cache save and
+ // relocated at AOT cache load.
+ address nopush_entry = nullptr;
// generate the common exit first so later stubs can rely on it if
// they want an UnsafeMemoryAccess exit non-local to the stub
@@ -2308,72 +2315,117 @@ class StubGenerator: public StubCodeGenerator {
// register the stub as the default exit with class UnsafeMemoryAccess
UnsafeMemoryAccess::set_common_exit_stub_pc(StubRoutines::_unsafecopy_common_exit);
- generate_copy_longs(StubId::stubgen_copy_byte_f_id, copy_f, c_rarg0, c_rarg1, t1);
- generate_copy_longs(StubId::stubgen_copy_byte_b_id, copy_b, c_rarg0, c_rarg1, t1);
+ // generate and publish riscv-specific bulk copy routines first
+ // so we can call them from other copy stubs
+ StubRoutines::riscv::_copy_byte_f = generate_copy_longs(StubId::stubgen_copy_byte_f_id, c_rarg0, c_rarg1, t1);
+ StubRoutines::riscv::_copy_byte_b = generate_copy_longs(StubId::stubgen_copy_byte_b_id, c_rarg0, c_rarg1, t1);
StubRoutines::riscv::_zero_blocks = generate_zero_blocks();
//*** jbyte
// Always need aligned and unaligned versions
- StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id, &entry);
- StubRoutines::_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_jbyte_arraycopy_id, entry, &entry_jbyte_arraycopy);
- StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jbyte_disjoint_arraycopy_id, &entry);
- StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jbyte_arraycopy_id, entry, nullptr);
+ StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jbyte_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_jbyte_arraycopy_id, StubRoutines::_jbyte_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jbyte_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jbyte_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_jbyte_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jbyte_arraycopy_id, StubRoutines::_arrayof_jbyte_disjoint_arraycopy_nopush, nullptr);
//*** jshort
// Always need aligned and unaligned versions
- StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jshort_disjoint_arraycopy_id, &entry);
- StubRoutines::_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_jshort_arraycopy_id, entry, &entry_jshort_arraycopy);
- StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jshort_disjoint_arraycopy_id, &entry);
- StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jshort_arraycopy_id, entry, nullptr);
+ StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jshort_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jshort_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_jshort_arraycopy_id, StubRoutines::_jshort_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is used by generic/unsafe copy
+ StubRoutines::_jshort_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jshort_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_jshort_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jshort_arraycopy_id, StubRoutines::_arrayof_jshort_disjoint_arraycopy_nopush, nullptr);
//*** jint
// Aligned versions
- StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jint_disjoint_arraycopy_id, &entry);
- StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jint_arraycopy_id, entry, &entry_jint_arraycopy);
+ StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jint_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_jint_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jint_arraycopy_id, StubRoutines::_arrayof_jint_disjoint_arraycopy_nopush, nullptr);
// In 64 bit we need both aligned and unaligned versions of jint arraycopy.
// entry_jint_arraycopy always points to the unaligned version
- StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &entry);
- StubRoutines::_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_jint_arraycopy_id, entry, &entry_jint_arraycopy);
+ StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jint_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_jint_arraycopy_id, StubRoutines::_jint_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jint_arraycopy_nopush = nopush_entry;
//*** jlong
// It is always aligned
- StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id, &entry);
- StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jlong_arraycopy_id, entry, &entry_jlong_arraycopy);
+ StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jlong_arraycopy_id, StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jlong_arraycopy_nopush = nopush_entry;
+ // disjoint normal/nopush and conjoint normal entries are not
+ // generated since the arrayof versions are the same
StubRoutines::_jlong_disjoint_arraycopy = StubRoutines::_arrayof_jlong_disjoint_arraycopy;
+ StubRoutines::_jlong_disjoint_arraycopy_nopush = StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush;
StubRoutines::_jlong_arraycopy = StubRoutines::_arrayof_jlong_arraycopy;
//*** oops
StubRoutines::_arrayof_oop_disjoint_arraycopy
- = generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_id, &entry);
+ = generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint arrayof nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush = nopush_entry;
StubRoutines::_arrayof_oop_arraycopy
- = generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_id, entry, &entry_oop_arraycopy);
+ = generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_id, StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint arrayof nopush entry is needed by generic/unsafe copy
+ StubRoutines::_oop_arraycopy_nopush = nopush_entry;
// Aligned versions without pre-barriers
StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit
- = generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_uninit_id, &entry);
- StubRoutines::_arrayof_oop_arraycopy_uninit
- = generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_uninit_id, entry, nullptr);
+ = generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_uninit_id, &nopush_entry);
+ // disjoint arrayof+uninit nopush entry is needed by conjoint copy
+ StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush = nopush_entry;
+ // note that we don't need a returned nopush entry because the
+ // generic/unsafe copy does not cater for uninit arrays.
+ StubRoutines::_arrayof_oop_arraycopy_uninit
+ = generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_uninit_id, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush, nullptr);
+
+ // for oop copies reuse arrayof entries for non-arrayof cases
StubRoutines::_oop_disjoint_arraycopy = StubRoutines::_arrayof_oop_disjoint_arraycopy;
+ StubRoutines::_oop_disjoint_arraycopy_nopush = StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush;
StubRoutines::_oop_arraycopy = StubRoutines::_arrayof_oop_arraycopy;
StubRoutines::_oop_disjoint_arraycopy_uninit = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit;
+ StubRoutines::_oop_disjoint_arraycopy_uninit_nopush = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush;
StubRoutines::_oop_arraycopy_uninit = StubRoutines::_arrayof_oop_arraycopy_uninit;
- StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &entry_checkcast_arraycopy);
+ StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &nopush_entry);
+ // checkcast nopush entry is needed by generic copy
+ StubRoutines::_checkcast_arraycopy_nopush = nopush_entry;
+ // note that we don't need a returned nopush entry because the
+ // generic copy does not cater for uninit arrays.
StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_uninit_id, nullptr);
- StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(entry_jbyte_arraycopy,
- entry_jshort_arraycopy,
- entry_jint_arraycopy,
- entry_jlong_arraycopy);
+ // unsafe arraycopy may fallback on conjoint stubs
+ StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(StubRoutines::_jbyte_arraycopy_nopush,
+ StubRoutines::_jshort_arraycopy_nopush,
+ StubRoutines::_jint_arraycopy_nopush,
+ StubRoutines::_jlong_arraycopy_nopush);
- StubRoutines::_generic_arraycopy = generate_generic_copy(entry_jbyte_arraycopy,
- entry_jshort_arraycopy,
- entry_jint_arraycopy,
- entry_oop_arraycopy,
- entry_jlong_arraycopy,
- entry_checkcast_arraycopy);
+ // generic arraycopy may fallback on conjoint stubs
+ StubRoutines::_generic_arraycopy = generate_generic_copy(StubRoutines::_jbyte_arraycopy_nopush,
+ StubRoutines::_jshort_arraycopy_nopush,
+ StubRoutines::_jint_arraycopy_nopush,
+ StubRoutines::_oop_arraycopy_nopush,
+ StubRoutines::_jlong_arraycopy_nopush,
+ StubRoutines::_checkcast_arraycopy_nopush);
StubRoutines::_jbyte_fill = generate_fill(StubId::stubgen_jbyte_fill_id);
StubRoutines::_jshort_fill = generate_fill(StubId::stubgen_jshort_fill_id);
@@ -6572,6 +6624,24 @@ static const int64_t right_3_bits = right_n_bits(3);
return start;
}
+ address generate_arrays_hashcode_powers_of_31() {
+ assert(UseRVV, "sanity");
+ const int lmul = 2;
+ const int stride = MaxVectorSize / sizeof(jint) * lmul;
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "arrays_hashcode_powers_of_31");
+ address start = __ pc();
+ for (int i = stride; i >= 0; i--) {
+ jint power_of_31 = 1;
+ for (int j = i; j > 0; j--) {
+ power_of_31 = java_multiply(power_of_31, 31);
+ }
+ __ emit_int32(power_of_31);
+ }
+
+ return start;
+ }
+
#endif // COMPILER2
/**
@@ -6766,6 +6836,10 @@ static const int64_t right_3_bits = right_n_bits(3);
StubRoutines::_bigIntegerRightShiftWorker = generate_bigIntegerRightShift();
}
+ if (UseVectorizedHashCodeIntrinsic && UseRVV) {
+ StubRoutines::riscv::_arrays_hashcode_powers_of_31 = generate_arrays_hashcode_powers_of_31();
+ }
+
if (UseSHA256Intrinsics) {
Sha2Generator sha2(_masm, this);
StubRoutines::_sha256_implCompress = sha2.generate_sha256_implCompress(StubId::stubgen_sha256_implCompress_id);
diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp
index 61f4aa3e722..692335d8c08 100644
--- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp
@@ -1073,9 +1073,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
}
// start execution
-#ifdef ASSERT
__ verify_frame_setup();
-#endif
// jvmti support
__ notify_method_entry();
@@ -1541,9 +1539,7 @@ address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
}
// start execution
-#ifdef ASSERT
__ verify_frame_setup();
-#endif
// jvmti support
__ notify_method_entry();
diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp
index 1011b8f1e7b..bd4a89d8199 100644
--- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp
+++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp
@@ -133,6 +133,7 @@ Address TemplateTable::at_bcp(int offset) {
void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
Register temp_reg, bool load_bc_into_bc_reg /*=true*/,
int byte_no) {
+ assert_different_registers(bc_reg, temp_reg);
if (!RewriteBytecodes) { return; }
Label L_patch_done;
@@ -196,7 +197,11 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
__ bind(L_okay);
#endif
- // patch bytecode
+ // Patch bytecode with release store to coordinate with ResolvedFieldEntry loads
+ // in fast bytecode codelets. load_field_entry has a memory barrier that gains
+ // the needed ordering, together with control dependency on entering the fast codelet
+ // itself.
+ __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore);
__ sb(bc_reg, at_bcp(0));
__ bind(L_patch_done);
}
@@ -2168,7 +2173,7 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
assert_different_registers(Rcache, index, temp);
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
- Label resolved, clinit_barrier_slow;
+ Label L_clinit_barrier_slow, L_done;
Bytecodes::Code code = bytecode();
__ load_method_entry(Rcache, index);
@@ -2185,12 +2190,20 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ mv(t0, (int) code);
- __ beq(temp, t0, resolved); // have we resolved this bytecode?
+
+ // Class initialization barrier for static methods
+ if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
+ __ bne(temp, t0, L_clinit_barrier_slow); // have we resolved this bytecode?
+ __ ld(temp, Address(Rcache, in_bytes(ResolvedMethodEntry::method_offset())));
+ __ load_method_holder(temp, temp);
+ __ clinit_barrier(temp, t0, &L_done, /*L_slow_path*/ nullptr);
+ __ bind(L_clinit_barrier_slow);
+ } else {
+ __ beq(temp, t0, L_done); // have we resolved this bytecode?
+ }
// resolve first time through
// Class initialization barrier slow path lands here as well.
- __ bind(clinit_barrier_slow);
-
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ mv(temp, (int) code);
__ call_VM(noreg, entry, temp);
@@ -2199,14 +2212,7 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
__ load_method_entry(Rcache, index);
// n.b. unlike x86 Rcache is now rcpool plus the indexed offset
// so all clients ofthis method must be modified accordingly
- __ bind(resolved);
-
- // Class initialization barrier for static methods
- if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
- __ ld(temp, Address(Rcache, in_bytes(ResolvedMethodEntry::method_offset())));
- __ load_method_holder(temp, temp);
- __ clinit_barrier(temp, t0, nullptr, &clinit_barrier_slow);
- }
+ __ bind(L_done);
}
void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
@@ -2215,13 +2221,13 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
const Register temp = x9;
assert_different_registers(Rcache, index, temp);
- Label resolved;
+ Label L_clinit_barrier_slow, L_done;
Bytecodes::Code code = bytecode();
switch (code) {
- case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
- case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
- default: break;
+ case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
+ case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
+ default: break;
}
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
@@ -2235,16 +2241,29 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
__ lbu(temp, Address(temp, 0));
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ mv(t0, (int) code); // have we resolved this bytecode?
- __ beq(temp, t0, resolved);
+
+ // Class initialization barrier for static fields
+ if (VM_Version::supports_fast_class_init_checks() &&
+ (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) {
+ const Register field_holder = temp;
+
+ __ bne(temp, t0, L_clinit_barrier_slow);
+ __ ld(field_holder, Address(Rcache, in_bytes(ResolvedFieldEntry::field_holder_offset())));
+ __ clinit_barrier(field_holder, t0, &L_done, /*L_slow_path*/ nullptr);
+ __ bind(L_clinit_barrier_slow);
+ } else {
+ __ beq(temp, t0, L_done);
+ }
// resolve first time through
+ // Class initialization barrier slow path lands here as well.
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ mv(temp, (int) code);
__ call_VM(noreg, entry, temp);
// Update registers with resolved info
__ load_field_entry(Rcache, index);
- __ bind(resolved);
+ __ bind(L_done);
}
void TemplateTable::load_resolved_field_entry(Register obj,
@@ -3014,6 +3033,7 @@ void TemplateTable::fast_storefield(TosState state) {
// X11: field offset, X12: field holder, X13: flags
load_resolved_field_entry(x12, x12, noreg, x11, x13);
+ __ verify_field_offset(x11);
{
Label notVolatile;
@@ -3101,6 +3121,8 @@ void TemplateTable::fast_accessfield(TosState state) {
__ load_field_entry(x12, x11);
__ load_sized_value(x11, Address(x12, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/);
+ __ verify_field_offset(x11);
+
__ load_unsigned_byte(x13, Address(x12, in_bytes(ResolvedFieldEntry::flags_offset())));
// x10: object
@@ -3156,7 +3178,9 @@ void TemplateTable::fast_xaccess(TosState state) {
__ ld(x10, aaddress(0));
// access constant pool cache
__ load_field_entry(x12, x13, 2);
+
__ load_sized_value(x11, Address(x12, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/);
+ __ verify_field_offset(x11);
// make sure exception is reported in correct bcp range (getfield is
// next instruction)
diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
index e0c3b303750..6f4babc872f 100644
--- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp
+++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
@@ -35,15 +35,28 @@
uint32_t VM_Version::_initial_vector_length = 0;
-#define DEF_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \
-VM_Version::NAME##RVFeatureValue VM_Version::NAME(PRETTY, BIT, FSTRING);
-RV_FEATURE_FLAGS(DEF_RV_FEATURE)
+#define DEF_RV_EXT_FEATURE(PRETTY, LINUX_BIT, FSTRING, FLAGF) \
+VM_Version::ext_##PRETTY##RVExtFeatureValue VM_Version::ext_##PRETTY;
+RV_EXT_FEATURE_FLAGS(DEF_RV_EXT_FEATURE)
+#undef DEF_RV_EXT_FEATURE
-#define ADD_RV_FEATURE_IN_LIST(NAME, PRETTY, BIT, FSTRING, FLAGF) \
- &VM_Version::NAME,
-VM_Version::RVFeatureValue* VM_Version::_feature_list[] = {
-RV_FEATURE_FLAGS(ADD_RV_FEATURE_IN_LIST)
+#define DEF_RV_NON_EXT_FEATURE(PRETTY, LINUX_BIT, FSTRING, FLAGF) \
+VM_Version::PRETTY##RVNonExtFeatureValue VM_Version::PRETTY;
+RV_NON_EXT_FEATURE_FLAGS(DEF_RV_NON_EXT_FEATURE)
+#undef DEF_RV_NON_EXT_FEATURE
+
+#define ADD_RV_EXT_FEATURE_IN_LIST(PRETTY, LINUX_BIT, FSTRING, FLAGF) \
+ &VM_Version::ext_##PRETTY,
+#define ADD_RV_NON_EXT_FEATURE_IN_LIST(PRETTY, LINUX_BIT, FSTRING, FLAGF) \
+ &VM_Version::PRETTY,
+ VM_Version::RVFeatureValue* VM_Version::_feature_list[] = {
+ RV_EXT_FEATURE_FLAGS(ADD_RV_EXT_FEATURE_IN_LIST)
+ RV_NON_EXT_FEATURE_FLAGS(ADD_RV_NON_EXT_FEATURE_IN_LIST)
nullptr};
+#undef ADD_RV_NON_EXT_FEATURE_IN_LIST
+#undef ADD_RV_EXT_FEATURE_IN_LIST
+
+VM_Version::RVExtFeatures* VM_Version::_rv_ext_features = new VM_Version::RVExtFeatures();
void VM_Version::useRVA20U64Profile() {
RV_USE_RVA20U64;
@@ -90,17 +103,6 @@ void VM_Version::common_initialize() {
useRVA23U64Profile();
}
- // Enable vendor specific features
-
- if (mvendorid.enabled()) {
- // Rivos
- if (mvendorid.value() == RIVOS) {
- if (FLAG_IS_DEFAULT(UseConservativeFence)) {
- FLAG_SET_DEFAULT(UseConservativeFence, false);
- }
- }
- }
-
if (UseZic64b) {
if (CacheLineSize != 64) {
assert(!FLAG_IS_DEFAULT(CacheLineSize), "default cache line size should be 64 bytes");
@@ -135,7 +137,7 @@ void VM_Version::common_initialize() {
FLAG_SET_DEFAULT(UseSignumIntrinsic, true);
}
- if (UseRVC && !ext_C.enabled()) {
+ if (UseRVC && !ext_c.enabled()) {
warning("RVC is not supported on this CPU");
FLAG_SET_DEFAULT(UseRVC, false);
@@ -147,7 +149,7 @@ void VM_Version::common_initialize() {
if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) {
FLAG_SET_DEFAULT(AvoidUnalignedAccesses,
- unaligned_access.value() != MISALIGNED_FAST);
+ unaligned_scalar.value() != MISALIGNED_SCALAR_FAST);
}
if (!AvoidUnalignedAccesses) {
@@ -162,7 +164,12 @@ void VM_Version::common_initialize() {
// This machine has fast unaligned memory accesses
if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) {
FLAG_SET_DEFAULT(UseUnalignedAccesses,
- unaligned_access.value() == MISALIGNED_FAST);
+ (unaligned_scalar.value() == MISALIGNED_SCALAR_FAST));
+ }
+
+ if (FLAG_IS_DEFAULT(AlignVector)) {
+ FLAG_SET_DEFAULT(AlignVector,
+ unaligned_vector.value() != MISALIGNED_VECTOR_FAST);
}
#ifdef __riscv_ztso
@@ -181,7 +188,7 @@ void VM_Version::common_initialize() {
FLAG_SET_DEFAULT(UsePopCountInstruction, false);
}
- if (UseZicboz && zicboz_block_size.enabled() && zicboz_block_size.value() > 0) {
+ if (UseZicboz && zicboz_block_size.value() > 0) {
assert(is_power_of_2(zicboz_block_size.value()), "Sanity");
if (FLAG_IS_DEFAULT(UseBlockZeroing)) {
FLAG_SET_DEFAULT(UseBlockZeroing, true);
@@ -195,13 +202,8 @@ void VM_Version::common_initialize() {
}
if (UseRVV) {
- if (!ext_V.enabled() && FLAG_IS_DEFAULT(UseRVV)) {
- warning("RVV is not supported on this CPU");
- FLAG_SET_DEFAULT(UseRVV, false);
- } else {
- // read vector length from vector CSR vlenb
- _initial_vector_length = cpu_vector_length();
- }
+ // read vector length from vector CSR vlenb
+ _initial_vector_length = cpu_vector_length();
}
// Misc Intrinsics that could depend on RVV.
@@ -221,36 +223,6 @@ void VM_Version::common_initialize() {
warning("CRC32C intrinsics are not available on this CPU.");
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
}
-
- // UseZvbb (depends on RVV).
- if (UseZvbb && !UseRVV) {
- warning("Cannot enable UseZvbb on cpu without RVV support.");
- FLAG_SET_DEFAULT(UseZvbb, false);
- }
-
- // UseZvbc (depends on RVV).
- if (UseZvbc && !UseRVV) {
- warning("Cannot enable UseZvbc on cpu without RVV support.");
- FLAG_SET_DEFAULT(UseZvbc, false);
- }
-
- // UseZvkn (depends on RVV).
- if (UseZvkn && !UseRVV) {
- warning("Cannot enable UseZvkn on cpu without RVV support.");
- FLAG_SET_DEFAULT(UseZvkn, false);
- }
-
- // UseZvfh (depends on RVV)
- if (UseZvfh) {
- if (!UseRVV) {
- warning("Cannot enable UseZvfh on cpu without RVV support.");
- FLAG_SET_DEFAULT(UseZvfh, false);
- }
- if (!UseZfh) {
- warning("Cannot enable UseZvfh on cpu without Zfh support.");
- FLAG_SET_DEFAULT(UseZvfh, false);
- }
- }
}
#ifdef COMPILER2
@@ -477,10 +449,6 @@ void VM_Version::c2_initialize() {
warning("AES/CTR intrinsics are not available on this CPU");
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
}
-
- if (FLAG_IS_DEFAULT(AlignVector)) {
- FLAG_SET_DEFAULT(AlignVector, AvoidUnalignedAccesses);
- }
}
#endif // COMPILER2
diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp
index d94385cd8ac..f74992cbc37 100644
--- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp
+++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp
@@ -46,31 +46,25 @@ class VM_Version : public Abstract_VM_Version {
RIVOS = 0x6cf, // JEDEC: 0x4f, Bank: 14
};
+ class RVExtFeatures;
+
class RVFeatureValue {
const char* const _pretty;
const bool _feature_string;
- const uint64_t _feature_bit;
- bool _enabled;
- int64_t _value;
+ const uint64_t _linux_feature_bit;
+
public:
- RVFeatureValue(const char* pretty, int bit_num, bool fstring) :
- _pretty(pretty), _feature_string(fstring), _feature_bit(nth_bit(bit_num)),
- _enabled(false), _value(-1) {
- }
- void enable_feature(int64_t value = 0) {
- _enabled = true;
- _value = value;
- }
- void disable_feature() {
- _enabled = false;
- _value = -1;
+ RVFeatureValue(const char* pretty, int linux_bit_num, bool fstring) :
+ _pretty(pretty), _feature_string(fstring), _linux_feature_bit(nth_bit(linux_bit_num)) {
}
+ virtual void enable_feature(int64_t value = 0) = 0;
+ virtual void disable_feature() = 0;
const char* pretty() { return _pretty; }
- uint64_t feature_bit() { return _feature_bit; }
+ uint64_t feature_bit() { return _linux_feature_bit; }
bool feature_string() { return _feature_string; }
- bool enabled() { return _enabled; }
- int64_t value() { return _value; }
+ virtual bool enabled() = 0;
virtual void update_flag() = 0;
+ virtual void log_enabled() = 0;
};
#define UPDATE_DEFAULT(flag) \
@@ -86,133 +80,316 @@ class VM_Version : public Abstract_VM_Version {
} \
} \
- #define UPDATE_DEFAULT_DEP(flag, dep) \
- void update_flag() { \
- assert(enabled(), "Must be."); \
- /* dep must be declared before */ \
- assert((uintptr_t)(this) > \
- (uintptr_t)(&dep), "Invalid"); \
- if (FLAG_IS_DEFAULT(flag)) { \
- if (dep.enabled()) { \
- FLAG_SET_DEFAULT(flag, true); \
- } else { \
- FLAG_SET_DEFAULT(flag, false); \
- /* Sync CPU features with flags */ \
- disable_feature(); \
- } \
- } else { \
- /* Sync CPU features with flags */ \
- if (!flag) { \
- disable_feature(); \
- } \
- } \
- } \
+ #define UPDATE_DEFAULT_DEP(flag, dep0, ...) \
+ void update_flag() { \
+ assert(enabled(), "Must be."); \
+ DEBUG_ONLY(verify_deps(dep0, ##__VA_ARGS__)); \
+ if (FLAG_IS_DEFAULT(flag)) { \
+ if (deps_all_enabled(dep0, ##__VA_ARGS__)) { \
+ FLAG_SET_DEFAULT(flag, true); \
+ } else { \
+ FLAG_SET_DEFAULT(flag, false); \
+ stringStream ss; \
+ deps_string(ss, dep0, ##__VA_ARGS__); \
+ warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \
+ /* Sync CPU features with flags */ \
+ disable_feature(); \
+ } \
+ } else { \
+ /* Sync CPU features with flags */ \
+ if (!flag) { \
+ disable_feature(); \
+ } else if (!deps_all_enabled(dep0, ##__VA_ARGS__)) { \
+ FLAG_SET_DEFAULT(flag, false); \
+ stringStream ss; \
+ deps_string(ss, dep0, ##__VA_ARGS__); \
+ warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \
+ /* Sync CPU features with flags */ \
+ disable_feature(); \
+ } \
+ } \
+ } \
#define NO_UPDATE_DEFAULT \
void update_flag() {} \
- // Frozen standard extensions
- // I RV64I
- // M Integer Multiplication and Division
- // A Atomic Instructions
- // F Single-Precision Floating-Point
- // D Single-Precision Floating-Point
- // (G = M + A + F + D)
- // Q Quad-Precision Floating-Point
- // C Compressed Instructions
- // H Hypervisor
- //
- // Others, open and non-standard
- // V Vector
- //
- // Cache Management Operations
- // Zicbom Cache Block Management Operations
- // Zicboz Cache Block Zero Operations
- // Zicbop Cache Block Prefetch Operations
- //
- // Bit-manipulation
- // Zba Address generation instructions
- // Zbb Basic bit-manipulation
- // Zbc Carry-less multiplication
- // Zbs Single-bit instructions
- //
- // Zfh Half-Precision Floating-Point instructions
- // Zfhmin Minimal Half-Precision Floating-Point instructions
- //
- // Zicond Conditional operations
- //
- // Zicsr Control and Status Register (CSR) Instructions
- // Zifencei Instruction-Fetch Fence
- // Zic64b Cache blocks must be 64 bytes in size, naturally aligned in the address space.
- // Zihintpause Pause instruction HINT
- //
- // Zc Code Size Reduction - Additional compressed instructions.
- // Zcb Simple code-size saving instructions
- //
- // Other features and settings
- // mvendorid Manufactory JEDEC id encoded, ISA vol 2 3.1.2..
- // marchid Id for microarch. Mvendorid plus marchid uniquely identify the microarch.
- // mimpid A unique encoding of the version of the processor implementation.
- // unaligned_access Unaligned memory accesses (unknown, unspported, emulated, slow, firmware, fast)
- // satp mode SATP bits (number of virtual addr bits) mbare, sv39, sv48, sv57, sv64
+
+ class RVExtFeatureValue : public RVFeatureValue {
+ const uint32_t _cpu_feature_index;
+
+ public:
+ RVExtFeatureValue(const char* pretty, int linux_bit_num, uint32_t cpu_feature_index, bool fstring) :
+ RVFeatureValue(pretty, linux_bit_num, fstring),
+ _cpu_feature_index(cpu_feature_index) {
+ }
+ int cpu_feature_index() {
+ // Can be used to check, for example, v is declared before Zvfh in RV_EXT_FEATURE_FLAGS.
+ return _cpu_feature_index;
+ }
+ bool enabled() {
+ return RVExtFeatures::current()->support_feature(_cpu_feature_index);
+ }
+ void enable_feature(int64_t value = 0) {
+ RVExtFeatures::current()->set_feature(_cpu_feature_index);
+ }
+ void disable_feature() {
+ RVExtFeatures::current()->clear_feature(_cpu_feature_index);
+ }
+ void log_enabled();
+
+ protected:
+ bool deps_all_enabled(RVExtFeatureValue* dep0, ...) {
+ assert(dep0 != nullptr, "must not");
+
+ va_list va;
+ va_start(va, dep0);
+ RVExtFeatureValue* next = dep0;
+ bool enabled = true;
+ while (next != nullptr && enabled) {
+ enabled = next->enabled();
+ next = va_arg(va, RVExtFeatureValue*);
+ }
+ va_end(va);
+ return enabled;
+ }
+
+ void deps_string(stringStream& ss, RVExtFeatureValue* dep0, ...) {
+ assert(dep0 != nullptr, "must not");
+ ss.print("%s (%s)", dep0->pretty(), dep0->enabled() ? "enabled" : "disabled");
+
+ va_list va;
+ va_start(va, dep0);
+ RVExtFeatureValue* next = nullptr;
+ while ((next = va_arg(va, RVExtFeatureValue*)) != nullptr) {
+ ss.print(", %s (%s)", next->pretty(), next->enabled() ? "enabled" : "disabled");
+ }
+ va_end(va);
+ }
+
+#ifdef ASSERT
+ void verify_deps(RVExtFeatureValue* dep0, ...) {
+ assert(dep0 != nullptr, "must not");
+ assert(cpu_feature_index() >= 0, "must");
+
+ va_list va;
+ va_start(va, dep0);
+ RVExtFeatureValue* next = dep0;
+ while (next != nullptr) {
+ assert(next->cpu_feature_index() >= 0, "must");
+ // We only need to check depenency relationship for extension flags.
+ // The dependant ones must be declared before this, for example, v must be declared
+ // before Zvfh in RV_EXT_FEATURE_FLAGS. The reason is in setup_cpu_available_features
+ // we need to make sure v is `update_flag`ed before Zvfh, so Zvfh is `update_flag`ed
+ // based on v.
+ assert(cpu_feature_index() > next->cpu_feature_index(), "Invalid");
+ next = va_arg(va, RVExtFeatureValue*);
+ }
+ va_end(va);
+ }
+#endif // ASSERT
+ };
+
+ class RVNonExtFeatureValue : public RVFeatureValue {
+ static const int64_t DEFAULT_VALUE = -1;
+ int64_t _value;
+
+ public:
+ RVNonExtFeatureValue(const char* pretty, int linux_bit_num, bool fstring) :
+ RVFeatureValue(pretty, linux_bit_num, fstring),
+ _value(DEFAULT_VALUE) {
+ }
+ bool enabled() { return _value != DEFAULT_VALUE; }
+ void enable_feature(int64_t value) {
+ assert(value != DEFAULT_VALUE, "Sanity");
+ _value = value;
+ }
+ void disable_feature() { _value = DEFAULT_VALUE; }
+ int64_t value() { return _value; }
+ void log_enabled();
+ };
public:
#define RV_NO_FLAG_BIT (BitsPerWord+1) // nth_bit will return 0 on values larger than BitsPerWord
// Note: the order matters, depender should be after their dependee. E.g. ext_V before ext_Zvbb.
- // declaration name , extension name, bit pos ,in str, mapped flag)
- #define RV_FEATURE_FLAGS(decl) \
- decl(ext_I , "i" , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \
- decl(ext_M , "m" , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \
- decl(ext_A , "a" , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \
- decl(ext_F , "f" , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \
- decl(ext_D , "d" , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \
- decl(ext_C , "c" , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \
- decl(ext_Q , "q" , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \
- decl(ext_H , "h" , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \
- decl(ext_V , "v" , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \
- decl(ext_Zicbom , "Zicbom" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \
- decl(ext_Zicboz , "Zicboz" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \
- decl(ext_Zicbop , "Zicbop" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \
- decl(ext_Zba , "Zba" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \
- decl(ext_Zbb , "Zbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \
- decl(ext_Zbc , "Zbc" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
- decl(ext_Zbs , "Zbs" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \
- decl(ext_Zbkb , "Zbkb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \
- decl(ext_Zcb , "Zcb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \
- decl(ext_Zfa , "Zfa" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \
- decl(ext_Zfh , "Zfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \
- decl(ext_Zfhmin , "Zfhmin" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \
- decl(ext_Zicsr , "Zicsr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
- decl(ext_Zicntr , "Zicntr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
- decl(ext_Zifencei , "Zifencei" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
- decl(ext_Zic64b , "Zic64b" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \
- decl(ext_Ztso , "Ztso" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \
- decl(ext_Zihintpause , "Zihintpause" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
- decl(ext_Zacas , "Zacas" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \
- decl(ext_Zvbb , "Zvbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, ext_V)) \
- decl(ext_Zvbc , "Zvbc" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, ext_V)) \
- decl(ext_Zvfh , "Zvfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, ext_V)) \
- decl(ext_Zvkn , "Zvkn" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, ext_V)) \
- decl(ext_Zicond , "Zicond" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \
- decl(mvendorid , "VendorId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
- decl(marchid , "ArchId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
- decl(mimpid , "ImpId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
- decl(unaligned_access , "Unaligned" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
- decl(satp_mode , "SATP" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
- decl(zicboz_block_size, "ZicbozBlockSize", RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
+ //
+ // Fields description in `decl`:
+ // declaration name, extension name, bit value from linux, feature string?, mapped flag)
+ #define RV_EXT_FEATURE_FLAGS(decl) \
+ /* A Atomic Instructions */ \
+ decl(a , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \
+ /* C Compressed Instructions */ \
+ decl(c , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \
+ /* D Single-Precision Floating-Point */ \
+ decl(d , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \
+ /* F Single-Precision Floating-Point */ \
+ decl(f , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \
+ /* H Hypervisor */ \
+ decl(h , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \
+ /* I RV64I */ \
+ decl(i , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \
+ /* M Integer Multiplication and Division */ \
+ decl(m , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \
+ /* Q Quad-Precision Floating-Point */ \
+ decl(q , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \
+ /* V Vector */ \
+ decl(v , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \
+ \
+ /* ----------------------- Other extensions ----------------------- */ \
+ \
+ /* Atomic compare-and-swap (CAS) instructions */ \
+ decl(Zacas , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \
+ /* Zba Address generation instructions */ \
+ decl(Zba , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \
+ /* Zbb Basic bit-manipulation */ \
+ decl(Zbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \
+ /* Zbc Carry-less multiplication */ \
+ decl(Zbc , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
+ /* Bitmanip instructions for Cryptography */ \
+ decl(Zbkb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \
+ /* Zbs Single-bit instructions */ \
+ decl(Zbs , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \
+ /* Zcb Simple code-size saving instructions */ \
+ decl(Zcb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \
+ /* Additional Floating-Point instructions */ \
+ decl(Zfa , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \
+ /* Zfh Half-Precision Floating-Point instructions */ \
+ decl(Zfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \
+ /* Zfhmin Minimal Half-Precision Floating-Point instructions */ \
+ decl(Zfhmin , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \
+ /* Zicbom Cache Block Management Operations */ \
+ decl(Zicbom , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \
+ /* Zicbop Cache Block Prefetch Operations */ \
+ decl(Zicbop , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \
+ /* Zicboz Cache Block Zero Operations */ \
+ decl(Zicboz , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \
+ /* Base Counters and Timers */ \
+ decl(Zicntr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
+ /* Zicond Conditional operations */ \
+ decl(Zicond , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \
+ /* Zicsr Control and Status Register (CSR) Instructions */ \
+ decl(Zicsr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
+ /* Zic64b Cache blocks must be 64 bytes in size, naturally aligned in the address space. */ \
+ decl(Zic64b , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \
+ /* Zifencei Instruction-Fetch Fence */ \
+ decl(Zifencei , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
+ /* Zihintpause Pause instruction HINT */ \
+ decl(Zihintpause , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
+ /* Total Store Ordering */ \
+ decl(Ztso , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \
+ /* Vector Basic Bit-manipulation */ \
+ decl(Zvbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, &ext_v, nullptr)) \
+ /* Vector Carryless Multiplication */ \
+ decl(Zvbc , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, &ext_v, nullptr)) \
+ /* Vector Extension for Half-Precision Floating-Point */ \
+ decl(Zvfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, &ext_v, &ext_Zfh, nullptr)) \
+ /* Shorthand for Zvkned + Zvknhb + Zvkb + Zvkt */ \
+ decl(Zvkn , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, &ext_v, nullptr)) \
- #define DECLARE_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \
- struct NAME##RVFeatureValue : public RVFeatureValue { \
- NAME##RVFeatureValue(const char* pretty, int bit, bool fstring) : \
- RVFeatureValue(pretty, bit, fstring) {} \
- FLAGF; \
- }; \
- static NAME##RVFeatureValue NAME; \
+ #define DECLARE_RV_EXT_FEATURE(PRETTY, LINUX_BIT, FSTRING, FLAGF) \
+ struct ext_##PRETTY##RVExtFeatureValue : public RVExtFeatureValue { \
+ ext_##PRETTY##RVExtFeatureValue() : \
+ RVExtFeatureValue(#PRETTY, LINUX_BIT, RVExtFeatures::CPU_##ext_##PRETTY, FSTRING) {} \
+ FLAGF; \
+ }; \
+ static ext_##PRETTY##RVExtFeatureValue ext_##PRETTY; \
- RV_FEATURE_FLAGS(DECLARE_RV_FEATURE)
- #undef DECLARE_RV_FEATURE
+ RV_EXT_FEATURE_FLAGS(DECLARE_RV_EXT_FEATURE)
+ #undef DECLARE_RV_EXT_FEATURE
+
+ // Non-extension features
+ //
+ #define RV_NON_EXT_FEATURE_FLAGS(decl) \
+ /* Id for microarch. Mvendorid plus marchid uniquely identify the microarch. */ \
+ decl(marchid , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
+ /* A unique encoding of the version of the processor implementation. */ \
+ decl(mimpid , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
+ /* Manufactory JEDEC id encoded, ISA vol 2 3.1.2.. */ \
+ decl(mvendorid , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
+ /* SATP bits (number of virtual addr bits) mbare, sv39, sv48, sv57, sv64 */ \
+ decl(satp_mode , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
+ /* Performance of misaligned scalar accesses (unknown, emulated, slow, fast, unsupported) */ \
+ decl(unaligned_scalar , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
+ /* Performance of misaligned vector accesses (unknown, unspported, slow, fast) */ \
+ decl(unaligned_vector , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
+ decl(zicboz_block_size , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
+
+ #define DECLARE_RV_NON_EXT_FEATURE(PRETTY, LINUX_BIT, FSTRING, FLAGF) \
+ struct PRETTY##RVNonExtFeatureValue : public RVNonExtFeatureValue { \
+ PRETTY##RVNonExtFeatureValue() : \
+ RVNonExtFeatureValue(#PRETTY, LINUX_BIT, FSTRING) {} \
+ FLAGF; \
+ }; \
+ static PRETTY##RVNonExtFeatureValue PRETTY; \
+
+ RV_NON_EXT_FEATURE_FLAGS(DECLARE_RV_NON_EXT_FEATURE)
+ #undef DECLARE_RV_NON_EXT_FEATURE
+
+private:
+ // Utility for AOT CPU feature store/check.
+ class RVExtFeatures : public CHeapObj {
+ public:
+ enum RVFeatureIndex {
+ #define DECLARE_RV_FEATURE_ENUM(PRETTY, LINUX_BIT, FSTRING, FLAGF) CPU_##ext_##PRETTY,
+
+ RV_EXT_FEATURE_FLAGS(DECLARE_RV_FEATURE_ENUM)
+ MAX_CPU_FEATURE_INDEX
+ #undef DECLARE_RV_FEATURE_ENUM
+ };
+ private:
+ uint64_t _features_bitmap[(MAX_CPU_FEATURE_INDEX / BitsPerLong) + 1];
+ STATIC_ASSERT(sizeof(_features_bitmap) * BitsPerByte >= MAX_CPU_FEATURE_INDEX);
+
+ // Number of 8-byte elements in _features_bitmap.
+ constexpr static int element_count() {
+ return sizeof(_features_bitmap) / sizeof(uint64_t);
+ }
+
+ static int element_index(RVFeatureIndex feature) {
+ int idx = feature / BitsPerLong;
+ assert(idx < element_count(), "Features array index out of bounds");
+ return idx;
+ }
+
+ static uint64_t feature_bit(RVFeatureIndex feature) {
+ return (1ULL << (feature % BitsPerLong));
+ }
+
+ static RVFeatureIndex convert(uint32_t index) {
+ assert(index < MAX_CPU_FEATURE_INDEX, "must");
+ return (RVFeatureIndex)index;
+ }
+
+ public:
+ static RVExtFeatures* current() {
+ return _rv_ext_features;
+ }
+
+ RVExtFeatures() {
+ for (int i = 0; i < element_count(); i++) {
+ _features_bitmap[i] = 0;
+ }
+ }
+
+ void set_feature(uint32_t feature) {
+ RVFeatureIndex f = convert(feature);
+ int idx = element_index(f);
+ _features_bitmap[idx] |= feature_bit(f);
+ }
+
+ void clear_feature(uint32_t feature) {
+ RVFeatureIndex f = convert(feature);
+ int idx = element_index(f);
+ _features_bitmap[idx] &= ~feature_bit(f);
+ }
+
+ bool support_feature(uint32_t feature) {
+ RVFeatureIndex f = convert(feature);
+ int idx = element_index(f);
+ return (_features_bitmap[idx] & feature_bit(f)) != 0;
+ }
+ };
// enable extensions based on profile, current supported profiles:
// RVA20U64
@@ -276,16 +453,24 @@ class VM_Version : public Abstract_VM_Version {
static VM_MODE parse_satp_mode(const char* vm_mode);
// Values from riscv_hwprobe()
- enum UNALIGNED_ACCESS : int {
- MISALIGNED_UNKNOWN = 0,
- MISALIGNED_EMULATED = 1,
- MISALIGNED_SLOW = 2,
- MISALIGNED_FAST = 3,
- MISALIGNED_UNSUPPORTED = 4
+ enum UNALIGNED_SCALAR_ACCESS : int {
+ MISALIGNED_SCALAR_UNKNOWN = 0,
+ MISALIGNED_SCALAR_EMULATED = 1,
+ MISALIGNED_SCALAR_SLOW = 2,
+ MISALIGNED_SCALAR_FAST = 3,
+ MISALIGNED_SCALAR_UNSUPPORTED = 4
+ };
+
+ enum UNALIGNED_VECTOR_ACCESS : int {
+ MISALIGNED_VECTOR_UNKNOWN = 0,
+ MISALIGNED_VECTOR_SLOW = 2,
+ MISALIGNED_VECTOR_FAST = 3,
+ MISALIGNED_VECTOR_UNSUPPORTED = 4
};
// Null terminated list
static RVFeatureValue* _feature_list[];
+ static RVExtFeatures* _rv_ext_features;
// Enables features in _feature_list
static void setup_cpu_available_features();
diff --git a/src/hotspot/cpu/s390/assembler_s390.inline.hpp b/src/hotspot/cpu/s390/assembler_s390.inline.hpp
index 567f3d75a62..3bab60f0bb6 100644
--- a/src/hotspot/cpu/s390/assembler_s390.inline.hpp
+++ b/src/hotspot/cpu/s390/assembler_s390.inline.hpp
@@ -26,7 +26,7 @@
#ifndef CPU_S390_ASSEMBLER_S390_INLINE_HPP
#define CPU_S390_ASSEMBLER_S390_INLINE_HPP
-#include "asm/assembler.inline.hpp"
+#include "asm/assembler.hpp"
#include "asm/codeBuffer.hpp"
#include "code/codeCache.hpp"
diff --git a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp
index 68e7114b3b6..f1272ee1a22 100644
--- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp
+++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp
@@ -234,12 +234,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
// Move address of the BasicObjectLock into Z_R1_scratch.
- if (_compute_lock) {
- // Lock_reg was destroyed by fast unlocking attempt => recompute it.
- ce->monitor_address(_monitor_ix, FrameMap::as_opr(Z_R1_scratch));
- } else {
- __ lgr_if_needed(Z_R1_scratch, _lock_reg->as_register());
- }
+
+ // Lock_reg was destroyed by fast unlocking attempt => recompute it.
+ ce->monitor_address(_monitor_ix, FrameMap::as_opr(Z_R1_scratch));
+
// Note: non-blocking leaf routine => no call info needed.
StubId exit_id;
if (ce->compilation()->has_fpu_code()) {
diff --git a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp
index ddba445154a..e219e9bbb40 100644
--- a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp
+++ b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp
@@ -282,13 +282,6 @@ LIR_Opr FrameMap::stack_pointer() {
return Z_SP_opr;
}
-// JSR 292
-// On ZARCH_64, there is no need to save the SP, because neither
-// method handle intrinsics nor compiled lambda forms modify it.
-LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
- return LIR_OprFact::illegalOpr;
-}
-
bool FrameMap::validate_frame() {
return true;
}
diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp
index b875eeca9ad..298234156c3 100644
--- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp
@@ -228,7 +228,7 @@ int LIR_Assembler::emit_unwind_handler() {
// StubId::c1_monitorexit_id expects lock address in Z_R1_scratch.
LIR_Opr lock = FrameMap::as_opr(Z_R1_scratch);
monitor_address(0, lock);
- stub = new MonitorExitStub(lock, true, 0);
+ stub = new MonitorExitStub(lock, 0);
__ unlock_object(Rtmp1, Rtmp2, lock->as_register(), *stub->entry());
__ bind(*stub->continuation());
}
@@ -2711,7 +2711,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
Register hdr = op->hdr_opr()->as_register();
Register lock = op->lock_opr()->as_register();
if (op->code() == lir_lock) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
// Add debug info for NullPointerException only if one is possible.
if (op->info() != nullptr) {
add_debug_info_for_null_check_here(op->info());
@@ -2719,7 +2718,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
__ lock_object(hdr, obj, lock, *op->stub()->entry());
// done
} else if (op->code() == lir_unlock) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
__ unlock_object(hdr, obj, lock, *op->stub()->entry());
} else {
ShouldNotReachHere();
diff --git a/src/hotspot/cpu/s390/c1_globals_s390.hpp b/src/hotspot/cpu/s390/c1_globals_s390.hpp
index 1b2b698a737..25e46cd1509 100644
--- a/src/hotspot/cpu/s390/c1_globals_s390.hpp
+++ b/src/hotspot/cpu/s390/c1_globals_s390.hpp
@@ -53,7 +53,6 @@ define_pd_global(size_t, CodeCacheMinBlockLength, 1);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, NeverActAsServerClassMachine, true);
define_pd_global(size_t, NewSizeThreadIncrease, 16*K);
-define_pd_global(uint64_t, MaxRAM, 1ULL*G);
define_pd_global(size_t, InitialCodeCacheSize, 160*K);
#endif // !COMPILER2
diff --git a/src/hotspot/cpu/s390/c2_globals_s390.hpp b/src/hotspot/cpu/s390/c2_globals_s390.hpp
index 94190c25f5b..431a36cda07 100644
--- a/src/hotspot/cpu/s390/c2_globals_s390.hpp
+++ b/src/hotspot/cpu/s390/c2_globals_s390.hpp
@@ -45,8 +45,7 @@ define_pd_global(intx, CompileThreshold, 10000);
define_pd_global(intx, OnStackReplacePercentage, 140);
define_pd_global(intx, ConditionalMoveLimit, 4);
define_pd_global(intx, FreqInlineSize, 175);
-// 10 prevents spill-split-recycle sanity check in JVM2008.xml.transform.
-define_pd_global(intx, InteriorEntryAlignment, 2);
+define_pd_global(intx, InteriorEntryAlignment, 4);
define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K));
define_pd_global(intx, RegisterCostAreaRatio, 12000);
define_pd_global(intx, LoopUnrollLimit, 60);
@@ -75,7 +74,6 @@ define_pd_global(size_t, NonNMethodCodeHeapSize, 5*M);
define_pd_global(size_t, CodeCacheExpansionSize, 64*K);
// Ergonomics related flags
-define_pd_global(uint64_t, MaxRAM, 128ULL*G);
define_pd_global(size_t, CodeCacheMinBlockLength, 4);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp
index dea3317270e..e4fe690663a 100644
--- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp
@@ -28,7 +28,6 @@
#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1BarrierSetRuntime.hpp"
#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1DirtyCardQueue.hpp"
#include "gc/g1/g1HeapRegion.hpp"
#include "gc/g1/g1SATBMarkQueueSet.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
@@ -205,104 +204,71 @@ void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
BLOCK_COMMENT("} generate_c2_pre_barrier_stub");
}
+static void generate_post_barrier(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
+
+ __ block_comment("generate_post_barrier {");
+
+ assert(thread == Z_thread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
+
+ // Does store cross heap regions?
+ if (VM_Version::has_DistinctOpnds()) {
+ __ z_xgrk(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
+ } else {
+ __ z_lgr(tmp1, store_addr);
+ __ z_xgr(tmp1, new_val);
+ }
+ __ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
+ __ branch_optimized(Assembler::bcondEqual, done);
+
+ // Crosses regions, storing null?
+ if (new_val_may_be_null) {
+ __ z_ltgr(new_val, new_val);
+ __ z_bre(done);
+ } else {
+#ifdef ASSERT
+ __ z_ltgr(new_val, new_val);
+ __ asm_assert(Assembler::bcondNotZero, "null oop not allowed (G1 post)", 0x322); // Checked by caller.
+#endif
+ }
+
+ __ z_srag(tmp1, store_addr, CardTable::card_shift());
+
+ Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
+ __ z_alg(tmp1, card_table_addr); // tmp1 := card address
+
+ if(UseCondCardMark) {
+ __ z_cli(0, tmp1, G1CardTable::clean_card_val());
+ __ branch_optimized(Assembler::bcondNotEqual, done);
+ }
+
+ static_assert(G1CardTable::dirty_card_val() == 0, "must be to use z_mvi");
+ __ z_mvi(0, tmp1, G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
+
+ __ block_comment("} generate_post_barrier");
+}
+
void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
Register store_addr,
Register new_val,
Register thread,
Register tmp1,
Register tmp2,
- G1PostBarrierStubC2* stub) {
+ bool new_val_may_be_null) {
BLOCK_COMMENT("g1_write_barrier_post_c2 {");
-
- assert(thread == Z_thread, "must be");
- assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, Z_R1_scratch);
-
- assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
-
- stub->initialize_registers(thread, tmp1, tmp2);
-
- BLOCK_COMMENT("generate_region_crossing_test {");
- if (VM_Version::has_DistinctOpnds()) {
- __ z_xgrk(tmp1, store_addr, new_val);
- } else {
- __ z_lgr(tmp1, store_addr);
- __ z_xgr(tmp1, new_val);
- }
- __ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes);
- __ branch_optimized(Assembler::bcondEqual, *stub->continuation());
- BLOCK_COMMENT("} generate_region_crossing_test");
-
- // crosses regions, storing null?
- if ((stub->barrier_data() & G1C2BarrierPostNotNull) == 0) {
- __ z_ltgr(new_val, new_val);
- __ branch_optimized(Assembler::bcondEqual, *stub->continuation());
- }
-
- BLOCK_COMMENT("generate_card_young_test {");
- CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
- // calculate address of card
- __ load_const_optimized(tmp2, (address)ct->card_table()->byte_map_base()); // Card table base.
- __ z_srlg(tmp1, store_addr, CardTable::card_shift()); // Index into card table.
- __ z_algr(tmp1, tmp2); // Explicit calculation needed for cli.
-
- // Filter young.
- __ z_cli(0, tmp1, G1CardTable::g1_young_card_val());
-
- BLOCK_COMMENT("} generate_card_young_test");
-
- // From here on, tmp1 holds the card address.
- __ branch_optimized(Assembler::bcondNotEqual, *stub->entry());
-
- __ bind(*stub->continuation());
-
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, new_val_may_be_null);
+ __ bind(done);
BLOCK_COMMENT("} g1_write_barrier_post_c2");
}
-void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const {
-
- BLOCK_COMMENT("generate_c2_post_barrier_stub {");
-
- Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
- Label runtime;
-
- Register thread = stub->thread();
- Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
- Register tmp2 = stub->tmp2();
- Register Rcard_addr = tmp1;
-
- __ bind(*stub->entry());
-
- BLOCK_COMMENT("generate_card_clean_test {");
- __ z_sync(); // Required to support concurrent cleaning.
- __ z_cli(0, Rcard_addr, 0); // Reload after membar.
- __ branch_optimized(Assembler::bcondEqual, *stub->continuation());
- BLOCK_COMMENT("} generate_card_clean_test");
-
- BLOCK_COMMENT("generate_dirty_card {");
- // Storing a region crossing, non-null oop, card is clean.
- // Dirty card and log.
- STATIC_ASSERT(CardTable::dirty_card_val() == 0);
- __ z_mvi(0, Rcard_addr, CardTable::dirty_card_val());
- BLOCK_COMMENT("} generate_dirty_card");
-
- generate_queue_test_and_insertion(masm,
- G1ThreadLocalData::dirty_card_queue_index_offset(),
- G1ThreadLocalData::dirty_card_queue_buffer_offset(),
- runtime,
- Z_thread, tmp1, tmp2);
-
- __ branch_optimized(Assembler::bcondAlways, *stub->continuation());
-
- __ bind(runtime);
-
- generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
-
- __ branch_optimized(Assembler::bcondAlways, *stub->continuation());
-
- BLOCK_COMMENT("} generate_c2_post_barrier_stub");
-}
-
#endif //COMPILER2
void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
@@ -451,99 +417,9 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato
Register Rtmp1, Register Rtmp2, Register Rtmp3) {
bool not_null = (decorators & IS_NOT_NULL) != 0;
- assert_different_registers(Rstore_addr, Rnew_val, Rtmp1, Rtmp2); // Most probably, Rnew_val == Rtmp3.
-
- Label callRuntime, filtered;
-
- CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
-
- BLOCK_COMMENT("g1_write_barrier_post {");
-
- // Does store cross heap regions?
- // It does if the two addresses specify different grain addresses.
- if (VM_Version::has_DistinctOpnds()) {
- __ z_xgrk(Rtmp1, Rstore_addr, Rnew_val);
- } else {
- __ z_lgr(Rtmp1, Rstore_addr);
- __ z_xgr(Rtmp1, Rnew_val);
- }
- __ z_srag(Rtmp1, Rtmp1, G1HeapRegion::LogOfHRGrainBytes);
- __ z_bre(filtered);
-
- // Crosses regions, storing null?
- if (not_null) {
-#ifdef ASSERT
- __ z_ltgr(Rnew_val, Rnew_val);
- __ asm_assert(Assembler::bcondNotZero, "null oop not allowed (G1 post)", 0x322); // Checked by caller.
-#endif
- } else {
- __ z_ltgr(Rnew_val, Rnew_val);
- __ z_bre(filtered);
- }
-
- Rnew_val = noreg; // end of lifetime
-
- // Storing region crossing non-null, is card already dirty?
- assert_different_registers(Rtmp1, Rtmp2, Rtmp3);
- // Make sure not to use Z_R0 for any of these registers.
- Register Rcard_addr = (Rtmp1 != Z_R0_scratch) ? Rtmp1 : Rtmp3;
- Register Rbase = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp3;
-
- // calculate address of card
- __ load_const_optimized(Rbase, (address)ct->card_table()->byte_map_base()); // Card table base.
- __ z_srlg(Rcard_addr, Rstore_addr, CardTable::card_shift()); // Index into card table.
- __ z_algr(Rcard_addr, Rbase); // Explicit calculation needed for cli.
- Rbase = noreg; // end of lifetime
-
- // Filter young.
- __ z_cli(0, Rcard_addr, G1CardTable::g1_young_card_val());
- __ z_bre(filtered);
-
- // Check the card value. If dirty, we're done.
- // This also avoids false sharing of the (already dirty) card.
- __ z_sync(); // Required to support concurrent cleaning.
- __ z_cli(0, Rcard_addr, G1CardTable::dirty_card_val()); // Reload after membar.
- __ z_bre(filtered);
-
- // Storing a region crossing, non-null oop, card is clean.
- // Dirty card and log.
- __ z_mvi(0, Rcard_addr, G1CardTable::dirty_card_val());
-
- Register Rcard_addr_x = Rcard_addr;
- Register Rqueue_index = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp1;
- if (Rcard_addr == Rqueue_index) {
- Rcard_addr_x = Z_R0_scratch; // Register shortage. We have to use Z_R0.
- }
- __ lgr_if_needed(Rcard_addr_x, Rcard_addr);
-
- generate_queue_test_and_insertion(masm,
- G1ThreadLocalData::dirty_card_queue_index_offset(),
- G1ThreadLocalData::dirty_card_queue_buffer_offset(),
- callRuntime,
- Z_thread, Rcard_addr_x, Rqueue_index);
- __ z_bru(filtered);
-
- __ bind(callRuntime);
-
- // TODO: do we need a frame? Introduced to be on the safe side.
- bool needs_frame = true;
- __ lgr_if_needed(Rcard_addr, Rcard_addr_x); // copy back asap. push_frame will destroy Z_R0_scratch!
-
- // VM call need frame to access(write) O register.
- if (needs_frame) {
- __ save_return_pc();
- __ push_frame_abi160(0); // Will use Z_R0 as tmp on old CPUs.
- }
-
- // Save the live input values.
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), Rcard_addr, Z_thread);
-
- if (needs_frame) {
- __ pop_frame();
- __ restore_return_pc();
- }
-
- __ bind(filtered);
+ Label done;
+ generate_post_barrier(masm, Rstore_addr, Rnew_val, Z_thread, Rtmp1, Rtmp2, done, !not_null);
+ __ bind(done);
BLOCK_COMMENT("} g1_write_barrier_post");
}
@@ -615,22 +491,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
__ branch_optimized(Assembler::bcondAlways, *stub->continuation());
}
-void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
- G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
- __ bind(*stub->entry());
- ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots.
- assert(stub->addr()->is_register(), "Precondition.");
- assert(stub->new_val()->is_register(), "Precondition.");
- Register new_val_reg = stub->new_val()->as_register();
- __ z_ltgr(new_val_reg, new_val_reg);
- __ branch_optimized(Assembler::bcondZero, *stub->continuation());
- __ z_lgr(Z_R1_scratch, stub->addr()->as_pointer_register());
- ce->emit_call_c(bs->post_barrier_c1_runtime_code_blob()->code_begin());
- __ branch_optimized(Assembler::bcondAlways, *stub->continuation());
-}
-
#undef __
+void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
+ masm->bind(done);
+}
+
#define __ sasm->
static OopMap* save_volatile_registers(StubAssembler* sasm, Register return_pc = Z_R14) {
@@ -705,92 +578,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ z_bru(restart);
}
-void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
- // Z_R1_scratch: oop address, address of updated memory slot
-
- BarrierSet* bs = BarrierSet::barrier_set();
- __ set_info("g1_post_barrier_slow_id", false);
-
- Register addr_oop = Z_R1_scratch;
- Register addr_card = Z_R1_scratch;
- Register r1 = Z_R6; // Must be saved/restored.
- Register r2 = Z_R7; // Must be saved/restored.
- Register cardtable = r1; // Must be non-volatile, because it is used to save addr_card.
- CardTableBarrierSet* ctbs = barrier_set_cast(bs);
- CardTable* ct = ctbs->card_table();
- CardTable::CardValue* byte_map_base = ct->byte_map_base();
-
- // Save registers used below (see assertion in G1PreBarrierStub::emit_code()).
- __ z_stg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
-
- Label not_already_dirty, restart, refill, young_card;
-
- // Calculate address of card corresponding to the updated oop slot.
- AddressLiteral rs(byte_map_base);
- __ z_srlg(addr_card, addr_oop, CardTable::card_shift());
- addr_oop = noreg; // dead now
- __ load_const_optimized(cardtable, rs); // cardtable :=
- __ z_agr(addr_card, cardtable); // addr_card := addr_oop>>card_shift + cardtable
-
- __ z_cli(0, addr_card, (int)G1CardTable::g1_young_card_val());
- __ z_bre(young_card);
-
- __ z_sync(); // Required to support concurrent cleaning.
-
- __ z_cli(0, addr_card, (int)CardTable::dirty_card_val());
- __ z_brne(not_already_dirty);
-
- __ bind(young_card);
- // We didn't take the branch, so we're already dirty: restore
- // used registers and return.
- __ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
- __ z_br(Z_R14);
-
- // Not dirty.
- __ bind(not_already_dirty);
-
- // First, dirty it: [addr_card] := 0
- __ z_mvi(0, addr_card, CardTable::dirty_card_val());
-
- Register idx = cardtable; // Must be non-volatile, because it is used to save addr_card.
- Register buf = r2;
- cardtable = noreg; // now dead
-
- // Save registers used below (see assertion in G1PreBarrierStub::emit_code()).
- __ z_stg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
-
- ByteSize dirty_card_q_index_byte_offset = G1ThreadLocalData::dirty_card_queue_index_offset();
- ByteSize dirty_card_q_buf_byte_offset = G1ThreadLocalData::dirty_card_queue_buffer_offset();
-
- __ bind(restart);
-
- // Get the index into the update buffer. G1DirtyCardQueue::_index is
- // a size_t so z_ltg is appropriate here.
- __ z_ltg(idx, Address(Z_thread, dirty_card_q_index_byte_offset));
-
- // index == 0?
- __ z_brz(refill);
-
- __ z_lg(buf, Address(Z_thread, dirty_card_q_buf_byte_offset));
- __ add2reg(idx, -oopSize);
-
- __ z_stg(addr_card, 0, idx, buf); // [_buf + index] :=
- __ z_stg(idx, Address(Z_thread, dirty_card_q_index_byte_offset));
- // Restore killed registers and return.
- __ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
- __ z_lg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
- __ z_br(Z_R14);
-
- __ bind(refill);
- save_volatile_registers(sasm);
- __ z_lgr(idx, addr_card); // Save addr_card, tmp3 must be non-volatile.
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1DirtyCardQueueSet::handle_zero_index_for_thread),
- Z_thread);
- __ z_lgr(addr_card, idx);
- restore_volatile_registers(sasm); // Restore addr_card.
- __ z_bru(restart);
-}
-
#undef __
#endif // COMPILER1
diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp
index 0f0bdd8b83c..fdec751c43b 100644
--- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp
+++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -33,9 +33,7 @@
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
-class G1PostBarrierStub;
class G1PreBarrierStubC2;
-class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -60,10 +58,16 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
public:
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
- void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
- void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
+
+ void g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2);
+
#endif // COMPILER1
#ifdef COMPILER2
@@ -81,9 +85,7 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
Register thread,
Register tmp1,
Register tmp2,
- G1PostBarrierStubC2* c2_stub);
- void generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const;
+ bool new_val_may_be_null);
#endif // COMPILER2
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
diff --git a/src/hotspot/cpu/s390/gc/g1/g1_s390.ad b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad
index 31f60c4aeff..000ac3bc5ba 100644
--- a/src/hotspot/cpu/s390/gc/g1/g1_s390.ad
+++ b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
// Copyright 2024 IBM Corporation. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
@@ -62,13 +62,13 @@ static void write_barrier_post(MacroAssembler* masm,
Register new_val,
Register tmp1,
Register tmp2) {
- if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ if (!G1BarrierStubC2::needs_post_barrier(node)) {
return;
}
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
- G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
- g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Z_thread, tmp1, tmp2, stub);
+ bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Z_thread, tmp1, tmp2, new_val_may_be_null);
}
%} // source
@@ -356,7 +356,7 @@ instruct g1CompareAndExchangeP(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval
__ z_lgr($res$$Register, $oldval$$Register); // previous content
- __ z_csg($oldval$$Register, $newval$$Register, 0, $mem_ptr$$reg);
+ __ z_csg($res$$Register, $newval$$Register, 0, $mem_ptr$$reg);
write_barrier_post(masm, this,
$mem_ptr$$Register /* store_addr */,
diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp
index 2d663061aec..c6f5a4e119c 100644
--- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp
@@ -171,6 +171,7 @@ void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Re
void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
+ __ align(4, __ offset() + OFFSET_TO_PATCHABLE_DATA); // must align the following block which requires atomic updates
__ block_comment("nmethod_entry_barrier (nmethod_entry_barrier) {");
// Load jump addr:
diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp
index acc0d3b4988..3e0b2be4873 100644
--- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp
@@ -66,6 +66,14 @@ public:
OptoReg::Name refine_register(const Node* node,
OptoReg::Name opto_reg) const;
#endif // COMPILER2
+
+ static const int OFFSET_TO_PATCHABLE_DATA_INSTRUCTION = 6 + 6 + 6; // iihf(6) + iilf(6) + lg(6)
+ static const int BARRIER_TOTAL_LENGTH = OFFSET_TO_PATCHABLE_DATA_INSTRUCTION + 6 + 6 + 2; // cfi(6) + larl(6) + bcr(2)
+
+ // first 2 bytes are for cfi instruction opcode and next 4 bytes will be the value/data to be patched,
+ // so we are skipping first 2 bytes and returning the address of value/data field
+ static const int OFFSET_TO_PATCHABLE_DATA = 6 + 6 + 6 + 2; // iihf(6) + iilf(6) + lg(6) + CFI_OPCODE(2)
+
};
#ifdef COMPILER2
diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp
index 8f43f4ef723..f6bf137da1c 100644
--- a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp
@@ -26,26 +26,32 @@
#include "code/codeBlob.hpp"
#include "code/nativeInst.hpp"
#include "code/nmethod.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "utilities/debug.hpp"
class NativeMethodBarrier: public NativeInstruction {
private:
- static const int PATCHABLE_INSTRUCTION_OFFSET = 3*6; // bytes
address get_barrier_start_address() const {
return NativeInstruction::addr_at(0);
}
address get_patchable_data_address() const {
- address inst_addr = get_barrier_start_address() + PATCHABLE_INSTRUCTION_OFFSET;
+ address start_address = get_barrier_start_address();
+#ifdef ASSERT
+ address inst_addr = start_address + BarrierSetAssembler::OFFSET_TO_PATCHABLE_DATA_INSTRUCTION;
- DEBUG_ONLY(Assembler::is_z_cfi(*((long*)inst_addr)));
- return inst_addr + 2;
+ unsigned long instr = 0;
+ Assembler::get_instruction(inst_addr, &instr);
+ assert(Assembler::is_z_cfi(instr), "sanity check");
+#endif // ASSERT
+
+ return start_address + BarrierSetAssembler::OFFSET_TO_PATCHABLE_DATA;
}
public:
- static const int BARRIER_TOTAL_LENGTH = PATCHABLE_INSTRUCTION_OFFSET + 2*6 + 2; // bytes
+ static const int BARRIER_TOTAL_LENGTH = BarrierSetAssembler::BARRIER_TOTAL_LENGTH;
int get_guard_value() const {
address data_addr = get_patchable_data_address();
@@ -77,23 +83,30 @@ class NativeMethodBarrier: public NativeInstruction {
#ifdef ASSERT
void verify() const {
+ unsigned long instr = 0;
int offset = 0; // bytes
const address start = get_barrier_start_address();
- MacroAssembler::is_load_const(/* address */ start + offset); // two instructions
+ assert(MacroAssembler::is_load_const(/* address */ start + offset), "sanity check"); // two instructions
offset += Assembler::instr_len(&start[offset]);
offset += Assembler::instr_len(&start[offset]);
- Assembler::is_z_lg(*((long*)(start + offset)));
+ Assembler::get_instruction(start + offset, &instr);
+ assert(Assembler::is_z_lg(instr), "sanity check");
offset += Assembler::instr_len(&start[offset]);
- Assembler::is_z_cfi(*((long*)(start + offset)));
+ // it will be assignment operation, So it doesn't matter what value is already present in instr
+ // hence, no need to 0 it out.
+ Assembler::get_instruction(start + offset, &instr);
+ assert(Assembler::is_z_cfi(instr), "sanity check");
offset += Assembler::instr_len(&start[offset]);
- Assembler::is_z_larl(*((long*)(start + offset)));
+ Assembler::get_instruction(start + offset, &instr);
+ assert(Assembler::is_z_larl(instr), "sanity check");
offset += Assembler::instr_len(&start[offset]);
- Assembler::is_z_bcr(*((long*)(start + offset)));
+ Assembler::get_instruction(start + offset, &instr);
+ assert(Assembler::is_z_bcr(instr), "sanity check");
offset += Assembler::instr_len(&start[offset]);
assert(offset == BARRIER_TOTAL_LENGTH, "check offset == barrier length constant");
diff --git a/src/hotspot/cpu/s390/javaFrameAnchor_s390.hpp b/src/hotspot/cpu/s390/javaFrameAnchor_s390.hpp
index ae8b8766159..307034ca0cd 100644
--- a/src/hotspot/cpu/s390/javaFrameAnchor_s390.hpp
+++ b/src/hotspot/cpu/s390/javaFrameAnchor_s390.hpp
@@ -35,38 +35,32 @@
// 3 - restoring an old state (javaCalls).
inline void clear(void) {
+ // No hardware barriers are necessary. All members are volatile and the profiler
+ // is run from a signal handler and only observers the thread its running on.
+
// Clearing _last_Java_sp must be first.
- OrderAccess::release();
+
_last_Java_sp = nullptr;
- // Fence?
- OrderAccess::fence();
_last_Java_pc = nullptr;
}
inline void set(intptr_t* sp, address pc) {
_last_Java_pc = pc;
-
- OrderAccess::release();
_last_Java_sp = sp;
}
void copy(JavaFrameAnchor* src) {
- // In order to make sure the transition state is valid for "this"
+ // No hardware barriers are necessary. All members are volatile and the profiler
+ // is run from a signal handler and only observers the thread its running on.
+
// we must clear _last_Java_sp before copying the rest of the new data.
- // Hack Alert: Temporary bugfix for 4717480/4721647
- // To act like previous version (pd_cache_state) don't null _last_Java_sp
- // unless the value is changing.
- //
if (_last_Java_sp != src->_last_Java_sp) {
- OrderAccess::release();
_last_Java_sp = nullptr;
- OrderAccess::fence();
}
_last_Java_pc = src->_last_Java_pc;
// Must be last so profiler will always see valid frame if has_last_frame() is true.
- OrderAccess::release();
_last_Java_sp = src->_last_Java_sp;
}
@@ -80,7 +74,7 @@
intptr_t* last_Java_fp(void) { return nullptr; }
intptr_t* last_Java_sp() const { return _last_Java_sp; }
- void set_last_Java_sp(intptr_t* sp) { OrderAccess::release(); _last_Java_sp = sp; }
+ void set_last_Java_sp(intptr_t* sp) { _last_Java_sp = sp; }
address last_Java_pc(void) { return _last_Java_pc; }
diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad
index 4c6b0d96e6f..ab991896b53 100644
--- a/src/hotspot/cpu/s390/s390.ad
+++ b/src/hotspot/cpu/s390/s390.ad
@@ -1947,6 +1947,7 @@ bool Matcher::is_spillable_arg(int reg) {
uint Matcher::int_pressure_limit()
{
// Medium size register set, 6 special purpose regs, 3 SOE regs.
+ // 10 prevents spill-split-recycle sanity check in JVM2008.xml.transform.
return (INTPRESSURE == -1) ? 10 : INTPRESSURE;
}
@@ -1960,30 +1961,25 @@ bool Matcher::use_asm_for_ldiv_by_con(jlong divisor) {
}
// Register for DIVI projection of divmodI
-RegMask Matcher::divI_proj_mask() {
+const RegMask& Matcher::divI_proj_mask() {
return _Z_RARG4_INT_REG_mask;
}
// Register for MODI projection of divmodI
-RegMask Matcher::modI_proj_mask() {
+const RegMask& Matcher::modI_proj_mask() {
return _Z_RARG3_INT_REG_mask;
}
// Register for DIVL projection of divmodL
-RegMask Matcher::divL_proj_mask() {
+const RegMask& Matcher::divL_proj_mask() {
return _Z_RARG4_LONG_REG_mask;
}
// Register for MODL projection of divmodL
-RegMask Matcher::modL_proj_mask() {
+const RegMask& Matcher::modL_proj_mask() {
return _Z_RARG3_LONG_REG_mask;
}
-// Copied from sparc.
-const RegMask Matcher::method_handle_invoke_SP_save_mask() {
- return RegMask();
-}
-
// Should the matcher clone input 'm' of node 'n'?
bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) {
if (is_encode_and_store_pattern(n, m)) {
diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
index 3b1d06cf560..db1ee8351ac 100644
--- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
+++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
@@ -2347,13 +2347,11 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs,
- AdapterHandlerEntry* handler) {
+ address entry_address[AdapterBlob::ENTRY_COUNT]) {
__ align(CodeEntryAlignment);
- address i2c_entry = __ pc();
+ entry_address[AdapterBlob::I2C] = __ pc();
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
- address c2i_unverified_entry;
-
Label skip_fixup;
{
Label ic_miss;
@@ -2363,7 +2361,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
// Unverified Entry Point UEP
__ align(CodeEntryAlignment);
- c2i_unverified_entry = __ pc();
+ entry_address[AdapterBlob::C2I_Unverified] = __ pc();
__ ic_check(2);
__ z_lg(Z_method, Address(Z_inline_cache, CompiledICData::speculated_method_offset()));
@@ -2376,10 +2374,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
// Fallthru to VEP. Duplicate LTG, but saved taken branch.
}
- address c2i_entry = __ pc();
+ entry_address[AdapterBlob::C2I] = __ pc();
// Class initialization barrier for static methods
- address c2i_no_clinit_check_entry = nullptr;
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
if (VM_Version::supports_fast_class_init_checks()) {
Label L_skip_barrier;
@@ -2396,12 +2394,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ z_br(klass);
__ bind(L_skip_barrier);
- c2i_no_clinit_check_entry = __ pc();
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
}
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
-
- handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
return;
}
diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp
index 2b39cc8318c..4e8fdf275e4 100644
--- a/src/hotspot/cpu/s390/templateTable_s390.cpp
+++ b/src/hotspot/cpu/s390/templateTable_s390.cpp
@@ -2360,7 +2360,7 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
assert_different_registers(Rcache, index);
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
- Label resolved, clinit_barrier_slow;
+ Label L_clinit_barrier_slow, L_done;
Bytecodes::Code code = bytecode();
switch (code) {
@@ -2375,27 +2375,30 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
__ load_method_entry(Rcache, index);
__ z_cli(Address(Rcache, bc_offset), code);
- __ z_bre(resolved);
+
+ // Class initialization barrier for static methods
+ if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
+ const Register method = Z_R1_scratch;
+ const Register klass = Z_R1_scratch;
+ __ z_brne(L_clinit_barrier_slow);
+ __ z_lg(method, Address(Rcache, in_bytes(ResolvedMethodEntry::method_offset())));
+ __ load_method_holder(klass, method);
+ __ clinit_barrier(klass, Z_thread, &L_done, /*L_slow_path*/ nullptr);
+ __ bind(L_clinit_barrier_slow);
+ } else {
+ __ z_bre(L_done);
+ }
// Resolve first time through
// Class initialization barrier slow path lands here as well.
- __ bind(clinit_barrier_slow);
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ load_const_optimized(Z_ARG2, (int)code);
__ call_VM(noreg, entry, Z_ARG2);
// Update registers with resolved info.
__ load_method_entry(Rcache, index);
- __ bind(resolved);
- // Class initialization barrier for static methods
- if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
- const Register method = Z_R1_scratch;
- const Register klass = Z_R1_scratch;
- __ z_lg(method, Address(Rcache, in_bytes(ResolvedMethodEntry::method_offset())));
- __ load_method_holder(klass, method);
- __ clinit_barrier(klass, Z_thread, nullptr /*L_fast_path*/, &clinit_barrier_slow);
- }
+ __ bind(L_done);
BLOCK_COMMENT("} resolve_cache_and_index_for_method");
}
@@ -2408,7 +2411,7 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
assert_different_registers(cache, index);
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
- NearLabel resolved;
+ Label L_clinit_barrier_slow, L_done;
Bytecodes::Code code = bytecode();
switch (code) {
@@ -2422,9 +2425,22 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
in_bytes(ResolvedFieldEntry::put_code_offset()) ;
__ z_cli(Address(cache, code_offset), code);
- __ z_bre(resolved);
+
+ // Class initialization barrier for static fields
+ if (VM_Version::supports_fast_class_init_checks() &&
+ (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) {
+ const Register field_holder = index;
+
+ __ z_brne(L_clinit_barrier_slow);
+ __ load_sized_value(field_holder, Address(cache, ResolvedFieldEntry::field_holder_offset()), sizeof(void*), false);
+ __ clinit_barrier(field_holder, Z_thread, &L_done, /*L_slow_path*/ nullptr);
+ __ bind(L_clinit_barrier_slow);
+ } else {
+ __ z_bre(L_done);
+ }
// resolve first time through
+ // Class initialization barrier slow path lands here as well.
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ load_const_optimized(Z_ARG2, (int)code);
__ call_VM(noreg, entry, Z_ARG2);
@@ -2432,7 +2448,7 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
// Update registers with resolved info.
__ load_field_entry(cache, index);
- __ bind(resolved);
+ __ bind(L_done);
BLOCK_COMMENT("} resolve_cache_and_index_for_field");
}
diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp
index 3f1140c937b..fd62e9358bf 100644
--- a/src/hotspot/cpu/x86/assembler_x86.cpp
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp
@@ -2225,6 +2225,44 @@ void Assembler::cvttss2sil(Register dst, XMMRegister src) {
emit_int16(0x2C, (0xC0 | encode));
}
+void Assembler::evcvttss2sisl(Register dst, XMMRegister src) {
+ assert(VM_Version::supports_avx10_2(), "");
+ 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(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
+ emit_int16(0x6D, (0xC0 | encode));
+}
+
+void Assembler::evcvttss2sisl(Register dst, Address src) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_is_evex_instruction();
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
+ emit_int8((unsigned char)0x6D);
+ emit_operand(dst, src, 0);
+}
+
+void Assembler::evcvttss2sisq(Register dst, XMMRegister src) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
+ emit_int16(0x6D, (0xC0 | encode));
+}
+
+void Assembler::evcvttss2sisq(Register dst, Address src) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_is_evex_instruction();
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
+ emit_int8((unsigned char)0x6D);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::cvttpd2dq(XMMRegister dst, XMMRegister src) {
int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit;
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -2310,6 +2348,25 @@ void Assembler::vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int16(0x5B, (0xC0 | encode));
}
+void Assembler::evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionAttr attributes(vector_len, /* rex_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(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
+ emit_int16(0x6D, (0xC0 | encode));
+}
+
+void Assembler::evcvttps2dqs(XMMRegister dst, Address src, int vector_len) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_is_evex_instruction();
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
+ emit_int8((unsigned char)0x6D);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) {
assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), "");
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -2317,6 +2374,25 @@ void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int16((unsigned char)0xE6, (0xC0 | encode));
}
+void Assembler::evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
+ emit_int16(0x6D, (0xC0 | encode));
+}
+
+void Assembler::evcvttpd2dqs(XMMRegister dst, Address src, int vector_len) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_is_evex_instruction();
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
+ emit_int8((unsigned char)0x6D);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len) {
assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), "");
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -2332,6 +2408,25 @@ void Assembler::evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int16(0x7A, (0xC0 | encode));
}
+void Assembler::evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionAttr attributes(vector_len, /* rex_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(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
+ emit_int16(0x6D, (0xC0 | encode));
+}
+
+void Assembler::evcvttps2qqs(XMMRegister dst, Address src, int vector_len) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_HV, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_is_evex_instruction();
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
+ emit_int8((unsigned char)0x6D);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512dq(), "");
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -2356,6 +2451,25 @@ void Assembler::evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int16(0x7A, (0xC0 | encode));
}
+void Assembler::evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
+ emit_int16(0x6D, (0xC0 | encode));
+}
+
+void Assembler::evcvttpd2qqs(XMMRegister dst, Address src, int vector_len) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_is_evex_instruction();
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
+ emit_int8((unsigned char)0x6D);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::evcvtqq2pd(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512dq(), "");
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -14988,6 +15102,44 @@ void Assembler::cvttsd2siq(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::evcvttsd2sisl(Register dst, XMMRegister src) {
+ assert(VM_Version::supports_avx10_2(), "");
+ 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(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
+ emit_int16(0x6D, (0xC0 | encode));
+}
+
+void Assembler::evcvttsd2sisl(Register dst, Address src) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_is_evex_instruction();
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
+ emit_int8((unsigned char)0x6D);
+ emit_operand(dst, src, 0);
+}
+
+void Assembler::evcvttsd2sisq(Register dst, XMMRegister src) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
+ emit_int16(0x6D, (0xC0 | encode));
+}
+
+void Assembler::evcvttsd2sisq(Register dst, Address src) {
+ assert(VM_Version::supports_avx10_2(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_is_evex_instruction();
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
+ emit_int8((unsigned char)0x6D);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::cvttsd2siq(Register dst, XMMRegister src) {
InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp
index 99dade412b2..c863191df4c 100644
--- a/src/hotspot/cpu/x86/assembler_x86.hpp
+++ b/src/hotspot/cpu/x86/assembler_x86.hpp
@@ -1316,11 +1316,19 @@ private:
void cvttsd2sil(Register dst, XMMRegister src);
void cvttsd2siq(Register dst, Address src);
void cvttsd2siq(Register dst, XMMRegister src);
+ void evcvttsd2sisl(Register dst, XMMRegister src);
+ void evcvttsd2sisl(Register dst, Address src);
+ void evcvttsd2sisq(Register dst, XMMRegister src);
+ void evcvttsd2sisq(Register dst, Address src);
// Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer
void cvttss2sil(Register dst, XMMRegister src);
void cvttss2siq(Register dst, XMMRegister src);
void cvtss2sil(Register dst, XMMRegister src);
+ void evcvttss2sisl(Register dst, XMMRegister src);
+ void evcvttss2sisl(Register dst, Address src);
+ void evcvttss2sisq(Register dst, XMMRegister src);
+ void evcvttss2sisq(Register dst, Address src);
// Convert vector double to int
void cvttpd2dq(XMMRegister dst, XMMRegister src);
@@ -1332,7 +1340,11 @@ private:
// Convert vector float to int/long
void vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len);
void vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len);
+ void evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len);
+ void evcvttps2dqs(XMMRegister dst, Address src, int vector_len);
void evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len);
+ void evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len);
+ void evcvttps2qqs(XMMRegister dst, Address src, int vector_len);
// Convert vector long to vector FP
void evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len);
@@ -1341,9 +1353,13 @@ private:
// Convert vector double to long
void evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len);
void evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len);
+ void evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len);
+ void evcvttpd2qqs(XMMRegister dst, Address src, int vector_len);
// Convert vector double to int
void vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len);
+ void evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len);
+ void evcvttpd2dqs(XMMRegister dst, Address src, int vector_len);
// Evex casts with truncation
void evpmovwb(XMMRegister dst, XMMRegister src, int vector_len);
diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp
index 2fd067a7749..95ce48f34db 100644
--- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp
@@ -207,10 +207,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- if (_compute_lock) {
- // lock_reg was destroyed by fast unlocking attempt => recompute it
- ce->monitor_address(_monitor_ix, _lock_reg);
- }
+
+ // lock_reg was destroyed by fast unlocking attempt => recompute it
+ ce->monitor_address(_monitor_ix, _lock_reg);
+
ce->store_parameter(_lock_reg->as_register(), 0);
// note: non-blocking leaf routine => no call info needed
StubId exit_id;
diff --git a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp
index bdbab432180..68c9814fd20 100644
--- a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp
@@ -326,13 +326,6 @@ LIR_Opr FrameMap::stack_pointer() {
return FrameMap::rsp_opr;
}
-// JSR 292
-// On x86, there is no need to save the SP, because neither
-// method handle intrinsics, nor compiled lambda forms modify it.
-LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
- return LIR_OprFact::illegalOpr;
-}
-
bool FrameMap::validate_frame() {
return true;
}
diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
index 98759295bb1..edeb0baea0e 100644
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
@@ -412,7 +412,7 @@ int LIR_Assembler::emit_unwind_handler() {
MonitorExitStub* stub = nullptr;
if (method()->is_synchronized()) {
monitor_address(0, FrameMap::rax_opr);
- stub = new MonitorExitStub(FrameMap::rax_opr, true, 0);
+ stub = new MonitorExitStub(FrameMap::rax_opr, 0);
__ unlock_object(rdi, rsi, rax, *stub->entry());
__ bind(*stub->continuation());
}
@@ -2730,7 +2730,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
Register hdr = op->hdr_opr()->as_register();
Register lock = op->lock_opr()->as_register();
if (op->code() == lir_lock) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
Register tmp = op->scratch_opr()->as_register();
// add debug info for NullPointerException only if one is possible
int null_check_offset = __ lock_object(hdr, obj, lock, tmp, *op->stub()->entry());
@@ -2739,7 +2738,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
}
// done
} else if (op->code() == lir_unlock) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
__ unlock_object(hdr, obj, lock, *op->stub()->entry());
} else {
Unimplemented();
diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
index 36efeafa940..c3d45f9d15d 100644
--- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
@@ -41,32 +41,32 @@
#include "utilities/checkedCast.hpp"
#include "utilities/globalDefinitions.hpp"
-int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register tmp, Label& slow_case) {
+int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register tmp, Label& slow_case) {
assert(hdr == rax, "hdr must be rax, for the cmpxchg instruction");
- assert_different_registers(hdr, obj, disp_hdr, tmp);
+ assert_different_registers(hdr, obj, basic_lock, tmp);
int null_check_offset = -1;
verify_oop(obj);
// save object being locked into the BasicObjectLock
- movptr(Address(disp_hdr, BasicObjectLock::obj_offset()), obj);
+ movptr(Address(basic_lock, BasicObjectLock::obj_offset()), obj);
null_check_offset = offset();
- lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case);
+ lightweight_lock(basic_lock, obj, hdr, tmp, slow_case);
return null_check_offset;
}
-void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
- assert(disp_hdr == rax, "disp_hdr must be rax, for the cmpxchg instruction");
- assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");
+void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) {
+ assert(basic_lock == rax, "basic_lock must be rax, for the cmpxchg instruction");
+ assert(hdr != obj && hdr != basic_lock && obj != basic_lock, "registers must be different");
// load object
- movptr(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
+ movptr(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
verify_oop(obj);
- lightweight_unlock(obj, disp_hdr, hdr, slow_case);
+ lightweight_unlock(obj, rax, hdr, slow_case);
}
diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp
index 6344a7b6ef1..f33e47aadb3 100644
--- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,17 +46,17 @@
void initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1);
// locking
- // hdr : must be rax, contents destroyed
- // obj : must point to the object to lock, contents preserved
- // disp_hdr: must point to the displaced header location, contents preserved
+ // hdr : must be rax, contents destroyed
+ // obj : must point to the object to lock, contents preserved
+ // basic_lock: must point to the basic lock, contents preserved
// returns code offset at which to add null check debug information
- int lock_object (Register swap, Register obj, Register disp_hdr, Register tmp, Label& slow_case);
+ int lock_object (Register swap, Register obj, Register basic_lock, Register tmp, Label& slow_case);
// unlocking
- // hdr : contents destroyed
- // obj : must point to the object to lock, contents preserved
- // disp_hdr: must be eax & must point to the displaced header location, contents destroyed
- void unlock_object(Register swap, Register obj, Register lock, Label& slow_case);
+ // hdr : contents destroyed
+ // obj : must point to the object to lock, contents preserved
+ // basic_lock: must be eax & must point to the basic lock, contents destroyed
+ void unlock_object(Register swap, Register obj, Register basic_lock, Label& slow_case);
void initialize_object(
Register obj, // result: pointer to object after successful allocation
diff --git a/src/hotspot/cpu/x86/c1_globals_x86.hpp b/src/hotspot/cpu/x86/c1_globals_x86.hpp
index be5c443a695..978b233bb63 100644
--- a/src/hotspot/cpu/x86/c1_globals_x86.hpp
+++ b/src/hotspot/cpu/x86/c1_globals_x86.hpp
@@ -52,7 +52,6 @@ define_pd_global(size_t, CodeCacheExpansionSize, 32*K );
define_pd_global(size_t, CodeCacheMinBlockLength, 1 );
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, NeverActAsServerClassMachine, true );
-define_pd_global(uint64_t, MaxRAM, 1ULL*G);
define_pd_global(bool, CICompileOSR, true );
#endif // !COMPILER2
define_pd_global(bool, UseTypeProfile, false);
diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
index 8c3f33e0aca..8386e57c389 100644
--- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
@@ -5053,12 +5053,12 @@ void C2_MacroAssembler::vector_cast_int_to_subword(BasicType to_elem_bt, XMMRegi
}
vpackuswb(dst, dst, zero, vec_enc);
break;
- default: assert(false, "%s", type2name(to_elem_bt));
+ default: assert(false, "Unexpected basic type for target of vector cast int to subword: %s", type2name(to_elem_bt));
}
}
/*
- * Algorithm for vector D2L and F2I conversions:-
+ * Algorithm for vector D2L and F2I conversions (AVX 10.2 unsupported):-
* a) Perform vector D2L/F2I cast.
* b) Choose fast path if none of the result vector lane contains 0x80000000 value.
* It signifies that source value could be any of the special floating point
@@ -5096,7 +5096,7 @@ void C2_MacroAssembler::vector_castF2X_evex(BasicType to_elem_bt, XMMRegister ds
case T_BYTE:
evpmovdb(dst, dst, vec_enc);
break;
- default: assert(false, "%s", type2name(to_elem_bt));
+ default: assert(false, "Unexpected basic type for target of vector castF2X EVEX: %s", type2name(to_elem_bt));
}
}
@@ -5143,7 +5143,7 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds
evpmovsqd(dst, dst, vec_enc);
evpmovdb(dst, dst, vec_enc);
break;
- default: assert(false, "%s", type2name(to_elem_bt));
+ default: assert(false, "Unexpected basic type for target of vector castD2X AVX512DQ EVEX: %s", type2name(to_elem_bt));
}
} else {
assert(type2aelembytes(to_elem_bt) <= 4, "");
@@ -5158,11 +5158,91 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds
case T_BYTE:
evpmovdb(dst, dst, vec_enc);
break;
- default: assert(false, "%s", type2name(to_elem_bt));
+ default: assert(false, "Unexpected basic type for target of vector castD2X EVEX: %s", type2name(to_elem_bt));
}
}
}
+void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) {
+ switch(to_elem_bt) {
+ case T_LONG:
+ evcvttps2qqs(dst, src, vec_enc);
+ break;
+ case T_INT:
+ evcvttps2dqs(dst, src, vec_enc);
+ break;
+ case T_SHORT:
+ evcvttps2dqs(dst, src, vec_enc);
+ evpmovdw(dst, dst, vec_enc);
+ break;
+ case T_BYTE:
+ evcvttps2dqs(dst, src, vec_enc);
+ evpmovdb(dst, dst, vec_enc);
+ break;
+ default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (reg src): %s", type2name(to_elem_bt));
+ }
+}
+
+void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) {
+ switch(to_elem_bt) {
+ case T_LONG:
+ evcvttps2qqs(dst, src, vec_enc);
+ break;
+ case T_INT:
+ evcvttps2dqs(dst, src, vec_enc);
+ break;
+ case T_SHORT:
+ evcvttps2dqs(dst, src, vec_enc);
+ evpmovdw(dst, dst, vec_enc);
+ break;
+ case T_BYTE:
+ evcvttps2dqs(dst, src, vec_enc);
+ evpmovdb(dst, dst, vec_enc);
+ break;
+ default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (mem src): %s", type2name(to_elem_bt));
+ }
+}
+
+void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) {
+ switch(to_elem_bt) {
+ case T_LONG:
+ evcvttpd2qqs(dst, src, vec_enc);
+ break;
+ case T_INT:
+ evcvttpd2dqs(dst, src, vec_enc);
+ break;
+ case T_SHORT:
+ evcvttpd2dqs(dst, src, vec_enc);
+ evpmovdw(dst, dst, vec_enc);
+ break;
+ case T_BYTE:
+ evcvttpd2dqs(dst, src, vec_enc);
+ evpmovdb(dst, dst, vec_enc);
+ break;
+ default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (reg src): %s", type2name(to_elem_bt));
+ }
+}
+
+void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) {
+ switch(to_elem_bt) {
+ case T_LONG:
+ evcvttpd2qqs(dst, src, vec_enc);
+ break;
+ case T_INT:
+ evcvttpd2dqs(dst, src, vec_enc);
+ break;
+ case T_SHORT:
+ evcvttpd2dqs(dst, src, vec_enc);
+ evpmovdw(dst, dst, vec_enc);
+ break;
+ case T_BYTE:
+ evcvttpd2dqs(dst, src, vec_enc);
+ evpmovdb(dst, dst, vec_enc);
+ break;
+ default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (mem src): %s", type2name(to_elem_bt));
+ }
+}
+
void C2_MacroAssembler::vector_round_double_evex(XMMRegister dst, XMMRegister src,
AddressLiteral double_sign_flip, AddressLiteral new_mxcsr, int vec_enc,
Register tmp, XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2) {
diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp
index 950fcb75290..aaee25f440a 100644
--- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp
@@ -347,6 +347,13 @@ public:
XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5,
AddressLiteral float_sign_flip, Register rscratch, int vec_enc);
+ void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc);
+
+ void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc);
+
+ void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc);
+
+ void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc);
void vector_cast_double_to_int_special_cases_avx(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2,
XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, Register rscratch,
diff --git a/src/hotspot/cpu/x86/c2_globals_x86.hpp b/src/hotspot/cpu/x86/c2_globals_x86.hpp
index a25f5da5e56..afd46a6fb08 100644
--- a/src/hotspot/cpu/x86/c2_globals_x86.hpp
+++ b/src/hotspot/cpu/x86/c2_globals_x86.hpp
@@ -52,9 +52,6 @@ define_pd_global(intx, LoopUnrollLimit, 60);
// InitialCodeCacheSize derived from specjbb2000 run.
define_pd_global(size_t, InitialCodeCacheSize, 2496*K); // Integral multiple of CodeCacheExpansionSize
define_pd_global(size_t, CodeCacheExpansionSize, 64*K);
-
-// Ergonomics related flags
-define_pd_global(uint64_t, MaxRAM, 128ULL*G);
#else
define_pd_global(intx, InteriorEntryAlignment, 4);
define_pd_global(size_t, NewSizeThreadIncrease, 4*K);
@@ -62,9 +59,6 @@ define_pd_global(intx, LoopUnrollLimit, 50); // Design center r
// InitialCodeCacheSize derived from specjbb2000 run.
define_pd_global(size_t, InitialCodeCacheSize, 2304*K); // Integral multiple of CodeCacheExpansionSize
define_pd_global(size_t, CodeCacheExpansionSize, 32*K);
-
-// Ergonomics related flags
-define_pd_global(uint64_t, MaxRAM, 4ULL*G);
#endif // AMD64
define_pd_global(intx, RegisterCostAreaRatio, 16000);
diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp
index 46ffda93699..5f52f2fabf2 100644
--- a/src/hotspot/cpu/x86/frame_x86.cpp
+++ b/src/hotspot/cpu/x86/frame_x86.cpp
@@ -219,8 +219,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
nmethod* nm = sender_blob->as_nmethod_or_null();
if (nm != nullptr) {
- if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) ||
- nm->method()->is_method_handle_intrinsic()) {
+ if (nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) {
return false;
}
}
@@ -443,47 +442,6 @@ JavaThread** frame::saved_thread_address(const frame& f) {
return thread_addr;
}
-//------------------------------------------------------------------------------
-// frame::verify_deopt_original_pc
-//
-// Verifies the calculated original PC of a deoptimization PC for the
-// given unextended SP.
-#ifdef ASSERT
-void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) {
- frame fr;
-
- // This is ugly but it's better than to change {get,set}_original_pc
- // to take an SP value as argument. And it's only a debugging
- // method anyway.
- fr._unextended_sp = unextended_sp;
-
- address original_pc = nm->get_original_pc(&fr);
- assert(nm->insts_contains_inclusive(original_pc),
- "original PC must be in the main code section of the compiled method (or must be immediately following it) original_pc: " INTPTR_FORMAT " unextended_sp: " INTPTR_FORMAT " name: %s", p2i(original_pc), p2i(unextended_sp), nm->name());
-}
-#endif
-
-//------------------------------------------------------------------------------
-// frame::adjust_unextended_sp
-#ifdef ASSERT
-void frame::adjust_unextended_sp() {
- // On x86, sites calling method handle intrinsics and lambda forms are treated
- // as any other call site. Therefore, no special action is needed when we are
- // returning to any of these call sites.
-
- if (_cb != nullptr) {
- nmethod* sender_nm = _cb->as_nmethod_or_null();
- if (sender_nm != nullptr) {
- // If the sender PC is a deoptimization point, get the original PC.
- if (sender_nm->is_deopt_entry(_pc) ||
- sender_nm->is_deopt_mh_entry(_pc)) {
- verify_deopt_original_pc(sender_nm, _unextended_sp);
- }
- }
- }
-}
-#endif
-
//------------------------------------------------------------------------------
// frame::sender_for_interpreter_frame
frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
diff --git a/src/hotspot/cpu/x86/frame_x86.hpp b/src/hotspot/cpu/x86/frame_x86.hpp
index f3034ee9263..19f37c42cf4 100644
--- a/src/hotspot/cpu/x86/frame_x86.hpp
+++ b/src/hotspot/cpu/x86/frame_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, 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
@@ -138,17 +138,10 @@
int _offset_unextended_sp; // for use in stack-chunk frames
};
- void adjust_unextended_sp() NOT_DEBUG_RETURN;
-
intptr_t* ptr_at_addr(int offset) const {
return (intptr_t*) addr_at(offset);
}
-#ifdef ASSERT
- // Used in frame::sender_for_{interpreter,compiled}_frame
- static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
-#endif
-
public:
// Constructors
diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp
index afc4ab8767b..ca51fe66786 100644
--- a/src/hotspot/cpu/x86/frame_x86.inline.hpp
+++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp
@@ -111,8 +111,6 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
}
inline void frame::setup(address pc) {
- adjust_unextended_sp();
-
address original_pc = get_deopt_original_pc();
if (original_pc != nullptr) {
_pc = original_pc;
@@ -209,7 +207,6 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
// assert(_pc != nullptr, "no pc?");
_cb = CodeCache::find_blob(_pc);
- adjust_unextended_sp();
address original_pc = get_deopt_original_pc();
if (original_pc != nullptr) {
diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp
index c1920b52837..a846289d91b 100644
--- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp
@@ -89,19 +89,53 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm
void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp) {
- __ push_call_clobbered_registers(false /* save_fpu */);
- if (c_rarg0 == count) { // On win64 c_rarg0 == rcx
- assert_different_registers(c_rarg1, addr);
- __ mov(c_rarg1, count);
- __ mov(c_rarg0, addr);
- } else {
- assert_different_registers(c_rarg0, count);
- __ mov(c_rarg0, addr);
- __ mov(c_rarg1, count);
- }
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);
- __ pop_call_clobbered_registers(false /* save_fpu */);
+ Label done;
+ __ testptr(count, count);
+ __ jcc(Assembler::zero, done);
+
+ // Calculate end address in "count".
+ Address::ScaleFactor scale = UseCompressedOops ? Address::times_4 : Address::times_8;
+ __ leaq(count, Address(addr, count, scale));
+
+ // Calculate start card address in "addr".
+ __ shrptr(addr, CardTable::card_shift());
+
+ Register thread = r15_thread;
+
+ __ movptr(tmp, Address(thread, in_bytes(G1ThreadLocalData::card_table_base_offset())));
+ __ addptr(addr, tmp);
+
+ // Calculate address of card of last word in the array.
+ __ subptr(count, 1);
+ __ shrptr(count, CardTable::card_shift());
+ __ addptr(count, tmp);
+
+ Label loop;
+ // Iterate from start card to end card (inclusive).
+ __ bind(loop);
+
+ Label is_clean_card;
+ if (UseCondCardMark) {
+ __ cmpb(Address(addr, 0), G1CardTable::clean_card_val());
+ __ jcc(Assembler::equal, is_clean_card);
+ } else {
+ __ movb(Address(addr, 0), G1CardTable::dirty_card_val());
+ }
+
+ Label next_card;
+ __ bind(next_card);
+ __ addptr(addr, sizeof(CardTable::CardValue));
+ __ cmpptr(addr, count);
+ __ jcc(Assembler::belowEqual, loop);
+ __ jmp(done);
+
+ __ bind(is_clean_card);
+ // Card was clean. Dirty card and go to next..
+ __ movb(Address(addr, 0), G1CardTable::dirty_card_val());
+ __ jmp(next_card);
+
+ __ bind(done);
}
void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
@@ -182,7 +216,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
// If expand_call is true then we expand the call_VM_leaf macro
// directly to skip generating the check by
// InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
-
const Register thread = r15_thread;
Label done;
@@ -235,76 +268,49 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
__ bind(done);
}
-static void generate_post_barrier_fast_path(MacroAssembler* masm,
- const Register store_addr,
- const Register new_val,
- const Register tmp,
- const Register tmp2,
- Label& done,
- bool new_val_may_be_null) {
- CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
+static void generate_post_barrier(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register tmp1,
+ Label& done,
+ bool new_val_may_be_null) {
+
+ assert_different_registers(store_addr, new_val, tmp1, noreg);
+
+ Register thread = r15_thread;
+
// Does store cross heap regions?
- __ movptr(tmp, store_addr); // tmp := store address
- __ xorptr(tmp, new_val); // tmp := store address ^ new value
- __ shrptr(tmp, G1HeapRegion::LogOfHRGrainBytes); // ((store address ^ new value) >> LogOfHRGrainBytes) == 0?
+ __ movptr(tmp1, store_addr); // tmp1 := store address
+ __ xorptr(tmp1, new_val); // tmp1 := store address ^ new value
+ __ shrptr(tmp1, G1HeapRegion::LogOfHRGrainBytes); // ((store address ^ new value) >> LogOfHRGrainBytes) == 0?
__ jcc(Assembler::equal, done);
+
// Crosses regions, storing null?
if (new_val_may_be_null) {
- __ cmpptr(new_val, NULL_WORD); // new value == null?
+ __ cmpptr(new_val, NULL_WORD); // new value == null?
__ jcc(Assembler::equal, done);
}
- // Storing region crossing non-null, is card young?
- __ movptr(tmp, store_addr); // tmp := store address
- __ shrptr(tmp, CardTable::card_shift()); // tmp := card address relative to card table base
- // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT
- // a valid address and therefore is not properly handled by the relocation code.
- __ movptr(tmp2, (intptr_t)ct->card_table()->byte_map_base()); // tmp2 := card table base address
- __ addptr(tmp, tmp2); // tmp := card address
- __ cmpb(Address(tmp, 0), G1CardTable::g1_young_card_val()); // *(card address) == young_card_val?
-}
-static void generate_post_barrier_slow_path(MacroAssembler* masm,
- const Register thread,
- const Register tmp,
- const Register tmp2,
- Label& done,
- Label& runtime) {
- __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); // StoreLoad membar
- __ cmpb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) == dirty_card_val?
- __ jcc(Assembler::equal, done);
+ __ movptr(tmp1, store_addr); // tmp1 := store address
+ __ shrptr(tmp1, CardTable::card_shift()); // tmp1 := card address relative to card table base
+
+ Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
+ __ addptr(tmp1, card_table_addr); // tmp1 := card address
+ if (UseCondCardMark) {
+ __ cmpb(Address(tmp1, 0), G1CardTable::clean_card_val()); // *(card address) == clean_card_val?
+ __ jcc(Assembler::notEqual, done);
+ }
// Storing a region crossing, non-null oop, card is clean.
- // Dirty card and log.
- __ movb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
- generate_queue_insertion(masm,
- G1ThreadLocalData::dirty_card_queue_index_offset(),
- G1ThreadLocalData::dirty_card_queue_buffer_offset(),
- runtime,
- thread, tmp, tmp2);
- __ jmp(done);
+ // Dirty card.
+ __ movb(Address(tmp1, 0), G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
}
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
Register store_addr,
Register new_val,
- Register tmp,
- Register tmp2) {
- const Register thread = r15_thread;
-
+ Register tmp) {
Label done;
- Label runtime;
-
- generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, done, true /* new_val_may_be_null */);
- // If card is young, jump to done
- __ jcc(Assembler::equal, done);
- generate_post_barrier_slow_path(masm, thread, tmp, tmp2, done, runtime);
-
- __ bind(runtime);
- // save the live input values
- RegSet saved = RegSet::of(store_addr);
- __ push_set(saved);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp, thread);
- __ pop_set(saved);
-
+ generate_post_barrier(masm, store_addr, new_val, tmp, done, true /* new_val_may_be_null */);
__ bind(done);
}
@@ -367,34 +373,10 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
Register store_addr,
Register new_val,
Register tmp,
- Register tmp2,
- G1PostBarrierStubC2* stub) {
- const Register thread = r15_thread;
- stub->initialize_registers(thread, tmp, tmp2);
-
- bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
- generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, *stub->continuation(), new_val_may_be_null);
- // If card is not young, jump to stub (slow path)
- __ jcc(Assembler::notEqual, *stub->entry());
-
- __ bind(*stub->continuation());
-}
-
-void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const {
- Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
- Label runtime;
- Register thread = stub->thread();
- Register tmp = stub->tmp1(); // tmp holds the card address.
- Register tmp2 = stub->tmp2();
- assert(stub->tmp3() == noreg, "not needed in this platform");
-
- __ bind(*stub->entry());
- generate_post_barrier_slow_path(masm, thread, tmp, tmp2, *stub->continuation(), runtime);
-
- __ bind(runtime);
- generate_c2_barrier_runtime_call(masm, stub, tmp, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
- __ jmp(*stub->continuation());
+ bool new_val_may_be_null) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, tmp, done, new_val_may_be_null);
+ __ bind(done);
}
#endif // COMPILER2
@@ -441,8 +423,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco
g1_write_barrier_post(masm /*masm*/,
tmp1 /* store_adr */,
new_val /* new_val */,
- tmp3 /* tmp */,
- tmp2 /* tmp2 */);
+ tmp3 /* tmp */);
}
}
}
@@ -476,21 +457,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
}
-void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
- G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
- __ bind(*stub->entry());
- assert(stub->addr()->is_register(), "Precondition.");
- assert(stub->new_val()->is_register(), "Precondition.");
- Register new_val_reg = stub->new_val()->as_register();
- __ cmpptr(new_val_reg, NULL_WORD);
- __ jcc(Assembler::equal, *stub->continuation());
- ce->store_parameter(stub->addr()->as_pointer_register(), 0);
- __ call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));
- __ jmp(*stub->continuation());
-}
-
#undef __
+void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2 /* unused on x86 */) {
+ Label done;
+ generate_post_barrier(masm, store_addr, new_val, tmp1, done, true /* new_val_may_be_null */);
+ masm->bind(done);
+}
+
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
@@ -555,78 +534,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ epilogue();
}
-void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
- __ prologue("g1_post_barrier", false);
-
- CardTableBarrierSet* ct =
- barrier_set_cast(BarrierSet::barrier_set());
-
- Label done;
- Label enqueued;
- Label runtime;
-
- // At this point we know new_value is non-null and the new_value crosses regions.
- // Must check to see if card is already dirty
-
- const Register thread = r15_thread;
-
- Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
- Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
-
- __ push_ppx(rax);
- __ push_ppx(rcx);
-
- const Register cardtable = rax;
- const Register card_addr = rcx;
-
- __ load_parameter(0, card_addr);
- __ shrptr(card_addr, CardTable::card_shift());
- // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT
- // a valid address and therefore is not properly handled by the relocation code.
- __ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base());
- __ addptr(card_addr, cardtable);
-
- __ cmpb(Address(card_addr, 0), G1CardTable::g1_young_card_val());
- __ jcc(Assembler::equal, done);
-
- __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
- __ cmpb(Address(card_addr, 0), CardTable::dirty_card_val());
- __ jcc(Assembler::equal, done);
-
- // storing region crossing non-null, card is clean.
- // dirty card and log.
-
- __ movb(Address(card_addr, 0), CardTable::dirty_card_val());
-
- const Register tmp = rdx;
- __ push_ppx(rdx);
-
- __ movptr(tmp, queue_index);
- __ testptr(tmp, tmp);
- __ jcc(Assembler::zero, runtime);
- __ subptr(tmp, wordSize);
- __ movptr(queue_index, tmp);
- __ addptr(tmp, buffer);
- __ movptr(Address(tmp, 0), card_addr);
- __ jmp(enqueued);
-
- __ bind(runtime);
- __ push_call_clobbered_registers();
-
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);
-
- __ pop_call_clobbered_registers();
-
- __ bind(enqueued);
- __ pop_ppx(rdx);
-
- __ bind(done);
- __ pop_ppx(rcx);
- __ pop_ppx(rax);
-
- __ epilogue();
-}
-
#undef __
#endif // COMPILER1
diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp
index 774e87b916c..4b2de41de69 100644
--- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,10 +31,8 @@
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
-class G1PostBarrierStub;
class G1BarrierStubC2;
class G1PreBarrierStubC2;
-class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -51,22 +49,28 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
void g1_write_barrier_post(MacroAssembler* masm,
Register store_addr,
Register new_val,
- Register tmp,
- Register tmp2);
+ Register tmp);
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2, Register tmp3);
public:
- void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
- void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
-
- void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
- void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
-
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1);
+#ifdef COMPILER1
+ void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
+
+ void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
+
+ void g1_write_barrier_post_c1(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2);
+#endif
+
#ifdef COMPILER2
void g1_write_barrier_pre_c2(MacroAssembler* masm,
Register obj,
@@ -79,10 +83,7 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
Register store_addr,
Register new_val,
Register tmp,
- Register tmp2,
- G1PostBarrierStubC2* c2_stub);
- void generate_c2_post_barrier_stub(MacroAssembler* masm,
- G1PostBarrierStubC2* stub) const;
+ bool new_val_may_be_null);
#endif // COMPILER2
};
diff --git a/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad
index 819cd97696c..94607cd6796 100644
--- a/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad
+++ b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2024, 2025, 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,15 +59,14 @@ static void write_barrier_post(MacroAssembler* masm,
const MachNode* node,
Register store_addr,
Register new_val,
- Register tmp1,
- Register tmp2) {
- if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ Register tmp1) {
+ if (!G1BarrierStubC2::needs_post_barrier(node)) {
return;
}
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
- G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
- g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, stub);
+ bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, new_val_may_be_null);
}
%}
@@ -95,8 +94,7 @@ instruct g1StoreP(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rRegP tmp3,
write_barrier_post(masm, this,
$tmp1$$Register /* store_addr */,
$src$$Register /* new_val */,
- $tmp3$$Register /* tmp1 */,
- $tmp2$$Register /* tmp2 */);
+ $tmp3$$Register /* tmp1 */);
%}
ins_pipe(ialu_mem_reg);
%}
@@ -127,8 +125,7 @@ instruct g1StoreN(memory mem, rRegN src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFl
write_barrier_post(masm, this,
$tmp1$$Register /* store_addr */,
$tmp2$$Register /* new_val */,
- $tmp3$$Register /* tmp1 */,
- $tmp2$$Register /* tmp2 */);
+ $tmp3$$Register /* tmp1 */);
%}
ins_pipe(ialu_mem_reg);
%}
@@ -158,8 +155,7 @@ instruct g1EncodePAndStoreN(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rR
write_barrier_post(masm, this,
$tmp1$$Register /* store_addr */,
$src$$Register /* new_val */,
- $tmp3$$Register /* tmp1 */,
- $tmp2$$Register /* tmp2 */);
+ $tmp3$$Register /* tmp1 */);
%}
ins_pipe(ialu_mem_reg);
%}
@@ -187,8 +183,7 @@ instruct g1CompareAndExchangeP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp
write_barrier_post(masm, this,
$mem$$Register /* store_addr */,
$tmp1$$Register /* new_val */,
- $tmp2$$Register /* tmp1 */,
- $tmp3$$Register /* tmp2 */);
+ $tmp2$$Register /* tmp1 */);
%}
ins_pipe(pipe_cmpxchg);
%}
@@ -214,8 +209,7 @@ instruct g1CompareAndExchangeN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp
write_barrier_post(masm, this,
$mem$$Register /* store_addr */,
$tmp1$$Register /* new_val */,
- $tmp2$$Register /* tmp1 */,
- $tmp3$$Register /* tmp2 */);
+ $tmp2$$Register /* tmp1 */);
%}
ins_pipe(pipe_cmpxchg);
%}
@@ -246,8 +240,7 @@ instruct g1CompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp1, rR
write_barrier_post(masm, this,
$mem$$Register /* store_addr */,
$tmp1$$Register /* new_val */,
- $tmp2$$Register /* tmp1 */,
- $tmp3$$Register /* tmp2 */);
+ $tmp2$$Register /* tmp1 */);
%}
ins_pipe(pipe_cmpxchg);
%}
@@ -279,8 +272,7 @@ instruct g1CompareAndSwapN(rRegI res, indirect mem, rRegN newval, rRegP tmp1, rR
write_barrier_post(masm, this,
$mem$$Register /* store_addr */,
$tmp1$$Register /* new_val */,
- $tmp2$$Register /* tmp1 */,
- $tmp3$$Register /* tmp2 */);
+ $tmp2$$Register /* tmp1 */);
%}
ins_pipe(pipe_cmpxchg);
%}
@@ -303,8 +295,7 @@ instruct g1GetAndSetP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP
write_barrier_post(masm, this,
$mem$$Register /* store_addr */,
$tmp1$$Register /* new_val */,
- $tmp2$$Register /* tmp1 */,
- $tmp3$$Register /* tmp2 */);
+ $tmp2$$Register /* tmp1 */);
%}
ins_pipe(pipe_cmpxchg);
%}
@@ -328,8 +319,7 @@ instruct g1GetAndSetN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP
write_barrier_post(masm, this,
$mem$$Register /* store_addr */,
$tmp1$$Register /* new_val */,
- $tmp2$$Register /* tmp1 */,
- $tmp3$$Register /* tmp2 */);
+ $tmp2$$Register /* tmp1 */);
%}
ins_pipe(pipe_cmpxchg);
%}
diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp
index 925444792ca..09c5d93dbb3 100644
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp
@@ -471,33 +471,33 @@ void SaveLiveRegisters::initialize(BarrierStubC2* stub) {
// Create mask of caller saved registers that need to
// be saved/restored if live
RegMask caller_saved;
- caller_saved.Insert(OptoReg::as_OptoReg(rax->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(rcx->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(rdx->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(rsi->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(rdi->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r8->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r9->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r10->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r11->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(rax->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(rcx->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(rdx->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(rsi->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(rdi->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r8->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r9->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r10->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r11->as_VMReg()));
if (UseAPX) {
- caller_saved.Insert(OptoReg::as_OptoReg(r16->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r17->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r18->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r19->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r20->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r21->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r22->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r23->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r24->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r25->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r26->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r27->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r28->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r29->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r30->as_VMReg()));
- caller_saved.Insert(OptoReg::as_OptoReg(r31->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r16->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r17->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r18->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r19->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r20->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r21->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r22->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r23->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r24->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r25->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r26->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r27->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r28->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r29->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r30->as_VMReg()));
+ caller_saved.insert(OptoReg::as_OptoReg(r31->as_VMReg()));
}
int gp_spill_size = 0;
@@ -511,7 +511,7 @@ void SaveLiveRegisters::initialize(BarrierStubC2* stub) {
const VMReg vm_reg = OptoReg::as_VMReg(opto_reg);
if (vm_reg->is_Register()) {
- if (caller_saved.Member(opto_reg)) {
+ if (caller_saved.member(opto_reg)) {
_gp_registers.append(vm_reg->as_Register());
gp_spill_size += 8;
}
diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp
index 0b19180ea06..ae93cca8c19 100644
--- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp
@@ -1410,11 +1410,9 @@ void ZBarrierSetAssembler::patch_barriers() {
}
}
-
#undef __
#define __ masm->
-
void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
// 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.
diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
index 3c1474ae861..abbeb66a1ca 100644
--- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
+++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2025, 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
@@ -34,8 +34,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
#define SUPPORTS_NATIVE_CX8
-#define SUPPORT_MONITOR_COUNT
-
#define CPU_MULTI_COPY_ATOMIC
// The expected size in bytes of a cache line.
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
index 0b41d594194..4f19b30b832 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
@@ -2431,14 +2431,6 @@ void MacroAssembler::pop_cont_fastpath() {
bind(L_done);
}
-void MacroAssembler::inc_held_monitor_count() {
- incrementq(Address(r15_thread, JavaThread::held_monitor_count_offset()));
-}
-
-void MacroAssembler::dec_held_monitor_count() {
- decrementq(Address(r15_thread, JavaThread::held_monitor_count_offset()));
-}
-
#ifdef ASSERT
void MacroAssembler::stop_if_in_cont(Register cont, const char* name) {
Label no_cont;
@@ -2897,7 +2889,8 @@ void MacroAssembler::vbroadcastss(XMMRegister dst, AddressLiteral src, int vecto
// vblendvps(XMMRegister dst, XMMRegister nds, XMMRegister src, XMMRegister mask, int vector_len, bool compute_mask = true, XMMRegister scratch = xnoreg)
void MacroAssembler::vblendvps(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister mask, int vector_len, bool compute_mask, XMMRegister scratch) {
// WARN: Allow dst == (src1|src2), mask == scratch
- bool blend_emulation = EnableX86ECoreOpts && UseAVX > 1;
+ bool blend_emulation = EnableX86ECoreOpts && UseAVX > 1 &&
+ !(VM_Version::is_intel_darkmont() && (dst == src1)); // partially fixed on Darkmont
bool scratch_available = scratch != xnoreg && scratch != src1 && scratch != src2 && scratch != dst;
bool dst_available = dst != mask && (dst != src1 || dst != src2);
if (blend_emulation && scratch_available && dst_available) {
@@ -2921,7 +2914,8 @@ void MacroAssembler::vblendvps(XMMRegister dst, XMMRegister src1, XMMRegister sr
// vblendvpd(XMMRegister dst, XMMRegister nds, XMMRegister src, XMMRegister mask, int vector_len, bool compute_mask = true, XMMRegister scratch = xnoreg)
void MacroAssembler::vblendvpd(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister mask, int vector_len, bool compute_mask, XMMRegister scratch) {
// WARN: Allow dst == (src1|src2), mask == scratch
- bool blend_emulation = EnableX86ECoreOpts && UseAVX > 1;
+ bool blend_emulation = EnableX86ECoreOpts && UseAVX > 1 &&
+ !(VM_Version::is_intel_darkmont() && (dst == src1)); // partially fixed on Darkmont
bool scratch_available = scratch != xnoreg && scratch != src1 && scratch != src2 && scratch != dst && (!compute_mask || scratch != mask);
bool dst_available = dst != mask && (dst != src1 || dst != src2);
if (blend_emulation && scratch_available && dst_available) {
@@ -5845,7 +5839,7 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned,
orl(value, rtmp);
}
- cmpptr(count, 2<sleep(FT_SLEEP_MILLISECS);
-
- end = os::elapsed_counter();
- OrderAccess::fence();
- fend = os::rdtsc();
-
- time_base += end - start;
- time_fast += fend - fstart;
-
- // basis for calculating the os tick start
- // to fast time tick start offset
- time_base_elapsed += end;
- time_fast_elapsed += (fend - _epoch);
- }
-
- time_base /= loopcount;
- time_fast /= loopcount;
- time_base_elapsed /= loopcount;
- time_fast_elapsed /= loopcount;
-}
-
-static jlong initialize_frequency() {
- assert(0 == tsc_frequency, "invariant");
+jlong Rdtsc::initialize_frequency() {
+ assert(0 == _tsc_frequency, "invariant");
assert(0 == _epoch, "invariant");
const jlong initial_counter = set_epoch();
if (initial_counter == 0) {
@@ -102,29 +59,6 @@ static jlong initialize_frequency() {
// for invariant tsc platforms, take the maximum qualified cpu frequency
tsc_freq = (double)VM_Version::maximum_qualified_cpu_frequency();
os_to_tsc_conv_factor = tsc_freq / os_freq;
- } else {
- // use measurements to estimate
- // a conversion factor and the tsc frequency
-
- volatile jlong time_base = 0;
- volatile jlong time_fast = 0;
- volatile jlong time_base_elapsed = 0;
- volatile jlong time_fast_elapsed = 0;
-
- // do measurements to get base data
- // on os timer and fast ticks tsc time relation.
- do_time_measurements(time_base, time_fast, time_base_elapsed, time_fast_elapsed);
-
- // if invalid measurements, cannot proceed
- if (time_fast == 0 || time_base == 0) {
- return 0;
- }
-
- os_to_tsc_conv_factor = (double)time_fast / (double)time_base;
- if (os_to_tsc_conv_factor > 1) {
- // estimate on tsc counter frequency
- tsc_freq = os_to_tsc_conv_factor * os_freq;
- }
}
if ((tsc_freq < 0) || (tsc_freq > 0 && tsc_freq <= os_freq) || (os_to_tsc_conv_factor <= 1)) {
@@ -136,47 +70,52 @@ static jlong initialize_frequency() {
return (jlong)tsc_freq;
}
-static bool initialize_elapsed_counter() {
- tsc_frequency = initialize_frequency();
- return tsc_frequency != 0 && _epoch != 0;
+bool Rdtsc::initialize_elapsed_counter() {
+ _tsc_frequency = initialize_frequency();
+ return _tsc_frequency != 0 && _epoch != 0;
}
static bool ergonomics() {
- const bool invtsc_support = Rdtsc::is_supported();
- if (FLAG_IS_DEFAULT(UseFastUnorderedTimeStamps) && invtsc_support) {
- FLAG_SET_ERGO(UseFastUnorderedTimeStamps, true);
- }
+ if (Rdtsc::is_supported()) {
+ // Use rdtsc when it is supported by default
+ FLAG_SET_ERGO_IF_DEFAULT(UseFastUnorderedTimeStamps, true);
+ } else if (UseFastUnorderedTimeStamps) {
+ assert(!FLAG_IS_DEFAULT(UseFastUnorderedTimeStamps), "Unexpected default value");
- bool ft_enabled = UseFastUnorderedTimeStamps && invtsc_support;
-
- if (!ft_enabled) {
- if (UseFastUnorderedTimeStamps && VM_Version::supports_tsc()) {
- warning("\nThe hardware does not support invariant tsc (INVTSC) register and/or cannot guarantee tsc synchronization between sockets at startup.\n"\
- "Values returned via rdtsc() are not guaranteed to be accurate, esp. when comparing values from cross sockets reads. Enabling UseFastUnorderedTimeStamps on non-invariant tsc hardware should be considered experimental.\n");
- ft_enabled = true;
- }
- }
-
- if (!ft_enabled) {
- // Warn if unable to support command-line flag
- if (UseFastUnorderedTimeStamps && !VM_Version::supports_tsc()) {
+ if (VM_Version::supports_tsc()) {
+ warning("Ignoring UseFastUnorderedTimeStamps, the hardware does not support invariant tsc (INVTSC) register and/or cannot guarantee tsc synchronization between sockets at startup.\n"
+ "Values returned via rdtsc() are not guaranteed to be accurate, esp. when comparing values from cross sockets reads.");
+ } else {
warning("Ignoring UseFastUnorderedTimeStamps, hardware does not support normal tsc");
}
+
+ // We do not support non invariant rdtsc
+ FLAG_SET_ERGO(UseFastUnorderedTimeStamps, false);
}
- return ft_enabled;
+ return UseFastUnorderedTimeStamps;
+}
+
+bool Rdtsc::initialize() {
+ precond(AtomicAccess::xchg(&_initialized, 1) == 0);
+ assert(0 == _tsc_frequency, "invariant");
+ assert(0 == _epoch, "invariant");
+
+ if (!ergonomics()) {
+ // We decided to ergonomically not support rdtsc.
+ return false;
+ }
+
+ // Try to initialize the elapsed counter
+ return initialize_elapsed_counter();
}
bool Rdtsc::is_supported() {
return VM_Version::supports_tscinv_ext();
}
-bool Rdtsc::is_elapsed_counter_enabled() {
- return rdtsc_elapsed_counter_enabled;
-}
-
jlong Rdtsc::frequency() {
- return tsc_frequency;
+ return _tsc_frequency;
}
jlong Rdtsc::elapsed_counter() {
@@ -191,19 +130,7 @@ jlong Rdtsc::raw() {
return os::rdtsc();
}
-bool Rdtsc::initialize() {
- static bool initialized = false;
- if (!initialized) {
- assert(!rdtsc_elapsed_counter_enabled, "invariant");
- VM_Version::initialize_tsc();
- assert(0 == tsc_frequency, "invariant");
- assert(0 == _epoch, "invariant");
- bool result = initialize_elapsed_counter(); // init hw
- if (result) {
- result = ergonomics(); // check logical state
- }
- rdtsc_elapsed_counter_enabled = result;
- initialized = true;
- }
- return rdtsc_elapsed_counter_enabled;
+bool Rdtsc::enabled() {
+ static bool enabled = initialize();
+ return enabled;
}
diff --git a/src/hotspot/cpu/x86/rdtsc_x86.hpp b/src/hotspot/cpu/x86/rdtsc_x86.hpp
index d9e77a0ae6b..a6519c439d3 100644
--- a/src/hotspot/cpu/x86/rdtsc_x86.hpp
+++ b/src/hotspot/cpu/x86/rdtsc_x86.hpp
@@ -38,14 +38,24 @@
// INVTSC is a minimal requirement for auto-enablement.
class Rdtsc : AllStatic {
+ private:
+ DEBUG_ONLY(static volatile int _initialized;)
+ static jlong _epoch;
+ static jlong _tsc_frequency;
+
+ static jlong set_epoch();
+
+ static jlong initialize_frequency();
+ static bool initialize_elapsed_counter();
+ static bool initialize();
+
public:
static jlong elapsed_counter(); // provides quick time stamps
static jlong frequency(); // tsc register
static bool is_supported(); // InvariantTSC
static jlong raw(); // direct rdtsc() access
- static bool is_elapsed_counter_enabled(); // turn off with -XX:-UseFastUnorderedTimeStamps
static jlong epoch();
- static bool initialize();
+ static bool enabled();
};
#endif // CPU_X86_RDTSC_X86_HPP
diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
index d60f535fefc..e702b587edd 100644
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
@@ -1007,8 +1007,8 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs,
- AdapterHandlerEntry* handler) {
- address i2c_entry = __ pc();
+ address entry_address[AdapterBlob::ENTRY_COUNT]) {
+ entry_address[AdapterBlob::I2C] = __ pc();
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
@@ -1021,7 +1021,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
// On exit from the interpreter, the interpreter will restore our SP (lest the
// compiled code, which relies solely on SP and not RBP, get sick).
- address c2i_unverified_entry = __ pc();
+ entry_address[AdapterBlob::C2I_Unverified] = __ pc();
Label skip_fixup;
Register data = rax;
@@ -1039,10 +1039,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
}
- address c2i_entry = __ pc();
+ entry_address[AdapterBlob::C2I] = __ pc();
// Class initialization barrier for static methods
- address c2i_no_clinit_check_entry = nullptr;
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
if (VM_Version::supports_fast_class_init_checks()) {
Label L_skip_barrier;
Register method = rbx;
@@ -1061,15 +1061,13 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
__ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path
__ bind(L_skip_barrier);
- c2i_no_clinit_check_entry = __ pc();
+ entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
}
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->c2i_entry_barrier(masm);
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
-
- handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
return;
}
@@ -1354,11 +1352,8 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj,
__ movptr(rax, Address(r15_thread, JavaThread::cont_fastpath_offset()));
__ movptr(Address(rsp, ContinuationEntry::parent_cont_fastpath_offset()), rax);
- __ movq(rax, Address(r15_thread, JavaThread::held_monitor_count_offset()));
- __ movq(Address(rsp, ContinuationEntry::parent_held_monitor_count_offset()), rax);
__ movptr(Address(r15_thread, JavaThread::cont_fastpath_offset()), 0);
- __ movq(Address(r15_thread, JavaThread::held_monitor_count_offset()), 0);
}
//---------------------------- continuation_enter_cleanup ---------------------------
@@ -1382,49 +1377,6 @@ static void continuation_enter_cleanup(MacroAssembler* masm) {
#endif
__ movptr(rbx, Address(rsp, ContinuationEntry::parent_cont_fastpath_offset()));
__ movptr(Address(r15_thread, JavaThread::cont_fastpath_offset()), rbx);
-
- if (CheckJNICalls) {
- // Check if this is a virtual thread continuation
- Label L_skip_vthread_code;
- __ cmpl(Address(rsp, ContinuationEntry::flags_offset()), 0);
- __ jcc(Assembler::equal, L_skip_vthread_code);
-
- // If the held monitor count is > 0 and this vthread is terminating then
- // it failed to release a JNI monitor. So we issue the same log message
- // that JavaThread::exit does.
- __ cmpptr(Address(r15_thread, JavaThread::jni_monitor_count_offset()), 0);
- __ jcc(Assembler::equal, L_skip_vthread_code);
-
- // rax may hold an exception oop, save it before the call
- __ push(rax);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held));
- __ pop(rax);
-
- // For vthreads we have to explicitly zero the JNI monitor count of the carrier
- // on termination. The held count is implicitly zeroed below when we restore from
- // the parent held count (which has to be zero).
- __ movq(Address(r15_thread, JavaThread::jni_monitor_count_offset()), 0);
-
- __ bind(L_skip_vthread_code);
- }
-#ifdef ASSERT
- else {
- // Check if this is a virtual thread continuation
- Label L_skip_vthread_code;
- __ cmpl(Address(rsp, ContinuationEntry::flags_offset()), 0);
- __ jcc(Assembler::equal, L_skip_vthread_code);
-
- // See comment just above. If not checking JNI calls the JNI count is only
- // needed for assertion checking.
- __ movq(Address(r15_thread, JavaThread::jni_monitor_count_offset()), 0);
-
- __ bind(L_skip_vthread_code);
- }
-#endif
-
- __ movq(rbx, Address(rsp, ContinuationEntry::parent_held_monitor_count_offset()));
- __ movq(Address(r15_thread, JavaThread::held_monitor_count_offset()), rbx);
-
__ movptr(rbx, Address(rsp, ContinuationEntry::parent_offset()));
__ movptr(Address(r15_thread, JavaThread::cont_entry_offset()), rbx);
__ addptr(rsp, checked_cast(ContinuationEntry::size()));
diff --git a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp
index 30a93fa4917..3e0e1d5bf07 100644
--- a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp
+++ b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp
@@ -41,10 +41,6 @@
do_stub(initial, verify_mxcsr) \
do_arch_entry(x86, initial, verify_mxcsr, verify_mxcsr_entry, \
verify_mxcsr_entry) \
- do_stub(initial, get_previous_sp) \
- do_arch_entry(x86, initial, get_previous_sp, \
- get_previous_sp_entry, \
- get_previous_sp_entry) \
do_stub(initial, f2i_fixup) \
do_arch_entry(x86, initial, f2i_fixup, f2i_fixup, f2i_fixup) \
do_stub(initial, f2l_fixup) \
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
index 6eb641daaf9..efb0411aa39 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
@@ -541,22 +541,6 @@ address StubGenerator::generate_orderaccess_fence() {
}
-// Support for intptr_t get_previous_sp()
-//
-// This routine is used to find the previous stack pointer for the
-// caller.
-address StubGenerator::generate_get_previous_sp() {
- StubId stub_id = StubId::stubgen_get_previous_sp_id;
- StubCodeMark mark(this, stub_id);
- address start = __ pc();
-
- __ movptr(rax, rsp);
- __ addptr(rax, 8); // return address is at the top of the stack.
- __ ret(0);
-
- return start;
-}
-
//----------------------------------------------------------------------------------------------------
// Support for void verify_mxcsr()
//
@@ -4083,8 +4067,6 @@ void StubGenerator::generate_initial_stubs() {
StubRoutines::_catch_exception_entry = generate_catch_exception();
// platform dependent
- StubRoutines::x86::_get_previous_sp_entry = generate_get_previous_sp();
-
StubRoutines::x86::_verify_mxcsr_entry = generate_verify_mxcsr();
StubRoutines::x86::_f2i_fixup = generate_f2i_fixup();
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp
index 44d13bbbf31..36315535d16 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp
@@ -68,12 +68,6 @@ class StubGenerator: public StubCodeGenerator {
// Support for intptr_t OrderAccess::fence()
address generate_orderaccess_fence();
- // Support for intptr_t get_previous_sp()
- //
- // This routine is used to find the previous stack pointer for the
- // caller.
- address generate_get_previous_sp();
-
//----------------------------------------------------------------------------------------------------
// Support for void verify_mxcsr()
//
@@ -393,6 +387,8 @@ class StubGenerator: public StubCodeGenerator {
XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, XMMRegister xmm8);
void ghash_last_8_avx2(Register subkeyHtbl);
+ void check_key_offset(Register key, int offset, int load_size);
+
// Load key and shuffle operation
void ev_load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask);
void ev_load_key(XMMRegister xmmdst, Register key, int offset, Register rscratch);
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp
index 6f698b954ad..f0726ded7e5 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp
@@ -1759,25 +1759,43 @@ void StubGenerator::roundDeclast(XMMRegister xmm_reg) {
__ vaesdeclast(xmm8, xmm8, xmm_reg, Assembler::AVX_512bit);
}
+// Check incoming byte offset against the int[] len. key is the pointer to the int[0].
+// This check happens often, so it is important for it to be very compact.
+void StubGenerator::check_key_offset(Register key, int offset, int load_size) {
+#ifdef ASSERT
+ Address key_length(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT));
+ assert((offset + load_size) % 4 == 0, "Alignment is good: %d + %d", offset, load_size);
+ int end_offset = (offset + load_size) / 4;
+ Label L_good;
+ __ cmpl(key_length, end_offset);
+ __ jccb(Assembler::greaterEqual, L_good);
+ __ hlt();
+ __ bind(L_good);
+#endif
+}
// Utility routine for loading a 128-bit key word in little endian format
void StubGenerator::load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask) {
+ check_key_offset(key, offset, 16);
__ movdqu(xmmdst, Address(key, offset));
__ pshufb(xmmdst, xmm_shuf_mask);
}
void StubGenerator::load_key(XMMRegister xmmdst, Register key, int offset, Register rscratch) {
+ check_key_offset(key, offset, 16);
__ movdqu(xmmdst, Address(key, offset));
__ pshufb(xmmdst, ExternalAddress(key_shuffle_mask_addr()), rscratch);
}
void StubGenerator::ev_load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask) {
+ check_key_offset(key, offset, 16);
__ movdqu(xmmdst, Address(key, offset));
__ pshufb(xmmdst, xmm_shuf_mask);
__ evshufi64x2(xmmdst, xmmdst, xmmdst, 0x0, Assembler::AVX_512bit);
}
void StubGenerator::ev_load_key(XMMRegister xmmdst, Register key, int offset, Register rscratch) {
+ check_key_offset(key, offset, 16);
__ movdqu(xmmdst, Address(key, offset));
__ pshufb(xmmdst, ExternalAddress(key_shuffle_mask_addr()), rscratch);
__ evshufi64x2(xmmdst, xmmdst, xmmdst, 0x0, Assembler::AVX_512bit);
@@ -3205,12 +3223,12 @@ void StubGenerator::ghash16_encrypt_parallel16_avx512(Register in, Register out,
//AES round 9
roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15);
- ev_load_key(AESKEY2, key, 11 * 16, rbx);
//AES rounds up to 11 (AES192) or 13 (AES256)
//AES128 is done
__ cmpl(NROUNDS, 52);
__ jcc(Assembler::less, last_aes_rnd);
__ bind(aes_192);
+ ev_load_key(AESKEY2, key, 11 * 16, rbx);
roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15);
ev_load_key(AESKEY1, key, 12 * 16, rbx);
roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15);
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp
index 743457f87af..d53fafafdb4 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp
@@ -76,50 +76,95 @@ static uint& get_profile_ctr(int shift) {
#endif // !PRODUCT
void StubGenerator::generate_arraycopy_stubs() {
- address entry;
- address entry_jbyte_arraycopy;
- address entry_jshort_arraycopy;
- address entry_jint_arraycopy;
- address entry_oop_arraycopy;
- address entry_jlong_arraycopy;
- address entry_checkcast_arraycopy;
+ // Some copy stubs publish a normal entry and then a 2nd 'fallback'
+ // entry immediately following their stack push. This can be used
+ // as a post-push branch target for compatible stubs when they
+ // identify a special case that can be handled by the fallback
+ // stub e.g a disjoint copy stub may be use as a special case
+ // fallback for its compatible conjoint copy stub.
+ //
+ // A no push entry is always returned in the following local and
+ // then published by assigning to the appropriate entry field in
+ // class StubRoutines. The entry value is then passed to the
+ // generator for the compatible stub. That means the entry must be
+ // listed when saving to/restoring from the AOT cache, ensuring
+ // that the inter-stub jumps are noted at AOT-cache save and
+ // relocated at AOT cache load.
+ address nopush_entry;
- StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(&entry);
- StubRoutines::_jbyte_arraycopy = generate_conjoint_byte_copy(entry, &entry_jbyte_arraycopy);
+ StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(&nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jbyte_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jbyte_arraycopy = generate_conjoint_byte_copy(StubRoutines::_jbyte_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jbyte_arraycopy_nopush = nopush_entry;
- StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_short_copy(&entry);
- StubRoutines::_jshort_arraycopy = generate_conjoint_short_copy(entry, &entry_jshort_arraycopy);
+ StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_short_copy(&nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jshort_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jshort_arraycopy = generate_conjoint_short_copy(StubRoutines::_jshort_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jshort_arraycopy_nopush = nopush_entry;
- StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_int_oop_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &entry);
- StubRoutines::_jint_arraycopy = generate_conjoint_int_oop_copy(StubId::stubgen_jint_arraycopy_id, entry, &entry_jint_arraycopy);
+ StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_int_oop_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jint_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jint_arraycopy = generate_conjoint_int_oop_copy(StubId::stubgen_jint_arraycopy_id, StubRoutines::_jint_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jint_arraycopy_nopush = nopush_entry;
+
+ StubRoutines::_jlong_disjoint_arraycopy = generate_disjoint_long_oop_copy(StubId::stubgen_jlong_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_jlong_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_jlong_arraycopy = generate_conjoint_long_oop_copy(StubId::stubgen_jlong_arraycopy_id, StubRoutines::_jlong_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_jlong_arraycopy_nopush = nopush_entry;
- StubRoutines::_jlong_disjoint_arraycopy = generate_disjoint_long_oop_copy(StubId::stubgen_jlong_disjoint_arraycopy_id, &entry);
- StubRoutines::_jlong_arraycopy = generate_conjoint_long_oop_copy(StubId::stubgen_jlong_arraycopy_id, entry, &entry_jlong_arraycopy);
if (UseCompressedOops) {
- StubRoutines::_oop_disjoint_arraycopy = generate_disjoint_int_oop_copy(StubId::stubgen_oop_disjoint_arraycopy_id, &entry);
- StubRoutines::_oop_arraycopy = generate_conjoint_int_oop_copy(StubId::stubgen_oop_arraycopy_id, entry, &entry_oop_arraycopy);
- StubRoutines::_oop_disjoint_arraycopy_uninit = generate_disjoint_int_oop_copy(StubId::stubgen_oop_disjoint_arraycopy_uninit_id, &entry);
- StubRoutines::_oop_arraycopy_uninit = generate_conjoint_int_oop_copy(StubId::stubgen_oop_arraycopy_uninit_id, entry, nullptr);
+ StubRoutines::_oop_disjoint_arraycopy = generate_disjoint_int_oop_copy(StubId::stubgen_oop_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_oop_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_oop_arraycopy = generate_conjoint_int_oop_copy(StubId::stubgen_oop_arraycopy_id, StubRoutines::_oop_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_oop_arraycopy_nopush = nopush_entry;
+ StubRoutines::_oop_disjoint_arraycopy_uninit = generate_disjoint_int_oop_copy(StubId::stubgen_oop_disjoint_arraycopy_uninit_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_oop_disjoint_arraycopy_uninit_nopush = nopush_entry;
+ // note that we don't need a returned nopush entry because the
+ // generic/unsafe copy does not cater for uninit arrays.
+ StubRoutines::_oop_arraycopy_uninit = generate_conjoint_int_oop_copy(StubId::stubgen_oop_arraycopy_uninit_id, StubRoutines::_oop_disjoint_arraycopy_uninit_nopush, nullptr);
} else {
- StubRoutines::_oop_disjoint_arraycopy = generate_disjoint_long_oop_copy(StubId::stubgen_oop_disjoint_arraycopy_id, &entry);
- StubRoutines::_oop_arraycopy = generate_conjoint_long_oop_copy(StubId::stubgen_oop_arraycopy_id, entry, &entry_oop_arraycopy);
- StubRoutines::_oop_disjoint_arraycopy_uninit = generate_disjoint_long_oop_copy(StubId::stubgen_oop_disjoint_arraycopy_uninit_id, &entry);
- StubRoutines::_oop_arraycopy_uninit = generate_conjoint_long_oop_copy(StubId::stubgen_oop_arraycopy_uninit_id, entry, nullptr);
+ StubRoutines::_oop_disjoint_arraycopy = generate_disjoint_long_oop_copy(StubId::stubgen_oop_disjoint_arraycopy_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_oop_disjoint_arraycopy_nopush = nopush_entry;
+ StubRoutines::_oop_arraycopy = generate_conjoint_long_oop_copy(StubId::stubgen_oop_arraycopy_id, StubRoutines::_oop_disjoint_arraycopy_nopush, &nopush_entry);
+ // conjoint nopush entry is needed by generic/unsafe copy
+ StubRoutines::_oop_arraycopy_nopush = nopush_entry;
+ StubRoutines::_oop_disjoint_arraycopy_uninit = generate_disjoint_long_oop_copy(StubId::stubgen_oop_disjoint_arraycopy_uninit_id, &nopush_entry);
+ // disjoint nopush entry is needed by conjoint copy
+ StubRoutines::_oop_disjoint_arraycopy_uninit_nopush = nopush_entry;
+ // note that we don't need a returned nopush entry because the
+ // generic/unsafe copy does not cater for uninit arrays.
+ StubRoutines::_oop_arraycopy_uninit = generate_conjoint_long_oop_copy(StubId::stubgen_oop_arraycopy_uninit_id, StubRoutines::_oop_disjoint_arraycopy_uninit_nopush, nullptr);
}
- StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &entry_checkcast_arraycopy);
+ StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &nopush_entry);
+ // checkcast nopush entry is needed by generic copy
+ StubRoutines::_checkcast_arraycopy_nopush = nopush_entry;
+ // note that we don't need a returned nopush entry because the
+ // generic copy does not cater for uninit arrays.
StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_uninit_id, nullptr);
- StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(entry_jbyte_arraycopy,
- entry_jshort_arraycopy,
- entry_jint_arraycopy,
- entry_jlong_arraycopy);
- StubRoutines::_generic_arraycopy = generate_generic_copy(entry_jbyte_arraycopy,
- entry_jshort_arraycopy,
- entry_jint_arraycopy,
- entry_oop_arraycopy,
- entry_jlong_arraycopy,
- entry_checkcast_arraycopy);
+ StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(StubRoutines::_jbyte_arraycopy_nopush,
+ StubRoutines::_jshort_arraycopy_nopush,
+ StubRoutines::_jint_arraycopy_nopush,
+ StubRoutines::_jlong_arraycopy_nopush);
+ StubRoutines::_generic_arraycopy = generate_generic_copy(StubRoutines::_jbyte_arraycopy_nopush,
+ StubRoutines::_jshort_arraycopy_nopush,
+ StubRoutines::_jint_arraycopy_nopush,
+ StubRoutines::_oop_arraycopy_nopush,
+ StubRoutines::_jlong_arraycopy_nopush,
+ StubRoutines::_checkcast_arraycopy_nopush);
StubRoutines::_jbyte_fill = generate_fill(StubId::stubgen_jbyte_fill_id);
StubRoutines::_jshort_fill = generate_fill(StubId::stubgen_jshort_fill_id);
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp
index c35f1b9f65e..73330dedc0f 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp
@@ -49,142 +49,142 @@
/* Represents 0x7FFFFFFFFFFFFFFF double precision in lower 64 bits*/
ATTRIBUTE_ALIGNED(16) static const juint _ABS_MASK[] =
{
- 4294967295, 2147483647, 0, 0
+ 0xFFFFFFFFUL, 0x7FFFFFFFUL, 0x00000000UL, 0x00000000UL
};
ATTRIBUTE_ALIGNED(4) static const juint _SIG_MASK[] =
{
- 0, 1032192
+ 0x00000000UL, 0x000FC000UL
};
ATTRIBUTE_ALIGNED(4) static const juint _EXP_MASK[] =
{
- 0, 3220176896
+ 0x00000000UL, 0xBFF00000UL
};
ATTRIBUTE_ALIGNED(4) static const juint _EXP_MSK2[] =
{
- 0, 3220193280
+ 0x00000000UL, 0xBFF04000UL
};
ATTRIBUTE_ALIGNED(4) static const juint _EXP_MSK3[] =
{
- 4294967295, 1048575
+ 0xFFFFFFFFUL, 0x000FFFFFUL
};
ATTRIBUTE_ALIGNED(4) static const juint _SCALE63[] =
{
- 0, 1138753536
+ 0x00000000UL, 0x43E00000UL
};
ATTRIBUTE_ALIGNED(4) static const juint _ZERON[] =
{
- 0, 2147483648
+ 0x00000000UL, 0x80000000UL
};
ATTRIBUTE_ALIGNED(4) static const juint _INF[] =
{
- 0, 2146435072
+ 0x00000000UL, 0x7FF00000UL
};
ATTRIBUTE_ALIGNED(4) static const juint _NEG_INF[] =
{
- 0, 4293918720
+ 0x00000000UL, 0xFFF00000UL
};
ATTRIBUTE_ALIGNED(16) static const juint _coeff_table[] =
{
- 1553778919, 3213899486, 3534952507, 3215266280, 1646371399,
- 3214412045, 477218588, 3216798151, 3582521621, 1066628362,
- 1007461464, 1068473053, 889629714, 1067378449, 1431655765,
- 1070945621
+ 0x5C9CC8E7UL, 0xBF9036DEUL, 0xD2B3183BUL, 0xBFA511E8UL, 0x6221A247UL,
+ 0xBF98090DUL, 0x1C71C71CUL, 0xBFBC71C7UL, 0xD588F115UL, 0x3F93750AUL,
+ 0x3C0CA458UL, 0x3FAF9ADDUL, 0x3506AC12UL, 0x3F9EE711UL, 0x55555555UL,
+ 0x3FD55555UL
};
ATTRIBUTE_ALIGNED(4) static const juint _rcp_table[] =
{
- 528611360, 3220144632, 2884679527, 3220082993, 1991868891, 3220024928,
- 2298714891, 3219970134, 58835168, 3219918343, 3035110223, 3219869313,
- 1617585086, 3219822831, 2500867033, 3219778702, 4241943008, 3219736752,
- 258732970, 3219696825, 404232216, 3219658776, 2172167368, 3219622476,
- 1544257904, 3219587808, 377579543, 3219554664, 1616385542, 3219522945,
- 813783277, 3219492562, 3940743189, 3219463431, 2689777499, 3219435478,
- 1700977147, 3219408632, 3169102082, 3219382828, 327235604, 3219358008,
- 1244336319, 3219334115, 1300311200, 3219311099, 3095471925, 3219288912,
- 2166487928, 3219267511, 2913108253, 3219246854, 293672978, 3219226904,
- 288737297, 3219207624, 1810275472, 3219188981, 174592167, 3219170945,
- 3539053052, 3219153485, 2164392968, 3219136576
+ 0x1F81F820UL, 0xBFEF81F8UL, 0xABF0B767UL, 0xBFEE9131UL, 0x76B981DBUL, 0xBFEDAE60UL,
+ 0x89039B0BUL, 0xBFECD856UL, 0x0381C0E0UL, 0xBFEC0E07UL, 0xB4E81B4FUL, 0xBFEB4E81UL,
+ 0x606A63BEUL, 0xBFEA98EFUL, 0x951033D9UL, 0xBFE9EC8EUL, 0xFCD6E9E0UL, 0xBFE948B0UL,
+ 0x0F6BF3AAUL, 0xBFE8ACB9UL, 0x18181818UL, 0xBFE81818UL, 0x8178A4C8UL, 0xBFE78A4CUL,
+ 0x5C0B8170UL, 0xBFE702E0UL, 0x16816817UL, 0xBFE68168UL, 0x60581606UL, 0xBFE60581UL,
+ 0x308158EDUL, 0xBFE58ED2UL, 0xEAE2F815UL, 0xBFE51D07UL, 0xA052BF5BUL, 0xBFE4AFD6UL,
+ 0x6562D9FBUL, 0xBFE446F8UL, 0xBCE4A902UL, 0xBFE3E22CUL, 0x13813814UL, 0xBFE38138UL,
+ 0x4A2B10BFUL, 0xBFE323E3UL, 0x4D812CA0UL, 0xBFE2C9FBUL, 0xB8812735UL, 0xBFE27350UL,
+ 0x8121FB78UL, 0xBFE21FB7UL, 0xADA2811DUL, 0xBFE1CF06UL, 0x11811812UL, 0xBFE18118UL,
+ 0x1135C811UL, 0xBFE135C8UL, 0x6BE69C90UL, 0xBFE0ECF5UL, 0x0A6810A7UL, 0xBFE0A681UL,
+ 0xD2F1A9FCUL, 0xBFE0624DUL, 0x81020408UL, 0xBFE02040UL
};
ATTRIBUTE_ALIGNED(4) static const juint _cbrt_table[] =
{
- 572345495, 1072698681, 1998204467, 1072709382, 3861501553, 1072719872,
- 2268192434, 1072730162, 2981979308, 1072740260, 270859143, 1072750176,
- 2958651392, 1072759916, 313113243, 1072769490, 919449400, 1072778903,
- 2809328903, 1072788162, 2222981587, 1072797274, 2352530781, 1072806244,
- 594152517, 1072815078, 1555767199, 1072823780, 4282421314, 1072832355,
- 2355578597, 1072840809, 1162590619, 1072849145, 797864051, 1072857367,
- 431273680, 1072865479, 2669831148, 1072873484, 733477752, 1072881387,
- 4280220604, 1072889189, 801961634, 1072896896, 2915370760, 1072904508,
- 1159613482, 1072912030, 2689944798, 1072919463, 1248687822, 1072926811,
- 2967951030, 1072934075, 630170432, 1072941259, 3760898254, 1072948363,
- 0, 1072955392, 2370273294, 1072962345, 1261754802, 1072972640,
- 546334065, 1072986123, 1054893830, 1072999340, 1571187597, 1073012304,
- 1107975175, 1073025027, 3606909377, 1073037519, 1113616747, 1073049792,
- 4154744632, 1073061853, 3358931423, 1073073713, 4060702372, 1073085379,
- 747576176, 1073096860, 3023138255, 1073108161, 1419988548, 1073119291,
- 1914185305, 1073130255, 294389948, 1073141060, 3761802570, 1073151710,
- 978281566, 1073162213, 823148820, 1073172572, 2420954441, 1073182792,
- 3815449908, 1073192878, 2046058587, 1073202835, 1807524753, 1073212666,
- 2628681401, 1073222375, 3225667357, 1073231966, 1555307421, 1073241443,
- 3454043099, 1073250808, 1208137896, 1073260066, 3659916772, 1073269218,
- 1886261264, 1073278269, 3593647839, 1073287220, 3086012205, 1073296075,
- 2769796922, 1073304836, 888716057, 1073317807, 2201465623, 1073334794,
- 164369365, 1073351447, 3462666733, 1073367780, 2773905457, 1073383810,
- 1342879088, 1073399550, 2543933975, 1073415012, 1684477781, 1073430209,
- 3532178543, 1073445151, 1147747300, 1073459850, 1928031793, 1073474314,
- 2079717015, 1073488553, 4016765315, 1073502575, 3670431139, 1073516389,
- 3549227225, 1073530002, 11637607, 1073543422, 588220169, 1073556654,
- 2635407503, 1073569705, 2042029317, 1073582582, 1925128962, 1073595290,
- 4136375664, 1073607834, 759964600, 1073620221, 4257606771, 1073632453,
- 297278907, 1073644538, 3655053093, 1073656477, 2442253172, 1073668277,
- 1111876799, 1073679941, 3330973139, 1073691472, 3438879452, 1073702875,
- 3671565478, 1073714153, 1317849547, 1073725310, 1642364115, 1073736348
+ 0x221D4C97UL, 0x3FF01539UL, 0x771A2E33UL, 0x3FF03F06UL, 0xE629D671UL, 0x3FF06800UL,
+ 0x8731DEB2UL, 0x3FF09032UL, 0xB1BD64ACUL, 0x3FF0B7A4UL, 0x1024FB87UL, 0x3FF0DE60UL,
+ 0xB0597000UL, 0x3FF1046CUL, 0x12A9BA9BUL, 0x3FF129D2UL, 0x36CDAF38UL, 0x3FF14E97UL,
+ 0xA772F507UL, 0x3FF172C2UL, 0x848001D3UL, 0x3FF1965AUL, 0x8C38C55DUL, 0x3FF1B964UL,
+ 0x236A0C45UL, 0x3FF1DBE6UL, 0x5CBB1F9FUL, 0x3FF1FDE4UL, 0xFF409042UL, 0x3FF21F63UL,
+ 0x8C6746E5UL, 0x3FF24069UL, 0x454BB99BUL, 0x3FF260F9UL, 0x2F8E7073UL, 0x3FF28117UL,
+ 0x19B4B6D0UL, 0x3FF2A0C7UL, 0x9F2263ECUL, 0x3FF2C00CUL, 0x2BB7FB78UL, 0x3FF2DEEBUL,
+ 0xFF1EFBBCUL, 0x3FF2FD65UL, 0x2FCCF6A2UL, 0x3FF31B80UL, 0xADC50708UL, 0x3FF3393CUL,
+ 0x451E4C2AUL, 0x3FF3569EUL, 0xA0554CDEUL, 0x3FF373A7UL, 0x4A6D76CEUL, 0x3FF3905BUL,
+ 0xB0E756B6UL, 0x3FF3ACBBUL, 0x258FA340UL, 0x3FF3C8CBUL, 0xE02AC0CEUL, 0x3FF3E48BUL,
+ 0x00000000UL, 0x3FF40000UL, 0x8D47800EUL, 0x3FF41B29UL, 0x4B34D9B2UL, 0x3FF44360UL,
+ 0x20906571UL, 0x3FF4780BUL, 0x3EE06706UL, 0x3FF4ABACUL, 0x5DA66B8DUL, 0x3FF4DE50UL,
+ 0x420A5C07UL, 0x3FF51003UL, 0xD6FD11C1UL, 0x3FF540CFUL, 0x4260716BUL, 0x3FF570C0UL,
+ 0xF7A45F38UL, 0x3FF59FDDUL, 0xC83539DFUL, 0x3FF5CE31UL, 0xF20966A4UL, 0x3FF5FBC3UL,
+ 0x2C8F1B70UL, 0x3FF6289CUL, 0xB4316DCFUL, 0x3FF654C1UL, 0x54A34E44UL, 0x3FF6803BUL,
+ 0x72182659UL, 0x3FF6AB0FUL, 0x118C08BCUL, 0x3FF6D544UL, 0xE0388D4AUL, 0x3FF6FEDEUL,
+ 0x3A4F645EUL, 0x3FF727E5UL, 0x31104114UL, 0x3FF7505CUL, 0x904CD549UL, 0x3FF77848UL,
+ 0xE36B2534UL, 0x3FF79FAEUL, 0x79F4605BUL, 0x3FF7C693UL, 0x6BBCA391UL, 0x3FF7ECFAUL,
+ 0x9CAE7EB9UL, 0x3FF812E7UL, 0xC043C71DUL, 0x3FF8385EUL, 0x5CB41B9DUL, 0x3FF85D63UL,
+ 0xCDE083DBUL, 0x3FF881F8UL, 0x4802B8A8UL, 0x3FF8A622UL, 0xDA25E5E4UL, 0x3FF8C9E2UL,
+ 0x706E1010UL, 0x3FF8ED3DUL, 0xD632B6DFUL, 0x3FF91034UL, 0xB7F0CF2DUL, 0x3FF932CBUL,
+ 0xA517BF3AUL, 0x3FF95504UL, 0x34F8BB19UL, 0x3FF987AFUL, 0x8337B317UL, 0x3FF9CA0AUL,
+ 0x09CC13D5UL, 0x3FFA0B17UL, 0xCE6419EDUL, 0x3FFA4AE4UL, 0xA5567031UL, 0x3FFA8982UL,
+ 0x500AB570UL, 0x3FFAC6FEUL, 0x97A15A17UL, 0x3FFB0364UL, 0x64671755UL, 0x3FFB3EC1UL,
+ 0xD288C46FUL, 0x3FFB791FUL, 0x44693BE4UL, 0x3FFBB28AUL, 0x72EB6E31UL, 0x3FFBEB0AUL,
+ 0x7BF5F697UL, 0x3FFC22A9UL, 0xEF6AF983UL, 0x3FFC596FUL, 0xDAC655A3UL, 0x3FFC8F65UL,
+ 0xD38CE8D9UL, 0x3FFCC492UL, 0x00B19367UL, 0x3FFCF8FEUL, 0x230F8709UL, 0x3FFD2CAEUL,
+ 0x9D15208FUL, 0x3FFD5FA9UL, 0x79B6E505UL, 0x3FFD91F6UL, 0x72BF2302UL, 0x3FFDC39AUL,
+ 0xF68C1570UL, 0x3FFDF49AUL, 0x2D4C23B8UL, 0x3FFE24FDUL, 0xFDC5EC73UL, 0x3FFE54C5UL,
+ 0x11B81DBBUL, 0x3FFE83FAUL, 0xD9DBAF25UL, 0x3FFEB29DUL, 0x9191D374UL, 0x3FFEE0B5UL,
+ 0x4245E4BFUL, 0x3FFF0E45UL, 0xC68A9DD3UL, 0x3FFF3B50UL, 0xCCF922DCUL, 0x3FFF67DBUL,
+ 0xDAD7A4A6UL, 0x3FFF93E9UL, 0x4E8CC9CBUL, 0x3FFFBF7EUL, 0x61E47CD3UL, 0x3FFFEA9CUL
};
ATTRIBUTE_ALIGNED(4) static const juint _D_table[] =
{
- 4050900474, 1014427190, 1157977860, 1016444461, 1374568199, 1017271387,
- 2809163288, 1016882676, 3742377377, 1013168191, 3101606597, 1017541672,
- 65224358, 1017217597, 2691591250, 1017266643, 4020758549, 1017689313,
- 1316310992, 1018030788, 1031537856, 1014090882, 3261395239, 1016413641,
- 886424999, 1016313335, 3114776834, 1014195875, 1681120620, 1017825416,
- 1329600273, 1016625740, 465474623, 1017097119, 4251633980, 1017169077,
- 1986990133, 1017710645, 752958613, 1017159641, 2216216792, 1018020163,
- 4282860129, 1015924861, 1557627859, 1016039538, 3889219754, 1018086237,
- 3684996408, 1017353275, 723532103, 1017717141, 2951149676, 1012528470,
- 831890937, 1017830553, 1031212645, 1017387331, 2741737450, 1017604974,
- 2863311531, 1003776682, 4276736099, 1013153088, 4111778382, 1015673686,
- 1728065769, 1016413986, 2708718031, 1018078833, 1069335005, 1015291224,
- 700037144, 1016482032, 2904566452, 1017226861, 4074156649, 1017622651,
- 25019565, 1015245366, 3601952608, 1015771755, 3267129373, 1017904664,
- 503203103, 1014921629, 2122011730, 1018027866, 3927295461, 1014189456,
- 2790625147, 1016024251, 1330460186, 1016940346, 4033568463, 1015538390,
- 3695818227, 1017509621, 257573361, 1017208868, 3227697852, 1017337964,
- 234118548, 1017169577, 4009025803, 1017278524, 1948343394, 1017749310,
- 678398162, 1018144239, 3083864863, 1016669086, 2415453452, 1017890370,
- 175467344, 1017330033, 3197359580, 1010339928, 2071276951, 1015941358,
- 268372543, 1016737773, 938132959, 1017389108, 1816750559, 1017337448,
- 4119203749, 1017152174, 2578653878, 1013108497, 2470331096, 1014678606,
- 123855735, 1016553320, 1265650889, 1014782687, 3414398172, 1017182638,
- 1040773369, 1016158401, 3483628886, 1016886550, 4140499405, 1016191425,
- 3893477850, 1016964495, 3935319771, 1009634717, 2978982660, 1015027112,
- 2452709923, 1017990229, 3190365712, 1015835149, 4237588139, 1015832925,
- 2610678389, 1017962711, 2127316774, 1017405770, 824267502, 1017959463,
- 2165924042, 1017912225, 2774007076, 1013257418, 4123916326, 1017582284,
- 1976417958, 1016959909, 4092806412, 1017711279, 119251817, 1015363631,
- 3475418768, 1017675415, 1972580503, 1015470684, 815541017, 1017517969,
- 2429917451, 1017397776, 4062888482, 1016749897, 68284153, 1017925678,
- 2207779246, 1016320298, 1183466520, 1017408657, 143326427, 1017060403
+ 0xF173D5FAUL, 0x3C76EE36UL, 0x45055704UL, 0x3C95B62DUL, 0x51EE3F07UL, 0x3CA2545BUL,
+ 0xA7706E18UL, 0x3C9C65F4UL, 0xDF1025A1UL, 0x3C63B83FUL, 0xB8DEC2C5UL, 0x3CA67428UL,
+ 0x03E33EA6UL, 0x3CA1823DUL, 0xA06E6C52UL, 0x3CA241D3UL, 0xEFA7E815UL, 0x3CA8B4E1UL,
+ 0x4E754FD0UL, 0x3CADEAC4UL, 0x3D7C04C0UL, 0x3C71CC82UL, 0xC264F127UL, 0x3C953DC9UL,
+ 0x34D5C5A7UL, 0x3C93B5F7UL, 0xB9A7B902UL, 0x3C7366A3UL, 0x6433DD6CUL, 0x3CAAC888UL,
+ 0x4F401711UL, 0x3C987A4CUL, 0x1BBE943FUL, 0x3C9FAB9FUL, 0xFD6AC93CUL, 0x3CA0C4B5UL,
+ 0x766F1035UL, 0x3CA90835UL, 0x2CE13C95UL, 0x3CA09FD9UL, 0x8418C8D8UL, 0x3CADC143UL,
+ 0xFF474261UL, 0x3C8DC87DUL, 0x5CD783D3UL, 0x3C8F8872UL, 0xE7D0C8AAUL, 0x3CAEC35DUL,
+ 0xDBA49538UL, 0x3CA3943BUL, 0x2B203947UL, 0x3CA92195UL, 0xAFE6F86CUL, 0x3C59F556UL,
+ 0x3195A5F9UL, 0x3CAADC99UL, 0x3D770E65UL, 0x3CA41943UL, 0xA36B97EAUL, 0x3CA76B6EUL,
+ 0xAAAAAAABUL, 0x3BD46AAAUL, 0xFEE9D063UL, 0x3C637D40UL, 0xF514C24EUL, 0x3C89F356UL,
+ 0x670030E9UL, 0x3C953F22UL, 0xA173C1CFUL, 0x3CAEA671UL, 0x3FBCC1DDUL, 0x3C841D58UL,
+ 0x29B9B818UL, 0x3C9648F0UL, 0xAD202AB4UL, 0x3CA1A66DUL, 0xF2D6B269UL, 0x3CA7B07BUL,
+ 0x017DC4ADUL, 0x3C836A36UL, 0xD6B16F60UL, 0x3C8B726BUL, 0xC2BC701DUL, 0x3CABFE18UL,
+ 0x1DFE451FUL, 0x3C7E799DUL, 0x7E7B5452UL, 0x3CADDF5AUL, 0xEA15C5E5UL, 0x3C734D90UL,
+ 0xA6558F7BUL, 0x3C8F4CBBUL, 0x4F4D361AUL, 0x3C9D473AUL, 0xF06B5ECFUL, 0x3C87E2D6UL,
+ 0xDC49B5F3UL, 0x3CA5F6F5UL, 0x0F5A41F1UL, 0x3CA16024UL, 0xC062C2BCUL, 0x3CA3586CUL,
+ 0x0DF45D94UL, 0x3CA0C6A9UL, 0xEEF4E10BUL, 0x3CA2703CUL, 0x74215C62UL, 0x3CA99F3EUL,
+ 0x286F88D2UL, 0x3CAFA5EFUL, 0xB7D00B1FUL, 0x3C99239EUL, 0x8FF8E50CUL, 0x3CABC642UL,
+ 0x0A756B50UL, 0x3CA33971UL, 0xBE93D5DCUL, 0x3C389058UL, 0x7B752D97UL, 0x3C8E08EEUL,
+ 0x0FFF0A3FUL, 0x3C9A2FEDUL, 0x37EAC5DFUL, 0x3CA42034UL, 0x6C4969DFUL, 0x3CA35668UL,
+ 0xF5860FA5UL, 0x3CA082AEUL, 0x99B322B6UL, 0x3C62CF11UL, 0x933E42D8UL, 0x3C7AC44EUL,
+ 0x0761E377UL, 0x3C975F68UL, 0x4B704CC9UL, 0x3C7C5ADFUL, 0xCB8394DCUL, 0x3CA0F9AEUL,
+ 0x3E08F0F9UL, 0x3C9158C1UL, 0xCFA3F556UL, 0x3C9C7516UL, 0xF6CB01CDUL, 0x3C91D9C1UL,
+ 0xE811C1DAUL, 0x3C9DA58FUL, 0xEA9036DBUL, 0x3C2DCD9DUL, 0xB18FAB04UL, 0x3C8015A8UL,
+ 0x92316223UL, 0x3CAD4C55UL, 0xBE291E10UL, 0x3C8C6A0DUL, 0xFC9476ABUL, 0x3C8C615DUL,
+ 0x9B9BCA75UL, 0x3CACE0D7UL, 0x7ECC4726UL, 0x3CA4614AUL, 0x312152EEUL, 0x3CACD427UL,
+ 0x811960CAUL, 0x3CAC1BA1UL, 0xA557FD24UL, 0x3C6514CAUL, 0xF5CDF826UL, 0x3CA712CCUL,
+ 0x75CDBEA6UL, 0x3C9D93A5UL, 0xF3F3450CUL, 0x3CA90AAFUL, 0x071BA369UL, 0x3C85382FUL,
+ 0xCF26AE90UL, 0x3CA87E97UL, 0x75933097UL, 0x3C86DA5CUL, 0x309C2B19UL, 0x3CA61791UL,
+ 0x90D5990BUL, 0x3CA44210UL, 0xF22AC222UL, 0x3C9A5F49UL, 0x0411EEF9UL, 0x3CAC502EUL,
+ 0x839809AEUL, 0x3C93D12AUL, 0x468A4418UL, 0x3CA46C91UL, 0x088AFCDBUL, 0x3C9F1C33UL
};
#define __ _masm->
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp
index 372c4898f37..dce4fbfc455 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp
@@ -77,226 +77,226 @@
ATTRIBUTE_ALIGNED(4) static const juint _HALFMASK[] =
{
- 4160749568, 2147483647
+ 0xF8000000UL, 0x7FFFFFFFUL
};
ATTRIBUTE_ALIGNED(4) static const juint _ONEMASK[] =
{
- 0, 1072693248
+ 0x00000000UL, 0x3FF00000UL
};
ATTRIBUTE_ALIGNED(4) static const juint _TWOMASK[] =
{
- 0, 1073741824
+ 0x00000000UL, 0x40000000UL
};
ATTRIBUTE_ALIGNED(16) static const juint _MASK3[] =
{
- 0, 4294967280, 0, 4294967280
+ 0x00000000UL, 0xFFFFFFF0UL, 0x00000000UL, 0xFFFFFFF0UL
};
ATTRIBUTE_ALIGNED(16) static const juint _RMASK[] =
{
- 4294705152, 4294967295, 4294705152, 4294967295
+ 0xFFFC0000UL, 0xFFFFFFFFUL, 0xFFFC0000UL, 0xFFFFFFFFUL
};
ATTRIBUTE_ALIGNED(16) static const juint _L2E[] =
{
- 1610612736, 1082594631, 4166901572, 1055174155
+ 0x60000000UL, 0x40871547UL, 0xF85DDF44UL, 0x3EE4AE0BUL
};
ATTRIBUTE_ALIGNED(16) static const juint _Shifter[] =
{
- 0, 1127743488, 0, 3275227136
+ 0x00000000UL, 0x43380000UL, 0x00000000UL, 0xC3380000UL
};
ATTRIBUTE_ALIGNED(16) static const juint _cv[] =
{
- 3884607281, 3168131199, 3607404735, 3190582024, 1874480759,
- 1032041131, 4286760334, 1053736893, 4277811695, 3211144770,
- 0, 0
+ 0xE78A6731UL, 0xBCD5D87FUL, 0xD704A0BFUL, 0xBE2C6B08UL, 0x6FBA4E77UL,
+ 0x3D83B2ABUL, 0xFF82C58EUL, 0x3ECEBFBDUL, 0xFEFA39EFUL, 0xBF662E42UL,
+ 0x00000000UL, 0x00000000UL
};
ATTRIBUTE_ALIGNED(4) static const juint _pv[] =
{
- 236289503, 1064135997, 463583772, 3215696314, 1441186365,
- 3212977891, 286331153, 1069617425, 2284589306, 1066820852,
- 1431655765, 3218429269
+ 0x0E157DDFUL, 0x3F6D6D3DUL, 0x1BA1BA1CUL, 0xBFABA1BAUL, 0x55E6C23DUL,
+ 0xBF8226E3UL, 0x11111111UL, 0x3FC11111UL, 0x882C10FAUL, 0x3F9664F4UL,
+ 0x55555555UL, 0xBFD55555UL
};
ATTRIBUTE_ALIGNED(16) static const juint _T2_neg_f[] =
{
- 0, 1072693248, 0, 0, 1797923801, 1072687577,
- 1950547427, 1013229059, 730821105, 1072681922, 2523232743, 1012067188,
- 915592468, 1072676282, 352947894, 3161024371, 2174652632, 1072670657,
- 4087714590, 1014450259, 35929225, 1072665048, 2809788041, 3159436968,
- 2912730644, 1072659453, 3490067722, 3163405074, 2038973688, 1072653874,
- 892941374, 1016046459, 1533953344, 1072648310, 769171851, 1015665633,
- 1222472308, 1072642761, 1054357470, 3161021018, 929806999, 1072637227,
- 3205336643, 1015259557, 481706282, 1072631708, 1696079173, 3162710528,
- 3999357479, 1072626203, 2258941616, 1015924724, 2719515920, 1072620714,
- 2760332941, 1015137933, 764307441, 1072615240, 3021057420, 3163329523,
- 2256325230, 1072609780, 580117746, 1015317295, 2728693978, 1072604335,
- 396109971, 3163462691, 2009970496, 1072598905, 2159039665, 3162572948,
- 4224142467, 1072593489, 3389820386, 1015207202, 610758006, 1072588089,
- 1965209397, 3161866232, 3884662774, 1072582702, 2158611599, 1014210185,
- 991358482, 1072577331, 838715019, 3163157668, 351641897, 1072571974,
- 2172261526, 3163010599, 1796832535, 1072566631, 3176955716, 3160585513,
- 863738719, 1072561303, 1326992220, 3162613197, 1679558232, 1072555989,
- 2390342287, 3163333970, 4076975200, 1072550689, 2029000899, 1015208535,
- 3594158869, 1072545404, 2456521700, 3163256561, 64696965, 1072540134,
- 1768797490, 1015816960, 1912561781, 1072534877, 3147495102, 1015678253,
- 382305176, 1072529635, 2347622376, 3162578625, 3898795731, 1072524406,
- 1249994144, 1011869818, 3707479175, 1072519192, 3613079303, 1014164738,
- 3939148246, 1072513992, 3210352148, 1015274323, 135105010, 1072508807,
- 1906148728, 3163375739, 721996136, 1072503635, 563754734, 1015371318,
- 1242007932, 1072498477, 1132034716, 3163339831, 1532734324, 1072493333,
- 3094216535, 3163162857, 1432208378, 1072488203, 1401068914, 3162363963,
- 778901109, 1072483087, 2248183955, 3161268751, 3706687593, 1072477984,
- 3521726940, 1013253067, 1464976603, 1072472896, 3507292405, 3161977534,
- 2483480501, 1072467821, 1216371780, 1013034172, 2307442995, 1072462760,
- 3190117721, 3162404539, 777507147, 1072457713, 4282924205, 1015187533,
- 2029714210, 1072452679, 613660079, 1015099143, 1610600570, 1072447659,
- 3766732298, 1015760183, 3657065772, 1072442652, 399025623, 3162957078,
- 3716502172, 1072437659, 2303740125, 1014042725, 1631695677, 1072432680,
- 2717633076, 3162344026, 1540824585, 1072427714, 1064017011, 3163487690,
- 3287523847, 1072422761, 1625971539, 3157009955, 2420883922, 1072417822,
- 2049810052, 1014119888, 3080351519, 1072412896, 3379126788, 3157218001,
- 815859274, 1072407984, 240396590, 3163487443, 4062661092, 1072403084,
- 1422616006, 3163255318, 4076559943, 1072398198, 2119478331, 3160758351,
- 703710506, 1072393326, 1384660846, 1015195891, 2380618042, 1072388466,
- 3149557219, 3163320799, 364333489, 1072383620, 3923737744, 3161421373,
- 3092190715, 1072378786, 814012168, 3159523422, 1822067026, 1072373966,
- 1241994956, 1015340290, 697153126, 1072369159, 1283515429, 3163283189,
- 3861050111, 1072364364, 254893773, 3162813180, 2572866477, 1072359583,
- 878562433, 1015521741, 977020788, 1072354815, 3065100517, 1015541563,
- 3218338682, 1072350059, 3404164304, 3162477108, 557149882, 1072345317,
- 3672720709, 1014537265, 1434058175, 1072340587, 251133233, 1015085769,
- 1405169241, 1072335870, 2998539689, 3162830951, 321958744, 1072331166,
- 3401933767, 1015794558, 2331271250, 1072326474, 812057446, 1012207446,
- 2990417245, 1072321795, 3683467745, 3163369326, 2152073944, 1072317129,
- 1486860576, 3163203456, 3964284211, 1072312475, 2111583915, 1015427164,
- 3985553595, 1072307834, 4002146062, 1015834136, 2069751141, 1072303206,
- 1562170675, 3162724681, 2366108318, 1072298590, 2867985102, 3161762254,
- 434316067, 1072293987, 2028358766, 1013458122, 424392917, 1072289396,
- 2749202995, 3162838718, 2191782032, 1072284817, 2960257726, 1013742662,
- 1297350157, 1072280251, 1308022040, 3163412558, 1892288442, 1072275697,
- 2446255666, 3162600381, 3833209506, 1072271155, 2722920684, 1013754842,
- 2682146384, 1072266626, 2082178513, 3163363419, 2591453363, 1072262109,
- 2132396182, 3159074198, 3418903055, 1072257604, 2527457337, 3160820604,
- 727685349, 1072253112, 2038246809, 3162358742, 2966275557, 1072248631,
- 2176155324, 3159842759, 1403662306, 1072244163, 2788809599, 3161671007,
- 194117574, 1072239707, 777528612, 3163412089, 3492293770, 1072235262,
- 2248032210, 1015386826, 2568320822, 1072230830, 2732824428, 1014352915,
- 1577608921, 1072226410, 1875489510, 3162968394, 380978316, 1072222002,
- 854188970, 3160462686, 3134592888, 1072217605, 4232266862, 1015991134,
- 1110089947, 1072213221, 1451641639, 1015474673, 2759350287, 1072208848,
- 1148526634, 1015894933, 3649726105, 1072204487, 4085036346, 1015649474,
- 3643909174, 1072200138, 3537586109, 1014354647, 2604962541, 1072195801,
- 2614425274, 3163539192, 396319521, 1072191476, 4172420816, 3159074632,
- 1176749997, 1072187162, 2738998779, 3162035844, 515457527, 1072182860,
- 836709333, 1015651226, 2571947539, 1072178569, 3558159064, 3163376669,
- 2916157145, 1072174290, 219487565, 1015309367, 1413356050, 1072170023,
- 1651349291, 3162668166, 2224145553, 1072165767, 3482522030, 3161489169,
- 919555682, 1072161523, 3121969534, 1012948226, 1660913392, 1072157290,
- 4218599604, 1015135707, 19972402, 1072153069, 3507899862, 1016009292,
- 158781403, 1072148859, 2221464712, 3163286453, 1944781191, 1072144660,
- 3993278767, 3161724279, 950803702, 1072140473, 1655364926, 1015237032,
- 1339972927, 1072136297, 167908909, 1015572152, 2980802057, 1072132132,
- 378619896, 1015773303, 1447192521, 1072127979, 1462857171, 3162514521,
- 903334909, 1072123837, 1636462108, 1015039997, 1218806132, 1072119706,
- 1818613052, 3162548441, 2263535754, 1072115586, 752233586, 3162639008,
- 3907805044, 1072111477, 2257091225, 3161550407, 1727278727, 1072107380,
- 3562710623, 1011471940, 4182873220, 1072103293, 629542646, 3161996303,
- 2555984613, 1072099218, 2652555442, 3162552692, 1013258799, 1072095154,
- 1748797611, 3160129082, 3721688645, 1072091100, 3069276937, 1015839401,
- 1963711167, 1072087058, 1744767757, 3160574294, 4201977662, 1072083026,
- 748330254, 1013594357, 1719614413, 1072079006, 330458198, 3163282740,
- 2979960120, 1072074996, 2599109725, 1014498493, 3561793907, 1072070997,
- 1157054053, 1011890350, 3339203574, 1072067009, 1483497780, 3162408754,
- 2186617381, 1072063032, 2270764084, 3163272713, 4273770423, 1072059065,
- 3383180809, 3163218901, 885834528, 1072055110, 1973258547, 3162261564,
- 488188413, 1072051165, 3199821029, 1015564048, 2956612997, 1072047230,
- 2118169751, 3162735553, 3872257780, 1072043306, 1253592103, 1015958334,
- 3111574537, 1072039393, 2606161479, 3162759746, 551349105, 1072035491,
- 3821916050, 3162106589, 363667784, 1072031599, 813753950, 1015785209,
- 2425981843, 1072027717, 2830390851, 3163346599, 2321106615, 1072023846,
- 2171176610, 1009535771, 4222122499, 1072019985, 1277378074, 3163256737,
- 3712504873, 1072016135, 88491949, 1015427660, 671025100, 1072012296,
- 3832014351, 3163022030, 3566716925, 1072008466, 1536826856, 1014142433,
- 3689071823, 1072004647, 2321004996, 3162552716, 917841882, 1072000839,
- 18715565, 1015659308, 3723038930, 1071997040, 378465264, 3162569582,
- 3395129871, 1071993252, 4025345435, 3162335388, 4109806887, 1071989474,
- 422403966, 1014469229, 1453150082, 1071985707, 498154669, 3161488062,
- 3896463087, 1071981949, 1139797873, 3161233805, 2731501122, 1071978202,
- 1774031855, 3162470021, 2135241198, 1071974465, 1236747871, 1013589147,
- 1990012071, 1071970738, 3529070563, 3162813193, 2178460671, 1071967021,
- 777878098, 3162842493, 2583551245, 1071963314, 3161094195, 1015606491,
- 3088564500, 1071959617, 1762311517, 1015045673, 3577096743, 1071955930,
- 2951496418, 1013793687, 3933059031, 1071952253, 2133366768, 3161531832,
- 4040676318, 1071948586, 4090609238, 1015663458, 3784486610, 1071944929,
- 1581883040, 3161698953, 3049340112, 1071941282, 3062915824, 1013170595,
- 1720398391, 1071937645, 3980678963, 3163300080, 3978100823, 1071934017,
- 3513027190, 1015845963, 1118294578, 1071930400, 2197495694, 3159909401,
- 1617004845, 1071926792, 82804944, 1010342778, 1065662932, 1071923194,
- 2533670915, 1014530238, 3645941911, 1071919605, 3814685081, 3161573341,
- 654919306, 1071916027, 3232961757, 3163047469, 569847338, 1071912458,
- 472945272, 3159290729, 3278348324, 1071908898, 3069497416, 1014750712,
- 78413852, 1071905349, 4183226867, 3163017251, 3743175029, 1071901808,
- 2072812490, 3162175075, 1276261410, 1071898278, 300981948, 1014684169,
- 1156440435, 1071894757, 2351451249, 1013967056, 3272845541, 1071891245,
- 928852419, 3163488248, 3219942644, 1071887743, 3798990616, 1015368806,
- 887463927, 1071884251, 3596744163, 3160794166, 460407023, 1071880768,
- 4237175092, 3163138469, 1829099622, 1071877294, 1016661181, 3163461005,
- 589198666, 1071873830, 2664346172, 3163157962, 926591435, 1071870375,
- 3208833762, 3162913514, 2732492859, 1071866929, 2691479646, 3162255684,
- 1603444721, 1071863493, 1548633640, 3162201326, 1726216749, 1071860066,
- 2466808228, 3161676405, 2992903935, 1071856648, 2218154406, 1015228193,
- 1000925746, 1071853240, 1018491672, 3163309544, 4232894513, 1071849840,
- 2383938684, 1014668519, 3991843581, 1071846450, 4092853457, 1014585763,
- 171030293, 1071843070, 3526460132, 1014428778, 1253935211, 1071839698,
- 1395382931, 3159702613, 2839424854, 1071836335, 1171596163, 1013041679,
- 526652809, 1071832982, 4223459736, 1015879375, 2799960843, 1071829637,
- 1423655381, 1015022151, 964107055, 1071826302, 2800439588, 3162833221,
- 3504003472, 1071822975, 3594001060, 3157330652, 1724976915, 1071819658,
- 420909223, 3163117379, 4112506593, 1071816349, 2947355221, 1014371048,
- 1972484976, 1071813050, 675290301, 3161640050, 3790955393, 1071809759,
- 2352942462, 3163180090, 874372905, 1071806478, 100263788, 1015940732,
- 1709341917, 1071803205, 2571168217, 1014152499, 1897844341, 1071799941,
- 1254300460, 1015275938, 1337108031, 1071796686, 3203724452, 1014677845,
- 4219606026, 1071793439, 2434574742, 1014681548, 1853186616, 1071790202,
- 3066496371, 1015656574, 2725843665, 1071786973, 1433917087, 1014838523,
- 2440944790, 1071783753, 2492769774, 1014147454, 897099801, 1071780542,
- 754756297, 1015241005, 2288159958, 1071777339, 2169144469, 1014876021,
- 2218315341, 1071774145, 2694295388, 3163288868, 586995997, 1071770960,
- 41662348, 3162627992, 1588871207, 1071767783, 143439582, 3162963416,
- 828946858, 1071764615, 10642492, 1015939438, 2502433899, 1071761455,
- 2148595913, 1015023991, 2214878420, 1071758304, 892270087, 3163116422,
- 4162030108, 1071755161, 2763428480, 1015529349, 3949972341, 1071752027,
- 2068408548, 1014913868, 1480023343, 1071748902, 2247196168, 1015327453,
- 948735466, 1071745785, 3516338028, 3162574883, 2257959872, 1071742676,
- 3802946148, 1012964927, 1014845819, 1071739576, 3117910646, 3161559105,
- 1416741826, 1071736484, 2196380210, 1011413563, 3366293073, 1071733400,
- 3119426314, 1014120554, 2471440686, 1071730325, 968836267, 3162214888,
- 2930322912, 1071727258, 2599499422, 3162714047, 351405227, 1071724200,
- 3125337328, 3159822479, 3228316108, 1071721149, 3010241991, 3158422804,
- 2875075254, 1071718107, 4144233330, 3163333716, 3490863953, 1071715073,
- 960797498, 3162948880, 685187902, 1071712048, 378731989, 1014843115,
- 2952712987, 1071709030, 3293494651, 3160120301, 1608493509, 1071706021,
- 3159622171, 3162807737, 852742562, 1071703020, 667253586, 1009793559,
- 590962156, 1071700027, 3829346666, 3163275597, 728909815, 1071697042,
- 383930225, 1015029468, 1172597893, 1071694065, 114433263, 1015347593,
- 1828292879, 1071691096, 1255956747, 1015588398, 2602514713, 1071688135,
- 2268929336, 1014354284, 3402036099, 1071685182, 405889334, 1015105656,
- 4133881824, 1071682237, 2148155345, 3162931299, 410360776, 1071679301,
- 1269990655, 1011975870, 728934454, 1071676372, 1413842688, 1014178612,
- 702412510, 1071673451, 3803266087, 3162280415, 238821257, 1071670538,
- 1469694871, 3162884987, 3541402996, 1071667632, 2759177317, 1014854626,
- 1928746161, 1071664735, 983617676, 1014285177, 3899555717, 1071661845,
- 427280750, 3162546972, 772914124, 1071658964, 4004372762, 1012230161,
- 1048019041, 1071656090, 1398474845, 3160510595, 339411585, 1071653224,
- 264588982, 3161636657, 2851812149, 1071650365, 2595802551, 1015767337,
- 4200250559, 1071647514, 2808127345, 3161781938
+ 0x00000000UL, 0x3FF00000UL, 0x00000000UL, 0x00000000UL, 0x6B2A23D9UL, 0x3FEFE9D9UL,
+ 0x7442FDE3UL, 0x3C64A603UL, 0x2B8F71F1UL, 0x3FEFD3C2UL, 0x966579E7UL, 0x3C52EB74UL,
+ 0x3692D514UL, 0x3FEFBDBAUL, 0x15098EB6UL, 0xBC696773UL, 0x819E90D8UL, 0x3FEFA7C1UL,
+ 0xF3A5931EUL, 0x3C774853UL, 0x02243C89UL, 0x3FEF91D8UL, 0xA779F689UL, 0xBC512EA8UL,
+ 0xAD9CBE14UL, 0x3FEF7BFDUL, 0xD006350AUL, 0xBC8DBB12UL, 0x798844F8UL, 0x3FEF6632UL,
+ 0x3539343EUL, 0x3C8FA37BUL, 0x5B6E4540UL, 0x3FEF5076UL, 0x2DD8A18BUL, 0x3C89D3E1UL,
+ 0x48DD7274UL, 0x3FEF3AC9UL, 0x3ED837DEUL, 0xBC695A5AUL, 0x376BBA97UL, 0x3FEF252BUL,
+ 0xBF0D8E43UL, 0x3C83A1A5UL, 0x1CB6412AUL, 0x3FEF0F9CUL, 0x65181D45UL, 0xBC832200UL,
+ 0xEE615A27UL, 0x3FEEFA1BUL, 0x86A4B6B0UL, 0x3C8DC7F4UL, 0xA2188510UL, 0x3FEEE4AAUL,
+ 0xA487568DUL, 0x3C81C68DUL, 0x2D8E67F1UL, 0x3FEECF48UL, 0xB411AD8CUL, 0xBC8C93F3UL,
+ 0x867CCA6EUL, 0x3FEEB9F4UL, 0x2293E4F2UL, 0x3C84832FUL, 0xA2A490DAUL, 0x3FEEA4AFUL,
+ 0x179C2893UL, 0xBC8E9C23UL, 0x77CDB740UL, 0x3FEE8F79UL, 0x80B054B1UL, 0xBC810894UL,
+ 0xFBC74C83UL, 0x3FEE7A51UL, 0xCA0C8DE2UL, 0x3C82D522UL, 0x24676D76UL, 0x3FEE6539UL,
+ 0x7522B735UL, 0xBC763FF8UL, 0xE78B3FF6UL, 0x3FEE502EUL, 0x80A9CC8FUL, 0x3C739E89UL,
+ 0x3B16EE12UL, 0x3FEE3B33UL, 0x31FDC68BUL, 0xBC89F4A4UL, 0x14F5A129UL, 0x3FEE2646UL,
+ 0x817A1496UL, 0xBC87B627UL, 0x6B197D17UL, 0x3FEE1167UL, 0xBD5C7F44UL, 0xBC62B529UL,
+ 0x337B9B5FUL, 0x3FEDFC97UL, 0x4F184B5CUL, 0xBC81A5CDUL, 0x641C0658UL, 0x3FEDE7D5UL,
+ 0x8E79BA8FUL, 0xBC8CA552UL, 0xF301B460UL, 0x3FEDD321UL, 0x78F018C3UL, 0x3C82DA57UL,
+ 0xD63A8315UL, 0x3FEDBE7CUL, 0x926B8BE4UL, 0xBC8B76F1UL, 0x03DB3285UL, 0x3FEDA9E6UL,
+ 0x696DB532UL, 0x3C8C2300UL, 0x71FF6075UL, 0x3FED955DUL, 0xBB9AF6BEUL, 0x3C8A052DUL,
+ 0x16C98398UL, 0x3FED80E3UL, 0x8BEDDFE8UL, 0xBC811EC1UL, 0xE862E6D3UL, 0x3FED6C76UL,
+ 0x4A8165A0UL, 0x3C4FE87AUL, 0xDCFBA487UL, 0x3FED5818UL, 0xD75B3707UL, 0x3C72ED02UL,
+ 0xEACAA1D6UL, 0x3FED43C8UL, 0xBF5A1614UL, 0x3C83DB53UL, 0x080D89F2UL, 0x3FED2F87UL,
+ 0x719D8578UL, 0xBC8D487BUL, 0x2B08C968UL, 0x3FED1B53UL, 0x219A36EEUL, 0x3C855636UL,
+ 0x4A07897CUL, 0x3FED072DUL, 0x43797A9CUL, 0xBC8CBC37UL, 0x5B5BAB74UL, 0x3FECF315UL,
+ 0xB86DFF57UL, 0xBC8A08E9UL, 0x555DC3FAUL, 0x3FECDF0BUL, 0x53829D72UL, 0xBC7DD83BUL,
+ 0x2E6D1675UL, 0x3FECCB0FUL, 0x86009093UL, 0xBC6D220FUL, 0xDCEF9069UL, 0x3FECB720UL,
+ 0xD1E949DCUL, 0x3C6503CBUL, 0x5751C4DBUL, 0x3FECA340UL, 0xD10D08F5UL, 0xBC77F2BEUL,
+ 0x9406E7B5UL, 0x3FEC8F6DUL, 0x48805C44UL, 0x3C61ACBCUL, 0x8988C933UL, 0x3FEC7BA8UL,
+ 0xBE255559UL, 0xBC7E76BBUL, 0x2E57D14BUL, 0x3FEC67F1UL, 0xFF483CADUL, 0x3C82884DUL,
+ 0x78FAFB22UL, 0x3FEC5447UL, 0x2493B5AFUL, 0x3C812F07UL, 0x5FFFD07AUL, 0x3FEC40ABUL,
+ 0xE083C60AUL, 0x3C8B4537UL, 0xD9FA652CUL, 0x3FEC2D1CUL, 0x17C8A5D7UL, 0xBC86E516UL,
+ 0xDD85529CUL, 0x3FEC199BUL, 0x895048DDUL, 0x3C711065UL, 0x6141B33DUL, 0x3FEC0628UL,
+ 0xA1FBCA34UL, 0xBC7D8A5AUL, 0x5BD71E09UL, 0x3FEBF2C2UL, 0x3F6B9C73UL, 0xBC8EFDCAUL,
+ 0xC3F3A207UL, 0x3FEBDF69UL, 0x60EA5B53UL, 0xBC2C2623UL, 0x904BC1D2UL, 0x3FEBCC1EUL,
+ 0x7A2D9E84UL, 0x3C723DD0UL, 0xB79A6F1FUL, 0x3FEBB8E0UL, 0xC9696204UL, 0xBC2F52D1UL,
+ 0x30A1064AUL, 0x3FEBA5B0UL, 0x0E54292EUL, 0xBC8EFCD3UL, 0xF22749E4UL, 0x3FEB928CUL,
+ 0x54CB65C6UL, 0xBC8B7216UL, 0xF2FB5E47UL, 0x3FEB7F76UL, 0x7E54AC3BUL, 0xBC65584FUL,
+ 0x29F1C52AUL, 0x3FEB6C6EUL, 0x52883F6EUL, 0x3C82A8F3UL, 0x8DE5593AUL, 0x3FEB5972UL,
+ 0xBBBA6DE3UL, 0xBC8C71DFUL, 0x15B749B1UL, 0x3FEB4684UL, 0xE9DF7C90UL, 0xBC6F763DUL,
+ 0xB84F15FBUL, 0x3FEB33A2UL, 0x3084D708UL, 0xBC52805EUL, 0x6C9A8952UL, 0x3FEB20CEUL,
+ 0x4A0756CCUL, 0x3C84DD02UL, 0x298DB666UL, 0x3FEB0E07UL, 0x4C80E425UL, 0xBC8BDEF5UL,
+ 0xE622F2FFUL, 0x3FEAFB4CUL, 0x0F315ECDUL, 0xBC84B2FCUL, 0x995AD3ADUL, 0x3FEAE89FUL,
+ 0x345DCC81UL, 0x3C87A1CDUL, 0x3A3C2774UL, 0x3FEAD5FFUL, 0xB6B1B8E5UL, 0x3C87EF3BUL,
+ 0xBFD3F37AUL, 0x3FEAC36BUL, 0xCAE76CD0UL, 0xBC7F9234UL, 0x21356EBAUL, 0x3FEAB0E5UL,
+ 0xDAE94545UL, 0x3C789C31UL, 0x5579FDBFUL, 0x3FEA9E6BUL, 0x0EF7FD31UL, 0x3C80FAC9UL,
+ 0x53C12E59UL, 0x3FEA8BFEUL, 0xB2BA15A9UL, 0xBC84F867UL, 0x1330B358UL, 0x3FEA799EUL,
+ 0xCAC563C7UL, 0x3C8BCB7EUL, 0x8AF46052UL, 0x3FEA674AUL, 0x30670366UL, 0x3C550F56UL,
+ 0xB23E255DUL, 0x3FEA5503UL, 0xDB8D41E1UL, 0xBC8D2F6EUL, 0x80460AD8UL, 0x3FEA42C9UL,
+ 0x589FB120UL, 0xBC8AA780UL, 0xEC4A2D33UL, 0x3FEA309BUL, 0x7DDC36ABUL, 0x3C86305CUL,
+ 0xED8EB8BBUL, 0x3FEA1E7AUL, 0xEE8BE70EUL, 0x3C8C6618UL, 0x7B5DE565UL, 0x3FEA0C66UL,
+ 0x5D1CD533UL, 0xBC835949UL, 0x8D07F29EUL, 0x3FE9FA5EUL, 0xAAF1FACEUL, 0xBC74A9CEUL,
+ 0x19E32323UL, 0x3FE9E863UL, 0x78E64C6EUL, 0x3C6824CAUL, 0x194BB8D5UL, 0x3FE9D674UL,
+ 0xA3DD8233UL, 0xBC8516BEUL, 0x82A3F090UL, 0x3FE9C491UL, 0xB071F2BEUL, 0x3C6C7C46UL,
+ 0x4D53FE0DUL, 0x3FE9B2BBUL, 0x4DF6D518UL, 0xBC8DD84EUL, 0x70CA07BAUL, 0x3FE9A0F1UL,
+ 0x91CEE632UL, 0xBC8173BDUL, 0xE47A22A2UL, 0x3FE98F33UL, 0xA24C78ECUL, 0x3C6CABDAUL,
+ 0x9FDE4E50UL, 0x3FE97D82UL, 0x7C1B85D1UL, 0xBC8D185BUL, 0x9A7670B3UL, 0x3FE96BDDUL,
+ 0x7F19C896UL, 0xBC4BA596UL, 0xCBC8520FUL, 0x3FE95A44UL, 0x96A5F039UL, 0xBC664B7CUL,
+ 0x2B5F98E5UL, 0x3FE948B8UL, 0x797D2D99UL, 0xBC7DC3D6UL, 0xB0CDC5E5UL, 0x3FE93737UL,
+ 0x81B57EBCUL, 0xBC575FC7UL, 0x53AA2FE2UL, 0x3FE925C3UL, 0xA639DB7FUL, 0xBC73455FUL,
+ 0x0B91FFC6UL, 0x3FE9145BUL, 0x2E582524UL, 0xBC8DD679UL, 0xD0282C8AUL, 0x3FE902FEUL,
+ 0x85FE3FD2UL, 0x3C8592CAUL, 0x99157736UL, 0x3FE8F1AEUL, 0xA2E3976CUL, 0x3C75CC13UL,
+ 0x5E0866D9UL, 0x3FE8E06AUL, 0x6FC9B2E6UL, 0xBC87114AUL, 0x16B5448CUL, 0x3FE8CF32UL,
+ 0x32E9E3AAUL, 0xBC60D55EUL, 0xBAD61778UL, 0x3FE8BE05UL, 0xFC43446EUL, 0x3C8ECB5EUL,
+ 0x422AA0DBUL, 0x3FE8ACE5UL, 0x56864B27UL, 0x3C86E9F1UL, 0xA478580FUL, 0x3FE89BD0UL,
+ 0x4475202AUL, 0x3C8D5395UL, 0xD98A6699UL, 0x3FE88AC7UL, 0xF37CB53AUL, 0x3C8994C2UL,
+ 0xD931A436UL, 0x3FE879CAUL, 0xD2DB47BDUL, 0x3C75D2D7UL, 0x9B4492EDUL, 0x3FE868D9UL,
+ 0x9BD4F6BAUL, 0xBC8FC6F8UL, 0x179F5B21UL, 0x3FE857F4UL, 0xF8B216D0UL, 0xBC4BA748UL,
+ 0x4623C7ADUL, 0x3FE8471AUL, 0xA341CDFBUL, 0xBC78D684UL, 0x1EB941F7UL, 0x3FE8364CUL,
+ 0x31DF2BD5UL, 0x3C899B9AUL, 0x994CCE13UL, 0x3FE82589UL, 0xD41532D8UL, 0xBC8D4C1DUL,
+ 0xADD106D9UL, 0x3FE814D2UL, 0x0D151D4DUL, 0x3C846437UL, 0x543E1A12UL, 0x3FE80427UL,
+ 0x626D972BUL, 0xBC827C86UL, 0x8491C491UL, 0x3FE7F387UL, 0xCF9311AEUL, 0xBC707F11UL,
+ 0x36CF4E62UL, 0x3FE7E2F3UL, 0xBA15797EUL, 0x3C605D02UL, 0x62FF86F0UL, 0x3FE7D26AUL,
+ 0xFB72B8B4UL, 0x3C81BDDBUL, 0x0130C132UL, 0x3FE7C1EDUL, 0xD1164DD6UL, 0x3C8F124CUL,
+ 0x0976CFDBUL, 0x3FE7B17BUL, 0x8468DC88UL, 0xBC8BEBB5UL, 0x73EB0187UL, 0x3FE7A114UL,
+ 0xEE04992FUL, 0xBC741577UL, 0x38AC1CF6UL, 0x3FE790B9UL, 0x62AADD3EUL, 0x3C8349A8UL,
+ 0x4FDE5D3FUL, 0x3FE78069UL, 0x0A02162DUL, 0x3C8866B8UL, 0xB1AB6E09UL, 0x3FE77024UL,
+ 0x169147F8UL, 0x3C8B7877UL, 0x564267C9UL, 0x3FE75FEBUL, 0x57316DD3UL, 0xBC802459UL,
+ 0x35D7CBFDUL, 0x3FE74FBDUL, 0x618A6E1CUL, 0x3C8047FDUL, 0x48A58174UL, 0x3FE73F9AUL,
+ 0x6C65D53CUL, 0xBC80A8D9UL, 0x86EAD08AUL, 0x3FE72F82UL, 0x2CD62C72UL, 0xBC820AA0UL,
+ 0xE8EC5F74UL, 0x3FE71F75UL, 0x86887A99UL, 0xBC716E47UL, 0x66F42E87UL, 0x3FE70F74UL,
+ 0xD45AA65FUL, 0x3C49D644UL, 0xF9519484UL, 0x3FE6FF7DUL, 0x25860EF6UL, 0xBC783C0FUL,
+ 0x98593AE5UL, 0x3FE6EF92UL, 0x9E1AC8B2UL, 0xBC80B974UL, 0x3C651A2FUL, 0x3FE6DFB2UL,
+ 0x683C88ABUL, 0xBC5BBE3AUL, 0xDDD47645UL, 0x3FE6CFDCUL, 0xB6F17309UL, 0x3C8C7AA9UL,
+ 0x750BDABFUL, 0x3FE6C012UL, 0x67FF0B0DUL, 0xBC628956UL, 0xFA75173EUL, 0x3FE6B052UL,
+ 0x2C9A9D0EUL, 0x3C6A38F5UL, 0x667F3BCDUL, 0x3FE6A09EUL, 0x13B26456UL, 0xBC8BDD34UL,
+ 0xB19E9538UL, 0x3FE690F4UL, 0x9AEB445DUL, 0x3C7804BDUL, 0xD44CA973UL, 0x3FE68155UL,
+ 0x44F73E65UL, 0x3C5038AEUL, 0xC70833F6UL, 0x3FE671C1UL, 0x586C6134UL, 0xBC7E8732UL,
+ 0x82552225UL, 0x3FE66238UL, 0x87591C34UL, 0xBC8BB609UL, 0xFEBC8FB7UL, 0x3FE652B9UL,
+ 0xC9A73E09UL, 0xBC8AE3D5UL, 0x34CCC320UL, 0x3FE64346UL, 0x759D8933UL, 0xBC7C483CUL,
+ 0x1D1929FDUL, 0x3FE633DDUL, 0xBEB964E5UL, 0x3C884710UL, 0xB03A5585UL, 0x3FE6247EUL,
+ 0x7E40B497UL, 0xBC8383C1UL, 0xE6CDF6F4UL, 0x3FE6152AUL, 0x4AB84C27UL, 0x3C8E4B3EUL,
+ 0xB976DC09UL, 0x3FE605E1UL, 0x9B56DE47UL, 0xBC83E242UL, 0x20DCEB71UL, 0x3FE5F6A3UL,
+ 0xE3CDCF92UL, 0xBC79EADDUL, 0x15AD2148UL, 0x3FE5E76FUL, 0x3080E65EUL, 0x3C8BA6F9UL,
+ 0x90998B93UL, 0x3FE5D845UL, 0xA8B45643UL, 0xBC8CD6A7UL, 0x8A5946B7UL, 0x3FE5C926UL,
+ 0x816986A2UL, 0x3C2C4B1BUL, 0xFBA87A03UL, 0x3FE5BA11UL, 0x4C233E1AUL, 0xBC8B77A1UL,
+ 0xDD485429UL, 0x3FE5AB07UL, 0x054647ADUL, 0x3C86324CUL, 0x27FF07CCUL, 0x3FE59C08UL,
+ 0xE467E60FUL, 0xBC87E2CEUL, 0xD497C7FDUL, 0x3FE58D12UL, 0x5B9A1DE8UL, 0x3C7295E1UL,
+ 0xDBE2C4CFUL, 0x3FE57E27UL, 0x8A57B9C4UL, 0xBC80B98CUL, 0x36B527DAUL, 0x3FE56F47UL,
+ 0x011D93ADUL, 0x3C89BB2CUL, 0xDDE910D2UL, 0x3FE56070UL, 0x168EEBF0UL, 0xBC80FB6EUL,
+ 0xCA5D920FUL, 0x3FE551A4UL, 0xEFEDE59BUL, 0xBC7D689CUL, 0xF4F6AD27UL, 0x3FE542E2UL,
+ 0x192D5F7EUL, 0x3C77926DUL, 0x569D4F82UL, 0x3FE5342BUL, 0x1DB13CADUL, 0xBC707ABEUL,
+ 0xE83F4EEFUL, 0x3FE5257DUL, 0x43EFEF71UL, 0xBC6C998DUL, 0xA2CF6642UL, 0x3FE516DAUL,
+ 0x69BD93EFUL, 0xBC7F7685UL, 0x7F4531EEUL, 0x3FE50841UL, 0x49B7465FUL, 0x3C6A249BUL,
+ 0x769D2CA7UL, 0x3FE4F9B2UL, 0xD25957E3UL, 0xBC84B309UL, 0x81D8ABFFUL, 0x3FE4EB2DUL,
+ 0x2E5D7A52UL, 0xBC85257DUL, 0x99FDDD0DUL, 0x3FE4DCB2UL, 0xBC6A7833UL, 0x3C88ECDBUL,
+ 0xB817C114UL, 0x3FE4CE41UL, 0x690ABD5DUL, 0x3C805E29UL, 0xD5362A27UL, 0x3FE4BFDAUL,
+ 0xAFEC42E2UL, 0x3C6D4397UL, 0xEA6DB7D7UL, 0x3FE4B17DUL, 0x7F2897F0UL, 0xBC7125B8UL,
+ 0xF0D7D3DEUL, 0x3FE4A32AUL, 0xF3D1BE56UL, 0x3C89CB62UL, 0xE192AED2UL, 0x3FE494E1UL,
+ 0x5E499EA0UL, 0xBC73B289UL, 0xB5C13CD0UL, 0x3FE486A2UL, 0xB69062F0UL, 0x3C63C1A3UL,
+ 0x668B3237UL, 0x3FE4786DUL, 0xED445733UL, 0xBC8C20F0UL, 0xED1D0057UL, 0x3FE46A41UL,
+ 0xD1648A76UL, 0x3C8C944BUL, 0x42A7D232UL, 0x3FE45C20UL, 0x82FB1F8EUL, 0xBC586419UL,
+ 0x6061892DUL, 0x3FE44E08UL, 0x04EF80D0UL, 0x3C389B7AUL, 0x3F84B9D4UL, 0x3FE43FFAUL,
+ 0x9704C003UL, 0x3C7880BEUL, 0xD950A897UL, 0x3FE431F5UL, 0xE35F7999UL, 0xBC71C7DDUL,
+ 0x2709468AUL, 0x3FE423FBUL, 0xC0B314DDUL, 0xBC88462DUL, 0x21F72E2AUL, 0x3FE4160AUL,
+ 0x1C309278UL, 0xBC4EF369UL, 0xC367A024UL, 0x3FE40822UL, 0xB6F4D048UL, 0x3C7BDDF8UL,
+ 0x04AC801CUL, 0x3FE3FA45UL, 0xF956F9F3UL, 0xBC87D023UL, 0xDF1C5175UL, 0x3FE3EC70UL,
+ 0x7B8C9BCAUL, 0xBC7AF663UL, 0x4C123422UL, 0x3FE3DEA6UL, 0x11F09EBCUL, 0x3C7ADA09UL,
+ 0x44EDE173UL, 0x3FE3D0E5UL, 0x8C284C71UL, 0x3C6FE8D0UL, 0xC313A8E5UL, 0x3FE3C32DUL,
+ 0x375D29C3UL, 0xBC8EFFF8UL, 0xBFEC6CF4UL, 0x3FE3B57FUL, 0xE26FFF18UL, 0x3C854C66UL,
+ 0x34E59FF7UL, 0x3FE3A7DBUL, 0xD661F5E3UL, 0xBC65E436UL, 0x1B7140EFUL, 0x3FE39A40UL,
+ 0xFC8E2934UL, 0xBC89A9A5UL, 0x6D05D866UL, 0x3FE38CAEUL, 0x3C9904BDUL, 0xBC8E958DUL,
+ 0x231E754AUL, 0x3FE37F26UL, 0x9ECEB23CUL, 0xBC89F5CAUL, 0x373AA9CBUL, 0x3FE371A7UL,
+ 0xBF42EAE2UL, 0xBC863AEAUL, 0xA2DE883BUL, 0x3FE36431UL, 0xA06CB85EUL, 0xBC7C3144UL,
+ 0x5F929FF1UL, 0x3FE356C5UL, 0x5C4E4628UL, 0xBC7B5CEEUL, 0x66E3FA2DUL, 0x3FE34962UL,
+ 0x930881A4UL, 0xBC735A75UL, 0xB26416FFUL, 0x3FE33C08UL, 0x843659A6UL, 0x3C832721UL,
+ 0x3BA8EA32UL, 0x3FE32EB8UL, 0x3CB4F318UL, 0xBC8C45E8UL, 0xFC4CD831UL, 0x3FE32170UL,
+ 0x8E18047CUL, 0x3C7A9CE7UL, 0xEDEEB2FDUL, 0x3FE31432UL, 0xF3F3FCD1UL, 0x3C7959A3UL,
+ 0x0A31B715UL, 0x3FE306FEUL, 0xD23182E4UL, 0x3C76F46AUL, 0x4ABD886BUL, 0x3FE2F9D2UL,
+ 0x532BDA93UL, 0xBC553C55UL, 0xA93E2F56UL, 0x3FE2ECAFUL, 0x45D52383UL, 0x3C61CA0FUL,
+ 0x1F641589UL, 0x3FE2DF96UL, 0xFBBCE198UL, 0x3C8D16CFUL, 0xA6E4030BUL, 0x3FE2D285UL,
+ 0x54DB41D5UL, 0x3C800247UL, 0x39771B2FUL, 0x3FE2C57EUL, 0xA6EB5124UL, 0xBC850145UL,
+ 0xD0DAD990UL, 0x3FE2B87FUL, 0xD6381AA4UL, 0xBC310ADCUL, 0x66D10F13UL, 0x3FE2AB8AUL,
+ 0x191690A7UL, 0xBC895743UL, 0xF51FDEE1UL, 0x3FE29E9DUL, 0xAFAD1255UL, 0x3C7612E8UL,
+ 0x7591BB70UL, 0x3FE291BAUL, 0x28401CBDUL, 0xBC72CC72UL, 0xE1F56381UL, 0x3FE284DFUL,
+ 0x8C3F0D7EUL, 0xBC8A4C3AUL, 0x341DDF29UL, 0x3FE2780EUL, 0x05F9E76CUL, 0x3C8E067CUL,
+ 0x65E27CDDUL, 0x3FE26B45UL, 0x9940E9D9UL, 0x3C72BD33UL, 0x711ECE75UL, 0x3FE25E85UL,
+ 0x4AC31B2CUL, 0x3C83E1A2UL, 0x4FB2A63FUL, 0x3FE251CEUL, 0xBEF4F4A4UL, 0x3C7AC155UL,
+ 0xFB82140AUL, 0x3FE2451FUL, 0x911CA996UL, 0x3C7ACFCCUL, 0x6E756238UL, 0x3FE2387AUL,
+ 0xB6C70573UL, 0x3C89B07EUL, 0xA27912D1UL, 0x3FE22BDDUL, 0x5577D69FUL, 0x3C7D34FBUL,
+ 0x917DDC96UL, 0x3FE21F49UL, 0x9494A5EEUL, 0x3C72A97EUL, 0x3578A819UL, 0x3FE212BEUL,
+ 0x2CFCAAC9UL, 0x3C83592DUL, 0x88628CD6UL, 0x3FE2063BUL, 0x814A8495UL, 0x3C7DC775UL,
+ 0x8438CE4DUL, 0x3FE1F9C1UL, 0xA097AF5CUL, 0xBC8BF524UL, 0x22FCD91DUL, 0x3FE1ED50UL,
+ 0x027BB78CUL, 0xBC81DF98UL, 0x5EB44027UL, 0x3FE1E0E7UL, 0x088CB6DEUL, 0xBC86FDD8UL,
+ 0x3168B9AAUL, 0x3FE1D487UL, 0x00A2643CUL, 0x3C8E016EUL, 0x95281C6BUL, 0x3FE1C82FUL,
+ 0x8010F8C9UL, 0x3C800977UL, 0x84045CD4UL, 0x3FE1BBE0UL, 0x352EF607UL, 0xBC895386UL,
+ 0xF8138A1CUL, 0x3FE1AF99UL, 0xA4B69280UL, 0x3C87BF85UL, 0xEB6FCB75UL, 0x3FE1A35BUL,
+ 0x7B4968E4UL, 0x3C7E5B4CUL, 0x58375D2FUL, 0x3FE19726UL, 0x85F17E08UL, 0x3C84AADDUL,
+ 0x388C8DEAUL, 0x3FE18AF9UL, 0xD1970F6CUL, 0xBC811023UL, 0x8695BBC0UL, 0x3FE17ED4UL,
+ 0xE2AC5A64UL, 0x3C609E3FUL, 0x3C7D517BUL, 0x3FE172B8UL, 0xB9D78A76UL, 0xBC719041UL,
+ 0x5471C3C2UL, 0x3FE166A4UL, 0x82EA1A32UL, 0x3C48F23BUL, 0xC8A58E51UL, 0x3FE15A98UL,
+ 0xB9EEAB0AUL, 0x3C72406AUL, 0x934F312EUL, 0x3FE14E95UL, 0x39BF44ABUL, 0xBC7B91E8UL,
+ 0xAEA92DE0UL, 0x3FE1429AUL, 0x9AF1369EUL, 0xBC832FBFUL, 0x14F204ABUL, 0x3FE136A8UL,
+ 0xBA48DCF0UL, 0xBC57108FUL, 0xC06C31CCUL, 0x3FE12ABDUL, 0xB36CA5C7UL, 0xBC41B514UL,
+ 0xAB5E2AB6UL, 0x3FE11EDBUL, 0xF703FB72UL, 0xBC8CA454UL, 0xD0125B51UL, 0x3FE11301UL,
+ 0x39449B3AUL, 0xBC86C510UL, 0x28D7233EUL, 0x3FE10730UL, 0x1692FDD5UL, 0x3C7D46EBUL,
+ 0xAFFED31BUL, 0x3FE0FB66UL, 0xC44EBD7BUL, 0xBC5B9BEDUL, 0x5FDFA9C5UL, 0x3FE0EFA5UL,
+ 0xBC54021BUL, 0xBC849DB9UL, 0x32D3D1A2UL, 0x3FE0E3ECUL, 0x27C57B52UL, 0x3C303A17UL,
+ 0x23395DECUL, 0x3FE0D83BUL, 0xE43F316AUL, 0xBC8BC14DUL, 0x2B7247F7UL, 0x3FE0CC92UL,
+ 0x16E24F71UL, 0x3C801EDCUL, 0x45E46C85UL, 0x3FE0C0F1UL, 0x06D21CEFUL, 0x3C84F989UL,
+ 0x6CF9890FUL, 0x3FE0B558UL, 0x4ADC610BUL, 0x3C88A62EUL, 0x9B1F3919UL, 0x3FE0A9C7UL,
+ 0x873D1D38UL, 0x3C75D16CUL, 0xCAC6F383UL, 0x3FE09E3EUL, 0x18316136UL, 0x3C814878UL,
+ 0xF66607E0UL, 0x3FE092BDUL, 0x800A3FD1UL, 0xBC868063UL, 0x18759BC8UL, 0x3FE08745UL,
+ 0x4BB284FFUL, 0x3C5186BEUL, 0x2B72A836UL, 0x3FE07BD4UL, 0x54458700UL, 0x3C732334UL,
+ 0x29DDF6DEUL, 0x3FE0706BUL, 0xE2B13C27UL, 0xBC7C91DFUL, 0x0E3C1F89UL, 0x3FE0650AUL,
+ 0x5799C397UL, 0xBC85CB7BUL, 0xD3158574UL, 0x3FE059B0UL, 0xA475B465UL, 0x3C7D73E2UL,
+ 0x72F654B1UL, 0x3FE04E5FUL, 0x3AA0D08CUL, 0x3C74C379UL, 0xE86E7F85UL, 0x3FE04315UL,
+ 0x1977C96EUL, 0xBC80A31CUL, 0x2E11BBCCUL, 0x3FE037D4UL, 0xEEADE11AUL, 0x3C556811UL,
+ 0x3E778061UL, 0x3FE02C9AUL, 0x535B085DUL, 0xBC619083UL, 0x143B0281UL, 0x3FE02168UL,
+ 0x0FC54EB6UL, 0xBC72BF31UL, 0xA9FB3335UL, 0x3FE0163DUL, 0x9AB8CDB7UL, 0x3C8B6129UL,
+ 0xFA5ABCBFUL, 0x3FE00B1AUL, 0xA7609F71UL, 0xBC74F6B2UL
};
#define __ _masm->
diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp
index 82ca18d8a1f..c8dafb2d023 100644
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp
+++ b/src/hotspot/cpu/x86/templateTable_x86.cpp
@@ -2196,8 +2196,7 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
const Register temp = rbx;
assert_different_registers(cache, index, temp);
- Label L_clinit_barrier_slow;
- Label resolved;
+ Label L_clinit_barrier_slow, L_done;
Bytecodes::Code code = bytecode();
@@ -2215,37 +2214,38 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
ShouldNotReachHere();
}
__ cmpl(temp, code); // have we resolved this bytecode?
- __ jcc(Assembler::equal, resolved);
-
- // resolve first time through
- // Class initialization barrier slow path lands here as well.
- __ bind(L_clinit_barrier_slow);
- address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
- __ movl(temp, code);
- __ call_VM(noreg, entry, temp);
- // Update registers with resolved info
- __ load_method_entry(cache, index);
-
- __ bind(resolved);
// Class initialization barrier for static methods
if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
const Register method = temp;
const Register klass = temp;
+ __ jcc(Assembler::notEqual, L_clinit_barrier_slow);
__ movptr(method, Address(cache, in_bytes(ResolvedMethodEntry::method_offset())));
__ load_method_holder(klass, method);
- __ clinit_barrier(klass, nullptr /*L_fast_path*/, &L_clinit_barrier_slow);
+ __ clinit_barrier(klass, &L_done, /*L_slow_path*/ nullptr);
+ __ bind(L_clinit_barrier_slow);
+ } else {
+ __ jcc(Assembler::equal, L_done);
}
+
+ // resolve first time through
+ // Class initialization barrier slow path lands here as well.
+ address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
+ __ movl(temp, code);
+ __ call_VM(noreg, entry, temp);
+ // Update registers with resolved info
+ __ load_method_entry(cache, index);
+ __ bind(L_done);
}
void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
- Register cache,
- Register index) {
+ Register cache,
+ Register index) {
const Register temp = rbx;
assert_different_registers(cache, index, temp);
- Label resolved;
+ Label L_clinit_barrier_slow, L_done;
Bytecodes::Code code = bytecode();
switch (code) {
@@ -2262,16 +2262,28 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
__ load_unsigned_byte(temp, Address(cache, in_bytes(ResolvedFieldEntry::put_code_offset())));
}
__ cmpl(temp, code); // have we resolved this bytecode?
- __ jcc(Assembler::equal, resolved);
+
+ // Class initialization barrier for static fields
+ if (VM_Version::supports_fast_class_init_checks() &&
+ (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) {
+ const Register field_holder = temp;
+
+ __ jcc(Assembler::notEqual, L_clinit_barrier_slow);
+ __ movptr(field_holder, Address(cache, in_bytes(ResolvedFieldEntry::field_holder_offset())));
+ __ clinit_barrier(field_holder, &L_done, /*L_slow_path*/ nullptr);
+ __ bind(L_clinit_barrier_slow);
+ } else {
+ __ jcc(Assembler::equal, L_done);
+ }
// resolve first time through
+ // Class initialization barrier slow path lands here as well.
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ movl(temp, code);
__ call_VM(noreg, entry, temp);
// Update registers with resolved info
__ load_field_entry(cache, index);
-
- __ bind(resolved);
+ __ bind(L_done);
}
void TemplateTable::load_resolved_field_entry(Register obj,
diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp
index f380f2ad271..213e988a581 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp
@@ -62,7 +62,7 @@ address VM_Version::_cpuinfo_segv_addr_apx = nullptr;
address VM_Version::_cpuinfo_cont_addr_apx = nullptr;
static BufferBlob* stub_blob;
-static const int stub_size = 2000;
+static const int stub_size = 2550;
int VM_Version::VM_Features::_features_bitmap_size = sizeof(VM_Version::VM_Features::_features_bitmap) / BytesPerLong;
@@ -73,10 +73,12 @@ extern "C" {
typedef void (*get_cpu_info_stub_t)(void*);
typedef void (*detect_virt_stub_t)(uint32_t, uint32_t*);
typedef void (*clear_apx_test_state_t)(void);
+ typedef void (*getCPUIDBrandString_stub_t)(void*);
}
static get_cpu_info_stub_t get_cpu_info_stub = nullptr;
static detect_virt_stub_t detect_virt_stub = nullptr;
static clear_apx_test_state_t clear_apx_test_state_stub = nullptr;
+static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = nullptr;
bool VM_Version::supports_clflush() {
// clflush should always be available on x86_64
@@ -139,7 +141,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT);
bool use_evex = FLAG_IS_DEFAULT(UseAVX) || (UseAVX > 2);
- Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4, std_cpuid24;
+ Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4, std_cpuid24, std_cpuid29;
Label sef_cpuid, sefsl1_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7;
Label ext_cpuid8, done, wrapup, vector_save_restore, apx_save_restore_warning;
Label legacy_setup, save_restore_except, legacy_save_restore, start_simd_check;
@@ -338,6 +340,16 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rdx);
+ //
+ // cpuid(0x29) APX NCI NDD NF (EAX = 29H, ECX = 0).
+ //
+ __ bind(std_cpuid29);
+ __ movl(rax, 0x29);
+ __ movl(rcx, 0);
+ __ cpuid();
+ __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid29_offset())));
+ __ movl(Address(rsi, 0), rbx);
+
//
// cpuid(0x24) Converged Vector ISA Main Leaf (EAX = 24H, ECX = 0).
//
@@ -2083,6 +2095,10 @@ bool VM_Version::is_intel_cascade_lake() {
return is_intel_skylake() && _stepping >= 5;
}
+bool VM_Version::is_intel_darkmont() {
+ return is_intel() && is_intel_server_family() && (_model == 0xCC || _model == 0xDD);
+}
+
// avx3_threshold() sets the threshold at which 64-byte instructions are used
// for implementing the array copy and clear operations.
// The Intel platforms that supports the serialize instruction
@@ -2117,6 +2133,8 @@ void VM_Version::initialize() {
g.generate_detect_virt());
clear_apx_test_state_stub = CAST_TO_FN_PTR(clear_apx_test_state_t,
g.clear_apx_test_state());
+ getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t,
+ g.generate_getCPUIDBrandString());
get_processor_features();
Assembler::precompute_instructions();
@@ -2173,15 +2191,6 @@ typedef enum {
TM_FLAG = 0x20000000
} FeatureEdxFlag;
-static BufferBlob* cpuid_brand_string_stub_blob;
-static const int cpuid_brand_string_stub_size = 550;
-
-extern "C" {
- typedef void (*getCPUIDBrandString_stub_t)(void*);
-}
-
-static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = nullptr;
-
// VM_Version statics
enum {
ExtendedFamilyIdLength_INTEL = 16,
@@ -2474,19 +2483,6 @@ const char* const _feature_extended_ecx_id[] = {
""
};
-void VM_Version::initialize_tsc(void) {
- ResourceMark rm;
-
- cpuid_brand_string_stub_blob = BufferBlob::create("getCPUIDBrandString_stub", cpuid_brand_string_stub_size);
- if (cpuid_brand_string_stub_blob == nullptr) {
- vm_exit_during_initialization("Unable to allocate getCPUIDBrandString_stub");
- }
- CodeBuffer c(cpuid_brand_string_stub_blob);
- VM_Version_StubGenerator g(&c);
- getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t,
- g.generate_getCPUIDBrandString());
-}
-
const char* VM_Version::cpu_model_description(void) {
uint32_t cpu_family = extended_cpu_family();
uint32_t cpu_model = extended_cpu_model();
@@ -2575,7 +2571,12 @@ void VM_Version::resolve_cpu_information_details(void) {
_no_of_threads = os::processor_count();
// find out number of threads per cpu package
- int threads_per_package = threads_per_core() * cores_per_cpu();
+ int threads_per_package = _cpuid_info.tpl_cpuidB1_ebx.bits.logical_cpus;
+ if (threads_per_package == 0) {
+ // Fallback code to avoid div by zero in subsequent code.
+ // CPUID 0Bh (ECX = 1) might return 0 on older AMD processor (EPYC 7763 at least)
+ threads_per_package = threads_per_core() * cores_per_cpu();
+ }
// use amount of threads visible to the process in order to guess number of sockets
_no_of_sockets = _no_of_threads / threads_per_package;
@@ -2729,6 +2730,10 @@ size_t VM_Version::cpu_write_support_string(char* const buf, size_t buf_len) {
WRITE_TO_BUF("Invariant TSC");
}
+ if (supports_hybrid()) {
+ WRITE_TO_BUF("Hybrid Architecture");
+ }
+
return written;
}
@@ -2914,7 +2919,8 @@ VM_Version::VM_Features VM_Version::CpuidInfo::feature_flags() const {
if (std_cpuid1_ecx.bits.popcnt != 0)
vm_features.set_feature(CPU_POPCNT);
if (sefsl1_cpuid7_edx.bits.apx_f != 0 &&
- xem_xcr0_eax.bits.apx_f != 0) {
+ xem_xcr0_eax.bits.apx_f != 0 &&
+ std_cpuid29_ebx.bits.apx_nci_ndd_nf != 0) {
vm_features.set_feature(CPU_APX_F);
}
if (std_cpuid1_ecx.bits.avx != 0 &&
diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp
index 54b3a93d64b..aa9a527e0b7 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.hpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.hpp
@@ -306,6 +306,14 @@ class VM_Version : public Abstract_VM_Version {
} bits;
};
+ union StdCpuidEax29Ecx0 {
+ uint32_t value;
+ struct {
+ uint32_t apx_nci_ndd_nf : 1,
+ : 31;
+ } bits;
+ };
+
union StdCpuid24MainLeafEax {
uint32_t value;
struct {
@@ -591,6 +599,10 @@ protected:
StdCpuid24MainLeafEax std_cpuid24_eax;
StdCpuid24MainLeafEbx std_cpuid24_ebx;
+ // cpuid function 0x29 APX Advanced Performance Extensions Leaf
+ // eax = 0x29, ecx = 0
+ StdCpuidEax29Ecx0 std_cpuid29_ebx;
+
// cpuid function 0xB (processor topology)
// ecx = 0
uint32_t tpl_cpuidB0_eax;
@@ -711,6 +723,7 @@ public:
static ByteSize std_cpuid0_offset() { return byte_offset_of(CpuidInfo, std_max_function); }
static ByteSize std_cpuid1_offset() { return byte_offset_of(CpuidInfo, std_cpuid1_eax); }
static ByteSize std_cpuid24_offset() { return byte_offset_of(CpuidInfo, std_cpuid24_eax); }
+ static ByteSize std_cpuid29_offset() { return byte_offset_of(CpuidInfo, std_cpuid29_ebx); }
static ByteSize dcp_cpuid4_offset() { return byte_offset_of(CpuidInfo, dcp_cpuid4_eax); }
static ByteSize sef_cpuid7_offset() { return byte_offset_of(CpuidInfo, sef_cpuid7_eax); }
static ByteSize sefsl1_cpuid7_offset() { return byte_offset_of(CpuidInfo, sefsl1_cpuid7_eax); }
@@ -760,7 +773,9 @@ public:
_features.set_feature(CPU_SSE2);
_features.set_feature(CPU_VZEROUPPER);
}
- static void set_apx_cpuFeatures() { _features.set_feature(CPU_APX_F); }
+ static void set_apx_cpuFeatures() {
+ _features.set_feature(CPU_APX_F);
+ }
static void set_bmi_cpuFeatures() {
_features.set_feature(CPU_BMI1);
_features.set_feature(CPU_BMI2);
@@ -923,6 +938,8 @@ public:
static bool is_intel_cascade_lake();
+ static bool is_intel_darkmont();
+
static int avx3_threshold();
static bool is_intel_tsc_synched_at_init();
@@ -1076,7 +1093,6 @@ public:
static bool supports_tscinv_ext(void);
- static void initialize_tsc();
static void initialize_cpu_information(void);
};
diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad
index 2eb748e350c..efe0482e095 100644
--- a/src/hotspot/cpu/x86/x86.ad
+++ b/src/hotspot/cpu/x86/x86.ad
@@ -7664,8 +7664,11 @@ instruct vcastFtoD_reg(vec dst, vec src) %{
instruct castFtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, rFlagsReg cr) %{
- predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
- type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4);
+ predicate(!VM_Version::supports_avx10_2() &&
+ !VM_Version::supports_avx512vl() &&
+ Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
+ type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4 &&
+ is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastF2X src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, KILL cr);
format %{ "vector_cast_f2x $dst,$src\t! using $xtmp1, $xtmp2, $xtmp3 and $xtmp4 as TEMP" %}
@@ -7687,7 +7690,8 @@ instruct castFtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec
%}
instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{
- predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) &&
+ predicate(!VM_Version::supports_avx10_2() &&
+ (VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastF2X src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr);
@@ -7709,6 +7713,33 @@ instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k
ins_pipe( pipe_slow );
%}
+instruct castFtoX_reg_avx10(vec dst, vec src) %{
+ predicate(VM_Version::supports_avx10_2() &&
+ is_integral_type(Matcher::vector_element_basic_type(n)));
+ match(Set dst (VectorCastF2X src));
+ format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %}
+ ins_encode %{
+ BasicType to_elem_bt = Matcher::vector_element_basic_type(this);
+ int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(this, $src);
+ __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct castFtoX_mem_avx10(vec dst, memory src) %{
+ predicate(VM_Version::supports_avx10_2() &&
+ is_integral_type(Matcher::vector_element_basic_type(n)));
+ match(Set dst (VectorCastF2X (LoadVector src)));
+ format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %}
+ ins_encode %{
+ int vlen = Matcher::vector_length(this);
+ BasicType to_elem_bt = Matcher::vector_element_basic_type(this);
+ int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(vlen * sizeof(jfloat));
+ __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
instruct vcastDtoF_reg(vec dst, vec src) %{
predicate(Matcher::vector_element_basic_type(n) == T_FLOAT);
match(Set dst (VectorCastD2X src));
@@ -7721,7 +7752,9 @@ instruct vcastDtoF_reg(vec dst, vec src) %{
%}
instruct castDtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, vec xtmp5, rFlagsReg cr) %{
- predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
+ predicate(!VM_Version::supports_avx10_2() &&
+ !VM_Version::supports_avx512vl() &&
+ Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastD2X src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, TEMP xtmp5, KILL cr);
@@ -7737,7 +7770,8 @@ instruct castDtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec
%}
instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{
- predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) &&
+ predicate(!VM_Version::supports_avx10_2() &&
+ (VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) &&
is_integral_type(Matcher::vector_element_basic_type(n)));
match(Set dst (VectorCastD2X src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr);
@@ -7753,6 +7787,33 @@ instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k
ins_pipe( pipe_slow );
%}
+instruct castDtoX_reg_avx10(vec dst, vec src) %{
+ predicate(VM_Version::supports_avx10_2() &&
+ is_integral_type(Matcher::vector_element_basic_type(n)));
+ match(Set dst (VectorCastD2X src));
+ format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %}
+ ins_encode %{
+ int vlen_enc = vector_length_encoding(this, $src);
+ BasicType to_elem_bt = Matcher::vector_element_basic_type(this);
+ __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct castDtoX_mem_avx10(vec dst, memory src) %{
+ predicate(VM_Version::supports_avx10_2() &&
+ is_integral_type(Matcher::vector_element_basic_type(n)));
+ match(Set dst (VectorCastD2X (LoadVector src)));
+ format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %}
+ ins_encode %{
+ int vlen = Matcher::vector_length(this);
+ int vlen_enc = vector_length_encoding(vlen * sizeof(jdouble));
+ BasicType to_elem_bt = Matcher::vector_element_basic_type(this);
+ __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
instruct vucast(vec dst, vec src) %{
match(Set dst (VectorUCastB2X src));
match(Set dst (VectorUCastS2X src));
diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad
index 0914bea82a1..62306b562d6 100644
--- a/src/hotspot/cpu/x86/x86_64.ad
+++ b/src/hotspot/cpu/x86/x86_64.ad
@@ -497,96 +497,96 @@ void reg_mask_init() {
// _ALL_REG_mask is generated by adlc from the all_reg register class below.
// We derive a number of subsets from it.
- _ANY_REG_mask = _ALL_REG_mask;
+ _ANY_REG_mask.assignFrom(_ALL_REG_mask);
if (PreserveFramePointer) {
- _ANY_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
- _ANY_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
+ _ANY_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
+ _ANY_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
}
if (need_r12_heapbase()) {
- _ANY_REG_mask.Remove(OptoReg::as_OptoReg(r12->as_VMReg()));
- _ANY_REG_mask.Remove(OptoReg::as_OptoReg(r12->as_VMReg()->next()));
+ _ANY_REG_mask.remove(OptoReg::as_OptoReg(r12->as_VMReg()));
+ _ANY_REG_mask.remove(OptoReg::as_OptoReg(r12->as_VMReg()->next()));
}
- _PTR_REG_mask = _ANY_REG_mask;
- _PTR_REG_mask.Remove(OptoReg::as_OptoReg(rsp->as_VMReg()));
- _PTR_REG_mask.Remove(OptoReg::as_OptoReg(rsp->as_VMReg()->next()));
- _PTR_REG_mask.Remove(OptoReg::as_OptoReg(r15->as_VMReg()));
- _PTR_REG_mask.Remove(OptoReg::as_OptoReg(r15->as_VMReg()->next()));
+ _PTR_REG_mask.assignFrom(_ANY_REG_mask);
+ _PTR_REG_mask.remove(OptoReg::as_OptoReg(rsp->as_VMReg()));
+ _PTR_REG_mask.remove(OptoReg::as_OptoReg(rsp->as_VMReg()->next()));
+ _PTR_REG_mask.remove(OptoReg::as_OptoReg(r15->as_VMReg()));
+ _PTR_REG_mask.remove(OptoReg::as_OptoReg(r15->as_VMReg()->next()));
if (!UseAPX) {
for (uint i = 0; i < sizeof(egprs)/sizeof(Register); i++) {
- _PTR_REG_mask.Remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg()));
- _PTR_REG_mask.Remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg()->next()));
+ _PTR_REG_mask.remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg()));
+ _PTR_REG_mask.remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg()->next()));
}
}
- _STACK_OR_PTR_REG_mask = _PTR_REG_mask;
- _STACK_OR_PTR_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());
+ _STACK_OR_PTR_REG_mask.assignFrom(_PTR_REG_mask);
+ _STACK_OR_PTR_REG_mask.or_with(STACK_OR_STACK_SLOTS_mask());
- _PTR_REG_NO_RBP_mask = _PTR_REG_mask;
- _PTR_REG_NO_RBP_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
- _PTR_REG_NO_RBP_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
+ _PTR_REG_NO_RBP_mask.assignFrom(_PTR_REG_mask);
+ _PTR_REG_NO_RBP_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
+ _PTR_REG_NO_RBP_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
- _PTR_NO_RAX_REG_mask = _PTR_REG_mask;
- _PTR_NO_RAX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()));
- _PTR_NO_RAX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()->next()));
+ _PTR_NO_RAX_REG_mask.assignFrom(_PTR_REG_mask);
+ _PTR_NO_RAX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg()));
+ _PTR_NO_RAX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg()->next()));
- _PTR_NO_RAX_RBX_REG_mask = _PTR_NO_RAX_REG_mask;
- _PTR_NO_RAX_RBX_REG_mask.Remove(OptoReg::as_OptoReg(rbx->as_VMReg()));
- _PTR_NO_RAX_RBX_REG_mask.Remove(OptoReg::as_OptoReg(rbx->as_VMReg()->next()));
+ _PTR_NO_RAX_RBX_REG_mask.assignFrom(_PTR_NO_RAX_REG_mask);
+ _PTR_NO_RAX_RBX_REG_mask.remove(OptoReg::as_OptoReg(rbx->as_VMReg()));
+ _PTR_NO_RAX_RBX_REG_mask.remove(OptoReg::as_OptoReg(rbx->as_VMReg()->next()));
- _LONG_REG_mask = _PTR_REG_mask;
- _STACK_OR_LONG_REG_mask = _LONG_REG_mask;
- _STACK_OR_LONG_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());
+ _LONG_REG_mask.assignFrom(_PTR_REG_mask);
+ _STACK_OR_LONG_REG_mask.assignFrom(_LONG_REG_mask);
+ _STACK_OR_LONG_REG_mask.or_with(STACK_OR_STACK_SLOTS_mask());
- _LONG_NO_RAX_RDX_REG_mask = _LONG_REG_mask;
- _LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()));
- _LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()->next()));
- _LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rdx->as_VMReg()));
- _LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rdx->as_VMReg()->next()));
+ _LONG_NO_RAX_RDX_REG_mask.assignFrom(_LONG_REG_mask);
+ _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg()));
+ _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg()->next()));
+ _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rdx->as_VMReg()));
+ _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rdx->as_VMReg()->next()));
- _LONG_NO_RCX_REG_mask = _LONG_REG_mask;
- _LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()));
- _LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()->next()));
+ _LONG_NO_RCX_REG_mask.assignFrom(_LONG_REG_mask);
+ _LONG_NO_RCX_REG_mask.remove(OptoReg::as_OptoReg(rcx->as_VMReg()));
+ _LONG_NO_RCX_REG_mask.remove(OptoReg::as_OptoReg(rcx->as_VMReg()->next()));
- _LONG_NO_RBP_R13_REG_mask = _LONG_REG_mask;
- _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
- _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
- _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()));
- _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()->next()));
+ _LONG_NO_RBP_R13_REG_mask.assignFrom(_LONG_REG_mask);
+ _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
+ _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
+ _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(r13->as_VMReg()));
+ _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(r13->as_VMReg()->next()));
- _INT_REG_mask = _ALL_INT_REG_mask;
+ _INT_REG_mask.assignFrom(_ALL_INT_REG_mask);
if (!UseAPX) {
for (uint i = 0; i < sizeof(egprs)/sizeof(Register); i++) {
- _INT_REG_mask.Remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg()));
+ _INT_REG_mask.remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg()));
}
}
if (PreserveFramePointer) {
- _INT_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
+ _INT_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
}
if (need_r12_heapbase()) {
- _INT_REG_mask.Remove(OptoReg::as_OptoReg(r12->as_VMReg()));
+ _INT_REG_mask.remove(OptoReg::as_OptoReg(r12->as_VMReg()));
}
- _STACK_OR_INT_REG_mask = _INT_REG_mask;
- _STACK_OR_INT_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());
+ _STACK_OR_INT_REG_mask.assignFrom(_INT_REG_mask);
+ _STACK_OR_INT_REG_mask.or_with(STACK_OR_STACK_SLOTS_mask());
- _INT_NO_RAX_RDX_REG_mask = _INT_REG_mask;
- _INT_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()));
- _INT_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rdx->as_VMReg()));
+ _INT_NO_RAX_RDX_REG_mask.assignFrom(_INT_REG_mask);
+ _INT_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg()));
+ _INT_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rdx->as_VMReg()));
- _INT_NO_RCX_REG_mask = _INT_REG_mask;
- _INT_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()));
+ _INT_NO_RCX_REG_mask.assignFrom(_INT_REG_mask);
+ _INT_NO_RCX_REG_mask.remove(OptoReg::as_OptoReg(rcx->as_VMReg()));
- _INT_NO_RBP_R13_REG_mask = _INT_REG_mask;
- _INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
- _INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()));
+ _INT_NO_RBP_R13_REG_mask.assignFrom(_INT_REG_mask);
+ _INT_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
+ _INT_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(r13->as_VMReg()));
// _FLOAT_REG_LEGACY_mask/_FLOAT_REG_EVEX_mask is generated by adlc
// from the float_reg_legacy/float_reg_evex register class.
- _FLOAT_REG_mask = VM_Version::supports_evex() ? _FLOAT_REG_EVEX_mask : _FLOAT_REG_LEGACY_mask;
+ _FLOAT_REG_mask.assignFrom(VM_Version::supports_evex() ? _FLOAT_REG_EVEX_mask : _FLOAT_REG_LEGACY_mask);
}
static bool generate_vzeroupper(Compile* C) {
@@ -756,7 +756,7 @@ static void emit_fp_min_max(MacroAssembler* masm, XMMRegister dst,
}
//=============================================================================
-const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
+const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::EMPTY;
int ConstantTable::calculate_table_base_offset() const {
return 0; // absolute addressing, no offset
@@ -1658,7 +1658,7 @@ bool Matcher::is_spillable_arg(int reg)
uint Matcher::int_pressure_limit()
{
- return (INTPRESSURE == -1) ? _INT_REG_mask.Size() : INTPRESSURE;
+ return (INTPRESSURE == -1) ? _INT_REG_mask.size() : INTPRESSURE;
}
uint Matcher::float_pressure_limit()
@@ -1666,7 +1666,7 @@ uint Matcher::float_pressure_limit()
// After experiment around with different values, the following default threshold
// works best for LCM's register pressure scheduling on x64.
uint dec_count = VM_Version::supports_evex() ? 4 : 2;
- uint default_float_pressure_threshold = _FLOAT_REG_mask.Size() - dec_count;
+ uint default_float_pressure_threshold = _FLOAT_REG_mask.size() - dec_count;
return (FLOATPRESSURE == -1) ? default_float_pressure_threshold : FLOATPRESSURE;
}
@@ -1678,30 +1678,25 @@ bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
}
// Register for DIVI projection of divmodI
-RegMask Matcher::divI_proj_mask() {
+const RegMask& Matcher::divI_proj_mask() {
return INT_RAX_REG_mask();
}
// Register for MODI projection of divmodI
-RegMask Matcher::modI_proj_mask() {
+const RegMask& Matcher::modI_proj_mask() {
return INT_RDX_REG_mask();
}
// Register for DIVL projection of divmodL
-RegMask Matcher::divL_proj_mask() {
+const RegMask& Matcher::divL_proj_mask() {
return LONG_RAX_REG_mask();
}
// Register for MODL projection of divmodL
-RegMask Matcher::modL_proj_mask() {
+const RegMask& Matcher::modL_proj_mask() {
return LONG_RDX_REG_mask();
}
-// Register for saving SP into on method handle invokes. Not used on x86_64.
-const RegMask Matcher::method_handle_invoke_SP_save_mask() {
- return NO_REG_mask();
-}
-
%}
//----------ENCODING BLOCK-----------------------------------------------------
@@ -11712,6 +11707,7 @@ instruct convD2F_reg_mem(regF dst, memory src)
// XXX do mem variants
instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr)
%{
+ predicate(!VM_Version::supports_avx10_2());
match(Set dst (ConvF2I src));
effect(KILL cr);
format %{ "convert_f2i $dst, $src" %}
@@ -11721,8 +11717,31 @@ instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr)
ins_pipe(pipe_slow);
%}
+instruct convF2I_reg_reg_avx10(rRegI dst, regF src)
+%{
+ predicate(VM_Version::supports_avx10_2());
+ match(Set dst (ConvF2I src));
+ format %{ "evcvttss2sisl $dst, $src" %}
+ ins_encode %{
+ __ evcvttss2sisl($dst$$Register, $src$$XMMRegister);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct convF2I_reg_mem_avx10(rRegI dst, memory src)
+%{
+ predicate(VM_Version::supports_avx10_2());
+ match(Set dst (ConvF2I (LoadF src)));
+ format %{ "evcvttss2sisl $dst, $src" %}
+ ins_encode %{
+ __ evcvttss2sisl($dst$$Register, $src$$Address);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr)
%{
+ predicate(!VM_Version::supports_avx10_2());
match(Set dst (ConvF2L src));
effect(KILL cr);
format %{ "convert_f2l $dst, $src"%}
@@ -11732,8 +11751,31 @@ instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr)
ins_pipe(pipe_slow);
%}
+instruct convF2L_reg_reg_avx10(rRegL dst, regF src)
+%{
+ predicate(VM_Version::supports_avx10_2());
+ match(Set dst (ConvF2L src));
+ format %{ "evcvttss2sisq $dst, $src" %}
+ ins_encode %{
+ __ evcvttss2sisq($dst$$Register, $src$$XMMRegister);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct convF2L_reg_mem_avx10(rRegL dst, memory src)
+%{
+ predicate(VM_Version::supports_avx10_2());
+ match(Set dst (ConvF2L (LoadF src)));
+ format %{ "evcvttss2sisq $dst, $src" %}
+ ins_encode %{
+ __ evcvttss2sisq($dst$$Register, $src$$Address);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr)
%{
+ predicate(!VM_Version::supports_avx10_2());
match(Set dst (ConvD2I src));
effect(KILL cr);
format %{ "convert_d2i $dst, $src"%}
@@ -11743,8 +11785,31 @@ instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr)
ins_pipe(pipe_slow);
%}
+instruct convD2I_reg_reg_avx10(rRegI dst, regD src)
+%{
+ predicate(VM_Version::supports_avx10_2());
+ match(Set dst (ConvD2I src));
+ format %{ "evcvttsd2sisl $dst, $src" %}
+ ins_encode %{
+ __ evcvttsd2sisl($dst$$Register, $src$$XMMRegister);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct convD2I_reg_mem_avx10(rRegI dst, memory src)
+%{
+ predicate(VM_Version::supports_avx10_2());
+ match(Set dst (ConvD2I (LoadD src)));
+ format %{ "evcvttsd2sisl $dst, $src" %}
+ ins_encode %{
+ __ evcvttsd2sisl($dst$$Register, $src$$Address);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr)
%{
+ predicate(!VM_Version::supports_avx10_2());
match(Set dst (ConvD2L src));
effect(KILL cr);
format %{ "convert_d2l $dst, $src"%}
@@ -11754,6 +11819,28 @@ instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr)
ins_pipe(pipe_slow);
%}
+instruct convD2L_reg_reg_avx10(rRegL dst, regD src)
+%{
+ predicate(VM_Version::supports_avx10_2());
+ match(Set dst (ConvD2L src));
+ format %{ "evcvttsd2sisq $dst, $src" %}
+ ins_encode %{
+ __ evcvttsd2sisq($dst$$Register, $src$$XMMRegister);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct convD2L_reg_mem_avx10(rRegL dst, memory src)
+%{
+ predicate(VM_Version::supports_avx10_2());
+ match(Set dst (ConvD2L (LoadD src)));
+ format %{ "evcvttsd2sisq $dst, $src" %}
+ ins_encode %{
+ __ evcvttsd2sisq($dst$$Register, $src$$Address);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
instruct round_double_reg(rRegL dst, regD src, rRegL rtmp, rcx_RegL rcx, rFlagsReg cr)
%{
match(Set dst (RoundD src));
diff --git a/src/hotspot/cpu/zero/assembler_zero.inline.hpp b/src/hotspot/cpu/zero/assembler_zero.inline.hpp
index 0a3f4fc25fa..d78eb39c973 100644
--- a/src/hotspot/cpu/zero/assembler_zero.inline.hpp
+++ b/src/hotspot/cpu/zero/assembler_zero.inline.hpp
@@ -26,7 +26,7 @@
#ifndef CPU_ZERO_ASSEMBLER_ZERO_INLINE_HPP
#define CPU_ZERO_ASSEMBLER_ZERO_INLINE_HPP
-#include "asm/assembler.inline.hpp"
+#include "asm/assembler.hpp"
#include "asm/codeBuffer.hpp"
#include "code/codeCache.hpp"
#include "runtime/handles.inline.hpp"
diff --git a/src/hotspot/cpu/zero/frame_zero.cpp b/src/hotspot/cpu/zero/frame_zero.cpp
index 52ccad2fa68..69bbea2972a 100644
--- a/src/hotspot/cpu/zero/frame_zero.cpp
+++ b/src/hotspot/cpu/zero/frame_zero.cpp
@@ -245,8 +245,6 @@ void frame::zero_print_on_error(int frame_index,
os::snprintf_checked(fieldbuf, buflen, "word[%d]", offset);
os::snprintf_checked(valuebuf, buflen, PTR_FORMAT, *addr);
zeroframe()->identify_word(frame_index, offset, fieldbuf, valuebuf, buflen);
- fieldbuf[buflen - 1] = '\0';
- valuebuf[buflen - 1] = '\0';
// Print the result
st->print_cr(" " PTR_FORMAT ": %-21s = %s", p2i(addr), fieldbuf, valuebuf);
diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp
index b2e406c205b..6e18097c992 100644
--- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp
+++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp
@@ -38,12 +38,6 @@
#include "opto/runtime.hpp"
#endif
-
-static address zero_null_code_stub() {
- address start = ShouldNotCallThisStub();
- return start;
-}
-
int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
VMRegPair *regs,
int total_args_passed) {
@@ -55,12 +49,9 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs,
- AdapterHandlerEntry* handler) {
- // foil any attempt to call the i2c, c2i or unverified c2i entries
- handler->set_entry_points(CAST_FROM_FN_PTR(address,zero_null_code_stub),
- CAST_FROM_FN_PTR(address,zero_null_code_stub),
- CAST_FROM_FN_PTR(address,zero_null_code_stub),
- nullptr);
+ address entry_address[AdapterBlob::ENTRY_COUNT]) {
+ ShouldNotCallThis();
+ return;
}
nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp
index 35cbd296a26..e1c7567a306 100644
--- a/src/hotspot/cpu/zero/vm_version_zero.cpp
+++ b/src/hotspot/cpu/zero/vm_version_zero.cpp
@@ -116,9 +116,8 @@ void VM_Version::initialize() {
}
// Enable error context decoding on known platforms
-#if defined(IA32) || defined(AMD64) || defined(ARM) || \
- defined(AARCH64) || defined(PPC) || defined(RISCV) || \
- defined(S390)
+#if defined(AMD64) || defined(ARM) || defined(AARCH64) || \
+ defined(PPC) || defined(RISCV) || defined(S390)
if (FLAG_IS_DEFAULT(DecodeErrorContext)) {
FLAG_SET_DEFAULT(DecodeErrorContext, true);
}
diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
index dbdc66b0eb6..5f81912c0d6 100644
--- a/src/hotspot/os/aix/os_aix.cpp
+++ b/src/hotspot/os/aix/os_aix.cpp
@@ -169,7 +169,7 @@ static void vmembk_print_on(outputStream* os);
////////////////////////////////////////////////////////////////////////////////
// global variables (for a description see os_aix.hpp)
-size_t os::Aix::_physical_memory = 0;
+physical_memory_size_type os::Aix::_physical_memory = 0;
pthread_t os::Aix::_main_thread = ((pthread_t)0);
@@ -254,43 +254,43 @@ static bool is_close_to_brk(address a) {
return false;
}
-bool os::free_memory(size_t& value) {
+bool os::free_memory(physical_memory_size_type& value) {
return Aix::available_memory(value);
}
-bool os::available_memory(size_t& value) {
+bool os::available_memory(physical_memory_size_type& value) {
return Aix::available_memory(value);
}
-bool os::Aix::available_memory(size_t& value) {
+bool os::Aix::available_memory(physical_memory_size_type& value) {
os::Aix::meminfo_t mi;
if (os::Aix::get_meminfo(&mi)) {
- value = static_cast(mi.real_free);
+ value = static_cast(mi.real_free);
return true;
} else {
return false;
}
}
-bool os::total_swap_space(size_t& value) {
+bool os::total_swap_space(physical_memory_size_type& value) {
perfstat_memory_total_t memory_info;
if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) {
return false;
}
- value = static_cast(memory_info.pgsp_total * 4 * K);
+ value = static_cast(memory_info.pgsp_total * 4 * K);
return true;
}
-bool os::free_swap_space(size_t& value) {
+bool os::free_swap_space(physical_memory_size_type& value) {
perfstat_memory_total_t memory_info;
if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) {
return false;
}
- value = static_cast(memory_info.pgsp_free * 4 * K);
+ value = static_cast(memory_info.pgsp_free * 4 * K);
return true;
}
-size_t os::physical_memory() {
+physical_memory_size_type os::physical_memory() {
return Aix::physical_memory();
}
@@ -329,7 +329,7 @@ void os::Aix::initialize_system_info() {
if (!os::Aix::get_meminfo(&mi)) {
assert(false, "os::Aix::get_meminfo failed.");
}
- _physical_memory = static_cast(mi.real_total);
+ _physical_memory = static_cast(mi.real_total);
}
// Helper function for tracing page sizes.
@@ -1054,7 +1054,7 @@ static void* dll_load_library(const char *filename, int *eno, char *ebuf, int eb
error_report = "dlerror returned no error description";
}
if (ebuf != nullptr && ebuflen > 0) {
- os::snprintf_checked(ebuf, ebuflen - 1, "%s, LIBPATH=%s, LD_LIBRARY_PATH=%s : %s",
+ os::snprintf_checked(ebuf, ebuflen, "%s, LIBPATH=%s, LD_LIBRARY_PATH=%s : %s",
filename, ::getenv("LIBPATH"), ::getenv("LD_LIBRARY_PATH"), error_report);
}
Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report);
@@ -2192,7 +2192,7 @@ jint os::init_2(void) {
os::Posix::init_2();
trcVerbose("processor count: %d", os::_processor_count);
- trcVerbose("physical memory: %zu", Aix::_physical_memory);
+ trcVerbose("physical memory: " PHYS_MEM_TYPE_FORMAT, Aix::_physical_memory);
// Initially build up the loaded dll map.
LoadedLibraries::reload();
diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp
index 1530f2adb76..a7bac40e79b 100644
--- a/src/hotspot/os/aix/os_aix.hpp
+++ b/src/hotspot/os/aix/os_aix.hpp
@@ -35,7 +35,7 @@ class os::Aix {
private:
- static size_t _physical_memory;
+ static physical_memory_size_type _physical_memory;
static pthread_t _main_thread;
// 0 = uninitialized, otherwise 16 bit number:
@@ -54,9 +54,9 @@ class os::Aix {
// 1 - EXTSHM=ON
static int _extshm;
- static bool available_memory(size_t& value);
- static bool free_memory(size_t& value);
- static size_t physical_memory() { return _physical_memory; }
+ static bool available_memory(physical_memory_size_type& value);
+ static bool free_memory(physical_memory_size_type& value);
+ static physical_memory_size_type physical_memory() { return _physical_memory; }
static void initialize_system_info();
// OS recognitions (AIX OS level) call this before calling Aix::os_version().
diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp
index 402abd7d579..7311afc197b 100644
--- a/src/hotspot/os/aix/porting_aix.cpp
+++ b/src/hotspot/os/aix/porting_aix.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012, 2024 SAP SE. All rights reserved.
+ * Copyright (c) 2025, 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
@@ -1154,7 +1155,7 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
error_report = "dlerror returned no error description";
}
if (ebuf != nullptr && ebuflen > 0) {
- os::snprintf_checked(ebuf, ebuflen - 1, "%s", error_report);
+ os::snprintf_checked(ebuf, ebuflen, "%s", error_report);
}
assert(false, "os::pd_dll_unload() ::dlclose() failed");
}
diff --git a/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp b/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp
index d0c06e2ebf1..3acaa9ab8f9 100644
--- a/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp
+++ b/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp
@@ -46,3 +46,7 @@ uint32_t ZNUMA::memory_id(uintptr_t addr) {
// NUMA support not enabled, assume everything belongs to node zero
return 0;
}
+
+int ZNUMA::numa_id_to_node(uint32_t numa_id) {
+ ShouldNotCallThis();
+}
diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
index b03dbd48cf8..3e5fa8b84e1 100644
--- a/src/hotspot/os/bsd/os_bsd.cpp
+++ b/src/hotspot/os/bsd/os_bsd.cpp
@@ -114,7 +114,7 @@
////////////////////////////////////////////////////////////////////////////////
// global variables
-size_t os::Bsd::_physical_memory = 0;
+physical_memory_size_type os::Bsd::_physical_memory = 0;
#ifdef __APPLE__
mach_timebase_info_data_t os::Bsd::_timebase_info = {0, 0};
@@ -133,19 +133,19 @@ static volatile int processor_id_next = 0;
////////////////////////////////////////////////////////////////////////////////
// utility functions
-bool os::available_memory(size_t& value) {
+bool os::available_memory(physical_memory_size_type& value) {
return Bsd::available_memory(value);
}
-bool os::free_memory(size_t& value) {
+bool os::free_memory(physical_memory_size_type& value) {
return Bsd::available_memory(value);
}
// Available here means free. Note that this number is of no much use. As an estimate
// for future memory pressure it is far too conservative, since MacOS will use a lot
// of unused memory for caches, and return it willingly in case of needs.
-bool os::Bsd::available_memory(size_t& value) {
- uint64_t available = static_cast(physical_memory() >> 2);
+bool os::Bsd::available_memory(physical_memory_size_type& value) {
+ physical_memory_size_type available = physical_memory() >> 2;
#ifdef __APPLE__
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
vm_statistics64_data_t vmstat;
@@ -160,7 +160,7 @@ bool os::Bsd::available_memory(size_t& value) {
return false;
}
#endif
- value = static_cast(available);
+ value = available;
return true;
}
@@ -180,35 +180,35 @@ void os::Bsd::print_uptime_info(outputStream* st) {
}
}
-bool os::total_swap_space(size_t& value) {
+bool os::total_swap_space(physical_memory_size_type& value) {
#if defined(__APPLE__)
struct xsw_usage vmusage;
size_t size = sizeof(vmusage);
if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) {
return false;
}
- value = static_cast(vmusage.xsu_total);
+ value = static_cast(vmusage.xsu_total);
return true;
#else
return false;
#endif
}
-bool os::free_swap_space(size_t& value) {
+bool os::free_swap_space(physical_memory_size_type& value) {
#if defined(__APPLE__)
struct xsw_usage vmusage;
size_t size = sizeof(vmusage);
if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) {
return false;
}
- value = static_cast(vmusage.xsu_avail);
+ value = static_cast(vmusage.xsu_avail);
return true;
#else
return false;
#endif
}
-size_t os::physical_memory() {
+physical_memory_size_type os::physical_memory() {
return Bsd::physical_memory();
}
@@ -231,8 +231,6 @@ size_t os::rss() {
// Cpu architecture string
#if defined(ZERO)
static char cpu_arch[] = ZERO_LIBARCH;
-#elif defined(IA32)
-static char cpu_arch[] = "i386";
#elif defined(AMD64)
static char cpu_arch[] = "amd64";
#elif defined(ARM)
@@ -286,7 +284,7 @@ void os::Bsd::initialize_system_info() {
len = sizeof(mem_val);
if (sysctl(mib, 2, &mem_val, &len, nullptr, 0) != -1) {
assert(len == sizeof(mem_val), "unexpected data size");
- _physical_memory = static_cast(mem_val);
+ _physical_memory = static_cast(mem_val);
} else {
_physical_memory = 256 * 1024 * 1024; // fallback (XXXBSD?)
}
@@ -297,7 +295,7 @@ void os::Bsd::initialize_system_info() {
// datasize rlimit restricts us anyway.
struct rlimit limits;
getrlimit(RLIMIT_DATA, &limits);
- _physical_memory = MIN2(_physical_memory, static_cast(limits.rlim_cur));
+ _physical_memory = MIN2(_physical_memory, static_cast(limits.rlim_cur));
}
#endif
}
@@ -1011,7 +1009,6 @@ bool os::dll_address_to_library_name(address addr, char* buf,
// same architecture as Hotspot is running on
void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebuflen) {
-#ifndef IA32
bool ieee_handling = IEEE_subnormal_handling_OK();
if (!ieee_handling) {
Events::log_dll_message(nullptr, "IEEE subnormal handling check failed before loading %s", filename);
@@ -1034,14 +1031,9 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebu
// numerical "accuracy", but we need to protect Java semantics first
// and foremost. See JDK-8295159.
- // This workaround is ineffective on IA32 systems because the MXCSR
- // register (which controls flush-to-zero mode) is not stored in the
- // legacy fenv.
-
fenv_t default_fenv;
int rtn = fegetenv(&default_fenv);
assert(rtn == 0, "fegetenv must succeed");
-#endif // IA32
void* result;
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
@@ -1061,7 +1053,6 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebu
} else {
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
log_info(os)("shared library load of %s was successful", filename);
-#ifndef IA32
if (! IEEE_subnormal_handling_OK()) {
// We just dlopen()ed a library that mangled the floating-point
// flags. Silently fix things now.
@@ -1086,7 +1077,6 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebu
assert(false, "fesetenv didn't work");
}
}
-#endif // IA32
}
return result;
@@ -1195,9 +1185,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
{EM_68K, EM_68K, ELFCLASS32, ELFDATA2MSB, (char*)"M68k"}
};
- #if (defined IA32)
- static Elf32_Half running_arch_code=EM_386;
- #elif (defined AMD64)
+ #if (defined AMD64)
static Elf32_Half running_arch_code=EM_X86_64;
#elif (defined __powerpc64__)
static Elf32_Half running_arch_code=EM_PPC64;
@@ -1219,7 +1207,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
static Elf32_Half running_arch_code=EM_68K;
#else
#error Method os::dll_load requires that one of following is defined:\
- IA32, AMD64, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K
+ AMD64, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K
#endif
// Identify compatibility class for VM's architecture and library's architecture
@@ -1469,12 +1457,12 @@ void os::print_memory_info(outputStream* st) {
st->print("Memory:");
st->print(" %zuk page", os::vm_page_size()>>10);
- size_t phys_mem = os::physical_memory();
- st->print(", physical %zuk",
+ physical_memory_size_type phys_mem = os::physical_memory();
+ st->print(", physical " PHYS_MEM_TYPE_FORMAT "k",
phys_mem >> 10);
- size_t avail_mem = 0;
+ physical_memory_size_type avail_mem = 0;
(void)os::available_memory(avail_mem);
- st->print("(%zuk free)",
+ st->print("(" PHYS_MEM_TYPE_FORMAT "k free)",
avail_mem >> 10);
if((sysctlbyname("vm.swapusage", &swap_usage, &size, nullptr, 0) == 0) || (errno == ENOMEM)) {
@@ -2495,7 +2483,7 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
error_report = "dlerror returned no error description";
}
if (ebuf != nullptr && ebuflen > 0) {
- os::snprintf_checked(ebuf, ebuflen - 1, "%s", error_report);
+ os::snprintf_checked(ebuf, ebuflen, "%s", error_report);
}
}
diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp
index 173cc5a40ad..82002917f39 100644
--- a/src/hotspot/os/bsd/os_bsd.hpp
+++ b/src/hotspot/os/bsd/os_bsd.hpp
@@ -42,12 +42,12 @@ class os::Bsd {
protected:
- static size_t _physical_memory;
+ static physical_memory_size_type _physical_memory;
static pthread_t _main_thread;
- static bool available_memory(size_t& value);
- static bool free_memory(size_t& value);
- static size_t physical_memory() { return _physical_memory; }
+ static bool available_memory(physical_memory_size_type& value);
+ static bool free_memory(physical_memory_size_type& value);
+ static physical_memory_size_type physical_memory() { return _physical_memory; }
static void initialize_system_info();
static void rebuild_cpu_to_node_map();
diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
index f935e2cbb9c..f5c4abeb4ca 100644
--- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
@@ -665,15 +665,13 @@ int CgroupSubsystem::active_processor_count() {
* -1 for unlimited
* OSCONTAINER_ERROR for not supported
*/
-jlong CgroupSubsystem::memory_limit_in_bytes() {
+jlong CgroupSubsystem::memory_limit_in_bytes(julong upper_bound) {
CachingCgroupController* contrl = memory_controller();
CachedMetric* memory_limit = contrl->metrics_cache();
if (!memory_limit->should_check_metric()) {
return memory_limit->value();
}
- julong phys_mem = static_cast(os::Linux::physical_memory());
- log_trace(os, container)("total physical memory: " JULONG_FORMAT, phys_mem);
- jlong mem_limit = contrl->controller()->read_memory_limit_in_bytes(phys_mem);
+ jlong mem_limit = contrl->controller()->read_memory_limit_in_bytes(upper_bound);
// Update cached metric to avoid re-reading container settings too often
memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT);
return mem_limit;
@@ -841,21 +839,16 @@ jlong CgroupController::limit_from_str(char* limit_str) {
// CgroupSubsystem implementations
-jlong CgroupSubsystem::memory_and_swap_limit_in_bytes() {
- julong phys_mem = static_cast(os::Linux::physical_memory());
- julong host_swap = os::Linux::host_swap();
- return memory_controller()->controller()->memory_and_swap_limit_in_bytes(phys_mem, host_swap);
+jlong CgroupSubsystem::memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) {
+ return memory_controller()->controller()->memory_and_swap_limit_in_bytes(upper_mem_bound, upper_swap_bound);
}
-jlong CgroupSubsystem::memory_and_swap_usage_in_bytes() {
- julong phys_mem = static_cast(os::Linux::physical_memory());
- julong host_swap = os::Linux::host_swap();
- return memory_controller()->controller()->memory_and_swap_usage_in_bytes(phys_mem, host_swap);
+jlong CgroupSubsystem::memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) {
+ return memory_controller()->controller()->memory_and_swap_usage_in_bytes(upper_mem_bound, upper_swap_bound);
}
-jlong CgroupSubsystem::memory_soft_limit_in_bytes() {
- julong phys_mem = static_cast(os::Linux::physical_memory());
- return memory_controller()->controller()->memory_soft_limit_in_bytes(phys_mem);
+jlong CgroupSubsystem::memory_soft_limit_in_bytes(julong upper_bound) {
+ return memory_controller()->controller()->memory_soft_limit_in_bytes(upper_bound);
}
jlong CgroupSubsystem::memory_throttle_limit_in_bytes() {
@@ -894,7 +887,6 @@ jlong CgroupSubsystem::cpu_usage_in_micros() {
return cpuacct_controller()->cpu_usage_in_micros();
}
-void CgroupSubsystem::print_version_specific_info(outputStream* st) {
- julong phys_mem = static_cast(os::Linux::physical_memory());
- memory_controller()->controller()->print_version_specific_info(st, phys_mem);
+void CgroupSubsystem::print_version_specific_info(outputStream* st, julong upper_mem_bound) {
+ memory_controller()->controller()->print_version_specific_info(st, upper_mem_bound);
}
diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
index 22e57d56c93..62a61432665 100644
--- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
@@ -233,14 +233,14 @@ class CgroupMemoryController: public CHeapObj {
public:
virtual jlong read_memory_limit_in_bytes(julong upper_bound) = 0;
virtual jlong memory_usage_in_bytes() = 0;
- virtual jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) = 0;
- virtual jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) = 0;
+ virtual jlong memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) = 0;
+ virtual jlong memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) = 0;
virtual jlong memory_soft_limit_in_bytes(julong upper_bound) = 0;
virtual jlong memory_throttle_limit_in_bytes() = 0;
virtual jlong memory_max_usage_in_bytes() = 0;
virtual jlong rss_usage_in_bytes() = 0;
virtual jlong cache_usage_in_bytes() = 0;
- virtual void print_version_specific_info(outputStream* st, julong host_mem) = 0;
+ virtual void print_version_specific_info(outputStream* st, julong upper_mem_bound) = 0;
virtual bool needs_hierarchy_adjustment() = 0;
virtual bool is_read_only() = 0;
virtual const char* subsystem_path() = 0;
@@ -251,7 +251,7 @@ class CgroupMemoryController: public CHeapObj {
class CgroupSubsystem: public CHeapObj {
public:
- jlong memory_limit_in_bytes();
+ jlong memory_limit_in_bytes(julong upper_bound);
int active_processor_count();
virtual jlong pids_max() = 0;
@@ -272,14 +272,14 @@ class CgroupSubsystem: public CHeapObj {
jlong cpu_usage_in_micros();
jlong memory_usage_in_bytes();
- jlong memory_and_swap_limit_in_bytes();
- jlong memory_and_swap_usage_in_bytes();
- jlong memory_soft_limit_in_bytes();
+ jlong memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound);
+ jlong memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound);
+ jlong memory_soft_limit_in_bytes(julong upper_bound);
jlong memory_throttle_limit_in_bytes();
jlong memory_max_usage_in_bytes();
jlong rss_usage_in_bytes();
jlong cache_usage_in_bytes();
- void print_version_specific_info(outputStream* st);
+ void print_version_specific_info(outputStream* st, julong upper_mem_bound);
};
// Utility class for storing info retrieved from /proc/cgroups,
diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
index 64cb53eda28..90f01565b84 100644
--- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
@@ -136,35 +136,35 @@ bool CgroupV1Controller::needs_hierarchy_adjustment() {
}
static inline
-void verbose_log(julong read_mem_limit, julong host_mem) {
+void verbose_log(julong read_mem_limit, julong upper_mem_bound) {
if (log_is_enabled(Debug, os, container)) {
jlong mem_limit = (jlong)read_mem_limit; // account for negative values
- if (mem_limit < 0 || read_mem_limit >= host_mem) {
+ if (mem_limit < 0 || read_mem_limit >= upper_mem_bound) {
const char *reason;
if (mem_limit == OSCONTAINER_ERROR) {
reason = "failed";
} else if (mem_limit == -1) {
reason = "unlimited";
} else {
- assert(read_mem_limit >= host_mem, "Expected read value exceeding host_mem");
+ assert(read_mem_limit >= upper_mem_bound, "Expected read value exceeding upper memory bound");
// Exceeding physical memory is treated as unlimited. This implementation
// caps it at host_mem since Cg v1 has no value to represent 'max'.
reason = "ignored";
}
- log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT,
- reason, mem_limit, host_mem);
+ log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", upper bound is " JLONG_FORMAT,
+ reason, mem_limit, upper_mem_bound);
}
}
}
-jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) {
+jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong upper_bound) {
julong memlimit;
CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.limit_in_bytes", "Memory Limit", memlimit);
- if (memlimit >= phys_mem) {
- verbose_log(memlimit, phys_mem);
+ if (memlimit >= upper_bound) {
+ verbose_log(memlimit, upper_bound);
return (jlong)-1;
} else {
- verbose_log(memlimit, phys_mem);
+ verbose_log(memlimit, upper_bound);
return (jlong)memlimit;
}
}
@@ -181,10 +181,10 @@ jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) {
* * -1 if there isn't any limit in place (note: includes values which exceed a physical
* upper bound)
*/
-jlong CgroupV1MemoryController::read_mem_swap(julong host_total_memsw) {
+jlong CgroupV1MemoryController::read_mem_swap(julong upper_memsw_bound) {
julong memswlimit;
CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit);
- if (memswlimit >= host_total_memsw) {
+ if (memswlimit >= upper_memsw_bound) {
log_trace(os, container)("Memory and Swap Limit is: Unlimited");
return (jlong)-1;
} else {
@@ -192,8 +192,8 @@ jlong CgroupV1MemoryController::read_mem_swap(julong host_total_memsw) {
}
}
-jlong CgroupV1MemoryController::memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) {
- jlong memory_swap = read_mem_swap(host_mem + host_swap);
+jlong CgroupV1MemoryController::memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) {
+ jlong memory_swap = read_mem_swap(upper_mem_bound + upper_swap_bound);
if (memory_swap == -1) {
return memory_swap;
}
@@ -202,7 +202,7 @@ jlong CgroupV1MemoryController::memory_and_swap_limit_in_bytes(julong host_mem,
// supported.
jlong swappiness = read_mem_swappiness();
if (swappiness == 0 || memory_swap == OSCONTAINER_ERROR) {
- jlong memlimit = read_memory_limit_in_bytes(host_mem);
+ jlong memlimit = read_memory_limit_in_bytes(upper_mem_bound);
if (memory_swap == OSCONTAINER_ERROR) {
log_trace(os, container)("Memory and Swap Limit has been reset to " JLONG_FORMAT " because swap is not supported", memlimit);
} else {
@@ -220,9 +220,9 @@ jlong memory_swap_usage_impl(CgroupController* ctrl) {
return (jlong)memory_swap_usage;
}
-jlong CgroupV1MemoryController::memory_and_swap_usage_in_bytes(julong phys_mem, julong host_swap) {
- jlong memory_sw_limit = memory_and_swap_limit_in_bytes(phys_mem, host_swap);
- jlong memory_limit = read_memory_limit_in_bytes(phys_mem);
+jlong CgroupV1MemoryController::memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) {
+ jlong memory_sw_limit = memory_and_swap_limit_in_bytes(upper_mem_bound, upper_swap_bound);
+ jlong memory_limit = read_memory_limit_in_bytes(upper_mem_bound);
if (memory_sw_limit > 0 && memory_limit > 0) {
jlong delta_swap = memory_sw_limit - memory_limit;
if (delta_swap > 0) {
@@ -238,10 +238,10 @@ jlong CgroupV1MemoryController::read_mem_swappiness() {
return (jlong)swappiness;
}
-jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong phys_mem) {
+jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong upper_bound) {
julong memsoftlimit;
CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.soft_limit_in_bytes", "Memory Soft Limit", memsoftlimit);
- if (memsoftlimit >= phys_mem) {
+ if (memsoftlimit >= upper_bound) {
log_trace(os, container)("Memory Soft Limit is: Unlimited");
return (jlong)-1;
} else {
@@ -336,10 +336,10 @@ jlong CgroupV1MemoryController::kernel_memory_usage_in_bytes() {
return (jlong)kmem_usage;
}
-jlong CgroupV1MemoryController::kernel_memory_limit_in_bytes(julong phys_mem) {
+jlong CgroupV1MemoryController::kernel_memory_limit_in_bytes(julong upper_bound) {
julong kmem_limit;
CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.limit_in_bytes", "Kernel Memory Limit", kmem_limit);
- if (kmem_limit >= phys_mem) {
+ if (kmem_limit >= upper_bound) {
return (jlong)-1;
}
return (jlong)kmem_limit;
@@ -351,9 +351,9 @@ jlong CgroupV1MemoryController::kernel_memory_max_usage_in_bytes() {
return (jlong)kmem_max_usage;
}
-void CgroupV1MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) {
+void CgroupV1MemoryController::print_version_specific_info(outputStream* st, julong mem_bound) {
jlong kmem_usage = kernel_memory_usage_in_bytes();
- jlong kmem_limit = kernel_memory_limit_in_bytes(phys_mem);
+ jlong kmem_limit = kernel_memory_limit_in_bytes(mem_bound);
jlong kmem_max_usage = kernel_memory_max_usage_in_bytes();
OSContainer::print_container_helper(st, kmem_limit, "kernel_memory_limit_in_bytes");
diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
index 33bf2ed6e55..02b2c6a9fce 100644
--- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
@@ -79,17 +79,17 @@ class CgroupV1MemoryController final : public CgroupMemoryController {
}
jlong read_memory_limit_in_bytes(julong upper_bound) override;
jlong memory_usage_in_bytes() override;
- jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) override;
- jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) override;
+ jlong memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) override;
+ jlong memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) override;
jlong memory_soft_limit_in_bytes(julong upper_bound) override;
jlong memory_throttle_limit_in_bytes() override;
jlong memory_max_usage_in_bytes() override;
jlong rss_usage_in_bytes() override;
jlong cache_usage_in_bytes() override;
jlong kernel_memory_usage_in_bytes();
- jlong kernel_memory_limit_in_bytes(julong host_mem);
+ jlong kernel_memory_limit_in_bytes(julong upper_bound);
jlong kernel_memory_max_usage_in_bytes();
- void print_version_specific_info(outputStream* st, julong host_mem) override;
+ void print_version_specific_info(outputStream* st, julong upper_mem_bound) override;
bool needs_hierarchy_adjustment() override {
return reader()->needs_hierarchy_adjustment();
}
@@ -101,7 +101,7 @@ class CgroupV1MemoryController final : public CgroupMemoryController {
const char* cgroup_path() override { return reader()->cgroup_path(); }
private:
jlong read_mem_swappiness();
- jlong read_mem_swap(julong host_total_memsw);
+ jlong read_mem_swap(julong upper_memsw_bound);
public:
CgroupV1MemoryController(const CgroupV1Controller& reader)
diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
index 661f7e909b5..38258a1f049 100644
--- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
@@ -181,7 +181,7 @@ jlong CgroupV2MemoryController::memory_usage_in_bytes() {
return (jlong)memusage;
}
-jlong CgroupV2MemoryController::memory_soft_limit_in_bytes(julong phys_mem) {
+jlong CgroupV2MemoryController::memory_soft_limit_in_bytes(julong upper_bound) {
jlong mem_soft_limit;
CONTAINER_READ_NUMBER_CHECKED_MAX(reader(), "/memory.low", "Memory Soft Limit", mem_soft_limit);
return mem_soft_limit;
@@ -224,19 +224,19 @@ jlong CgroupV2MemoryController::cache_usage_in_bytes() {
// respectively. In order to properly report a cgroup v1 like
// compound value we need to sum the two values. Setting a swap limit
// without also setting a memory limit is not allowed.
-jlong CgroupV2MemoryController::memory_and_swap_limit_in_bytes(julong phys_mem,
- julong host_swap /* unused in cg v2 */) {
+jlong CgroupV2MemoryController::memory_and_swap_limit_in_bytes(julong upper_mem_bound,
+ julong upper_swap_bound /* unused in cg v2 */) {
jlong swap_limit;
bool is_ok = reader()->read_number_handle_max("/memory.swap.max", &swap_limit);
if (!is_ok) {
// Some container tests rely on this trace logging to happen.
log_trace(os, container)("Swap Limit failed: %d", OSCONTAINER_ERROR);
// swap disabled at kernel level, treat it as no swap
- return read_memory_limit_in_bytes(phys_mem);
+ return read_memory_limit_in_bytes(upper_mem_bound);
}
log_trace(os, container)("Swap Limit is: " JLONG_FORMAT, swap_limit);
if (swap_limit >= 0) {
- jlong memory_limit = read_memory_limit_in_bytes(phys_mem);
+ jlong memory_limit = read_memory_limit_in_bytes(upper_mem_bound);
assert(memory_limit >= 0, "swap limit without memory limit?");
return memory_limit + swap_limit;
}
@@ -252,7 +252,7 @@ jlong memory_swap_current_value(CgroupV2Controller* ctrl) {
return (jlong)swap_current;
}
-jlong CgroupV2MemoryController::memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) {
+jlong CgroupV2MemoryController::memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) {
jlong memory_usage = memory_usage_in_bytes();
if (memory_usage >= 0) {
jlong swap_current = memory_swap_current_value(reader());
@@ -276,7 +276,7 @@ jlong memory_limit_value(CgroupV2Controller* ctrl) {
* memory limit in bytes or
* -1 for unlimited, OSCONTAINER_ERROR for an error
*/
-jlong CgroupV2MemoryController::read_memory_limit_in_bytes(julong phys_mem) {
+jlong CgroupV2MemoryController::read_memory_limit_in_bytes(julong upper_bound) {
jlong limit = memory_limit_value(reader());
if (log_is_enabled(Trace, os, container)) {
if (limit == -1) {
@@ -287,18 +287,18 @@ jlong CgroupV2MemoryController::read_memory_limit_in_bytes(julong phys_mem) {
}
if (log_is_enabled(Debug, os, container)) {
julong read_limit = (julong)limit; // avoid signed/unsigned compare
- if (limit < 0 || read_limit >= phys_mem) {
+ if (limit < 0 || read_limit >= upper_bound) {
const char* reason;
if (limit == -1) {
reason = "unlimited";
} else if (limit == OSCONTAINER_ERROR) {
reason = "failed";
} else {
- assert(read_limit >= phys_mem, "Expected mem limit to exceed host memory");
+ assert(read_limit >= upper_bound, "Expected mem limit to exceed upper memory bound");
reason = "ignored";
}
- log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT,
- reason, limit, phys_mem);
+ log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", upper bound is " JLONG_FORMAT,
+ reason, limit, upper_bound);
}
}
return limit;
@@ -327,7 +327,7 @@ bool CgroupV2Controller::needs_hierarchy_adjustment() {
return strcmp(_cgroup_path, "/") != 0;
}
-void CgroupV2MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) {
+void CgroupV2MemoryController::print_version_specific_info(outputStream* st, julong upper_mem_bound) {
jlong swap_current = memory_swap_current_value(reader());
jlong swap_limit = memory_swap_limit_value(reader());
diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
index e26f37925ca..07db126ce90 100644
--- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
@@ -115,15 +115,15 @@ class CgroupV2MemoryController final: public CgroupMemoryController {
}
jlong read_memory_limit_in_bytes(julong upper_bound) override;
- jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swp) override;
- jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swp) override;
+ jlong memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) override;
+ jlong memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) override;
jlong memory_soft_limit_in_bytes(julong upper_bound) override;
jlong memory_throttle_limit_in_bytes() override;
jlong memory_usage_in_bytes() override;
jlong memory_max_usage_in_bytes() override;
jlong rss_usage_in_bytes() override;
jlong cache_usage_in_bytes() override;
- void print_version_specific_info(outputStream* st, julong host_mem) override;
+ void print_version_specific_info(outputStream* st, julong upper_mem_bound) override;
bool is_read_only() override {
return reader()->is_read_only();
}
diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp
index 2dc6fa7b9c9..7c27080eb5e 100644
--- a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp
+++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp
@@ -46,6 +46,10 @@ class CompilerThreadTimeoutLinux : public CHeapObj {
bool init_timeout();
void arm();
void disarm();
+ void reset() {
+ disarm();
+ arm();
+ };
};
#endif //LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP
diff --git a/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp b/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp
index 74e69655940..ab7498b313c 100644
--- a/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp
+++ b/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp
@@ -32,12 +32,35 @@
#include "runtime/os.hpp"
#include "utilities/debug.hpp"
+static uint* z_numa_id_to_node = nullptr;
+static uint32_t* z_node_to_numa_id = nullptr;
+
void ZNUMA::pd_initialize() {
_enabled = UseNUMA;
+ size_t configured_nodes = 0;
+
+ if (UseNUMA) {
+ const size_t max_nodes = os::Linux::numa_num_configured_nodes();
+ z_numa_id_to_node = NEW_C_HEAP_ARRAY(uint, max_nodes, mtGC);
+ configured_nodes = os::numa_get_leaf_groups(z_numa_id_to_node, 0);
+
+ z_node_to_numa_id = NEW_C_HEAP_ARRAY(uint32_t, max_nodes, mtGC);
+
+ // Fill the array with invalid NUMA ids
+ for (uint32_t i = 0; i < max_nodes; i++) {
+ z_node_to_numa_id[i] = (uint32_t)-1;
+ }
+
+ // Fill the reverse mappings
+ for (uint32_t i = 0; i < configured_nodes; i++) {
+ z_node_to_numa_id[z_numa_id_to_node[i]] = i;
+ }
+ }
+
// UseNUMA and is_faked() are mutually excluded in zArguments.cpp.
_count = UseNUMA
- ? os::Linux::numa_max_node() + 1
+ ? configured_nodes
: !FLAG_IS_DEFAULT(ZFakeNUMA)
? ZFakeNUMA
: 1; // No NUMA nodes
@@ -54,7 +77,7 @@ uint32_t ZNUMA::id() {
return 0;
}
- return os::Linux::get_node_by_cpu(ZCPU::id());
+ return z_node_to_numa_id[os::Linux::get_node_by_cpu(ZCPU::id())];
}
uint32_t ZNUMA::memory_id(uintptr_t addr) {
@@ -63,14 +86,21 @@ uint32_t ZNUMA::memory_id(uintptr_t addr) {
return 0;
}
- uint32_t id = (uint32_t)-1;
+ int node = -1;
- if (ZSyscall::get_mempolicy((int*)&id, nullptr, 0, (void*)addr, MPOL_F_NODE | MPOL_F_ADDR) == -1) {
+ if (ZSyscall::get_mempolicy(&node, nullptr, 0, (void*)addr, MPOL_F_NODE | MPOL_F_ADDR) == -1) {
ZErrno err;
fatal("Failed to get NUMA id for memory at " PTR_FORMAT " (%s)", addr, err.to_string());
}
- assert(id < _count, "Invalid NUMA id");
+ DEBUG_ONLY(const int max_nodes = os::Linux::numa_num_configured_nodes();)
+ assert(node < max_nodes, "NUMA node is out of bounds node=%d, max=%d", node, max_nodes);
- return id;
+ return z_node_to_numa_id[node];
+}
+
+int ZNUMA::numa_id_to_node(uint32_t numa_id) {
+ assert(numa_id < _count, "NUMA id out of range 0 <= %ud <= %ud", numa_id, _count);
+
+ return (int)z_numa_id_to_node[numa_id];
}
diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp
index 84dfcbd6614..25ffd0b8078 100644
--- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp
+++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp
@@ -629,7 +629,7 @@ retry:
size_t ZPhysicalMemoryBacking::commit_numa_preferred(zbacking_offset offset, size_t length, uint32_t numa_id) const {
// Setup NUMA policy to allocate memory from a preferred node
- os::Linux::numa_set_preferred((int)numa_id);
+ os::Linux::numa_set_preferred(ZNUMA::numa_id_to_node(numa_id));
const size_t committed = commit_default(offset, length);
diff --git a/src/hotspot/os/linux/memMapPrinter_linux.cpp b/src/hotspot/os/linux/memMapPrinter_linux.cpp
index 91fd552eec5..228a823dcb0 100644
--- a/src/hotspot/os/linux/memMapPrinter_linux.cpp
+++ b/src/hotspot/os/linux/memMapPrinter_linux.cpp
@@ -106,6 +106,7 @@ public:
PRINTIF(info.swap > 0, "swap");
PRINTIF(info.ht, "huge");
PRINTIF(info.anonhugepages > 0, "thp");
+ PRINTIF(info.thpeligible, "thpel");
PRINTIF(info.hg, "thpad");
PRINTIF(info.nh, "nothp");
if (num_printed == 0) {
@@ -135,6 +136,7 @@ public:
st->print_cr(" com: mapping committed (swap space reserved)");
st->print_cr(" swap: mapping partly or completely swapped out");
st->print_cr(" thp: mapping uses THP");
+ st->print_cr(" thpel: mapping is THP-eligible");
st->print_cr(" thpad: mapping is THP-madvised");
st->print_cr(" nothp: mapping is forbidden to use THP");
st->print_cr(" huge: mapping uses hugetlb pages");
diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp
index 899e7535fde..561f2d4926c 100644
--- a/src/hotspot/os/linux/osContainer_linux.cpp
+++ b/src/hotspot/os/linux/osContainer_linux.cpp
@@ -84,8 +84,8 @@ void OSContainer::init() {
// We can be in one of two cases:
// 1.) On a physical Linux system without any limit
// 2.) On a physical Linux system with a limit enforced by other means (like systemd slice)
- any_mem_cpu_limit_present = cgroup_subsystem->memory_limit_in_bytes() > 0 ||
- os::Linux::active_processor_count() != cgroup_subsystem->active_processor_count();
+ any_mem_cpu_limit_present = memory_limit_in_bytes() > 0 ||
+ os::Linux::active_processor_count() != active_processor_count();
if (any_mem_cpu_limit_present) {
reason = " because either a cpu or a memory limit is present";
} else {
@@ -103,24 +103,47 @@ const char * OSContainer::container_type() {
return cgroup_subsystem->container_type();
}
+bool OSContainer::available_memory_in_container(julong& value) {
+ jlong mem_limit = memory_limit_in_bytes();
+ jlong mem_usage = memory_usage_in_bytes();
+
+ if (mem_limit > 0 && mem_usage <= 0) {
+ log_debug(os, container)("container memory usage failed: " JLONG_FORMAT, mem_usage);
+ }
+
+ if (mem_limit <= 0 || mem_usage <= 0) {
+ return false;
+ }
+
+ value = mem_limit > mem_usage ? static_cast(mem_limit - mem_usage) : 0;
+
+ return true;
+}
+
jlong OSContainer::memory_limit_in_bytes() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
- return cgroup_subsystem->memory_limit_in_bytes();
+ julong phys_mem = static_cast(os::Linux::physical_memory());
+ return cgroup_subsystem->memory_limit_in_bytes(phys_mem);
}
jlong OSContainer::memory_and_swap_limit_in_bytes() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
- return cgroup_subsystem->memory_and_swap_limit_in_bytes();
+ julong phys_mem = static_cast(os::Linux::physical_memory());
+ julong host_swap = os::Linux::host_swap();
+ return cgroup_subsystem->memory_and_swap_limit_in_bytes(phys_mem, host_swap);
}
jlong OSContainer::memory_and_swap_usage_in_bytes() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
- return cgroup_subsystem->memory_and_swap_usage_in_bytes();
+ julong phys_mem = static_cast(os::Linux::physical_memory());
+ julong host_swap = os::Linux::host_swap();
+ return cgroup_subsystem->memory_and_swap_usage_in_bytes(phys_mem, host_swap);
}
jlong OSContainer::memory_soft_limit_in_bytes() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
- return cgroup_subsystem->memory_soft_limit_in_bytes();
+ julong phys_mem = static_cast(os::Linux::physical_memory());
+ return cgroup_subsystem->memory_soft_limit_in_bytes(phys_mem);
}
jlong OSContainer::memory_throttle_limit_in_bytes() {
@@ -150,7 +173,8 @@ jlong OSContainer::cache_usage_in_bytes() {
void OSContainer::print_version_specific_info(outputStream* st) {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
- cgroup_subsystem->print_version_specific_info(st);
+ julong phys_mem = static_cast(os::Linux::physical_memory());
+ cgroup_subsystem->print_version_specific_info(st, phys_mem);
}
char * OSContainer::cpu_cpuset_cpus() {
diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp
index d9b024dbbb5..6258714c48b 100644
--- a/src/hotspot/os/linux/osContainer_linux.hpp
+++ b/src/hotspot/os/linux/osContainer_linux.hpp
@@ -50,6 +50,7 @@ class OSContainer: AllStatic {
static inline bool is_containerized();
static const char * container_type();
+ static bool available_memory_in_container(julong& value);
static jlong memory_limit_in_bytes();
static jlong memory_and_swap_limit_in_bytes();
static jlong memory_and_swap_usage_in_bytes();
diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index 3d44d839735..8137347dd4f 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -154,13 +154,12 @@ enum CoredumpFilterBit {
////////////////////////////////////////////////////////////////////////////////
// global variables
-size_t os::Linux::_physical_memory = 0;
+physical_memory_size_type os::Linux::_physical_memory = 0;
address os::Linux::_initial_thread_stack_bottom = nullptr;
uintptr_t os::Linux::_initial_thread_stack_size = 0;
int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = nullptr;
-int (*os::Linux::_pthread_setname_np)(pthread_t, const char*) = nullptr;
pthread_t os::Linux::_main_thread;
bool os::Linux::_supports_fast_thread_cpu_time = false;
const char * os::Linux::_libc_version = nullptr;
@@ -214,32 +213,19 @@ static bool suppress_primordial_thread_resolution = false;
// utility functions
-julong os::Linux::available_memory_in_container() {
- julong avail_mem = static_cast(-1L);
- if (OSContainer::is_containerized()) {
- jlong mem_limit = OSContainer::memory_limit_in_bytes();
- jlong mem_usage;
- if (mem_limit > 0 && (mem_usage = OSContainer::memory_usage_in_bytes()) < 1) {
- log_debug(os, container)("container memory usage failed: " JLONG_FORMAT ", using host value", mem_usage);
- }
- if (mem_limit > 0 && mem_usage > 0) {
- avail_mem = mem_limit > mem_usage ? (julong)mem_limit - (julong)mem_usage : 0;
- }
+bool os::available_memory(physical_memory_size_type& value) {
+ julong avail_mem = 0;
+ if (OSContainer::is_containerized() && OSContainer::available_memory_in_container(avail_mem)) {
+ log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem);
+ value = static_cast(avail_mem);
+ return true;
}
- return avail_mem;
-}
-bool os::available_memory(size_t& value) {
return Linux::available_memory(value);
}
-bool os::Linux::available_memory(size_t& value) {
- julong avail_mem = available_memory_in_container();
- if (avail_mem != static_cast(-1L)) {
- log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem);
- value = static_cast(avail_mem);
- return true;
- }
+bool os::Linux::available_memory(physical_memory_size_type& value) {
+ julong avail_mem = static_cast(-1L);
FILE *fp = os::fopen("/proc/meminfo", "r");
if (fp != nullptr) {
@@ -253,47 +239,48 @@ bool os::Linux::available_memory(size_t& value) {
fclose(fp);
}
if (avail_mem == static_cast(-1L)) {
- size_t free_mem = 0;
+ physical_memory_size_type free_mem = 0;
if (!free_memory(free_mem)) {
return false;
}
avail_mem = static_cast(free_mem);
}
log_trace(os)("available memory: " JULONG_FORMAT, avail_mem);
- value = static_cast(avail_mem);
+ value = static_cast(avail_mem);
return true;
}
-bool os::free_memory(size_t& value) {
+bool os::free_memory(physical_memory_size_type& value) {
+ julong free_mem = 0;
+ if (OSContainer::is_containerized() && OSContainer::available_memory_in_container(free_mem)) {
+ log_trace(os)("free container memory: " JULONG_FORMAT, free_mem);
+ value = static_cast(free_mem);
+ return true;
+ }
+
return Linux::free_memory(value);
}
-bool os::Linux::free_memory(size_t& value) {
+bool os::Linux::free_memory(physical_memory_size_type& value) {
// values in struct sysinfo are "unsigned long"
struct sysinfo si;
- julong free_mem = available_memory_in_container();
- if (free_mem != static_cast(-1L)) {
- log_trace(os)("free container memory: " JULONG_FORMAT, free_mem);
- value = static_cast(free_mem);
- return true;
- }
int ret = sysinfo(&si);
if (ret != 0) {
return false;
}
- free_mem = (julong)si.freeram * si.mem_unit;
+ julong free_mem = (julong)si.freeram * si.mem_unit;
log_trace(os)("free memory: " JULONG_FORMAT, free_mem);
- value = static_cast(free_mem);
+ value = static_cast(free_mem);
return true;
}
-bool os::total_swap_space(size_t& value) {
+bool os::total_swap_space(physical_memory_size_type& value) {
if (OSContainer::is_containerized()) {
jlong memory_and_swap_limit_in_bytes = OSContainer::memory_and_swap_limit_in_bytes();
jlong memory_limit_in_bytes = OSContainer::memory_limit_in_bytes();
if (memory_limit_in_bytes > 0 && memory_and_swap_limit_in_bytes > 0) {
- value = static_cast(memory_and_swap_limit_in_bytes - memory_limit_in_bytes);
+ value = static_cast(memory_and_swap_limit_in_bytes - memory_limit_in_bytes);
return true;
}
} // fallback to the host swap space if the container did return the unbound value of -1
@@ -303,30 +290,30 @@ bool os::total_swap_space(size_t& value) {
assert(false, "sysinfo failed in total_swap_space(): %s", os::strerror(errno));
return false;
}
- value = static_cast(si.totalswap * si.mem_unit);
+ value = static_cast(si.totalswap) * si.mem_unit;
return true;
}
-static bool host_free_swap_f(size_t& value) {
+static bool host_free_swap_f(physical_memory_size_type& value) {
struct sysinfo si;
int ret = sysinfo(&si);
if (ret != 0) {
assert(false, "sysinfo failed in host_free_swap_f(): %s", os::strerror(errno));
return false;
}
- value = static_cast(si.freeswap * si.mem_unit);
+ value = static_cast(si.freeswap) * si.mem_unit;
return true;
}
-bool os::free_swap_space(size_t& value) {
+bool os::free_swap_space(physical_memory_size_type& value) {
// os::total_swap_space() might return the containerized limit which might be
// less than host_free_swap(). The upper bound of free swap needs to be the lower of the two.
- size_t total_swap_space = 0;
- size_t host_free_swap = 0;
+ physical_memory_size_type total_swap_space = 0;
+ physical_memory_size_type host_free_swap = 0;
if (!os::total_swap_space(total_swap_space) || !host_free_swap_f(host_free_swap)) {
return false;
}
- size_t host_free_swap_val = MIN2(total_swap_space, host_free_swap);
+ physical_memory_size_type host_free_swap_val = MIN2(total_swap_space, host_free_swap);
if (OSContainer::is_containerized()) {
jlong mem_swap_limit = OSContainer::memory_and_swap_limit_in_bytes();
jlong mem_limit = OSContainer::memory_limit_in_bytes();
@@ -342,31 +329,31 @@ bool os::free_swap_space(size_t& value) {
jlong delta_usage = mem_swap_usage - mem_usage;
if (delta_usage >= 0) {
jlong free_swap = delta_limit - delta_usage;
- value = free_swap >= 0 ? static_cast(free_swap) : 0;
+ value = free_swap >= 0 ? static_cast(free_swap) : 0;
return true;
}
}
}
// unlimited or not supported. Fall through to return host value
log_trace(os,container)("os::free_swap_space: container_swap_limit=" JLONG_FORMAT
- " container_mem_limit=" JLONG_FORMAT " returning host value: %zu",
+ " container_mem_limit=" JLONG_FORMAT " returning host value: " PHYS_MEM_TYPE_FORMAT,
mem_swap_limit, mem_limit, host_free_swap_val);
}
value = host_free_swap_val;
return true;
}
-size_t os::physical_memory() {
+physical_memory_size_type os::physical_memory() {
if (OSContainer::is_containerized()) {
jlong mem_limit;
if ((mem_limit = OSContainer::memory_limit_in_bytes()) > 0) {
log_trace(os)("total container memory: " JLONG_FORMAT, mem_limit);
- return static_cast(mem_limit);
+ return static_cast(mem_limit);
}
}
- size_t phys_mem = Linux::physical_memory();
- log_trace(os)("total system memory: %zu", phys_mem);
+ physical_memory_size_type phys_mem = Linux::physical_memory();
+ log_trace(os)("total system memory: " PHYS_MEM_TYPE_FORMAT, phys_mem);
return phys_mem;
}
@@ -550,7 +537,7 @@ void os::Linux::initialize_system_info() {
fclose(fp);
}
}
- _physical_memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE));
+ _physical_memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE));
assert(processor_count() > 0, "linux error");
}
@@ -860,11 +847,9 @@ static void *thread_native_entry(Thread *thread) {
osthread->set_thread_id(checked_cast(os::current_thread_id()));
if (UseNUMA) {
- int lgrp_id = os::numa_get_group_id();
- if (lgrp_id != -1) {
- thread->set_lgrp_id(lgrp_id);
- }
+ thread->update_lgrp_id();
}
+
// initialize signal mask for this thread
PosixSignals::hotspot_sigmask(thread);
@@ -1191,10 +1176,7 @@ bool os::create_attached_thread(JavaThread* thread) {
thread->set_osthread(osthread);
if (UseNUMA) {
- int lgrp_id = os::numa_get_group_id();
- if (lgrp_id != -1) {
- thread->set_lgrp_id(lgrp_id);
- }
+ thread->update_lgrp_id();
}
if (os::is_primordial_thread()) {
@@ -1813,9 +1795,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
{EM_LOONGARCH, EM_LOONGARCH, ELFCLASS64, ELFDATA2LSB, (char*)"LoongArch"},
};
-#if (defined IA32)
- static Elf32_Half running_arch_code=EM_386;
-#elif (defined AMD64) || (defined X32)
+#if (defined AMD64)
static Elf32_Half running_arch_code=EM_X86_64;
#elif (defined __sparc) && (defined _LP64)
static Elf32_Half running_arch_code=EM_SPARCV9;
@@ -1849,7 +1829,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
static Elf32_Half running_arch_code=EM_LOONGARCH;
#else
#error Method os::dll_load requires that one of following is defined:\
- AARCH64, ALPHA, ARM, AMD64, IA32, LOONGARCH64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, RISCV, S390, SH, __sparc
+ AARCH64, ALPHA, ARM, AMD64, LOONGARCH64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, RISCV, S390, SH, __sparc
#endif
// Identify compatibility class for VM's architecture and library's architecture
@@ -1911,7 +1891,6 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
}
void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
-#ifndef IA32
bool ieee_handling = IEEE_subnormal_handling_OK();
if (!ieee_handling) {
Events::log_dll_message(nullptr, "IEEE subnormal handling check failed before loading %s", filename);
@@ -1934,14 +1913,9 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
// numerical "accuracy", but we need to protect Java semantics first
// and foremost. See JDK-8295159.
- // This workaround is ineffective on IA32 systems because the MXCSR
- // register (which controls flush-to-zero mode) is not stored in the
- // legacy fenv.
-
fenv_t default_fenv;
int rtn = fegetenv(&default_fenv);
assert(rtn == 0, "fegetenv must succeed");
-#endif // IA32
void* result;
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
@@ -1961,7 +1935,6 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
} else {
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
log_info(os)("shared library load of %s was successful", filename);
-#ifndef IA32
// Quickly test to make sure subnormals are correctly handled.
if (! IEEE_subnormal_handling_OK()) {
// We just dlopen()ed a library that mangled the floating-point flags.
@@ -1987,7 +1960,6 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
assert(false, "fesetenv didn't work");
}
}
-#endif // IA32
}
return result;
}
@@ -2609,12 +2581,12 @@ void os::print_memory_info(outputStream* st) {
// values in struct sysinfo are "unsigned long"
struct sysinfo si;
sysinfo(&si);
- size_t phys_mem = physical_memory();
- st->print(", physical %zuk",
+ physical_memory_size_type phys_mem = physical_memory();
+ st->print(", physical " PHYS_MEM_TYPE_FORMAT "k",
phys_mem >> 10);
- size_t avail_mem = 0;
+ physical_memory_size_type avail_mem = 0;
(void)os::available_memory(avail_mem);
- st->print("(%zuk free)",
+ st->print("(" PHYS_MEM_TYPE_FORMAT "k free)",
avail_mem >> 10);
st->print(", swap " UINT64_FORMAT "k",
((jlong)si.totalswap * si.mem_unit) >> 10);
@@ -2631,7 +2603,7 @@ void os::print_memory_info(outputStream* st) {
// before "flags" so if we find a second "model name", then the
// "flags" field is considered missing.
static bool print_model_name_and_flags(outputStream* st, char* buf, size_t buflen) {
-#if defined(IA32) || defined(AMD64)
+#if defined(AMD64)
// Other platforms have less repetitive cpuinfo files
FILE *fp = os::fopen("/proc/cpuinfo", "r");
if (fp) {
@@ -2690,7 +2662,7 @@ static void print_sys_devices_cpu_info(outputStream* st) {
}
// we miss the cpufreq entries on Power and s390x
-#if defined(IA32) || defined(AMD64)
+#if defined(AMD64)
_print_ascii_file_h("BIOS frequency limitation", "/sys/devices/system/cpu/cpu0/cpufreq/bios_limit", st);
_print_ascii_file_h("Frequency switch latency (ns)", "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_transition_latency", st);
_print_ascii_file_h("Available cpu frequencies", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies", st);
@@ -2743,7 +2715,7 @@ void os::jfr_report_memory_info() {
#endif // INCLUDE_JFR
-#if defined(AMD64) || defined(IA32) || defined(X32)
+#if defined(AMD64)
const char* search_string = "model name";
#elif defined(M68K)
const char* search_string = "CPU";
@@ -2796,8 +2768,6 @@ void os::get_summary_cpu_info(char* cpuinfo, size_t length) {
strncpy(cpuinfo, "x86_64", length);
#elif defined(ARM) // Order wrt. AARCH64 is relevant!
strncpy(cpuinfo, "ARM", length);
-#elif defined(IA32)
- strncpy(cpuinfo, "x86_32", length);
#elif defined(PPC)
strncpy(cpuinfo, "PPC64", length);
#elif defined(RISCV)
@@ -3097,14 +3067,9 @@ int os::Linux::sched_getcpu_syscall(void) {
unsigned int cpu = 0;
long retval = -1;
-#if defined(IA32)
- #ifndef SYS_getcpu
- #define SYS_getcpu 318
- #endif
- retval = syscall(SYS_getcpu, &cpu, nullptr, nullptr);
-#elif defined(AMD64)
-// Unfortunately we have to bring all these macros here from vsyscall.h
-// to be able to compile on old linuxes.
+#if defined(AMD64)
+ // Unfortunately we have to bring all these macros here from vsyscall.h
+ // to be able to compile on old linuxes.
#define __NR_vgetcpu 2
#define VSYSCALL_START (-10UL << 20)
#define VSYSCALL_SIZE 1024
@@ -4376,10 +4341,6 @@ void os::init(void) {
// _main_thread points to the thread that created/loaded the JVM.
Linux::_main_thread = pthread_self();
- // retrieve entry point for pthread_setname_np
- Linux::_pthread_setname_np =
- (int(*)(pthread_t, const char*))dlsym(RTLD_DEFAULT, "pthread_setname_np");
-
check_pax();
// Check the availability of MADV_POPULATE_WRITE.
@@ -4481,87 +4442,6 @@ void os::Linux::disable_numa(const char* reason, bool warning) {
FLAG_SET_ERGO(UseNUMAInterleaving, false);
}
-#if defined(IA32) && !defined(ZERO)
-/*
- * Work-around (execute code at a high address) for broken NX emulation using CS limit,
- * Red Hat patch "Exec-Shield" (IA32 only).
- *
- * Map and execute at a high VA to prevent CS lazy updates race with SMP MM
- * invalidation.Further code generation by the JVM will no longer cause CS limit
- * updates.
- *
- * Affects IA32: RHEL 5 & 6, Ubuntu 10.04 (LTS), 10.10, 11.04, 11.10, 12.04.
- * @see JDK-8023956
- */
-static void workaround_expand_exec_shield_cs_limit() {
- assert(os::Linux::initial_thread_stack_bottom() != nullptr, "sanity");
- size_t page_size = os::vm_page_size();
-
- /*
- * JDK-8197429
- *
- * Expand the stack mapping to the end of the initial stack before
- * attempting to install the codebuf. This is needed because newer
- * Linux kernels impose a distance of a megabyte between stack
- * memory and other memory regions. If we try to install the
- * codebuf before expanding the stack the installation will appear
- * to succeed but we'll get a segfault later if we expand the stack
- * in Java code.
- *
- */
- if (os::is_primordial_thread()) {
- address limit = os::Linux::initial_thread_stack_bottom();
- if (! DisablePrimordialThreadGuardPages) {
- limit += StackOverflow::stack_red_zone_size() +
- StackOverflow::stack_yellow_zone_size();
- }
- os::Linux::expand_stack_to(limit);
- }
-
- /*
- * Take the highest VA the OS will give us and exec
- *
- * Although using -(pagesz) as mmap hint works on newer kernel as you would
- * think, older variants affected by this work-around don't (search forward only).
- *
- * On the affected distributions, we understand the memory layout to be:
- *
- * TASK_LIMIT= 3G, main stack base close to TASK_LIMT.
- *
- * A few pages south main stack will do it.
- *
- * If we are embedded in an app other than launcher (initial != main stack),
- * we don't have much control or understanding of the address space, just let it slide.
- */
- char* hint = (char*)(os::Linux::initial_thread_stack_bottom() -
- (StackOverflow::stack_guard_zone_size() + page_size));
- char* codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread);
-
- if (codebuf == nullptr) {
- // JDK-8197429: There may be a stack gap of one megabyte between
- // the limit of the stack and the nearest memory region: this is a
- // Linux kernel workaround for CVE-2017-1000364. If we failed to
- // map our codebuf, try again at an address one megabyte lower.
- hint -= 1 * M;
- codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread);
- }
-
- if ((codebuf == nullptr) || (!os::commit_memory(codebuf, page_size, true))) {
- return; // No matter, we tried, best effort.
- }
-
- log_info(os)("[CS limit NX emulation work-around, exec code at: %p]", codebuf);
-
- // Some code to exec: the 'ret' instruction
- codebuf[0] = 0xC3;
-
- // Call the code in the codebuf
- __asm__ volatile("call *%0" : : "r"(codebuf));
-
- // keep the page mapped so CS limit isn't reduced.
-}
-#endif // defined(IA32) && !defined(ZERO)
-
// this is called _after_ the global arguments have been parsed
jint os::init_2(void) {
@@ -4582,17 +4462,10 @@ jint os::init_2(void) {
return JNI_ERR;
}
-#if defined(IA32) && !defined(ZERO)
- // Need to ensure we've determined the process's initial stack to
- // perform the workaround
- Linux::capture_initial_stack(JavaThread::stack_size_at_create());
- workaround_expand_exec_shield_cs_limit();
-#else
suppress_primordial_thread_resolution = Arguments::created_by_java_launcher();
if (!suppress_primordial_thread_resolution) {
Linux::capture_initial_stack(JavaThread::stack_size_at_create());
}
-#endif
Linux::libpthread_init();
Linux::sched_getcpu_init();
@@ -4856,14 +4729,24 @@ uint os::processor_id() {
}
void os::set_native_thread_name(const char *name) {
- if (Linux::_pthread_setname_np) {
- char buf [16]; // according to glibc manpage, 16 chars incl. '/0'
- (void) os::snprintf(buf, sizeof(buf), "%s", name);
- buf[sizeof(buf) - 1] = '\0';
- const int rc = Linux::_pthread_setname_np(pthread_self(), buf);
- // ERANGE should not happen; all other errors should just be ignored.
- assert(rc != ERANGE, "pthread_setname_np failed");
+ char buf[16]; // according to glibc manpage, 16 chars incl. '/0'
+ // We may need to truncate the thread name. Since a common pattern
+ // for thread names is to be both longer than 15 chars and have a
+ // trailing number ("DispatcherWorkerThread21", "C2 CompilerThread#54" etc),
+ // we preserve the end of the thread name by truncating the middle
+ // (e.g. "Dispatc..read21").
+ const size_t len = strlen(name);
+ if (len < sizeof(buf)) {
+ strcpy(buf, name);
+ } else {
+ (void) os::snprintf(buf, sizeof(buf), "%.7s..%.6s", name, name + len - 6);
}
+ // Note: we use the system call here instead of calling pthread_setname_np
+ // since this is the only way to make ASAN aware of our thread names. Even
+ // though ASAN intercepts both prctl and pthread_setname_np, it only processes
+ // the thread name given to the former.
+ int rc = prctl(PR_SET_NAME, buf);
+ assert(rc == 0, "prctl(PR_SET_NAME) failed");
}
////////////////////////////////////////////////////////////////////////////////
@@ -5455,7 +5338,7 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
error_report = "dlerror returned no error description";
}
if (ebuf != nullptr && ebuflen > 0) {
- os::snprintf_checked(ebuf, ebuflen - 1, "%s", error_report);
+ os::snprintf_checked(ebuf, ebuflen, "%s", error_report);
}
}
diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp
index 497d383200d..b77cd9f3c81 100644
--- a/src/hotspot/os/linux/os_linux.hpp
+++ b/src/hotspot/os/linux/os_linux.hpp
@@ -33,7 +33,6 @@ class os::Linux {
friend class os;
static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *);
- static int (*_pthread_setname_np)(pthread_t, const char*);
static address _initial_thread_stack_bottom;
static uintptr_t _initial_thread_stack_size;
@@ -50,11 +49,11 @@ class os::Linux {
protected:
- static size_t _physical_memory;
+ static physical_memory_size_type _physical_memory;
static pthread_t _main_thread;
- static bool available_memory(size_t& value);
- static bool free_memory(size_t& value);
+ static bool available_memory(physical_memory_size_type& value);
+ static bool free_memory(physical_memory_size_type& value);
static void initialize_system_info();
@@ -117,7 +116,7 @@ class os::Linux {
static address initial_thread_stack_bottom(void) { return _initial_thread_stack_bottom; }
static uintptr_t initial_thread_stack_size(void) { return _initial_thread_stack_size; }
- static size_t physical_memory() { return _physical_memory; }
+ static physical_memory_size_type physical_memory() { return _physical_memory; }
static julong host_swap();
static intptr_t* ucontext_get_sp(const ucontext_t* uc);
diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp
index 7caf8f98a00..5708194521f 100644
--- a/src/hotspot/os/linux/os_perf_linux.cpp
+++ b/src/hotspot/os/linux/os_perf_linux.cpp
@@ -705,11 +705,9 @@ bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(st
if (atoi(entry->d_name) != 0) {
jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
- buffer[PATH_MAX - 1] = '\0';
if (is_dir(buffer)) {
jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name);
- buffer[PATH_MAX - 1] = '\0';
if (fsize(buffer, size) != OS_ERR) {
return true;
}
@@ -724,7 +722,6 @@ void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() {
char buffer[PATH_MAX];
jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name);
- buffer[PATH_MAX - 1] = '\0';
if ((fp = os::fopen(buffer, "r")) != nullptr) {
if (fgets(buffer, PATH_MAX, fp) != nullptr) {
char* start, *end;
@@ -752,7 +749,6 @@ char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() {
char* cmdline = nullptr;
jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name);
- buffer[PATH_MAX - 1] = '\0';
if ((fp = os::fopen(buffer, "r")) != nullptr) {
size_t size = 0;
char dummy;
@@ -787,7 +783,6 @@ char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {
char buffer[PATH_MAX];
jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);
- buffer[PATH_MAX - 1] = '\0';
return os::realpath(buffer, _exePath, PATH_MAX);
}
@@ -1001,7 +996,6 @@ int64_t NetworkPerformanceInterface::NetworkPerformance::read_counter(const char
return -1;
}
- buf[num_bytes] = '\0';
int64_t value = strtoll(buf, nullptr, 10);
return value;
diff --git a/src/hotspot/os/linux/procMapsParser.cpp b/src/hotspot/os/linux/procMapsParser.cpp
index 71b828bcefb..47c5c6cc594 100644
--- a/src/hotspot/os/linux/procMapsParser.cpp
+++ b/src/hotspot/os/linux/procMapsParser.cpp
@@ -76,8 +76,16 @@ void ProcSmapsParser::scan_additional_line(ProcSmapsInfo& out) {
SCAN("Private_Hugetlb", out.private_hugetlb);
SCAN("Shared_Hugetlb", out.shared_hugetlb);
SCAN("Swap", out.swap);
- int i = 0;
#undef SCAN
+
+ // scan THPeligible into a bool
+ int thpel = 0;
+ if (::sscanf(_line, "THPeligible: %d", &thpel) == 1) {
+ assert(thpel == 1 || thpel == 0, "Unexpected value %d", thpel);
+ out.thpeligible = (thpel == 1);
+ return;
+ }
+
// scan some flags too
if (strncmp(_line, "VmFlags:", 8) == 0) {
#define SCAN(flag) { out.flag = (::strstr(_line + 8, " " #flag) != nullptr); }
diff --git a/src/hotspot/os/linux/procMapsParser.hpp b/src/hotspot/os/linux/procMapsParser.hpp
index 0971c4fb084..06035333b2f 100644
--- a/src/hotspot/os/linux/procMapsParser.hpp
+++ b/src/hotspot/os/linux/procMapsParser.hpp
@@ -49,6 +49,7 @@ struct ProcSmapsInfo {
size_t shared_hugetlb;
size_t anonhugepages;
size_t swap;
+ bool thpeligible;
bool rd, wr, ex;
bool sh; // shared
bool nr; // no reserve
@@ -64,7 +65,7 @@ struct ProcSmapsInfo {
from = to = nullptr;
prot[0] = filename[0] = '\0';
kernelpagesize = rss = private_hugetlb = shared_hugetlb = anonhugepages = swap = 0;
- rd = wr = ex = sh = nr = hg = ht = nh = false;
+ thpeligible = rd = wr = ex = sh = nr = hg = ht = nh = false;
}
};
diff --git a/src/hotspot/os/posix/os_posix.inline.hpp b/src/hotspot/os/posix/os_posix.inline.hpp
index 67be82e4d63..f1ec9411f2a 100644
--- a/src/hotspot/os/posix/os_posix.inline.hpp
+++ b/src/hotspot/os/posix/os_posix.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2025, 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
@@ -34,9 +34,6 @@
#include
#include
-// Aix does not have NUMA support but need these for compilation.
-inline bool os::numa_has_group_homing() { AIX_ONLY(ShouldNotReachHere();) return false; }
-
// Platform Mutex/Monitor implementation
inline void PlatformMutex::lock() {
diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp
index ed83487265c..2cc0263d291 100644
--- a/src/hotspot/os/posix/perfMemory_posix.cpp
+++ b/src/hotspot/os/posix/perfMemory_posix.cpp
@@ -26,6 +26,7 @@
#include "classfile/vmSymbols.hpp"
#include "jvm_io.h"
#include "logging/log.hpp"
+#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "nmt/memTracker.hpp"
@@ -71,9 +72,7 @@ static char* create_standard_memory(size_t size) {
// commit memory
if (!os::commit_memory(mapAddress, size, !ExecMem)) {
- if (PrintMiscellaneous && Verbose) {
- warning("Could not commit PerfData memory\n");
- }
+ log_debug(perf)("could not commit PerfData memory");
os::release_memory(mapAddress, size);
return nullptr;
}
@@ -297,11 +296,12 @@ static DIR *open_directory_secure(const char* dirname) {
RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result);
if (result == OS_ERR) {
// Directory doesn't exist or is a symlink, so there is nothing to cleanup.
- if (PrintMiscellaneous && Verbose) {
+ if (log_is_enabled(Debug, perf)) {
+ LogStreamHandle(Debug, perf) log;
if (errno == ELOOP) {
- warning("directory %s is a symlink and is not secure\n", dirname);
+ log.print_cr("directory %s is a symlink and is not secure", dirname);
} else {
- warning("could not open directory %s: %s\n", dirname, os::strerror(errno));
+ log.print_cr("could not open directory %s: %s", dirname, os::strerror(errno));
}
}
return dirp;
@@ -371,9 +371,7 @@ static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) {
// handle errors, otherwise shared memory files will be created in cwd.
result = fchdir(fd);
if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("could not change to directory %s", dirname);
- }
+ log_debug(perf)("could not change to directory %s", dirname);
if (*saved_cwd_fd != -1) {
::close(*saved_cwd_fd);
*saved_cwd_fd = -1;
@@ -411,16 +409,12 @@ static bool is_file_secure(int fd, const char *filename) {
// Determine if the file is secure.
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("fstat failed on %s: %s\n", filename, os::strerror(errno));
- }
+ log_debug(perf)("fstat failed on %s: %s", filename, os::strerror(errno));
return false;
}
if (statbuf.st_nlink > 1) {
// A file with multiple links is not expected.
- if (PrintMiscellaneous && Verbose) {
- warning("file %s has multiple links\n", filename);
- }
+ log_debug(perf)("file %s has multiple links", filename);
return false;
}
return true;
@@ -447,10 +441,10 @@ static char* get_user_name(uid_t uid) {
int result = getpwuid_r(uid, &pwent, pwbuf, (size_t)bufsize, &p);
if (result != 0 || p == nullptr || p->pw_name == nullptr || *(p->pw_name) == '\0') {
- if (PrintMiscellaneous && Verbose) {
+ if (log_is_enabled(Debug, perf)) {
+ LogStreamHandle(Debug, perf) log;
if (result != 0) {
- warning("Could not retrieve passwd entry: %s\n",
- os::strerror(result));
+ log.print_cr("Could not retrieve passwd entry: %s", os::strerror(result));
}
else if (p == nullptr) {
// this check is added to protect against an observed problem
@@ -463,13 +457,11 @@ static char* get_user_name(uid_t uid) {
// message may result in an erroneous message.
// Bug Id 89052 was opened with RedHat.
//
- warning("Could not retrieve passwd entry: %s\n",
- os::strerror(errno));
+ log.print_cr("Could not retrieve passwd entry: %s", os::strerror(errno));
}
else {
- warning("Could not determine user name: %s\n",
- p->pw_name == nullptr ? "pw_name = null" :
- "pw_name zero length");
+ log.print_cr("Could not determine user name: %s",
+ p->pw_name == nullptr ? "pw_name = null" : "pw_name zero length");
}
}
FREE_C_HEAP_ARRAY(char, pwbuf);
@@ -680,10 +672,10 @@ static void remove_file(const char* path) {
// maliciously planted, the directory's presence won't hurt anything.
//
RESTARTABLE(::unlink(path), result);
- if (PrintMiscellaneous && Verbose && result == OS_ERR) {
+ if (log_is_enabled(Debug, perf) && result == OS_ERR) {
if (errno != ENOENT) {
- warning("Could not unlink shared memory backing"
- " store file %s : %s\n", path, os::strerror(errno));
+ log_debug(perf)("could not unlink shared memory backing store file %s : %s",
+ path, os::strerror(errno));
}
}
}
@@ -819,23 +811,16 @@ static bool make_user_tmp_dir(const char* dirname) {
// The directory already exists and was probably created by another
// JVM instance. However, this could also be the result of a
// deliberate symlink. Verify that the existing directory is safe.
- //
if (!is_directory_secure(dirname)) {
// directory is not secure
- if (PrintMiscellaneous && Verbose) {
- warning("%s directory is insecure\n", dirname);
- }
+ log_debug(perf)("%s directory is insecure", dirname);
return false;
}
}
else {
// we encountered some other failure while attempting
// to create the directory
- //
- if (PrintMiscellaneous && Verbose) {
- warning("could not create directory %s: %s\n",
- dirname, os::strerror(errno));
- }
+ log_debug(perf)("could not create directory %s: %s", dirname, os::strerror(errno));
return false;
}
}
@@ -872,11 +857,12 @@ static int create_sharedmem_file(const char* dirname, const char* filename, size
int fd;
RESTARTABLE(os::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR), fd);
if (fd == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
+ if (log_is_enabled(Debug, perf)) {
+ LogStreamHandle(Debug, perf) log;
if (errno == ELOOP) {
- warning("file %s is a symlink and is not secure\n", filename);
+ log.print_cr("file %s is a symlink and is not secure", filename);
} else {
- warning("could not create file %s: %s\n", filename, os::strerror(errno));
+ log.print_cr("could not create file %s: %s", filename, os::strerror(errno));
}
}
// close the directory and reset the current working directory
@@ -924,18 +910,14 @@ static int create_sharedmem_file(const char* dirname, const char* filename, size
// truncate the file to get rid of any existing data
RESTARTABLE(::ftruncate(fd, (off_t)0), result);
if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("could not truncate shared memory file: %s\n", os::strerror(errno));
- }
+ log_debug(perf)("could not truncate shared memory file: %s", os::strerror(errno));
::close(fd);
return -1;
}
// set the file size
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("could not set shared memory file size: %s\n", os::strerror(errno));
- }
+ log_debug(perf)("could not set shared memory file size: %s", os::strerror(errno));
::close(fd);
return -1;
}
@@ -1057,9 +1039,7 @@ static char* mmap_create_shared(size_t size) {
assert(result != OS_ERR, "could not close file");
if (mapAddress == MAP_FAILED) {
- if (PrintMiscellaneous && Verbose) {
- warning("mmap failed - %s\n", os::strerror(errno));
- }
+ log_debug(perf)("mmap failed - %s", os::strerror(errno));
remove_file(filename);
FREE_C_HEAP_ARRAY(char, filename);
return nullptr;
@@ -1135,9 +1115,7 @@ static size_t sharedmem_filesize(int fd, TRAPS) {
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("fstat failed: %s\n", os::strerror(errno));
- }
+ log_debug(perf)("fstat failed: %s", os::strerror(errno));
THROW_MSG_0(vmSymbols::java_io_IOException(),
"Could not determine PerfMemory size");
}
@@ -1212,9 +1190,7 @@ static void mmap_attach_shared(int vmid, char** addr, size_t* sizep, TRAPS) {
assert(result != OS_ERR, "could not close file");
if (mapAddress == MAP_FAILED) {
- if (PrintMiscellaneous && Verbose) {
- warning("mmap failed: %s\n", os::strerror(errno));
- }
+ log_debug(perf)("mmap failed: %s", os::strerror(errno));
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"Could not map PerfMemory");
}
@@ -1244,13 +1220,9 @@ void PerfMemory::create_memory_region(size_t size) {
else {
_start = create_shared_memory(size);
if (_start == nullptr) {
-
// creation of the shared memory region failed, attempt
// to create a contiguous, non-shared memory region instead.
- //
- if (PrintMiscellaneous && Verbose) {
- warning("Reverting to non-shared PerfMemory region.\n");
- }
+ log_debug(perf)("Reverting to non-shared PerfMemory region.");
FLAG_SET_ERGO(PerfDisableSharedMem, true);
_start = create_standard_memory(size);
}
diff --git a/src/hotspot/os/posix/safefetch_sigjmp.cpp b/src/hotspot/os/posix/safefetch_sigjmp.cpp
index 9f6ef34070b..572805acb7b 100644
--- a/src/hotspot/os/posix/safefetch_sigjmp.cpp
+++ b/src/hotspot/os/posix/safefetch_sigjmp.cpp
@@ -67,6 +67,14 @@ ATTRIBUTE_NO_ASAN static bool _SafeFetchXX_internal(const T *adr, T* result) {
T n = 0;
+#ifdef AIX
+ // AIX allows reading from nullptr without signalling
+ if (adr == nullptr) {
+ *result = 0;
+ return false;
+ }
+#endif
+
// Set up a jump buffer. Anchor its pointer in TLS. Then read from the unsafe address.
// If that address was invalid, we fault, and in the signal handler we will jump back
// to the jump point.
diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp
index 886bd453415..5833e324070 100644
--- a/src/hotspot/os/posix/signals_posix.cpp
+++ b/src/hotspot/os/posix/signals_posix.cpp
@@ -42,6 +42,7 @@
#include "signals_posix.hpp"
#include "suspendResume_posix.hpp"
#include "utilities/checkedCast.hpp"
+#include "utilities/deferredStatic.hpp"
#include "utilities/events.hpp"
#include "utilities/ostream.hpp"
#include "utilities/parseInteger.hpp"
@@ -167,9 +168,9 @@ static get_signal_t get_signal_action = nullptr;
// suspend/resume support
#if defined(__APPLE__)
- static OSXSemaphore sr_semaphore;
+static DeferredStatic sr_semaphore;
#else
- static PosixSemaphore sr_semaphore;
+static DeferredStatic sr_semaphore;
#endif
// Signal number used to suspend/resume a thread
@@ -177,7 +178,7 @@ static get_signal_t get_signal_action = nullptr;
int PosixSignals::SR_signum = SIGUSR2;
// sun.misc.Signal support
-static Semaphore* sig_semaphore = nullptr;
+static DeferredStatic sig_semaphore;
// a counter for each possible signal value
static volatile jint pending_signals[NSIG+1] = { 0 };
@@ -351,17 +352,16 @@ static void jdk_misc_signal_init() {
::memset((void*)pending_signals, 0, sizeof(pending_signals));
// Initialize signal semaphore
- sig_semaphore = new Semaphore();
+ int sem_count = 0;
+ sig_semaphore.initialize(sem_count);
}
void os::signal_notify(int sig) {
- if (sig_semaphore != nullptr) {
+ // Signal thread is not created with ReduceSignalUsage and jdk_misc_signal_init
+ // initialization isn't called.
+ if (!ReduceSignalUsage) {
AtomicAccess::inc(&pending_signals[sig]);
sig_semaphore->signal();
- } else {
- // Signal thread is not created with ReduceSignalUsage and jdk_misc_signal_init
- // initialization isn't called.
- assert(ReduceSignalUsage, "signal semaphore should be created");
}
}
@@ -621,9 +621,7 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info,
if (cb != nullptr && cb->is_nmethod()) {
nmethod* nm = cb->as_nmethod();
assert(nm->insts_contains_inclusive(pc), "");
- address deopt = nm->is_method_handle_return(pc) ?
- nm->deopt_mh_handler_begin() :
- nm->deopt_handler_begin();
+ address deopt = nm->deopt_handler_begin();
assert(deopt != nullptr, "");
frame fr = os::fetch_frame_from_context(uc);
@@ -1698,7 +1696,7 @@ static void SR_handler(int sig, siginfo_t* siginfo, void* context) {
pthread_sigmask(SIG_BLOCK, nullptr, &suspend_set);
sigdelset(&suspend_set, PosixSignals::SR_signum);
- sr_semaphore.signal();
+ sr_semaphore->signal();
// wait here until we are resumed
while (1) {
@@ -1707,7 +1705,7 @@ static void SR_handler(int sig, siginfo_t* siginfo, void* context) {
SuspendResume::State result = osthread->sr.running();
if (result == SuspendResume::SR_RUNNING) {
// double check AIX doesn't need this!
- sr_semaphore.signal();
+ sr_semaphore->signal();
break;
} else if (result != SuspendResume::SR_SUSPENDED) {
ShouldNotReachHere();
@@ -1733,6 +1731,9 @@ static void SR_handler(int sig, siginfo_t* siginfo, void* context) {
}
static int SR_initialize() {
+ int sem_count = 0;
+ sr_semaphore.initialize(sem_count);
+
struct sigaction act;
char *s;
// Get signal number to use for suspend/resume
@@ -1780,7 +1781,7 @@ static int sr_notify(OSThread* osthread) {
// but this seems the normal response to library errors
bool PosixSignals::do_suspend(OSThread* osthread) {
assert(osthread->sr.is_running(), "thread should be running");
- assert(!sr_semaphore.trywait(), "semaphore has invalid state");
+ assert(!sr_semaphore->trywait(), "semaphore has invalid state");
// mark as suspended and send signal
if (osthread->sr.request_suspend() != SuspendResume::SR_SUSPEND_REQUEST) {
@@ -1795,7 +1796,7 @@ bool PosixSignals::do_suspend(OSThread* osthread) {
// managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED
while (true) {
- if (sr_semaphore.timedwait(2)) {
+ if (sr_semaphore->timedwait(2)) {
break;
} else {
// timeout
@@ -1804,7 +1805,7 @@ bool PosixSignals::do_suspend(OSThread* osthread) {
return false;
} else if (cancelled == SuspendResume::SR_SUSPENDED) {
// make sure that we consume the signal on the semaphore as well
- sr_semaphore.wait();
+ sr_semaphore->wait();
break;
} else {
ShouldNotReachHere();
@@ -1819,7 +1820,7 @@ bool PosixSignals::do_suspend(OSThread* osthread) {
void PosixSignals::do_resume(OSThread* osthread) {
assert(osthread->sr.is_suspended(), "thread should be suspended");
- assert(!sr_semaphore.trywait(), "invalid semaphore state");
+ assert(!sr_semaphore->trywait(), "invalid semaphore state");
if (osthread->sr.request_wakeup() != SuspendResume::SR_WAKEUP_REQUEST) {
// failed to switch to WAKEUP_REQUEST
@@ -1829,7 +1830,7 @@ void PosixSignals::do_resume(OSThread* osthread) {
while (true) {
if (sr_notify(osthread) == 0) {
- if (sr_semaphore.timedwait(2)) {
+ if (sr_semaphore->timedwait(2)) {
if (osthread->sr.is_running()) {
return;
}
diff --git a/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp b/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp
index dc7521dde56..e2bd6803584 100644
--- a/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp
+++ b/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp
@@ -46,3 +46,7 @@ uint32_t ZNUMA::memory_id(uintptr_t addr) {
// NUMA support not enabled, assume everything belongs to node zero
return 0;
}
+
+int ZNUMA::numa_id_to_node(uint32_t numa_id) {
+ ShouldNotCallThis();
+}
diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
index 8d4c93f3080..ce2baeaf46c 100644
--- a/src/hotspot/os/windows/os_windows.cpp
+++ b/src/hotspot/os/windows/os_windows.cpp
@@ -534,13 +534,6 @@ static unsigned thread_native_entry(void* t) {
OSThread* osthr = thread->osthread();
assert(osthr->get_state() == RUNNABLE, "invalid os thread state");
- if (UseNUMA) {
- int lgrp_id = os::numa_get_group_id();
- if (lgrp_id != -1) {
- thread->set_lgrp_id(lgrp_id);
- }
- }
-
// Diagnostic code to investigate JDK-6573254
int res = 30115; // non-java thread
if (thread->is_Java_thread()) {
@@ -598,13 +591,6 @@ static OSThread* create_os_thread(Thread* thread, HANDLE thread_handle,
osthread->set_thread_handle(thread_handle);
osthread->set_thread_id(thread_id);
- if (UseNUMA) {
- int lgrp_id = os::numa_get_group_id();
- if (lgrp_id != -1) {
- thread->set_lgrp_id(lgrp_id);
- }
- }
-
// Initial thread state is INITIALIZED, not SUSPENDED
osthread->set_state(INITIALIZED);
@@ -848,22 +834,22 @@ jlong os::elapsed_frequency() {
}
-bool os::available_memory(size_t& value) {
+bool os::available_memory(physical_memory_size_type& value) {
return win32::available_memory(value);
}
-bool os::free_memory(size_t& value) {
+bool os::free_memory(physical_memory_size_type& value) {
return win32::available_memory(value);
}
-bool os::win32::available_memory(size_t& value) {
+bool os::win32::available_memory(physical_memory_size_type& value) {
// Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect
// value if total memory is larger than 4GB
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
BOOL res = GlobalMemoryStatusEx(&ms);
if (res == TRUE) {
- value = static_cast(ms.ullAvailPhys);
+ value = static_cast(ms.ullAvailPhys);
return true;
} else {
assert(false, "GlobalMemoryStatusEx failed in os::win32::available_memory(): %lu", ::GetLastError());
@@ -871,12 +857,12 @@ bool os::win32::available_memory(size_t& value) {
}
}
-bool os::total_swap_space(size_t& value) {
+bool os::total_swap_space(physical_memory_size_type& value) {
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
BOOL res = GlobalMemoryStatusEx(&ms);
if (res == TRUE) {
- value = static_cast(ms.ullTotalPageFile);
+ value = static_cast(ms.ullTotalPageFile);
return true;
} else {
assert(false, "GlobalMemoryStatusEx failed in os::total_swap_space(): %lu", ::GetLastError());
@@ -884,12 +870,12 @@ bool os::total_swap_space(size_t& value) {
}
}
-bool os::free_swap_space(size_t& value) {
+bool os::free_swap_space(physical_memory_size_type& value) {
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
BOOL res = GlobalMemoryStatusEx(&ms);
if (res == TRUE) {
- value = static_cast(ms.ullAvailPageFile);
+ value = static_cast(ms.ullAvailPageFile);
return true;
} else {
assert(false, "GlobalMemoryStatusEx failed in os::free_swap_space(): %lu", ::GetLastError());
@@ -897,7 +883,7 @@ bool os::free_swap_space(size_t& value) {
}
}
-size_t os::physical_memory() {
+physical_memory_size_type os::physical_memory() {
return win32::physical_memory();
}
@@ -1841,12 +1827,12 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
}
if (lib_arch_str != nullptr) {
- os::snprintf_checked(ebuf, ebuflen - 1,
+ os::snprintf_checked(ebuf, ebuflen,
"Can't load %s-bit .dll on a %s-bit platform",
lib_arch_str, running_arch_str);
} else {
// don't know what architecture this dll was build for
- os::snprintf_checked(ebuf, ebuflen - 1,
+ os::snprintf_checked(ebuf, ebuflen,
"Can't load this .dll (machine code=0x%x) on a %s-bit platform",
lib_arch, running_arch_str);
}
@@ -2644,14 +2630,13 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
DWORD exception_code = exception_record->ExceptionCode;
#if defined(_M_ARM64)
address pc = (address) exceptionInfo->ContextRecord->Pc;
+
+ if (handle_safefetch(exception_code, pc, (void*)exceptionInfo->ContextRecord)) {
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
#elif defined(_M_AMD64)
address pc = (address) exceptionInfo->ContextRecord->Rip;
-#else
- #error unknown architecture
-#endif
- Thread* t = Thread::current_or_null_safe();
-#if defined(_M_AMD64)
if ((exception_code == EXCEPTION_ACCESS_VIOLATION) &&
VM_Version::is_cpuinfo_segv_addr(pc)) {
// Verify that OS save/restore AVX registers.
@@ -2664,6 +2649,8 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
VM_Version::clear_apx_test_state();
return Handle_Exception(exceptionInfo, VM_Version::cpuinfo_cont_addr_apx());
}
+#else
+ #error unknown architecture
#endif
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
@@ -2674,6 +2661,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
}
#endif
+ Thread* t = Thread::current_or_null_safe();
if (t != nullptr && t->is_Java_thread()) {
JavaThread* thread = JavaThread::cast(t);
bool in_java = thread->thread_state() == _thread_in_Java;
@@ -2704,10 +2692,8 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
// Fatal red zone violation.
overflow_state->disable_stack_red_zone();
tty->print_raw_cr("An unrecoverable stack overflow has occurred.");
-#if !defined(USE_VECTORED_EXCEPTION_HANDLING)
report_error(t, exception_code, pc, exception_record,
exceptionInfo->ContextRecord);
-#endif
return EXCEPTION_CONTINUE_SEARCH;
}
} else if (exception_code == EXCEPTION_ACCESS_VIOLATION) {
@@ -2759,10 +2745,8 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
}
// Stack overflow or null pointer exception in native code.
-#if !defined(USE_VECTORED_EXCEPTION_HANDLING)
report_error(t, exception_code, pc, exception_record,
exceptionInfo->ContextRecord);
-#endif
return EXCEPTION_CONTINUE_SEARCH;
} // /EXCEPTION_ACCESS_VIOLATION
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -2811,9 +2795,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
if (cb != nullptr && cb->is_nmethod()) {
nmethod* nm = cb->as_nmethod();
frame fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord);
- address deopt = nm->is_method_handle_return(pc) ?
- nm->deopt_mh_handler_begin() :
- nm->deopt_handler_begin();
+ address deopt = nm->deopt_handler_begin();
assert(nm->insts_contains_inclusive(pc), "");
nm->set_original_pc(&fr, pc);
// Set pc to handler
@@ -2824,41 +2806,21 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
}
}
-#if !defined(USE_VECTORED_EXCEPTION_HANDLING)
- if (exception_code != EXCEPTION_BREAKPOINT) {
+ bool should_report_error = (exception_code != EXCEPTION_BREAKPOINT);
+
+#if defined(_M_ARM64)
+ should_report_error = should_report_error &&
+ FAILED(exception_code) &&
+ (exception_code != EXCEPTION_UNCAUGHT_CXX_EXCEPTION);
+#endif
+
+ if (should_report_error) {
report_error(t, exception_code, pc, exception_record,
exceptionInfo->ContextRecord);
}
-#endif
- return EXCEPTION_CONTINUE_SEARCH;
-}
-
-#if defined(USE_VECTORED_EXCEPTION_HANDLING)
-LONG WINAPI topLevelVectoredExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
- PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
-#if defined(_M_ARM64)
- address pc = (address) exceptionInfo->ContextRecord->Pc;
-#elif defined(_M_AMD64)
- address pc = (address) exceptionInfo->ContextRecord->Rip;
-#else
- #error unknown architecture
-#endif
-
- // Fast path for code part of the code cache
- if (CodeCache::low_bound() <= pc && pc < CodeCache::high_bound()) {
- return topLevelExceptionFilter(exceptionInfo);
- }
-
- // If the exception occurred in the codeCache, pass control
- // to our normal exception handler.
- CodeBlob* cb = CodeCache::find_blob(pc);
- if (cb != nullptr) {
- return topLevelExceptionFilter(exceptionInfo);
- }
return EXCEPTION_CONTINUE_SEARCH;
}
-#endif
#if defined(USE_VECTORED_EXCEPTION_HANDLING)
LONG WINAPI topLevelUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
@@ -3188,7 +3150,6 @@ void os::large_page_init() {
_large_page_size = os::win32::large_page_init_decide_size();
const size_t default_page_size = os::vm_page_size();
if (_large_page_size > default_page_size) {
-#if !defined(IA32)
if (EnableAllLargePageSizesForWindows) {
size_t min_size = GetLargePageMinimum();
@@ -3197,7 +3158,6 @@ void os::large_page_init() {
_page_sizes.add(page_size);
}
}
-#endif
_page_sizes.add(_large_page_size);
}
@@ -3961,25 +3921,25 @@ int os::current_process_id() {
return (_initial_pid ? _initial_pid : _getpid());
}
-int os::win32::_processor_type = 0;
+int os::win32::_processor_type = 0;
// Processor level is not available on non-NT systems, use vm_version instead
-int os::win32::_processor_level = 0;
-size_t os::win32::_physical_memory = 0;
+int os::win32::_processor_level = 0;
+physical_memory_size_type os::win32::_physical_memory = 0;
-bool os::win32::_is_windows_server = false;
+bool os::win32::_is_windows_server = false;
// 6573254
// Currently, the bug is observed across all the supported Windows releases,
// including the latest one (as of this writing - Windows Server 2012 R2)
-bool os::win32::_has_exit_bug = true;
+bool os::win32::_has_exit_bug = true;
-int os::win32::_major_version = 0;
-int os::win32::_minor_version = 0;
-int os::win32::_build_number = 0;
-int os::win32::_build_minor = 0;
+int os::win32::_major_version = 0;
+int os::win32::_minor_version = 0;
+int os::win32::_build_number = 0;
+int os::win32::_build_minor = 0;
-bool os::win32::_processor_group_warning_displayed = false;
-bool os::win32::_job_object_processor_group_warning_displayed = false;
+bool os::win32::_processor_group_warning_displayed = false;
+bool os::win32::_job_object_processor_group_warning_displayed = false;
void getWindowsInstallationType(char* buffer, int bufferSize) {
HKEY hKey;
@@ -4198,12 +4158,7 @@ void os::win32::initialize_system_info() {
if (res != TRUE) {
assert(false, "GlobalMemoryStatusEx failed in os::win32::initialize_system_info(): %lu", ::GetLastError());
}
- _physical_memory = static_cast(ms.ullTotalPhys);
-
- if (FLAG_IS_DEFAULT(MaxRAM)) {
- // Adjust MaxRAM according to the maximum virtual address space available.
- FLAG_SET_DEFAULT(MaxRAM, MIN2(MaxRAM, (uint64_t) ms.ullTotalVirtual));
- }
+ _physical_memory = static_cast(ms.ullTotalPhys);
_is_windows_server = IsWindowsServer();
@@ -4535,7 +4490,7 @@ jint os::init_2(void) {
// Setup Windows Exceptions
#if defined(USE_VECTORED_EXCEPTION_HANDLING)
- topLevelVectoredExceptionHandler = AddVectoredExceptionHandler(1, topLevelVectoredExceptionFilter);
+ topLevelVectoredExceptionHandler = AddVectoredExceptionHandler(1, topLevelExceptionFilter);
previousUnhandledExceptionFilter = SetUnhandledExceptionFilter(topLevelUnhandledExceptionFilter);
#endif
@@ -6297,3 +6252,106 @@ const void* os::get_saved_assert_context(const void** sigInfo) {
*sigInfo = nullptr;
return nullptr;
}
+
+/*
+ * Windows/x64 does not use stack frames the way expected by Java:
+ * [1] in most cases, there is no frame pointer. All locals are addressed via RSP
+ * [2] in rare cases, when alloca() is used, a frame pointer is used, but this may
+ * not be RBP.
+ * See http://msdn.microsoft.com/en-us/library/ew5tede7.aspx
+ *
+ * So it's not possible to print the native stack using the
+ * while (...) {... fr = os::get_sender_for_C_frame(&fr); }
+ * loop in vmError.cpp. We need to roll our own loop.
+ * This approach works for Windows AArch64 as well.
+ */
+bool os::win32::platform_print_native_stack(outputStream* st, const void* context,
+ char* buf, int buf_size, address& lastpc)
+{
+ CONTEXT ctx;
+ if (context != nullptr) {
+ memcpy(&ctx, context, sizeof(ctx));
+ } else {
+ RtlCaptureContext(&ctx);
+ }
+
+ st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
+
+ DWORD machine_type;
+ STACKFRAME stk;
+ memset(&stk, 0, sizeof(stk));
+ stk.AddrStack.Mode = AddrModeFlat;
+ stk.AddrFrame.Mode = AddrModeFlat;
+ stk.AddrPC.Mode = AddrModeFlat;
+
+#if defined(_M_AMD64)
+ stk.AddrStack.Offset = ctx.Rsp;
+ stk.AddrFrame.Offset = ctx.Rbp;
+ stk.AddrPC.Offset = ctx.Rip;
+ machine_type = IMAGE_FILE_MACHINE_AMD64;
+#elif defined(_M_ARM64)
+ stk.AddrStack.Offset = ctx.Sp;
+ stk.AddrFrame.Offset = ctx.Fp;
+ stk.AddrPC.Offset = ctx.Pc;
+ machine_type = IMAGE_FILE_MACHINE_ARM64;
+#else
+ #error unknown architecture
+#endif
+
+ // Ensure we consider dynamically loaded DLLs
+ SymbolEngine::refreshModuleList();
+
+ int count = 0;
+ address lastpc_internal = 0;
+ while (count++ < StackPrintLimit) {
+ 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;
+
+ if (pc != nullptr) {
+ if (count == 2 && lastpc_internal == pc) {
+ // Skip it -- StackWalk64() may return the same PC
+ // (but different SP) on the first try.
+ } else {
+ // Don't try to create a frame(sp, fp, pc) -- on WinX64, stk.AddrFrame
+ // may not contain what Java expects, and may cause the frame() constructor
+ // to crash. Let's just print out the symbolic address.
+ frame::print_C_frame(st, buf, buf_size, pc);
+ // print source file and line, if available
+ char buf[128];
+ int line_no;
+ if (SymbolEngine::get_source_info(pc, buf, sizeof(buf), &line_no)) {
+ st->print(" (%s:%d)", buf, line_no);
+ } else {
+ st->print(" (no source info available)");
+ }
+ st->cr();
+ }
+ lastpc_internal = pc;
+ }
+
+ PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
+ if (p == nullptr) {
+ // StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash.
+ lastpc = lastpc_internal;
+ break;
+ }
+
+ BOOL result = WindowsDbgHelp::stackWalk64(
+ machine_type, // __in DWORD MachineType,
+ GetCurrentProcess(), // __in HANDLE hProcess,
+ GetCurrentThread(), // __in HANDLE hThread,
+ &stk, // __inout LP STACKFRAME64 StackFrame,
+ &ctx); // __inout PVOID ContextRecord,
+
+ if (!result) {
+ break;
+ }
+ }
+ if (count > StackPrintLimit) {
+ st->print_cr("......");
+ }
+ st->cr();
+
+ return true;
+}
diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp
index 1426dc8be93..f1153bbbfd3 100644
--- a/src/hotspot/os/windows/os_windows.hpp
+++ b/src/hotspot/os/windows/os_windows.hpp
@@ -38,18 +38,18 @@ class os::win32 {
friend class os;
protected:
- static int _processor_type;
- static int _processor_level;
- static size_t _physical_memory;
- static bool _is_windows_server;
- static bool _has_exit_bug;
- static bool _processor_group_warning_displayed;
- static bool _job_object_processor_group_warning_displayed;
+ static int _processor_type;
+ static int _processor_level;
+ static physical_memory_size_type _physical_memory;
+ static bool _is_windows_server;
+ static bool _has_exit_bug;
+ static bool _processor_group_warning_displayed;
+ static bool _job_object_processor_group_warning_displayed;
- static int _major_version;
- static int _minor_version;
- static int _build_number;
- static int _build_minor;
+ static int _major_version;
+ static int _minor_version;
+ static int _build_number;
+ static int _build_minor;
static void print_windows_version(outputStream* st);
static void print_uptime_info(outputStream* st);
@@ -102,9 +102,9 @@ class os::win32 {
static int processor_level() {
return _processor_level;
}
- static bool available_memory(size_t& value);
- static bool free_memory(size_t& value);
- static size_t physical_memory() { return _physical_memory; }
+ static bool available_memory(physical_memory_size_type& value);
+ static bool free_memory(physical_memory_size_type& value);
+ static physical_memory_size_type physical_memory() { return _physical_memory; }
// load dll from Windows system directory or Windows directory
static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen);
@@ -150,6 +150,8 @@ public:
// signal support
static void* install_signal_handler(int sig, signal_handler_t handler);
static void* user_handler();
+
+ static void context_set_pc(CONTEXT* uc, address pc);
};
#endif // OS_WINDOWS_OS_WINDOWS_HPP
diff --git a/src/hotspot/os/windows/os_windows.inline.hpp b/src/hotspot/os/windows/os_windows.inline.hpp
index 41471224b6c..9eebbee2d8b 100644
--- a/src/hotspot/os/windows/os_windows.inline.hpp
+++ b/src/hotspot/os/windows/os_windows.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, 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
@@ -62,8 +62,6 @@ inline void os::map_stack_shadow_pages(address sp) {
state->set_shadow_zone_growth_watermark(original_sp);
}
-inline bool os::numa_has_group_homing() { return false; }
-
// Platform Mutex/Monitor implementation
inline void PlatformMutex::lock() {
diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp
index a9b2eebb7be..f54a2b52cca 100644
--- a/src/hotspot/os/windows/perfMemory_windows.cpp
+++ b/src/hotspot/os/windows/perfMemory_windows.cpp
@@ -24,6 +24,7 @@
#include "classfile/vmSymbols.hpp"
#include "logging/log.hpp"
+#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "nmt/memTracker.hpp"
@@ -41,11 +42,7 @@
#include
#include
#include
-
-typedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)(
- IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
- IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
- IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet);
+#include
// Standard Memory Implementation Details
@@ -62,9 +59,7 @@ static char* create_standard_memory(size_t size) {
// commit memory
if (!os::commit_memory(mapAddress, size, !ExecMem)) {
- if (PrintMiscellaneous && Verbose) {
- warning("Could not commit PerfData memory\n");
- }
+ log_debug(perf)("could not commit PerfData memory");
os::release_memory(mapAddress, size);
return nullptr;
}
@@ -90,25 +85,21 @@ static void delete_standard_memory(char* addr, size_t size) {
static void save_memory_to_file(char* addr, size_t size) {
const char* destfile = PerfMemory::get_perfdata_file_path();
- assert(destfile[0] != '\0', "invalid Perfdata file path");
+ assert(destfile[0] != '\0', "invalid PerfData file path");
int fd = ::_open(destfile, _O_BINARY|_O_CREAT|_O_WRONLY|_O_TRUNC,
_S_IREAD|_S_IWRITE);
if (fd == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("Could not create Perfdata save file: %s: %s\n",
- destfile, os::strerror(errno));
- }
+ log_debug(perf)("could not create PerfData save file: %s: %s",
+ destfile, os::strerror(errno));
} else {
for (size_t remaining = size; remaining > 0;) {
int nbytes = ::_write(fd, addr, (unsigned int)remaining);
if (nbytes == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("Could not write Perfdata save file: %s: %s\n",
- destfile, os::strerror(errno));
- }
+ log_debug(perf)("could not write PerfData save file: %s: %s",
+ destfile, os::strerror(errno));
break;
}
@@ -117,10 +108,8 @@ static void save_memory_to_file(char* addr, size_t size) {
}
int result = ::_close(fd);
- if (PrintMiscellaneous && Verbose) {
- if (result == OS_ERR) {
- warning("Could not close %s: %s\n", destfile, os::strerror(errno));
- }
+ if (result == OS_ERR) {
+ log_debug(perf)("could not close %s: %s", destfile, os::strerror(errno));
}
}
@@ -220,10 +209,8 @@ static bool is_directory_secure(const char* path) {
}
else {
// unexpected error, declare the path insecure
- if (PrintMiscellaneous && Verbose) {
- warning("could not get attributes for file %s: "
- " lasterror = %d\n", path, lasterror);
- }
+ log_debug(perf)("could not get attributes for file %s: lasterror = %d",
+ path, lasterror);
return false;
}
}
@@ -234,9 +221,7 @@ static bool is_directory_secure(const char* path) {
// as some types of reparse points might be acceptable, but it
// is probably more secure to avoid these conditions.
//
- if (PrintMiscellaneous && Verbose) {
- warning("%s is a reparse point\n", path);
- }
+ log_debug(perf)("%s is a reparse point", path);
return false;
}
@@ -253,10 +238,8 @@ static bool is_directory_secure(const char* path) {
// this is either a regular file or some other type of file,
// any of which are unexpected and therefore insecure.
//
- if (PrintMiscellaneous && Verbose) {
- warning("%s is not a directory, file attributes = "
- INTPTR_FORMAT "\n", path, fa);
- }
+ log_debug(perf)("%s is not a directory, file attributes : "
+ INTPTR_FORMAT, path, fa);
return false;
}
}
@@ -492,11 +475,9 @@ static void remove_file(const char* dirname, const char* filename) {
strcat(path, filename);
if (::unlink(path) == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- if (errno != ENOENT) {
- warning("Could not unlink shared memory backing"
- " store file %s : %s\n", path, os::strerror(errno));
- }
+ if (errno != ENOENT) {
+ log_debug(perf)("could not unlink shared memory backing store file %s : %s",
+ path, os::strerror(errno));
}
}
@@ -515,20 +496,16 @@ static bool is_alive(int pid) {
HANDLE ph = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (ph == nullptr) {
// the process does not exist.
- if (PrintMiscellaneous && Verbose) {
- DWORD lastError = GetLastError();
- if (lastError != ERROR_INVALID_PARAMETER) {
- warning("OpenProcess failed: %d\n", GetLastError());
- }
+ DWORD lastError = GetLastError();
+ if (lastError != ERROR_INVALID_PARAMETER) {
+ log_debug(perf)("OpenProcess failed: %d", lastError);
}
return false;
}
DWORD exit_status;
if (!GetExitCodeProcess(ph, &exit_status)) {
- if (PrintMiscellaneous && Verbose) {
- warning("GetExitCodeProcess failed: %d\n", GetLastError());
- }
+ log_debug(perf)("GetExitCodeProcess failed: %d", GetLastError());
CloseHandle(ph);
return false;
}
@@ -545,17 +522,13 @@ static bool is_filesystem_secure(const char* path) {
char fs_type[MAX_PATH];
if (PerfBypassFileSystemCheck) {
- if (PrintMiscellaneous && Verbose) {
- warning("bypassing file system criteria checks for %s\n", path);
- }
+ log_debug(perf)("bypassing file system criteria checks for %s", path);
return true;
}
char* first_colon = strchr((char *)path, ':');
if (first_colon == nullptr) {
- if (PrintMiscellaneous && Verbose) {
- warning("expected device specifier in path: %s\n", path);
- }
+ log_debug(perf)("expected device specifier in path: %s", path);
return false;
}
@@ -576,29 +549,22 @@ static bool is_filesystem_secure(const char* path) {
if (!GetVolumeInformation(root_path, nullptr, 0, nullptr, &maxpath,
&flags, fs_type, MAX_PATH)) {
// we can't get information about the volume, so assume unsafe.
- if (PrintMiscellaneous && Verbose) {
- warning("could not get device information for %s: "
- " path = %s: lasterror = %d\n",
- root_path, path, GetLastError());
- }
+ log_debug(perf)("could not get device information for %s: path = %s: lasterror = %d",
+ root_path, path, GetLastError());
return false;
}
if ((flags & FS_PERSISTENT_ACLS) == 0) {
// file system doesn't support ACLs, declare file system unsafe
- if (PrintMiscellaneous && Verbose) {
- warning("file system type %s on device %s does not support"
- " ACLs\n", fs_type, root_path);
- }
+ log_debug(perf)("file system type %s on device %s does not support ACLs",
+ fs_type, root_path);
return false;
}
if ((flags & FS_VOL_IS_COMPRESSED) != 0) {
// file system is compressed, declare file system unsafe
- if (PrintMiscellaneous && Verbose) {
- warning("file system type %s on device %s is compressed\n",
- fs_type, root_path);
- }
+ log_debug(perf)("file system type %s on device %s is compressed",
+ fs_type, root_path);
return false;
}
@@ -704,9 +670,7 @@ static HANDLE create_file_mapping(const char* name, HANDLE fh, LPSECURITY_ATTRIB
name); /* LPCTSTR name for object */
if (fmh == nullptr) {
- if (PrintMiscellaneous && Verbose) {
- warning("CreateFileMapping failed, lasterror = %d\n", GetLastError());
- }
+ log_debug(perf)("CreateFileMapping failed, lasterror = %d", GetLastError());
return nullptr;
}
@@ -717,9 +681,7 @@ static HANDLE create_file_mapping(const char* name, HANDLE fh, LPSECURITY_ATTRIB
// the other processes either exit or close their mapping objects
// and/or mapped views of this mapping object.
//
- if (PrintMiscellaneous && Verbose) {
- warning("file mapping already exists, lasterror = %d\n", GetLastError());
- }
+ log_debug(perf)("file mapping already exists, lasterror = %d", GetLastError());
CloseHandle(fmh);
return nullptr;
@@ -783,9 +745,7 @@ static PSID get_user_sid(HANDLE hProcess) {
// get the process token
if (!OpenProcessToken(hProcess, TOKEN_READ, &hAccessToken)) {
- if (PrintMiscellaneous && Verbose) {
- warning("OpenProcessToken failure: lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("OpenProcessToken failure: lasterror = %d", GetLastError());
return nullptr;
}
@@ -795,10 +755,8 @@ static PSID get_user_sid(HANDLE hProcess) {
if (!GetTokenInformation(hAccessToken, TokenUser, nullptr, rsize, &rsize)) {
DWORD lasterror = GetLastError();
if (lasterror != ERROR_INSUFFICIENT_BUFFER) {
- if (PrintMiscellaneous && Verbose) {
- warning("GetTokenInformation failure: lasterror = %d,"
- " rsize = %d\n", lasterror, rsize);
- }
+ log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d",
+ lasterror, rsize);
CloseHandle(hAccessToken);
return nullptr;
}
@@ -808,10 +766,8 @@ static PSID get_user_sid(HANDLE hProcess) {
// get the user token information
if (!GetTokenInformation(hAccessToken, TokenUser, token_buf, rsize, &rsize)) {
- if (PrintMiscellaneous && Verbose) {
- warning("GetTokenInformation failure: lasterror = %d,"
- " rsize = %d\n", GetLastError(), rsize);
- }
+ log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d",
+ GetLastError(), rsize);
FREE_C_HEAP_ARRAY(char, token_buf);
CloseHandle(hAccessToken);
return nullptr;
@@ -821,10 +777,8 @@ static PSID get_user_sid(HANDLE hProcess) {
PSID pSID = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
if (!CopySid(nbytes, pSID, token_buf->User.Sid)) {
- if (PrintMiscellaneous && Verbose) {
- warning("GetTokenInformation failure: lasterror = %d,"
- " rsize = %d\n", GetLastError(), rsize);
- }
+ log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d",
+ GetLastError(), rsize);
FREE_C_HEAP_ARRAY(char, token_buf);
FREE_C_HEAP_ARRAY(char, pSID);
CloseHandle(hAccessToken);
@@ -866,10 +820,8 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
// retrieve any existing access control list.
if (!GetSecurityDescriptorDacl(pSD, &exists, &oldACL, &isdefault)) {
- if (PrintMiscellaneous && Verbose) {
- warning("GetSecurityDescriptor failure: lasterror = %d \n",
- GetLastError());
- }
+ log_debug(perf)("GetSecurityDescriptor failure: lasterror = %d",
+ GetLastError());
return false;
}
@@ -886,10 +838,8 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
if (!GetAclInformation(oldACL, &aclinfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation)) {
- if (PrintMiscellaneous && Verbose) {
- warning("GetAclInformation failure: lasterror = %d \n", GetLastError());
- return false;
- }
+ log_debug(perf)("GetAclInformation failure: lasterror = %d", GetLastError());
+ return false;
}
} else {
aclinfo.AceCount = 0; // assume null DACL
@@ -914,9 +864,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
newACL = (PACL) NEW_C_HEAP_ARRAY(char, newACLsize, mtInternal);
if (!InitializeAcl(newACL, newACLsize, ACL_REVISION)) {
- if (PrintMiscellaneous && Verbose) {
- warning("InitializeAcl failure: lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError());
FREE_C_HEAP_ARRAY(char, newACL);
return false;
}
@@ -927,9 +875,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
while (ace_index < aclinfo.AceCount) {
LPVOID ace;
if (!GetAce(oldACL, ace_index, &ace)) {
- if (PrintMiscellaneous && Verbose) {
- warning("InitializeAcl failure: lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError());
FREE_C_HEAP_ARRAY(char, newACL);
return false;
}
@@ -954,9 +900,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
if (matches == 0) {
if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace,
((PACE_HEADER)ace)->AceSize)) {
- if (PrintMiscellaneous && Verbose) {
- warning("AddAce failure: lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("AddAce failure: lasterror = %d", GetLastError());
FREE_C_HEAP_ARRAY(char, newACL);
return false;
}
@@ -969,10 +913,8 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
for (int i = 0; i < ace_count; i++) {
if (!AddAccessAllowedAce(newACL, ACL_REVISION,
aces[i].mask, aces[i].pSid)) {
- if (PrintMiscellaneous && Verbose) {
- warning("AddAccessAllowedAce failure: lasterror = %d \n",
- GetLastError());
- }
+ log_debug(perf)("AddAccessAllowedAce failure: lasterror = %d",
+ GetLastError());
FREE_C_HEAP_ARRAY(char, newACL);
return false;
}
@@ -985,17 +927,13 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
while (ace_index < aclinfo.AceCount) {
LPVOID ace;
if (!GetAce(oldACL, ace_index, &ace)) {
- if (PrintMiscellaneous && Verbose) {
- warning("InitializeAcl failure: lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError());
FREE_C_HEAP_ARRAY(char, newACL);
return false;
}
if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace,
((PACE_HEADER)ace)->AceSize)) {
- if (PrintMiscellaneous && Verbose) {
- warning("AddAce failure: lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("AddAce failure: lasterror = %d", GetLastError());
FREE_C_HEAP_ARRAY(char, newACL);
return false;
}
@@ -1005,39 +943,23 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
// add the new ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD, TRUE, newACL, FALSE)) {
- if (PrintMiscellaneous && Verbose) {
- warning("SetSecurityDescriptorDacl failure:"
- " lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("SetSecurityDescriptorDacl failure: lasterror = %d", GetLastError());
FREE_C_HEAP_ARRAY(char, newACL);
return false;
}
- // if running on windows 2000 or later, set the automatic inheritance
- // control flags.
- SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl;
- _SetSecurityDescriptorControl = (SetSecurityDescriptorControlFnPtr)
- GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),
- "SetSecurityDescriptorControl");
-
- if (_SetSecurityDescriptorControl != nullptr) {
- // We do not want to further propagate inherited DACLs, so making them
- // protected prevents that.
- if (!_SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED,
- SE_DACL_PROTECTED)) {
- if (PrintMiscellaneous && Verbose) {
- warning("SetSecurityDescriptorControl failure:"
- " lasterror = %d \n", GetLastError());
- }
- FREE_C_HEAP_ARRAY(char, newACL);
- return false;
- }
+ // We do not want to further propagate inherited DACLs, so making them
+ // protected prevents that.
+ if (!SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) {
+ log_debug(perf)("SetSecurityDescriptorControl failure: lasterror = %d", GetLastError());
+ FREE_C_HEAP_ARRAY(char, newACL);
+ return false;
}
- // Note, the security descriptor maintains a reference to the newACL, not
- // a copy of it. Therefore, the newACL is not freed here. It is freed when
- // the security descriptor containing its reference is freed.
- //
- return true;
+
+ // Note, the security descriptor maintains a reference to the newACL, not
+ // a copy of it. Therefore, the newACL is not freed here. It is freed when
+ // the security descriptor containing its reference is freed.
+ return true;
}
// method to create a security attributes structure, which contains a
@@ -1057,10 +979,7 @@ static LPSECURITY_ATTRIBUTES make_security_attr(ace_data_t aces[], int count) {
// initialize the security descriptor
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
- if (PrintMiscellaneous && Verbose) {
- warning("InitializeSecurityDescriptor failure: "
- "lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("InitializeSecurityDescriptor failure: lasterror = %d", GetLastError());
free_security_desc(pSD);
return nullptr;
}
@@ -1113,11 +1032,7 @@ static LPSECURITY_ATTRIBUTES make_user_everybody_admin_security_attr(
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &administratorsSid)) {
-
- if (PrintMiscellaneous && Verbose) {
- warning("AllocateAndInitializeSid failure: "
- "lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("AllocateAndInitializeSid failure: lasterror = %d", GetLastError());
return nullptr;
}
@@ -1131,11 +1046,7 @@ static LPSECURITY_ATTRIBUTES make_user_everybody_admin_security_attr(
if (!AllocateAndInitializeSid( &SIDAuthEverybody, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &everybodySid)) {
-
- if (PrintMiscellaneous && Verbose) {
- warning("AllocateAndInitializeSid failure: "
- "lasterror = %d \n", GetLastError());
- }
+ log_debug(perf)("AllocateAndInitializeSid failure: lasterror = %d", GetLastError());
return nullptr;
}
@@ -1236,9 +1147,7 @@ static bool make_user_tmp_dir(const char* dirname) {
//
if (!is_directory_secure(dirname)) {
// directory is not secure
- if (PrintMiscellaneous && Verbose) {
- warning("%s directory is insecure\n", dirname);
- }
+ log_debug(perf)("%s directory is insecure", dirname);
free_security_attr(pDirSA);
return false;
}
@@ -1249,16 +1158,11 @@ static bool make_user_tmp_dir(const char* dirname) {
// DACLs might fix the corrupted the DACLs.
SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
if (!SetFileSecurity(dirname, secInfo, pDirSA->lpSecurityDescriptor)) {
- if (PrintMiscellaneous && Verbose) {
- lasterror = GetLastError();
- warning("SetFileSecurity failed for %s directory. lasterror %d \n",
- dirname, lasterror);
- }
+ lasterror = GetLastError();
+ log_debug(perf)("SetFileSecurity failed for %s directory. lasterror = %d", dirname, lasterror);
}
} else {
- if (PrintMiscellaneous && Verbose) {
- warning("CreateDirectory failed: %d\n", GetLastError());
- }
+ log_debug(perf)("CreateDirectory failed: %d", GetLastError());
free_security_attr(pDirSA);
return false;
}
@@ -1325,9 +1229,7 @@ static HANDLE create_sharedmem_resources(const char* dirname, const char* filena
if (fh == INVALID_HANDLE_VALUE) {
DWORD lasterror = GetLastError();
- if (PrintMiscellaneous && Verbose) {
- warning("could not create file %s: %d\n", filename, lasterror);
- }
+ log_debug(perf)("could not create file %s: %d", filename, lasterror);
free_security_attr(lpSmoSA);
return nullptr;
}
@@ -1353,10 +1255,8 @@ static HANDLE create_sharedmem_resources(const char* dirname, const char* filena
struct stat statbuf;
int ret_code = ::stat(filename, &statbuf);
if (ret_code == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("Could not get status information from file %s: %s\n",
- filename, os::strerror(errno));
- }
+ log_debug(perf)("could not get status information from file %s: %s",
+ filename, os::strerror(errno));
CloseHandle(fmh);
CloseHandle(fh);
fh = nullptr;
@@ -1369,9 +1269,7 @@ static HANDLE create_sharedmem_resources(const char* dirname, const char* filena
// call it when we observe the size as zero (0).
if (statbuf.st_size == 0 && FlushFileBuffers(fh) != TRUE) {
DWORD lasterror = GetLastError();
- if (PrintMiscellaneous && Verbose) {
- warning("could not flush file %s: %d\n", filename, lasterror);
- }
+ log_debug(perf)("could not flush file %s: %d", filename, lasterror);
CloseHandle(fmh);
CloseHandle(fh);
fh = nullptr;
@@ -1402,10 +1300,8 @@ static HANDLE open_sharedmem_object(const char* objectname, DWORD ofm_access, TR
if (fmh == nullptr) {
DWORD lasterror = GetLastError();
- if (PrintMiscellaneous && Verbose) {
- warning("OpenFileMapping failed for shared memory object %s:"
- " lasterror = %d\n", objectname, lasterror);
- }
+ log_debug(perf)("OpenFileMapping failed for shared memory object %s:"
+ " lasterror = %d", objectname, lasterror);
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
err_msg("Could not open PerfMemory, error %d", lasterror),
INVALID_HANDLE_VALUE);
@@ -1485,9 +1381,7 @@ static char* mapping_create_shared(size_t size) {
(DWORD)size); /* DWORD Number of bytes to map */
if (mapAddress == nullptr) {
- if (PrintMiscellaneous && Verbose) {
- warning("MapViewOfFile failed, lasterror = %d\n", GetLastError());
- }
+ log_debug(perf)("MapViewOfFile failed, lasterror = %d", GetLastError());
CloseHandle(sharedmem_fileMapHandle);
sharedmem_fileMapHandle = nullptr;
return nullptr;
@@ -1551,20 +1445,14 @@ static size_t sharedmem_filesize(const char* filename, TRAPS) {
// inconsistencies
//
if (::stat(filename, &statbuf) == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("stat %s failed: %s\n", filename, os::strerror(errno));
- }
+ log_debug(perf)("stat %s failed: %s", filename, os::strerror(errno));
THROW_MSG_0(vmSymbols::java_io_IOException(),
"Could not determine PerfMemory size");
}
if ((statbuf.st_size == 0) || (statbuf.st_size % os::vm_page_size() != 0)) {
- if (PrintMiscellaneous && Verbose) {
- warning("unexpected file size: size = %zu\n",
- statbuf.st_size);
- }
- THROW_MSG_0(vmSymbols::java_io_IOException(),
- "Invalid PerfMemory size");
+ log_debug(perf)("unexpected file size: size = %zu", statbuf.st_size);
+ THROW_MSG_0(vmSymbols::java_io_IOException(), "Invalid PerfMemory size");
}
return statbuf.st_size;
@@ -1637,9 +1525,7 @@ static void open_file_mapping(int vmid, char** addrp, size_t* sizep, TRAPS) {
size); /* DWORD Number of bytes to map */
if (mapAddress == nullptr) {
- if (PrintMiscellaneous && Verbose) {
- warning("MapViewOfFile failed, lasterror = %d\n", GetLastError());
- }
+ log_debug(perf)("MapViewOfFile failed, lasterror = %d", GetLastError());
CloseHandle(fmh);
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"Could not map PerfMemory");
@@ -1708,9 +1594,7 @@ void PerfMemory::create_memory_region(size_t size) {
// creation of the shared memory region failed, attempt
// to create a contiguous, non-shared memory region instead.
//
- if (PrintMiscellaneous && Verbose) {
- warning("Reverting to non-shared PerfMemory region.\n");
- }
+ log_debug(perf)("Reverting to non-shared PerfMemory region.");
FLAG_SET_ERGO(PerfDisableSharedMem, true);
_start = create_standard_memory(size);
}
diff --git a/src/hotspot/os/windows/safefetch_static_windows.cpp b/src/hotspot/os/windows/safefetch_static_windows.cpp
new file mode 100644
index 00000000000..3ea8b96b32d
--- /dev/null
+++ b/src/hotspot/os/windows/safefetch_static_windows.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2022 SAP SE. All rights reserved.
+ * Copyright (c) 2022, 2025, 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 "os_windows.hpp"
+#include "runtime/os.hpp"
+#include "runtime/safefetch.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#ifdef SAFEFETCH_METHOD_STATIC_ASSEMBLY
+
+// SafeFetch handling, static assembly style:
+//
+// SafeFetch32 and SafeFetchN are implemented via static assembly
+// and live in os_cpu/xx_xx/safefetch_xx_xx.S
+
+extern "C" char _SafeFetch32_continuation[];
+extern "C" char _SafeFetch32_fault[];
+
+#ifdef _LP64
+extern "C" char _SafeFetchN_continuation[];
+extern "C" char _SafeFetchN_fault[];
+#endif // _LP64
+
+bool handle_safefetch(int exception_code, address pc, void* context) {
+ CONTEXT* ctx = (CONTEXT*)context;
+ if (exception_code == EXCEPTION_ACCESS_VIOLATION && ctx != nullptr) {
+ if (pc == (address)_SafeFetch32_fault) {
+ os::win32::context_set_pc(ctx, (address)_SafeFetch32_continuation);
+ return true;
+ }
+#ifdef _LP64
+ if (pc == (address)_SafeFetchN_fault) {
+ os::win32::context_set_pc(ctx, (address)_SafeFetchN_continuation);
+ return true;
+ }
+#endif
+ }
+ return false;
+}
+
+#endif // SAFEFETCH_METHOD_STATIC_ASSEMBLY
diff --git a/src/hotspot/cpu/aarch64/bytecodes_aarch64.cpp b/src/hotspot/os_cpu/aix_ppc/atomicAccess_aix_ppc.hpp
similarity index 80%
rename from src/hotspot/cpu/aarch64/bytecodes_aarch64.cpp
rename to src/hotspot/os_cpu/aix_ppc/atomicAccess_aix_ppc.hpp
index 119ad8baec3..9a314667fcb 100644
--- a/src/hotspot/cpu/aarch64/bytecodes_aarch64.cpp
+++ b/src/hotspot/os_cpu/aix_ppc/atomicAccess_aix_ppc.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, Red Hat Inc. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,5 @@
*
*/
-#include "interpreter/bytecodes.hpp"
-
-
+// Including inline assembler functions that are shared between multiple PPC64 platforms.
+#include "atomicAccess_ppc.hpp"
diff --git a/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.hpp b/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.hpp
index 9ca6c18d5bb..d395add6d69 100644
--- a/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.hpp
+++ b/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2019 SAP SE. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,62 +23,5 @@
*
*/
-#ifndef OS_CPU_AIX_PPC_ORDERACCESS_AIX_PPC_HPP
-#define OS_CPU_AIX_PPC_ORDERACCESS_AIX_PPC_HPP
-
-// Included in orderAccess.hpp header file.
-
-// Compiler version last used for testing: xlc 12
-// Please update this information when this file changes
-
-// Implementation of class OrderAccess.
-
-//
-// Machine barrier instructions:
-//
-// - sync Two-way memory barrier, aka fence.
-// - lwsync orders Store|Store,
-// Load|Store,
-// Load|Load,
-// but not Store|Load
-// - eieio orders Store|Store
-// - isync Invalidates speculatively executed instructions,
-// but isync may complete before storage accesses
-// associated with instructions preceding isync have
-// been performed.
-//
-// Semantic barrier instructions:
-// (as defined in orderAccess.hpp)
-//
-// - release orders Store|Store, (maps to lwsync)
-// Load|Store
-// - acquire orders Load|Store, (maps to lwsync)
-// Load|Load
-// - fence orders Store|Store, (maps to sync)
-// Load|Store,
-// Load|Load,
-// Store|Load
-//
-
-#define inlasm_sync() __asm__ __volatile__ ("sync" : : : "memory");
-#define inlasm_lwsync() __asm__ __volatile__ ("lwsync" : : : "memory");
-#define inlasm_eieio() __asm__ __volatile__ ("eieio" : : : "memory");
-#define inlasm_isync() __asm__ __volatile__ ("isync" : : : "memory");
-
-inline void OrderAccess::loadload() { inlasm_lwsync(); }
-inline void OrderAccess::storestore() { inlasm_lwsync(); }
-inline void OrderAccess::loadstore() { inlasm_lwsync(); }
-inline void OrderAccess::storeload() { inlasm_sync(); }
-
-inline void OrderAccess::acquire() { inlasm_lwsync(); }
-inline void OrderAccess::release() { inlasm_lwsync(); }
-inline void OrderAccess::fence() { inlasm_sync(); }
-inline void OrderAccess::cross_modify_fence_impl()
- { inlasm_isync(); }
-
-#undef inlasm_sync
-#undef inlasm_lwsync
-#undef inlasm_eieio
-#undef inlasm_isync
-
-#endif // OS_CPU_AIX_PPC_ORDERACCESS_AIX_PPC_HPP
+// Including inline assembler functions that are shared between multiple PPC64 platforms.
+#include "orderAccess_ppc.hpp"
diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp
index 98b17aaacfc..afef21b091a 100644
--- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp
+++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2024 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 2025 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -254,6 +254,18 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
goto run_stub;
}
+ // SIGTRAP-based nmethod entry barriers.
+ else if (sig == SIGTRAP && TrapBasedNMethodEntryBarriers &&
+ nativeInstruction_at(pc)->is_sigtrap_nmethod_entry_barrier() &&
+ CodeCache::contains((void*) pc)) {
+ if (TraceTraps) {
+ tty->print_cr("trap: nmethod entry barrier at " INTPTR_FORMAT " (SIGTRAP)", p2i(pc));
+ }
+ stub = StubRoutines::method_entry_barrier();
+ uc->uc_mcontext.jmp_context.lr = (uintptr_t)(pc + BytesPerInstWord); // emulate call by setting LR
+ goto run_stub;
+ }
+
// SIGTRAP-based ic miss check in compiled code.
else if (sig == SIGTRAP && TrapBasedICMissChecks &&
nativeInstruction_at(pc)->is_sigtrap_ic_miss_check()) {
@@ -282,6 +294,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGSEGV)", p2i(pc));
}
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
+ goto run_stub;
}
#ifdef COMPILER2
diff --git a/src/hotspot/os_cpu/bsd_aarch64/atomic_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/atomicAccess_bsd_aarch64.hpp
similarity index 95%
rename from src/hotspot/os_cpu/bsd_aarch64/atomic_bsd_aarch64.hpp
rename to src/hotspot/os_cpu/bsd_aarch64/atomicAccess_bsd_aarch64.hpp
index 1ecdd59f59e..3d2c632ace8 100644
--- a/src/hotspot/os_cpu/bsd_aarch64/atomic_bsd_aarch64.hpp
+++ b/src/hotspot/os_cpu/bsd_aarch64/atomicAccess_bsd_aarch64.hpp
@@ -24,12 +24,12 @@
*
*/
-#ifndef OS_CPU_BSD_AARCH64_ATOMIC_BSD_AARCH64_HPP
-#define OS_CPU_BSD_AARCH64_ATOMIC_BSD_AARCH64_HPP
+#ifndef OS_CPU_BSD_AARCH64_ATOMICACCESS_BSD_AARCH64_HPP
+#define OS_CPU_BSD_AARCH64_ATOMICACCESS_BSD_AARCH64_HPP
#include "utilities/debug.hpp"
-// Implementation of class atomic
+// Implementation of class AtomicAccess
// Note that memory_order_conservative requires a full barrier after atomic stores.
// See https://patchwork.kernel.org/patch/3575821/
@@ -129,5 +129,4 @@ struct AtomicAccess::PlatformOrderedStore
void operator()(volatile T* p, T v) const { release_store(p, v); OrderAccess::fence(); }
};
-
-#endif // OS_CPU_BSD_AARCH64_ATOMIC_BSD_AARCH64_HPP
+#endif // OS_CPU_BSD_AARCH64_ATOMICACCESS_BSD_AARCH64_HPP
diff --git a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp
similarity index 97%
rename from src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp
rename to src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp
index 8fbc319e766..975580fbd71 100644
--- a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp
+++ b/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp
@@ -22,10 +22,10 @@
*
*/
-#ifndef OS_CPU_BSD_X86_ATOMIC_BSD_X86_HPP
-#define OS_CPU_BSD_X86_ATOMIC_BSD_X86_HPP
+#ifndef OS_CPU_BSD_X86_ATOMICACCESS_BSD_X86_HPP
+#define OS_CPU_BSD_X86_ATOMICACCESS_BSD_X86_HPP
-// Implementation of class atomic
+// Implementation of class AtomicAccess
template
struct AtomicAccess::PlatformAdd {
@@ -230,4 +230,4 @@ struct AtomicAccess::PlatformOrderedStore<8, RELEASE_X_FENCE>
};
#endif // AMD64
-#endif // OS_CPU_BSD_X86_ATOMIC_BSD_X86_HPP
+#endif // OS_CPU_BSD_X86_ATOMICACCESS_BSD_X86_HPP
diff --git a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp
similarity index 96%
rename from src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp
rename to src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp
index b5cedac867b..6a720dac54e 100644
--- a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp
+++ b/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp
@@ -23,13 +23,13 @@
*
*/
-#ifndef OS_CPU_BSD_ZERO_ATOMIC_BSD_ZERO_HPP
-#define OS_CPU_BSD_ZERO_ATOMIC_BSD_ZERO_HPP
+#ifndef OS_CPU_BSD_ZERO_ATOMICACCESS_BSD_ZERO_HPP
+#define OS_CPU_BSD_ZERO_ATOMICACCESS_BSD_ZERO_HPP
#include "orderAccess_bsd_zero.hpp"
#include "runtime/os.hpp"
-// Implementation of class atomic
+// Implementation of class AtomicAccess
template
struct AtomicAccess::PlatformAdd {
@@ -149,4 +149,4 @@ inline void AtomicAccess::PlatformStore<8>::operator()(T volatile* dest,
__atomic_store(dest, &store_value, __ATOMIC_RELAXED);
}
-#endif // OS_CPU_BSD_ZERO_ATOMIC_BSD_ZERO_HPP
+#endif // OS_CPU_BSD_ZERO_ATOMICACCESS_BSD_ZERO_HPP
diff --git a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp
index 3fefbdbe56c..facad184426 100644
--- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp
+++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp
@@ -24,7 +24,6 @@
*/
#include "asm/assembler.inline.hpp"
-#include "atomic_bsd_zero.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
@@ -36,6 +35,7 @@
#include "prims/jniFastGetField.hpp"
#include "prims/jvm_misc.hpp"
#include "runtime/arguments.hpp"
+#include "runtime/atomicAccess.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/java.hpp"
diff --git a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp
similarity index 97%
rename from src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp
rename to src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp
index 4940cbdc246..6e5f53edfa3 100644
--- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp
+++ b/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp
@@ -23,13 +23,13 @@
*
*/
-#ifndef OS_CPU_LINUX_AARCH64_ATOMIC_LINUX_AARCH64_HPP
-#define OS_CPU_LINUX_AARCH64_ATOMIC_LINUX_AARCH64_HPP
+#ifndef OS_CPU_LINUX_AARCH64_ATOMICACCESS_LINUX_AARCH64_HPP
+#define OS_CPU_LINUX_AARCH64_ATOMICACCESS_LINUX_AARCH64_HPP
#include "atomic_aarch64.hpp"
#include "runtime/vm_version.hpp"
-// Implementation of class atomic
+// Implementation of class AtomicAccess
// Note that memory_order_conservative requires a full barrier after atomic stores.
// See https://patchwork.kernel.org/patch/3575821/
@@ -217,4 +217,4 @@ struct AtomicAccess::PlatformOrderedStore
void operator()(volatile T* p, T v) const { release_store(p, v); OrderAccess::fence(); }
};
-#endif // OS_CPU_LINUX_AARCH64_ATOMIC_LINUX_AARCH64_HPP
+#endif // OS_CPU_LINUX_AARCH64_ATOMICACCESS_LINUX_AARCH64_HPP
diff --git a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp
similarity index 97%
rename from src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp
rename to src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp
index db00c347dea..5b5f9da51a6 100644
--- a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp
+++ b/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp
@@ -22,14 +22,14 @@
*
*/
-#ifndef OS_CPU_LINUX_ARM_ATOMIC_LINUX_ARM_HPP
-#define OS_CPU_LINUX_ARM_ATOMIC_LINUX_ARM_HPP
+#ifndef OS_CPU_LINUX_ARM_ATOMICACCESS_LINUX_ARM_HPP
+#define OS_CPU_LINUX_ARM_ATOMICACCESS_LINUX_ARM_HPP
#include "memory/allStatic.hpp"
#include "runtime/os.hpp"
#include "runtime/vm_version.hpp"
-// Implementation of class atomic
+// Implementation of class AtomicAccess
class ARMAtomicFuncs : AllStatic {
public:
@@ -178,4 +178,4 @@ inline T AtomicAccess::PlatformCmpxchg<8>::operator()(T volatile* dest,
return cmpxchg_using_helper(reorder_cmpxchg_long_func, dest, compare_value, exchange_value);
}
-#endif // OS_CPU_LINUX_ARM_ATOMIC_LINUX_ARM_HPP
+#endif // OS_CPU_LINUX_ARM_ATOMICACCESS_LINUX_ARM_HPP
diff --git a/test/jdk/sun/tools/jrunscript/Hello.java b/src/hotspot/os_cpu/linux_ppc/atomicAccess_linux_ppc.hpp
similarity index 79%
rename from test/jdk/sun/tools/jrunscript/Hello.java
rename to src/hotspot/os_cpu/linux_ppc/atomicAccess_linux_ppc.hpp
index 48b6c9298ab..9a314667fcb 100644
--- a/test/jdk/sun/tools/jrunscript/Hello.java
+++ b/src/hotspot/os_cpu/linux_ppc/atomicAccess_linux_ppc.hpp
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -19,16 +20,8 @@
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
+ *
*/
-/**
- * This is a test program used in the test jrunscript-cp.sh
- *
- *
- */
-public class Hello {
- public Hello() {}
- public String getString() {
- return "hello";
- }
-}
+// Including inline assembler functions that are shared between multiple PPC64 platforms.
+#include "atomicAccess_ppc.hpp"
diff --git a/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp
deleted file mode 100644
index 9f1d90c26bd..00000000000
--- a/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2019 SAP SE. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_LINUX_PPC_ATOMIC_LINUX_PPC_HPP
-#define OS_CPU_LINUX_PPC_ATOMIC_LINUX_PPC_HPP
-
-#ifndef PPC64
-#error "Atomic currently only implemented for PPC64"
-#endif
-
-#include "orderAccess_linux_ppc.hpp"
-#include "utilities/debug.hpp"
-
-// Implementation of class atomic
-
-//
-// machine barrier instructions:
-//
-// - sync two-way memory barrier, aka fence
-// - lwsync orders Store|Store,
-// Load|Store,
-// Load|Load,
-// but not Store|Load
-// - eieio orders memory accesses for device memory (only)
-// - isync invalidates speculatively executed instructions
-// From the POWER ISA 2.06 documentation:
-// "[...] an isync instruction prevents the execution of
-// instructions following the isync until instructions
-// preceding the isync have completed, [...]"
-// From IBM's AIX assembler reference:
-// "The isync [...] instructions causes the processor to
-// refetch any instructions that might have been fetched
-// prior to the isync instruction. The instruction isync
-// causes the processor to wait for all previous instructions
-// to complete. Then any instructions already fetched are
-// discarded and instruction processing continues in the
-// environment established by the previous instructions."
-//
-// semantic barrier instructions:
-// (as defined in orderAccess.hpp)
-//
-// - release orders Store|Store, (maps to lwsync)
-// Load|Store
-// - acquire orders Load|Store, (maps to lwsync)
-// Load|Load
-// - fence orders Store|Store, (maps to sync)
-// Load|Store,
-// Load|Load,
-// Store|Load
-//
-
-inline void pre_membar(atomic_memory_order order) {
- switch (order) {
- case memory_order_relaxed:
- case memory_order_acquire: break;
- case memory_order_release:
- case memory_order_acq_rel: __asm__ __volatile__ ("lwsync" : : : "memory"); break;
- default /*conservative*/ : __asm__ __volatile__ ("sync" : : : "memory"); break;
- }
-}
-
-inline void post_membar(atomic_memory_order order) {
- switch (order) {
- case memory_order_relaxed:
- case memory_order_release: break;
- case memory_order_acquire:
- case memory_order_acq_rel: __asm__ __volatile__ ("isync" : : : "memory"); break;
- default /*conservative*/ : __asm__ __volatile__ ("sync" : : : "memory"); break;
- }
-}
-
-
-template
-struct AtomicAccess::PlatformAdd {
- template
- D add_then_fetch(D volatile* dest, I add_value, atomic_memory_order order) const;
-
- template
- D fetch_then_add(D volatile* dest, I add_value, atomic_memory_order order) const {
- return add_then_fetch(dest, add_value, order) - add_value;
- }
-};
-
-template<>
-template
-inline D AtomicAccess::PlatformAdd<4>::add_then_fetch(D volatile* dest, I add_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(4 == sizeof(I));
- STATIC_ASSERT(4 == sizeof(D));
-
- D result;
-
- pre_membar(order);
-
- __asm__ __volatile__ (
- "1: lwarx %0, 0, %2 \n"
- " add %0, %0, %1 \n"
- " stwcx. %0, 0, %2 \n"
- " bne- 1b \n"
- : /*%0*/"=&r" (result)
- : /*%1*/"r" (add_value), /*%2*/"r" (dest)
- : "cc", "memory" );
-
- post_membar(order);
-
- return result;
-}
-
-
-template<>
-template
-inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(8 == sizeof(I));
- STATIC_ASSERT(8 == sizeof(D));
-
- D result;
-
- pre_membar(order);
-
- __asm__ __volatile__ (
- "1: ldarx %0, 0, %2 \n"
- " add %0, %0, %1 \n"
- " stdcx. %0, 0, %2 \n"
- " bne- 1b \n"
- : /*%0*/"=&r" (result)
- : /*%1*/"r" (add_value), /*%2*/"r" (dest)
- : "cc", "memory" );
-
- post_membar(order);
-
- return result;
-}
-
-template<>
-template
-inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,
- T exchange_value,
- atomic_memory_order order) const {
- // Note that xchg doesn't necessarily do an acquire
- // (see synchronizer.cpp).
-
- T old_value;
- const uint64_t zero = 0;
-
- pre_membar(order);
-
- __asm__ __volatile__ (
- /* atomic loop */
- "1: \n"
- " lwarx %[old_value], %[dest], %[zero] \n"
- " stwcx. %[exchange_value], %[dest], %[zero] \n"
- " bne- 1b \n"
- /* exit */
- "2: \n"
- /* out */
- : [old_value] "=&r" (old_value),
- "=m" (*dest)
- /* in */
- : [dest] "b" (dest),
- [zero] "r" (zero),
- [exchange_value] "r" (exchange_value),
- "m" (*dest)
- /* clobber */
- : "cc",
- "memory"
- );
-
- post_membar(order);
-
- return old_value;
-}
-
-template<>
-template
-inline T AtomicAccess::PlatformXchg<8>::operator()(T volatile* dest,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(8 == sizeof(T));
- // Note that xchg doesn't necessarily do an acquire
- // (see synchronizer.cpp).
-
- T old_value;
- const uint64_t zero = 0;
-
- pre_membar(order);
-
- __asm__ __volatile__ (
- /* atomic loop */
- "1: \n"
- " ldarx %[old_value], %[dest], %[zero] \n"
- " stdcx. %[exchange_value], %[dest], %[zero] \n"
- " bne- 1b \n"
- /* exit */
- "2: \n"
- /* out */
- : [old_value] "=&r" (old_value),
- "=m" (*dest)
- /* in */
- : [dest] "b" (dest),
- [zero] "r" (zero),
- [exchange_value] "r" (exchange_value),
- "m" (*dest)
- /* clobber */
- : "cc",
- "memory"
- );
-
- post_membar(order);
-
- return old_value;
-}
-
-template<>
-template
-inline T AtomicAccess::PlatformCmpxchg<1>::operator()(T volatile* dest,
- T compare_value,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(1 == sizeof(T));
-
- // Note that cmpxchg guarantees a two-way memory barrier across
- // the cmpxchg, so it's really a 'fence_cmpxchg_fence' if not
- // specified otherwise (see atomicAccess.hpp).
-
- // Using 32 bit internally.
- unsigned int old_value, loaded_value;
- pre_membar(order);
-
- __asm__ __volatile__ (
- /* atomic loop */
- "1: \n"
- " lbarx %[old_value], 0, %[dest] \n"
- /* extract byte and compare */
- " cmpw %[compare_value], %[old_value] \n"
- " bne- 2f \n"
- /* replace byte and try to store */
- " stbcx. %[exchange_value], 0, %[dest] \n"
- " bne- 1b \n"
- /* exit */
- "2: \n"
- /* out */
- : [old_value] "=&r" (old_value),
- [loaded_value] "=&r" (loaded_value),
- "=m" (*dest)
- /* in */
- : [dest] "b" (dest),
- [compare_value] "r" (compare_value),
- [exchange_value] "r" (exchange_value),
- "m" (*dest)
- /* clobber */
- : "cc",
- "memory"
- );
-
- post_membar(order);
-
- return PrimitiveConversions::cast((unsigned char)old_value);
-}
-
-template<>
-template
-inline T AtomicAccess::PlatformCmpxchg<4>::operator()(T volatile* dest,
- T compare_value,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(4 == sizeof(T));
-
- // Note that cmpxchg guarantees a two-way memory barrier across
- // the cmpxchg, so it's really a 'fence_cmpxchg_fence' if not
- // specified otherwise (see atomicAccess.hpp).
-
- T old_value;
- const uint64_t zero = 0;
-
- pre_membar(order);
-
- __asm__ __volatile__ (
- /* simple guard */
- " lwz %[old_value], 0(%[dest]) \n"
- " cmpw %[compare_value], %[old_value] \n"
- " bne- 2f \n"
- /* atomic loop */
- "1: \n"
- " lwarx %[old_value], %[dest], %[zero] \n"
- " cmpw %[compare_value], %[old_value] \n"
- " bne- 2f \n"
- " stwcx. %[exchange_value], %[dest], %[zero] \n"
- " bne- 1b \n"
- /* exit */
- "2: \n"
- /* out */
- : [old_value] "=&r" (old_value),
- "=m" (*dest)
- /* in */
- : [dest] "b" (dest),
- [zero] "r" (zero),
- [compare_value] "r" (compare_value),
- [exchange_value] "r" (exchange_value),
- "m" (*dest)
- /* clobber */
- : "cc",
- "memory"
- );
-
- post_membar(order);
-
- return old_value;
-}
-
-template<>
-template
-inline T AtomicAccess::PlatformCmpxchg<8>::operator()(T volatile* dest,
- T compare_value,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(8 == sizeof(T));
-
- // Note that cmpxchg guarantees a two-way memory barrier across
- // the cmpxchg, so it's really a 'fence_cmpxchg_fence' if not
- // specified otherwise (see atomicAccess.hpp).
-
- T old_value;
- const uint64_t zero = 0;
-
- pre_membar(order);
-
- __asm__ __volatile__ (
- /* simple guard */
- " ld %[old_value], 0(%[dest]) \n"
- " cmpd %[compare_value], %[old_value] \n"
- " bne- 2f \n"
- /* atomic loop */
- "1: \n"
- " ldarx %[old_value], %[dest], %[zero] \n"
- " cmpd %[compare_value], %[old_value] \n"
- " bne- 2f \n"
- " stdcx. %[exchange_value], %[dest], %[zero] \n"
- " bne- 1b \n"
- /* exit */
- "2: \n"
- /* out */
- : [old_value] "=&r" (old_value),
- "=m" (*dest)
- /* in */
- : [dest] "b" (dest),
- [zero] "r" (zero),
- [compare_value] "r" (compare_value),
- [exchange_value] "r" (exchange_value),
- "m" (*dest)
- /* clobber */
- : "cc",
- "memory"
- );
-
- post_membar(order);
-
- return old_value;
-}
-
-template
-struct AtomicAccess::PlatformOrderedLoad
-{
- template
- T operator()(const volatile T* p) const {
- T t = AtomicAccess::load(p);
- // Use twi-isync for load_acquire (faster than lwsync).
- __asm__ __volatile__ ("twi 0,%0,0\n isync\n" : : "r" (t) : "memory");
- return t;
- }
-};
-
-#endif // OS_CPU_LINUX_PPC_ATOMIC_LINUX_PPC_HPP
diff --git a/src/hotspot/os_cpu/linux_ppc/gc/z/zSyscall_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/gc/z/zSyscall_linux_ppc.hpp
index 5950b52136d..1b2b5dad7d7 100644
--- a/src/hotspot/os_cpu/linux_ppc/gc/z/zSyscall_linux_ppc.hpp
+++ b/src/hotspot/os_cpu/linux_ppc/gc/z/zSyscall_linux_ppc.hpp
@@ -31,7 +31,6 @@
// Support for building on older Linux systems
//
-
#ifndef SYS_memfd_create
#define SYS_memfd_create 360
#endif
diff --git a/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.hpp
index 2e6eb1f3878..d395add6d69 100644
--- a/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.hpp
+++ b/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 SAP SE. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,66 +23,5 @@
*
*/
-#ifndef OS_CPU_LINUX_PPC_ORDERACCESS_LINUX_PPC_HPP
-#define OS_CPU_LINUX_PPC_ORDERACCESS_LINUX_PPC_HPP
-
-// Included in orderAccess.hpp header file.
-
-#ifndef PPC64
-#error "OrderAccess currently only implemented for PPC64"
-#endif
-
-// Compiler version last used for testing: gcc 4.1.2
-// Please update this information when this file changes
-
-// Implementation of class OrderAccess.
-
-//
-// Machine barrier instructions:
-//
-// - sync Two-way memory barrier, aka fence.
-// - lwsync orders Store|Store,
-// Load|Store,
-// Load|Load,
-// but not Store|Load
-// - eieio orders Store|Store
-// - isync Invalidates speculatively executed instructions,
-// but isync may complete before storage accesses
-// associated with instructions preceding isync have
-// been performed.
-//
-// Semantic barrier instructions:
-// (as defined in orderAccess.hpp)
-//
-// - release orders Store|Store, (maps to lwsync)
-// Load|Store
-// - acquire orders Load|Store, (maps to lwsync)
-// Load|Load
-// - fence orders Store|Store, (maps to sync)
-// Load|Store,
-// Load|Load,
-// Store|Load
-//
-
-#define inlasm_sync() __asm__ __volatile__ ("sync" : : : "memory");
-#define inlasm_lwsync() __asm__ __volatile__ ("lwsync" : : : "memory");
-#define inlasm_eieio() __asm__ __volatile__ ("eieio" : : : "memory");
-#define inlasm_isync() __asm__ __volatile__ ("isync" : : : "memory");
-
-inline void OrderAccess::loadload() { inlasm_lwsync(); }
-inline void OrderAccess::storestore() { inlasm_lwsync(); }
-inline void OrderAccess::loadstore() { inlasm_lwsync(); }
-inline void OrderAccess::storeload() { inlasm_sync(); }
-
-inline void OrderAccess::acquire() { inlasm_lwsync(); }
-inline void OrderAccess::release() { inlasm_lwsync(); }
-inline void OrderAccess::fence() { inlasm_sync(); }
-inline void OrderAccess::cross_modify_fence_impl()
- { inlasm_isync(); }
-
-#undef inlasm_sync
-#undef inlasm_lwsync
-#undef inlasm_eieio
-#undef inlasm_isync
-
-#endif // OS_CPU_LINUX_PPC_ORDERACCESS_LINUX_PPC_HPP
+// Including inline assembler functions that are shared between multiple PPC64 platforms.
+#include "orderAccess_ppc.hpp"
diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp
index 55618947143..5909b5799b9 100644
--- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp
+++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2024 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 2025 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -286,6 +286,17 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
stub = SharedRuntime::polling_page_return_handler_blob()->entry_point();
}
+ // SIGTRAP-based nmethod entry barriers.
+ else if (sig == SIGTRAP && TrapBasedNMethodEntryBarriers &&
+ nativeInstruction_at(pc)->is_sigtrap_nmethod_entry_barrier() &&
+ CodeCache::contains((void*) pc)) {
+ if (TraceTraps) {
+ tty->print_cr("trap: nmethod entry barrier at " INTPTR_FORMAT " (SIGTRAP)", p2i(pc));
+ }
+ stub = StubRoutines::method_entry_barrier();
+ uc->uc_mcontext.regs->link = (uintptr_t)(pc + BytesPerInstWord); // emulate call by setting LR
+ }
+
// SIGTRAP-based ic miss check in compiled code.
else if (sig == SIGTRAP && TrapBasedICMissChecks &&
nativeInstruction_at(pc)->is_sigtrap_ic_miss_check()) {
diff --git a/src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp
similarity index 97%
rename from src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp
rename to src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp
index f713465edeb..6d57ea55a83 100644
--- a/src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp
+++ b/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp
@@ -23,12 +23,12 @@
*
*/
-#ifndef OS_CPU_LINUX_RISCV_ATOMIC_LINUX_RISCV_HPP
-#define OS_CPU_LINUX_RISCV_ATOMIC_LINUX_RISCV_HPP
+#ifndef OS_CPU_LINUX_RISCV_ATOMICACCESS_LINUX_RISCV_HPP
+#define OS_CPU_LINUX_RISCV_ATOMICACCESS_LINUX_RISCV_HPP
#include "runtime/vm_version.hpp"
-// Implementation of class atomic
+// Implementation of class AtomicAccess
// Note that memory_order_conservative requires a full barrier after atomic stores.
// See https://patchwork.kernel.org/patch/3575821/
@@ -226,4 +226,4 @@ struct AtomicAccess::PlatformOrderedStore
#undef FULL_COMPILER_ATOMIC_SUPPORT
-#endif // OS_CPU_LINUX_RISCV_ATOMIC_LINUX_RISCV_HPP
+#endif // OS_CPU_LINUX_RISCV_ATOMICACCESS_LINUX_RISCV_HPP
diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp
index 3e5fb4610de..ec756c44fe6 100644
--- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp
+++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp
@@ -89,7 +89,24 @@
#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0)
#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0)
-#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
+#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
+
+#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7
+
+#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8
+
+#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9
+#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0
+#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1
+#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2
+#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3
+#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4
+
+#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10
+#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0
+#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2
+#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3
+#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4
#ifndef NR_riscv_hwprobe
#ifndef NR_arch_specific_syscall
@@ -117,7 +134,11 @@ static struct riscv_hwprobe query[] = {{RISCV_HWPROBE_KEY_MVENDORID, 0},
{RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0},
{RISCV_HWPROBE_KEY_IMA_EXT_0, 0},
{RISCV_HWPROBE_KEY_CPUPERF_0, 0},
- {RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, 0}};
+ {RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, 0},
+ {RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS, 0},
+ {RISCV_HWPROBE_KEY_TIME_CSR_FREQ, 0},
+ {RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF, 0},
+ {RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF, 0}};
bool RiscvHwprobe::probe_features() {
assert(!rw_hwprobe_completed, "Called twice.");
@@ -146,26 +167,19 @@ static bool is_set(int64_t key, uint64_t value_mask) {
void RiscvHwprobe::add_features_from_query_result() {
assert(rw_hwprobe_completed, "hwprobe not init yet.");
- if (is_valid(RISCV_HWPROBE_KEY_MVENDORID)) {
- VM_Version::mvendorid.enable_feature(query[RISCV_HWPROBE_KEY_MVENDORID].value);
- }
- if (is_valid(RISCV_HWPROBE_KEY_MARCHID)) {
- VM_Version::marchid.enable_feature(query[RISCV_HWPROBE_KEY_MARCHID].value);
- }
- if (is_valid(RISCV_HWPROBE_KEY_MIMPID)) {
- VM_Version::mimpid.enable_feature(query[RISCV_HWPROBE_KEY_MIMPID].value);
- }
+ // ====== extensions ======
+ //
if (is_set(RISCV_HWPROBE_KEY_BASE_BEHAVIOR, RISCV_HWPROBE_BASE_BEHAVIOR_IMA)) {
- VM_Version::ext_I.enable_feature();
- VM_Version::ext_M.enable_feature();
- VM_Version::ext_A.enable_feature();
- }
- if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_FD)) {
- VM_Version::ext_F.enable_feature();
- VM_Version::ext_D.enable_feature();
+ VM_Version::ext_a.enable_feature();
+ VM_Version::ext_i.enable_feature();
+ VM_Version::ext_m.enable_feature();
}
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_C)) {
- VM_Version::ext_C.enable_feature();
+ VM_Version::ext_c.enable_feature();
+ }
+ if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_FD)) {
+ VM_Version::ext_d.enable_feature();
+ VM_Version::ext_f.enable_feature();
}
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_V)) {
// Linux signal return bug when using vector with vlen > 128b in pre 6.8.5.
@@ -178,24 +192,32 @@ void RiscvHwprobe::add_features_from_query_result() {
log.info("Vector not enabled automatically via hwprobe, but can be turned on with -XX:+UseRVV.");
}
} else {
- VM_Version::ext_V.enable_feature();
+ VM_Version::ext_v.enable_feature();
}
}
+
+#ifndef PRODUCT
+ if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZACAS)) {
+ VM_Version::ext_Zacas.enable_feature();
+ }
+#endif
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBA)) {
VM_Version::ext_Zba.enable_feature();
}
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBB)) {
VM_Version::ext_Zbb.enable_feature();
}
+#ifndef PRODUCT
+ if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBKB)) {
+ VM_Version::ext_Zbkb.enable_feature();
+ }
+#endif
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBS)) {
VM_Version::ext_Zbs.enable_feature();
}
#ifndef PRODUCT
- if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICBOZ)) {
- VM_Version::ext_Zicboz.enable_feature();
- }
- if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBKB)) {
- VM_Version::ext_Zbkb.enable_feature();
+ if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFA)) {
+ VM_Version::ext_Zfa.enable_feature();
}
#endif
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFH)) {
@@ -205,15 +227,28 @@ void RiscvHwprobe::add_features_from_query_result() {
VM_Version::ext_Zfhmin.enable_feature();
}
#ifndef PRODUCT
+ if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICBOZ)) {
+ VM_Version::ext_Zicboz.enable_feature();
+ }
+ // Currently tests shows that cmove using Zicond instructions will bring
+ // performance regression, but to get a test coverage all the time, will
+ // still prefer to enabling it in debug version.
+ if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICOND)) {
+ VM_Version::ext_Zicond.enable_feature();
+ }
+ if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZTSO)) {
+ VM_Version::ext_Ztso.enable_feature();
+ }
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVBB)) {
VM_Version::ext_Zvbb.enable_feature();
}
-#endif
-#ifndef PRODUCT
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVBC)) {
VM_Version::ext_Zvbc.enable_feature();
}
#endif
+ if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVFH)) {
+ VM_Version::ext_Zvfh.enable_feature();
+ }
#ifndef PRODUCT
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVKNED) &&
is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVKNHB) &&
@@ -222,33 +257,31 @@ void RiscvHwprobe::add_features_from_query_result() {
VM_Version::ext_Zvkn.enable_feature();
}
#endif
- if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVFH)) {
- VM_Version::ext_Zvfh.enable_feature();
+
+ // ====== non-extensions ======
+ //
+ if (is_valid(RISCV_HWPROBE_KEY_MARCHID)) {
+ VM_Version::marchid.enable_feature(query[RISCV_HWPROBE_KEY_MARCHID].value);
}
-#ifndef PRODUCT
- if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFA)) {
- VM_Version::ext_Zfa.enable_feature();
+ if (is_valid(RISCV_HWPROBE_KEY_MIMPID)) {
+ VM_Version::mimpid.enable_feature(query[RISCV_HWPROBE_KEY_MIMPID].value);
}
-#endif
-#ifndef PRODUCT
- if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZTSO)) {
- VM_Version::ext_Ztso.enable_feature();
+ if (is_valid(RISCV_HWPROBE_KEY_MVENDORID)) {
+ VM_Version::mvendorid.enable_feature(query[RISCV_HWPROBE_KEY_MVENDORID].value);
}
-#endif
-#ifndef PRODUCT
- if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZACAS)) {
- VM_Version::ext_Zacas.enable_feature();
- }
- // Currently tests shows that cmove using Zicond instructions will bring
- // performance regression, but to get a test coverage all the time, will
- // still prefer to enabling it in debug version.
- if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICOND)) {
- VM_Version::ext_Zicond.enable_feature();
- }
-#endif
+ // RISCV_HWPROBE_KEY_CPUPERF_0 is deprecated and returns similar values
+ // to RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF. Keep it there for backward
+ // compatibility with old kernels.
if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) {
- VM_Version::unaligned_access.enable_feature(
+ VM_Version::unaligned_scalar.enable_feature(
query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK);
+ } else if (is_valid(RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF)) {
+ VM_Version::unaligned_scalar.enable_feature(
+ query[RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF].value);
+ }
+ if (is_valid(RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF)) {
+ VM_Version::unaligned_vector.enable_feature(
+ query[RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF].value);
}
if (is_valid(RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE)) {
VM_Version::zicboz_block_size.enable_feature(query[RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE].value);
diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
index cf9429b6bea..0799de014a9 100644
--- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
+++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
@@ -100,21 +100,28 @@
#endif
uint32_t VM_Version::cpu_vector_length() {
- assert(ext_V.enabled(), "should not call this");
return (uint32_t)read_csr(CSR_VLENB);
}
+void VM_Version::RVExtFeatureValue::log_enabled() {
+ log_debug(os, cpu)("Enabled RV64 feature \"%s\"", pretty());
+}
+
+void VM_Version::RVNonExtFeatureValue::log_enabled() {
+ log_debug(os, cpu)("Enabled RV64 feature \"%s\" (%ld)", pretty(), value());
+}
+
void VM_Version::setup_cpu_available_features() {
- assert(ext_I.feature_bit() == HWCAP_ISA_I, "Bit for I must follow Linux HWCAP");
- assert(ext_M.feature_bit() == HWCAP_ISA_M, "Bit for M must follow Linux HWCAP");
- assert(ext_A.feature_bit() == HWCAP_ISA_A, "Bit for A must follow Linux HWCAP");
- assert(ext_F.feature_bit() == HWCAP_ISA_F, "Bit for F must follow Linux HWCAP");
- assert(ext_D.feature_bit() == HWCAP_ISA_D, "Bit for D must follow Linux HWCAP");
- assert(ext_C.feature_bit() == HWCAP_ISA_C, "Bit for C must follow Linux HWCAP");
- assert(ext_Q.feature_bit() == HWCAP_ISA_Q, "Bit for Q must follow Linux HWCAP");
- assert(ext_H.feature_bit() == HWCAP_ISA_H, "Bit for H must follow Linux HWCAP");
- assert(ext_V.feature_bit() == HWCAP_ISA_V, "Bit for V must follow Linux HWCAP");
+ assert(ext_i.feature_bit() == HWCAP_ISA_I, "Bit for I must follow Linux HWCAP");
+ assert(ext_m.feature_bit() == HWCAP_ISA_M, "Bit for M must follow Linux HWCAP");
+ assert(ext_a.feature_bit() == HWCAP_ISA_A, "Bit for A must follow Linux HWCAP");
+ assert(ext_f.feature_bit() == HWCAP_ISA_F, "Bit for F must follow Linux HWCAP");
+ assert(ext_d.feature_bit() == HWCAP_ISA_D, "Bit for D must follow Linux HWCAP");
+ assert(ext_c.feature_bit() == HWCAP_ISA_C, "Bit for C must follow Linux HWCAP");
+ assert(ext_q.feature_bit() == HWCAP_ISA_Q, "Bit for Q must follow Linux HWCAP");
+ assert(ext_h.feature_bit() == HWCAP_ISA_H, "Bit for H must follow Linux HWCAP");
+ assert(ext_v.feature_bit() == HWCAP_ISA_V, "Bit for V must follow Linux HWCAP");
if (!RiscvHwprobe::probe_features()) {
os_aux_features();
@@ -145,9 +152,8 @@ void VM_Version::setup_cpu_available_features() {
continue;
}
- log_debug(os, cpu)("Enabled RV64 feature \"%s\" (%ld)",
- _feature_list[i]->pretty(),
- _feature_list[i]->value());
+ _feature_list[i]->log_enabled();
+
// The feature string
if (_feature_list[i]->feature_string()) {
const char* tmp = _feature_list[i]->pretty();
@@ -303,7 +309,7 @@ void VM_Version::rivos_features() {
ext_Zvfh.enable_feature();
- unaligned_access.enable_feature(MISALIGNED_FAST);
+ unaligned_scalar.enable_feature(MISALIGNED_SCALAR_FAST);
satp_mode.enable_feature(VM_SV48);
// Features dependent on march/mimpid.
diff --git a/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp
similarity index 98%
rename from src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp
rename to src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp
index ec620e3907a..5849d69ae2f 100644
--- a/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp
+++ b/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp
@@ -23,8 +23,8 @@
*
*/
-#ifndef OS_CPU_LINUX_S390_ATOMIC_LINUX_S390_HPP
-#define OS_CPU_LINUX_S390_ATOMIC_LINUX_S390_HPP
+#ifndef OS_CPU_LINUX_S390_ATOMICACCESS_LINUX_S390_HPP
+#define OS_CPU_LINUX_S390_ATOMICACCESS_LINUX_S390_HPP
#include "runtime/atomicAccess.hpp"
#include "runtime/os.hpp"
@@ -345,4 +345,4 @@ struct AtomicAccess::PlatformOrderedLoad
T operator()(const volatile T* p) const { T t = *p; OrderAccess::acquire(); return t; }
};
-#endif // OS_CPU_LINUX_S390_ATOMIC_LINUX_S390_HPP
+#endif // OS_CPU_LINUX_S390_ATOMICACCESS_LINUX_S390_HPP
diff --git a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp
similarity index 97%
rename from src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp
rename to src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp
index 561224f56be..c9af982525d 100644
--- a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp
+++ b/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp
@@ -22,10 +22,10 @@
*
*/
-#ifndef OS_CPU_LINUX_X86_ATOMIC_LINUX_X86_HPP
-#define OS_CPU_LINUX_X86_ATOMIC_LINUX_X86_HPP
+#ifndef OS_CPU_LINUX_X86_ATOMICACCESS_LINUX_X86_HPP
+#define OS_CPU_LINUX_X86_ATOMICACCESS_LINUX_X86_HPP
-// Implementation of class atomic
+// Implementation of class AtomicAccess
template
struct AtomicAccess::PlatformAdd {
@@ -230,4 +230,4 @@ struct AtomicAccess::PlatformOrderedStore<8, RELEASE_X_FENCE>
};
#endif // AMD64
-#endif // OS_CPU_LINUX_X86_ATOMIC_LINUX_X86_HPP
+#endif // OS_CPU_LINUX_X86_ATOMICACCESS_LINUX_X86_HPP
diff --git a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp
similarity index 96%
rename from src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp
rename to src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp
index 05d567d3e28..376ef7a9dc9 100644
--- a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp
+++ b/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp
@@ -23,12 +23,12 @@
*
*/
-#ifndef OS_CPU_LINUX_ZERO_ATOMIC_LINUX_ZERO_HPP
-#define OS_CPU_LINUX_ZERO_ATOMIC_LINUX_ZERO_HPP
+#ifndef OS_CPU_LINUX_ZERO_ATOMICACCESS_LINUX_ZERO_HPP
+#define OS_CPU_LINUX_ZERO_ATOMICACCESS_LINUX_ZERO_HPP
#include "orderAccess_linux_zero.hpp"
-// Implementation of class atomic
+// Implementation of class AtomicAccess
template
struct AtomicAccess::PlatformAdd {
@@ -149,4 +149,4 @@ inline void AtomicAccess::PlatformStore<8>::operator()(T volatile* dest,
__atomic_store(dest, &store_value, __ATOMIC_RELAXED);
}
-#endif // OS_CPU_LINUX_ZERO_ATOMIC_LINUX_ZERO_HPP
+#endif // OS_CPU_LINUX_ZERO_ATOMICACCESS_LINUX_ZERO_HPP
diff --git a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp
index c9ac461851a..ee9c5e2dfb2 100644
--- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp
+++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp
@@ -24,7 +24,6 @@
*/
#include "asm/assembler.inline.hpp"
-#include "atomic_linux_zero.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
@@ -36,6 +35,7 @@
#include "prims/jniFastGetField.hpp"
#include "prims/jvm_misc.hpp"
#include "runtime/arguments.hpp"
+#include "runtime/atomicAccess.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/java.hpp"
@@ -86,9 +86,7 @@ char* os::non_memory_address_word() {
address os::Posix::ucontext_get_pc(const ucontext_t* uc) {
if (DecodeErrorContext) {
-#if defined(IA32)
- return (address)uc->uc_mcontext.gregs[REG_EIP];
-#elif defined(AMD64)
+#if defined(AMD64)
return (address)uc->uc_mcontext.gregs[REG_RIP];
#elif defined(ARM)
return (address)uc->uc_mcontext.arm_pc;
@@ -117,9 +115,7 @@ void os::Posix::ucontext_set_pc(ucontext_t* uc, address pc) {
intptr_t* os::Linux::ucontext_get_sp(const ucontext_t* uc) {
if (DecodeErrorContext) {
-#if defined(IA32)
- return (intptr_t*)uc->uc_mcontext.gregs[REG_UESP];
-#elif defined(AMD64)
+#if defined(AMD64)
return (intptr_t*)uc->uc_mcontext.gregs[REG_RSP];
#elif defined(ARM)
return (intptr_t*)uc->uc_mcontext.arm_sp;
@@ -144,9 +140,7 @@ intptr_t* os::Linux::ucontext_get_sp(const ucontext_t* uc) {
intptr_t* os::Linux::ucontext_get_fp(const ucontext_t* uc) {
if (DecodeErrorContext) {
-#if defined(IA32)
- return (intptr_t*)uc->uc_mcontext.gregs[REG_EBP];
-#elif defined(AMD64)
+#if defined(AMD64)
return (intptr_t*)uc->uc_mcontext.gregs[REG_RBP];
#elif defined(ARM)
return (intptr_t*)uc->uc_mcontext.arm_fp;
diff --git a/src/hotspot/os_cpu/windows_aarch64/atomic_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp
similarity index 96%
rename from src/hotspot/os_cpu/windows_aarch64/atomic_windows_aarch64.hpp
rename to src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp
index 42c5b0e4a6c..62b6e3f87ec 100644
--- a/src/hotspot/os_cpu/windows_aarch64/atomic_windows_aarch64.hpp
+++ b/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp
@@ -23,8 +23,8 @@
*
*/
-#ifndef OS_CPU_WINDOWS_AARCH64_ATOMIC_WINDOWS_AARCH64_HPP
-#define OS_CPU_WINDOWS_AARCH64_ATOMIC_WINDOWS_AARCH64_HPP
+#ifndef OS_CPU_WINDOWS_AARCH64_ATOMICACCESS_WINDOWS_AARCH64_HPP
+#define OS_CPU_WINDOWS_AARCH64_ATOMICACCESS_WINDOWS_AARCH64_HPP
#include
#include "runtime/os.hpp"
@@ -109,4 +109,4 @@ DEFINE_INTRINSIC_CMPXCHG(InterlockedCompareExchange64, __int64)
#undef DEFINE_INTRINSIC_CMPXCHG
-#endif // OS_CPU_WINDOWS_AARCH64_ATOMIC_WINDOWS_AARCH64_HPP
+#endif // OS_CPU_WINDOWS_AARCH64_ATOMICACCESS_WINDOWS_AARCH64_HPP
diff --git a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp
index 01105e6d51e..d99e0167cbd 100644
--- a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp
+++ b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp
@@ -115,6 +115,10 @@ intptr_t* os::fetch_bcp_from_context(const void* ucVoid) {
return reinterpret_cast(uc->REG_BCP);
}
+void os::win32::context_set_pc(CONTEXT* uc, address pc) {
+ uc->Pc = (intptr_t)pc;
+}
+
bool os::win32::get_frame_at_stack_banging_point(JavaThread* thread,
struct _EXCEPTION_POINTERS* exceptionInfo, address pc, frame* fr) {
PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
diff --git a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.inline.hpp b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.inline.hpp
index 794aa12155b..568b6e3938e 100644
--- a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.inline.hpp
+++ b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.inline.hpp
@@ -26,10 +26,17 @@
#define OS_CPU_WINDOWS_AARCH64_OS_WINDOWS_AARCH64_INLINE_HPP
#include "runtime/os.hpp"
+#include "os_windows.hpp"
inline bool os::register_code_area(char *low, char *high) {
// Using Vectored Exception Handling
return true;
}
+#define HAVE_PLATFORM_PRINT_NATIVE_STACK 1
+inline bool os::platform_print_native_stack(outputStream* st, const void* context,
+ char *buf, int buf_size, address& lastpc) {
+ return os::win32::platform_print_native_stack(st, context, buf, buf_size, lastpc);
+}
+
#endif // OS_CPU_WINDOWS_AARCH64_OS_WINDOWS_AARCH64_INLINE_HPP
diff --git a/src/hotspot/os_cpu/windows_aarch64/safefetch_windows_aarch64.S b/src/hotspot/os_cpu/windows_aarch64/safefetch_windows_aarch64.S
new file mode 100644
index 00000000000..494b68fe4cd
--- /dev/null
+++ b/src/hotspot/os_cpu/windows_aarch64/safefetch_windows_aarch64.S
@@ -0,0 +1,65 @@
+;
+; Copyright (c) 2022 SAP SE. All rights reserved.
+; Copyright (c) 2022, 2025, 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.
+;
+
+ ; Support for int SafeFetch32(int* address, int defaultval);
+ ;
+ ; x0 : address
+ ; w1 : defaultval
+
+ ; needed to align function start to 4 byte
+ ALIGN 4
+ EXPORT _SafeFetch32_fault
+ EXPORT _SafeFetch32_continuation
+ EXPORT SafeFetch32_impl
+ AREA safefetch_text, CODE
+
+SafeFetch32_impl
+_SafeFetch32_fault
+ ldr w0, [x0]
+ ret
+
+_SafeFetch32_continuation
+ mov x0, x1
+ ret
+
+ ; Support for intptr_t SafeFetchN(intptr_t* address, intptr_t defaultval);
+ ;
+ ; x0 : address
+ ; x1 : defaultval
+
+ ALIGN 4
+ EXPORT _SafeFetchN_fault
+ EXPORT _SafeFetchN_continuation
+ EXPORT SafeFetchN_impl
+
+SafeFetchN_impl
+_SafeFetchN_fault
+ ldr x0, [x0]
+ ret
+
+_SafeFetchN_continuation
+ mov x0, x1
+ ret
+
+ END
diff --git a/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp
similarity index 97%
rename from src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp
rename to src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp
index 4529da29092..a95da151688 100644
--- a/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp
+++ b/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp
@@ -22,8 +22,8 @@
*
*/
-#ifndef OS_CPU_WINDOWS_X86_ATOMIC_WINDOWS_X86_HPP
-#define OS_CPU_WINDOWS_X86_ATOMIC_WINDOWS_X86_HPP
+#ifndef OS_CPU_WINDOWS_X86_ATOMICACCESS_WINDOWS_X86_HPP
+#define OS_CPU_WINDOWS_X86_ATOMICACCESS_WINDOWS_X86_HPP
#include
#include "runtime/os.hpp"
@@ -111,4 +111,4 @@ DEFINE_INTRINSIC_CMPXCHG(InterlockedCompareExchange64, __int64)
#undef DEFINE_INTRINSIC_CMPXCHG
-#endif // OS_CPU_WINDOWS_X86_ATOMIC_WINDOWS_X86_HPP
+#endif // OS_CPU_WINDOWS_X86_ATOMICACCESS_WINDOWS_X86_HPP
diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
index c188919595c..c688848c790 100644
--- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
+++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
@@ -51,6 +51,8 @@
#include "utilities/vmError.hpp"
#include "windbghelp.hpp"
+#include
+
#undef REG_SP
#undef REG_FP
@@ -197,98 +199,6 @@ bool handle_FLT_exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
}
#endif
-#ifdef HAVE_PLATFORM_PRINT_NATIVE_STACK
-/*
- * Windows/x64 does not use stack frames the way expected by Java:
- * [1] in most cases, there is no frame pointer. All locals are addressed via RSP
- * [2] in rare cases, when alloca() is used, a frame pointer is used, but this may
- * not be RBP.
- * See http://msdn.microsoft.com/en-us/library/ew5tede7.aspx
- *
- * So it's not possible to print the native stack using the
- * while (...) {... fr = os::get_sender_for_C_frame(&fr); }
- * loop in vmError.cpp. We need to roll our own loop.
- */
-bool os::win32::platform_print_native_stack(outputStream* st, const void* context,
- char *buf, int buf_size, address& lastpc)
-{
- CONTEXT ctx;
- if (context != nullptr) {
- memcpy(&ctx, context, sizeof(ctx));
- } else {
- RtlCaptureContext(&ctx);
- }
-
- st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
-
- STACKFRAME stk;
- memset(&stk, 0, sizeof(stk));
- stk.AddrStack.Offset = ctx.Rsp;
- stk.AddrStack.Mode = AddrModeFlat;
- stk.AddrFrame.Offset = ctx.Rbp;
- stk.AddrFrame.Mode = AddrModeFlat;
- stk.AddrPC.Offset = ctx.Rip;
- stk.AddrPC.Mode = AddrModeFlat;
-
- // Ensure we consider dynamically loaded dll's
- SymbolEngine::refreshModuleList();
-
- int count = 0;
- address lastpc_internal = 0;
- while (count++ < StackPrintLimit) {
- 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;
-
- if (pc != nullptr) {
- if (count == 2 && lastpc_internal == pc) {
- // Skip it -- StackWalk64() may return the same PC
- // (but different SP) on the first try.
- } else {
- // Don't try to create a frame(sp, fp, pc) -- on WinX64, stk.AddrFrame
- // may not contain what Java expects, and may cause the frame() constructor
- // to crash. Let's just print out the symbolic address.
- frame::print_C_frame(st, buf, buf_size, pc);
- // print source file and line, if available
- char buf[128];
- int line_no;
- if (SymbolEngine::get_source_info(pc, buf, sizeof(buf), &line_no)) {
- st->print(" (%s:%d)", buf, line_no);
- } else {
- st->print(" (no source info available)");
- }
- st->cr();
- }
- lastpc_internal = pc;
- }
-
- PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
- if (!p) {
- // StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash.
- lastpc = lastpc_internal;
- break;
- }
-
- BOOL result = WindowsDbgHelp::stackWalk64(
- IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType,
- GetCurrentProcess(), // __in HANDLE hProcess,
- GetCurrentThread(), // __in HANDLE hThread,
- &stk, // __inout LP STACKFRAME64 StackFrame,
- &ctx); // __inout PVOID ContextRecord,
-
- if (!result) {
- break;
- }
- }
- if (count > StackPrintLimit) {
- st->print_cr("......");
- }
- st->cr();
-
- return true;
-}
-#endif // HAVE_PLATFORM_PRINT_NATIVE_STACK
-
address os::fetch_frame_from_context(const void* ucVoid,
intptr_t** ret_sp, intptr_t** ret_fp) {
@@ -339,11 +249,15 @@ intptr_t* os::fetch_bcp_from_context(const void* ucVoid) {
// Returns the current stack pointer. Accurate value needed for
// os::verify_stack_alignment().
+// The function is intentionally not inlined. This way, the transfer of control
+// into this method must be made with a call instruction. The MSVC
+// _AddressOfReturnAddress() intrinsic returns the address of the return PC
+// saved by that call instruction. Therefore, the stack pointer of the caller
+// just before the call instruction, is acquired by skipping over the return PC
+// slot in the stack.
+__declspec(noinline)
address os::current_stack_pointer() {
- typedef address get_sp_func();
- get_sp_func* func = CAST_TO_FN_PTR(get_sp_func*,
- StubRoutines::x86::get_previous_sp_entry());
- return (*func)();
+ return ((address)_AddressOfReturnAddress()) + sizeof(void*);
}
bool os::win32::get_frame_at_stack_banging_point(JavaThread* thread,
@@ -500,11 +414,7 @@ void os::setup_fpu() {
#ifndef PRODUCT
void os::verify_stack_alignment() {
- // The current_stack_pointer() calls generated get_previous_sp stub routine.
- // Only enable the assert after the routine becomes available.
- if (StubRoutines::initial_stubs_code() != nullptr) {
- assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment");
- }
+ assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment");
}
#endif
diff --git a/src/hotspot/share/adlc/archDesc.cpp b/src/hotspot/share/adlc/archDesc.cpp
index 263752c521d..2461903ea26 100644
--- a/src/hotspot/share/adlc/archDesc.cpp
+++ b/src/hotspot/share/adlc/archDesc.cpp
@@ -899,10 +899,12 @@ int ArchDesc::emit_msg(int quiet, int flag, int line, const char *fmt,
// Construct the name of the register mask.
static const char *getRegMask(const char *reg_class_name) {
- if( reg_class_name == nullptr ) return "RegMask::Empty";
+ if (reg_class_name == nullptr) {
+ return "RegMask::EMPTY";
+ }
if (strcmp(reg_class_name,"Universe")==0) {
- return "RegMask::Empty";
+ return "RegMask::EMPTY";
} else if (strcmp(reg_class_name,"stack_slots")==0) {
return "(Compile::current()->FIRST_STACK_mask())";
} else if (strcmp(reg_class_name, "dynamic")==0) {
@@ -920,7 +922,7 @@ static const char *getRegMask(const char *reg_class_name) {
// Convert a register class name to its register mask.
const char *ArchDesc::reg_class_to_reg_mask(const char *rc_name) {
- const char *reg_mask = "RegMask::Empty";
+ const char* reg_mask = "RegMask::EMPTY";
if( _register ) {
RegClass *reg_class = _register->getRegClass(rc_name);
@@ -939,7 +941,7 @@ const char *ArchDesc::reg_class_to_reg_mask(const char *rc_name) {
// Obtain the name of the RegMask for an OperandForm
const char *ArchDesc::reg_mask(OperandForm &opForm) {
- const char *regMask = "RegMask::Empty";
+ const char* regMask = "RegMask::EMPTY";
// Check constraints on result's register class
const char *result_class = opForm.constrained_reg_class();
@@ -968,9 +970,9 @@ const char *ArchDesc::reg_mask(InstructForm &inForm) {
abort();
}
- // Instructions producing 'Universe' use RegMask::Empty
+ // Instructions producing 'Universe' use RegMask::EMPTY
if (strcmp(result,"Universe") == 0) {
- return "RegMask::Empty";
+ return "RegMask::EMPTY";
}
// Lookup this result operand and get its register class
diff --git a/src/hotspot/share/adlc/formsopt.cpp b/src/hotspot/share/adlc/formsopt.cpp
index 92489da2f5a..fbd1043492e 100644
--- a/src/hotspot/share/adlc/formsopt.cpp
+++ b/src/hotspot/share/adlc/formsopt.cpp
@@ -162,22 +162,24 @@ bool RegisterForm::verify() {
return valid;
}
+// Compute the least number of words required for registers in register masks.
+int RegisterForm::words_for_regs() {
+ return (_reg_ctr + 31) >> 5;
+}
+
// Compute RegMask size
int RegisterForm::RegMask_Size() {
- // Need at least this many words
- int words_for_regs = (_reg_ctr + 31)>>5;
- // The array of Register Mask bits should be large enough to cover
- // all the machine registers and all parameters that need to be passed
- // on the stack (stack registers) up to some interesting limit. Methods
- // that need more parameters will NOT be compiled. On Intel, the limit
- // is something like 90+ parameters.
+ // The array of Register Mask bits should be large enough to cover all the
+ // machine registers, as well as a certain number of parameters that need to
+ // be passed on the stack (stack registers). The number of parameters that can
+ // fit in the mask should be dimensioned to cover most common cases.
// - Add a few (3 words == 96 bits) for incoming & outgoing arguments to
// calls.
// - Round up to the next doubleword size.
// - Add one more word to accommodate a reasonable number of stack locations
// in the register mask regardless of how much slack is created by rounding.
// This was found necessary after adding 16 new registers for APX.
- return (words_for_regs + 3 + 1 + 1) & ~1;
+ return (words_for_regs() + 3 + 1 + 1) & ~1;
}
void RegisterForm::dump() { // Debug printer
@@ -369,14 +371,14 @@ void RegClass::build_register_masks(FILE* fp) {
for(i = 0; i < len - 1; i++) {
fprintf(fp," 0x%x,", regs_in_word(i, false));
}
- fprintf(fp," 0x%x );\n", regs_in_word(i, false));
+ fprintf(fp, " 0x%x, false );\n", regs_in_word(i, false));
if (_stack_or_reg) {
fprintf(fp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper);
for(i = 0; i < len - 1; i++) {
fprintf(fp," 0x%x,", regs_in_word(i, true));
}
- fprintf(fp," 0x%x );\n", regs_in_word(i, true));
+ fprintf(fp, " 0x%x, true );\n", regs_in_word(i, true));
}
delete[] rc_name_to_upper;
}
diff --git a/src/hotspot/share/adlc/formsopt.hpp b/src/hotspot/share/adlc/formsopt.hpp
index 34cbc24bed0..9e0c9db854d 100644
--- a/src/hotspot/share/adlc/formsopt.hpp
+++ b/src/hotspot/share/adlc/formsopt.hpp
@@ -93,6 +93,8 @@ public:
Dict _allocClass; // Dictionary of allocation classes
static int _reg_ctr; // Register counter
+ static int words_for_regs(); // Compute the least number of words required for
+ // registers in register masks.
static int RegMask_Size(); // Compute RegMask size
// Public Methods
diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp
index 35bdbfd6962..f378047aabc 100644
--- a/src/hotspot/share/adlc/formssel.cpp
+++ b/src/hotspot/share/adlc/formssel.cpp
@@ -2422,7 +2422,7 @@ const char *OperandForm::constrained_reg_class() const {
// Return the register class associated with 'leaf'.
const char *OperandForm::in_reg_class(uint leaf, FormDict &globals) {
- const char *reg_class = nullptr; // "RegMask::Empty";
+ const char* reg_class = nullptr; // "RegMask::EMPTY";
if((_matrule == nullptr) || (_matrule->is_chain_rule(globals))) {
reg_class = constrained_reg_class();
diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp
index caf2c9952a6..9cbd6aaf66f 100644
--- a/src/hotspot/share/adlc/output_c.cpp
+++ b/src/hotspot/share/adlc/output_c.cpp
@@ -2323,7 +2323,7 @@ private:
if (strcmp(rep_var,"$Register") == 0) return "as_Register";
if (strcmp(rep_var,"$KRegister") == 0) return "as_KRegister";
if (strcmp(rep_var,"$FloatRegister") == 0) return "as_FloatRegister";
-#if defined(IA32) || defined(AMD64)
+#if defined(AMD64)
if (strcmp(rep_var,"$XMMRegister") == 0) return "as_XMMRegister";
#endif
if (strcmp(rep_var,"$CondRegister") == 0) return "as_ConditionRegister";
@@ -2837,7 +2837,7 @@ static void defineIn_RegMask(FILE *fp, FormDict &globals, OperandForm &oper) {
if (strcmp(first_reg_class, "stack_slots") == 0) {
fprintf(fp," return &(Compile::current()->FIRST_STACK_mask());\n");
} else if (strcmp(first_reg_class, "dynamic") == 0) {
- fprintf(fp," return &RegMask::Empty;\n");
+ fprintf(fp, " return &RegMask::EMPTY;\n");
} else {
const char* first_reg_class_to_upper = toUpper(first_reg_class);
fprintf(fp," return &%s_mask();\n", first_reg_class_to_upper);
diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp
index 0ef8b19c79f..6cb82f4df7f 100644
--- a/src/hotspot/share/adlc/output_h.cpp
+++ b/src/hotspot/share/adlc/output_h.cpp
@@ -99,6 +99,8 @@ void ArchDesc::buildMachRegisterNumbers(FILE *fp_hpp) {
fprintf(fp_hpp, "\n// Size of register-mask in ints\n");
fprintf(fp_hpp, "#define RM_SIZE_IN_INTS %d\n", RegisterForm::RegMask_Size());
+ fprintf(fp_hpp, "// Minimum size of register-mask in ints\n");
+ fprintf(fp_hpp, "#define RM_SIZE_IN_INTS_MIN %d\n", RegisterForm::words_for_regs());
fprintf(fp_hpp, "// Unroll factor for loops over the data in a RegMask\n");
fprintf(fp_hpp, "#define FORALL_BODY ");
int len = RegisterForm::RegMask_Size();
@@ -757,20 +759,15 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) {
if (_pipeline->_maxcycleused <= 32) {
fprintf(fp_hpp, "protected:\n");
- fprintf(fp_hpp, " %s _mask;\n\n", _pipeline->_maxcycleused <= 32 ? "uint" : "uint64_t" );
+ fprintf(fp_hpp, " uint32_t _mask;\n\n");
fprintf(fp_hpp, "public:\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask() : _mask(0) {}\n\n");
- if (_pipeline->_maxcycleused <= 32)
- fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint mask) : _mask(mask) {}\n\n");
- else {
- fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint mask1, uint mask2) : _mask((((uint64_t)mask1) << 32) | mask2) {}\n\n");
- fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint64_t mask) : _mask(mask) {}\n\n");
- }
+ fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint32_t mask) : _mask(mask) {}\n\n");
fprintf(fp_hpp, " bool overlaps(const Pipeline_Use_Cycle_Mask &in2) const {\n");
fprintf(fp_hpp, " return ((_mask & in2._mask) != 0);\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator<<=(int n) {\n");
- fprintf(fp_hpp, " _mask <<= n;\n");
+ fprintf(fp_hpp, " _mask <<= (n < 32) ? n : 31;\n");
fprintf(fp_hpp, " return *this;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " void Or(const Pipeline_Use_Cycle_Mask &in2) {\n");
@@ -783,7 +780,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) {
fprintf(fp_hpp, "protected:\n");
uint masklen = (_pipeline->_maxcycleused + 31) >> 5;
uint l;
- fprintf(fp_hpp, " uint ");
+ fprintf(fp_hpp, " uint32_t ");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, "_mask%d%s", l, l < masklen ? ", " : ";\n\n");
fprintf(fp_hpp, "public:\n");
@@ -792,7 +789,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) {
fprintf(fp_hpp, "_mask%d(0)%s", l, l < masklen ? ", " : " {}\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(");
for (l = 1; l <= masklen; l++)
- fprintf(fp_hpp, "uint mask%d%s", l, l < masklen ? ", " : ") : ");
+ fprintf(fp_hpp, "uint32_t mask%d%s", l, l < masklen ? ", " : ") : ");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, "_mask%d(mask%d)%s", l, l, l < masklen ? ", " : " {}\n\n");
@@ -803,10 +800,10 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) {
fprintf(fp_hpp, " return out;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " bool overlaps(const Pipeline_Use_Cycle_Mask &in2) const {\n");
- fprintf(fp_hpp, " return (");
+ fprintf(fp_hpp, " return ");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, "((_mask%d & in2._mask%d) != 0)%s", l, l, l < masklen ? " || " : "");
- fprintf(fp_hpp, ") ? true : false;\n");
+ fprintf(fp_hpp, ";\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator<<=(int n) {\n");
fprintf(fp_hpp, " if (n >= 32)\n");
@@ -817,10 +814,10 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) {
fprintf(fp_hpp, " } while ((n -= 32) >= 32);\n\n");
fprintf(fp_hpp, " if (n > 0) {\n");
fprintf(fp_hpp, " uint m = 32 - n;\n");
- fprintf(fp_hpp, " uint mask = (1 << n) - 1;\n");
- fprintf(fp_hpp, " uint temp%d = mask & (_mask%d >> m); _mask%d <<= n;\n", 2, 1, 1);
+ fprintf(fp_hpp, " uint32_t mask = (1 << n) - 1;\n");
+ fprintf(fp_hpp, " uint32_t temp%d = mask & (_mask%d >> m); _mask%d <<= n;\n", 2, 1, 1);
for (l = 2; l < masklen; l++) {
- fprintf(fp_hpp, " uint temp%d = mask & (_mask%d >> m); _mask%d <<= n; _mask%d |= temp%d;\n", l+1, l, l, l, l);
+ fprintf(fp_hpp, " uint32_t temp%d = mask & (_mask%d >> m); _mask%d <<= n; _mask%d |= temp%d;\n", l+1, l, l, l, l);
}
fprintf(fp_hpp, " _mask%d <<= n; _mask%d |= temp%d;\n", masklen, masklen, masklen);
fprintf(fp_hpp, " }\n");
@@ -870,8 +867,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) {
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " void step(uint cycles) {\n");
fprintf(fp_hpp, " _used = 0;\n");
- fprintf(fp_hpp, " uint max_shift = 8 * sizeof(_mask) - 1;\n");
- fprintf(fp_hpp, " _mask <<= (cycles < max_shift) ? cycles : max_shift;\n");
+ fprintf(fp_hpp, " _mask <<= cycles;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " friend class Pipeline_Use;\n");
fprintf(fp_hpp, "};\n\n");
diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp
index 35bbd2f657f..430d4949467 100644
--- a/src/hotspot/share/asm/codeBuffer.hpp
+++ b/src/hotspot/share/asm/codeBuffer.hpp
@@ -57,7 +57,6 @@ public:
OSR_Entry,
Exceptions, // Offset where exception handler lives
Deopt, // Offset where deopt handler lives
- DeoptMH, // Offset where MethodHandle deopt handler lives
UnwindHandler, // Offset to default unwind handler
max_Entries };
@@ -77,7 +76,6 @@ public:
_values[OSR_Entry ] = 0;
_values[Exceptions ] = -1;
_values[Deopt ] = -1;
- _values[DeoptMH ] = -1;
_values[UnwindHandler ] = -1;
}
diff --git a/src/hotspot/share/c1/c1_CodeStubs.hpp b/src/hotspot/share/c1/c1_CodeStubs.hpp
index 5d1c51bdbbf..9a462006bcc 100644
--- a/src/hotspot/share/c1/c1_CodeStubs.hpp
+++ b/src/hotspot/share/c1/c1_CodeStubs.hpp
@@ -138,7 +138,7 @@ class ConversionStub: public CodeStub {
public:
ConversionStub(Bytecodes::Code bytecode, LIR_Opr input, LIR_Opr result)
: _bytecode(bytecode), _input(input), _result(result) {
- NOT_IA32( ShouldNotReachHere(); ) // used only on x86-32
+ ShouldNotReachHere();
}
Bytecodes::Code bytecode() { return _bytecode; }
@@ -371,21 +371,16 @@ class MonitorEnterStub: public MonitorAccessStub {
class MonitorExitStub: public MonitorAccessStub {
private:
- bool _compute_lock;
int _monitor_ix;
public:
- MonitorExitStub(LIR_Opr lock_reg, bool compute_lock, int monitor_ix)
+ MonitorExitStub(LIR_Opr lock_reg, int monitor_ix)
: MonitorAccessStub(LIR_OprFact::illegalOpr, lock_reg),
- _compute_lock(compute_lock), _monitor_ix(monitor_ix) { }
+ _monitor_ix(monitor_ix) { }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
assert(_obj_reg->is_illegal(), "unused");
- if (_compute_lock) {
- visitor->do_temp(_lock_reg);
- } else {
- visitor->do_input(_lock_reg);
- }
+ visitor->do_temp(_lock_reg);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("MonitorExitStub"); }
diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp
index bb5ceb0106b..368cf604eeb 100644
--- a/src/hotspot/share/c1/c1_Compilation.cpp
+++ b/src/hotspot/share/c1/c1_Compilation.cpp
@@ -310,14 +310,6 @@ void Compilation::emit_code_epilog(LIR_Assembler* assembler) {
code_offsets->set_value(CodeOffsets::Deopt, assembler->emit_deopt_handler());
CHECK_BAILOUT();
- // Emit the MethodHandle deopt handler code (if required).
- if (has_method_handle_invokes()) {
- // We can use the same code as for the normal deopt handler, we
- // just need a different entry point address.
- code_offsets->set_value(CodeOffsets::DeoptMH, assembler->emit_deopt_handler());
- CHECK_BAILOUT();
- }
-
// Emit the handler to remove the activation from the stack and
// dispatch to the caller.
offsets()->set_value(CodeOffsets::UnwindHandler, assembler->emit_unwind_handler());
@@ -574,7 +566,6 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho
, _has_unsafe_access(false)
, _has_irreducible_loops(false)
, _would_profile(false)
-, _has_method_handle_invokes(false)
, _has_reserved_stack_access(method->has_reserved_stack_access())
, _has_monitors(method->is_synchronized() || method->has_monitor_bytecodes())
, _has_scoped_access(method->is_scoped())
diff --git a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp
index 0c6b95e66c5..5125e0bbe0a 100644
--- a/src/hotspot/share/c1/c1_Compilation.hpp
+++ b/src/hotspot/share/c1/c1_Compilation.hpp
@@ -79,7 +79,6 @@ class Compilation: public StackObj {
bool _has_unsafe_access;
bool _has_irreducible_loops;
bool _would_profile;
- bool _has_method_handle_invokes; // True if this method has MethodHandle invokes.
bool _has_reserved_stack_access;
bool _has_monitors; // Fastpath monitors detection for Continuations
bool _has_scoped_access; // For shared scope closure
@@ -180,10 +179,6 @@ class Compilation: public StackObj {
// Statistics gathering
void notice_inlined_method(ciMethod* method);
- // JSR 292
- bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
- void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; }
-
bool has_reserved_stack_access() const { return _has_reserved_stack_access; }
void set_has_reserved_stack_access(bool z) { _has_reserved_stack_access = z; }
diff --git a/src/hotspot/share/c1/c1_FrameMap.hpp b/src/hotspot/share/c1/c1_FrameMap.hpp
index f10c4d3f226..67ae92e9875 100644
--- a/src/hotspot/share/c1/c1_FrameMap.hpp
+++ b/src/hotspot/share/c1/c1_FrameMap.hpp
@@ -155,9 +155,6 @@ class FrameMap : public CompilationResourceObj {
// Opr representing the stack_pointer on this platform
static LIR_Opr stack_pointer();
- // JSR 292
- static LIR_Opr method_handle_invoke_SP_save_opr();
-
static BasicTypeArray* signature_type_array_for(const ciMethod* method);
// for outgoing calls, these also update the reserved area to
diff --git a/src/hotspot/share/c1/c1_IR.cpp b/src/hotspot/share/c1/c1_IR.cpp
index ae8332116b3..238a9bdda0d 100644
--- a/src/hotspot/share/c1/c1_IR.cpp
+++ b/src/hotspot/share/c1/c1_IR.cpp
@@ -190,7 +190,6 @@ CodeEmitInfo::CodeEmitInfo(ValueStack* stack, XHandlers* exception_handlers, boo
, _exception_handlers(exception_handlers)
, _oop_map(nullptr)
, _stack(stack)
- , _is_method_handle_invoke(false)
, _deoptimize_on_exception(deoptimize_on_exception)
, _force_reexecute(false) {
assert(_stack != nullptr, "must be non null");
@@ -203,7 +202,6 @@ CodeEmitInfo::CodeEmitInfo(CodeEmitInfo* info, ValueStack* stack)
, _exception_handlers(nullptr)
, _oop_map(nullptr)
, _stack(stack == nullptr ? info->_stack : stack)
- , _is_method_handle_invoke(info->_is_method_handle_invoke)
, _deoptimize_on_exception(info->_deoptimize_on_exception)
, _force_reexecute(info->_force_reexecute) {
@@ -218,7 +216,7 @@ void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_
// record the safepoint before recording the debug info for enclosing scopes
recorder->add_safepoint(pc_offset, _oop_map->deep_copy());
bool reexecute = _force_reexecute || _scope_debug_info->should_reexecute();
- _scope_debug_info->record_debug_info(recorder, pc_offset, reexecute, _is_method_handle_invoke);
+ _scope_debug_info->record_debug_info(recorder, pc_offset, reexecute);
recorder->end_safepoint(pc_offset);
}
diff --git a/src/hotspot/share/c1/c1_IR.hpp b/src/hotspot/share/c1/c1_IR.hpp
index a9a7a026390..d6a4cddb9d7 100644
--- a/src/hotspot/share/c1/c1_IR.hpp
+++ b/src/hotspot/share/c1/c1_IR.hpp
@@ -234,7 +234,7 @@ class IRScopeDebugInfo: public CompilationResourceObj {
//Whether we should reexecute this bytecode for deopt
bool should_reexecute();
- void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool reexecute, bool is_method_handle_invoke = false) {
+ void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool reexecute) {
if (caller() != nullptr) {
// Order is significant: Must record caller first.
caller()->record_debug_info(recorder, pc_offset, false/*reexecute*/);
@@ -248,7 +248,7 @@ class IRScopeDebugInfo: public CompilationResourceObj {
bool has_ea_local_in_scope = false;
bool arg_escape = false;
recorder->describe_scope(pc_offset, methodHandle(), scope()->method(), bci(),
- reexecute, rethrow_exception, is_method_handle_invoke, return_oop,
+ reexecute, rethrow_exception, return_oop,
has_ea_local_in_scope, arg_escape, locvals, expvals, monvals);
}
};
@@ -262,7 +262,6 @@ class CodeEmitInfo: public CompilationResourceObj {
XHandlers* _exception_handlers;
OopMap* _oop_map;
ValueStack* _stack; // used by deoptimization (contains also monitors
- bool _is_method_handle_invoke; // true if the associated call site is a MethodHandle call site.
bool _deoptimize_on_exception;
bool _force_reexecute; // force the reexecute flag on, used for patching stub
@@ -288,9 +287,6 @@ class CodeEmitInfo: public CompilationResourceObj {
void add_register_oop(LIR_Opr opr);
void record_debug_info(DebugInformationRecorder* recorder, int pc_offset);
- bool is_method_handle_invoke() const { return _is_method_handle_invoke; }
- void set_is_method_handle_invoke(bool x) { _is_method_handle_invoke = x; }
-
bool force_reexecute() const { return _force_reexecute; }
void set_force_reexecute() { _force_reexecute = true; }
diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp
index f11e178bd55..012c0f92f25 100644
--- a/src/hotspot/share/c1/c1_LIR.cpp
+++ b/src/hotspot/share/c1/c1_LIR.cpp
@@ -709,11 +709,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
}
if (opJavaCall->_info) do_info(opJavaCall->_info);
- if (FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr &&
- opJavaCall->is_method_handle_invoke()) {
- opJavaCall->_method_handle_invoke_SP_save_opr = FrameMap::method_handle_invoke_SP_save_opr();
- do_temp(opJavaCall->_method_handle_invoke_SP_save_opr);
- }
do_call();
if (opJavaCall->_result->is_valid()) do_output(opJavaCall->_result);
diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp
index 0427c868e6f..847184731ce 100644
--- a/src/hotspot/share/c1/c1_LIR.hpp
+++ b/src/hotspot/share/c1/c1_LIR.hpp
@@ -1176,7 +1176,6 @@ class LIR_OpJavaCall: public LIR_OpCall {
private:
ciMethod* _method;
LIR_Opr _receiver;
- LIR_Opr _method_handle_invoke_SP_save_opr; // Used in LIR_OpVisitState::visit to store the reference to FrameMap::method_handle_invoke_SP_save_opr.
public:
LIR_OpJavaCall(LIR_Code code, ciMethod* method,
@@ -1186,7 +1185,6 @@ class LIR_OpJavaCall: public LIR_OpCall {
: LIR_OpCall(code, addr, result, arguments, info)
, _method(method)
, _receiver(receiver)
- , _method_handle_invoke_SP_save_opr(LIR_OprFact::illegalOpr)
{ assert(is_in_range(code, begin_opJavaCall, end_opJavaCall), "code check"); }
LIR_OpJavaCall(LIR_Code code, ciMethod* method,
@@ -1195,7 +1193,6 @@ class LIR_OpJavaCall: public LIR_OpCall {
: LIR_OpCall(code, (address)vtable_offset, result, arguments, info)
, _method(method)
, _receiver(receiver)
- , _method_handle_invoke_SP_save_opr(LIR_OprFact::illegalOpr)
{ assert(is_in_range(code, begin_opJavaCall, end_opJavaCall), "code check"); }
LIR_Opr receiver() const { return _receiver; }
diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp
index 6dbd35f054f..e22b5103514 100644
--- a/src/hotspot/share/c1/c1_LIRAssembler.cpp
+++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp
@@ -478,12 +478,6 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) {
fatal("unexpected op code: %s", op->name());
break;
}
-
- // JSR 292
- // Record if this method has MethodHandle invokes.
- if (op->is_method_handle_invoke()) {
- compilation()->set_has_method_handle_invokes(true);
- }
}
@@ -533,16 +527,6 @@ void LIR_Assembler::emit_op1(LIR_Op1* op) {
safepoint_poll(op->in_opr(), op->info());
break;
-#ifdef IA32
- case lir_fxch:
- fxch(op->in_opr()->as_jint());
- break;
-
- case lir_fld:
- fld(op->in_opr()->as_jint());
- break;
-#endif // IA32
-
case lir_branch:
break;
@@ -618,12 +602,6 @@ void LIR_Assembler::emit_op0(LIR_Op0* op) {
osr_entry();
break;
-#ifdef IA32
- case lir_fpop_raw:
- fpop();
- break;
-#endif // IA32
-
case lir_breakpoint:
breakpoint();
break;
diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp
index b30667dcac3..f6807abcd7a 100644
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp
@@ -635,7 +635,7 @@ void LIRGenerator::monitor_exit(LIR_Opr object, LIR_Opr lock, LIR_Opr new_hdr, L
// setup registers
LIR_Opr hdr = lock;
lock = new_hdr;
- CodeStub* slow_path = new MonitorExitStub(lock, true, monitor_no);
+ CodeStub* slow_path = new MonitorExitStub(lock, monitor_no);
__ load_stack_address_monitor(monitor_no, lock);
__ unlock_object(hdr, object, lock, scratch, slow_path);
}
@@ -2712,19 +2712,7 @@ void LIRGenerator::do_Invoke(Invoke* x) {
// emit invoke code
assert(receiver->is_illegal() || receiver->is_equal(LIR_Assembler::receiverOpr()), "must match");
- // JSR 292
- // Preserve the SP over MethodHandle call sites, if needed.
ciMethod* target = x->target();
- bool is_method_handle_invoke = (// %%% FIXME: Are both of these relevant?
- target->is_method_handle_intrinsic() ||
- target->is_compiled_lambda_form());
- if (is_method_handle_invoke) {
- info->set_is_method_handle_invoke(true);
- if(FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) {
- __ move(FrameMap::stack_pointer(), FrameMap::method_handle_invoke_SP_save_opr());
- }
- }
-
switch (x->code()) {
case Bytecodes::_invokestatic:
__ call_static(target, result_register,
@@ -2757,13 +2745,6 @@ void LIRGenerator::do_Invoke(Invoke* x) {
break;
}
- // JSR 292
- // Restore the SP after MethodHandle call sites, if needed.
- if (is_method_handle_invoke
- && FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) {
- __ move(FrameMap::method_handle_invoke_SP_save_opr(), FrameMap::stack_pointer());
- }
-
if (result_register->is_valid()) {
LIR_Opr result = rlock_result(x);
__ move(result_register, result);
diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp
index 637c7c46ef4..a4c956ff5be 100644
--- a/src/hotspot/share/c1/c1_Runtime1.cpp
+++ b/src/hotspot/share/c1/c1_Runtime1.cpp
@@ -541,9 +541,6 @@ extern void vm_exit(int code);
// unpack_with_exception entry instead. This makes life for the exception blob easier
// because making that same check and diverting is painful from assembly language.
JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* current, oopDesc* ex, address pc, nmethod*& nm))
- // Reset method handle flag.
- current->set_is_method_handle_return(false);
-
Handle exception(current, ex);
// This function is called when we are about to throw an exception. Therefore,
@@ -622,8 +619,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c
if (guard_pages_enabled) {
address fast_continuation = nm->handler_for_exception_and_pc(exception, pc);
if (fast_continuation != nullptr) {
- // Set flag if return address is a method handle call site.
- current->set_is_method_handle_return(nm->is_method_handle_return(pc));
return fast_continuation;
}
}
@@ -660,8 +655,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c
}
current->set_vm_result_oop(exception());
- // Set flag if return address is a method handle call site.
- current->set_is_method_handle_return(nm->is_method_handle_return(pc));
if (log_is_enabled(Info, exceptions)) {
ResourceMark rm;
diff --git a/src/hotspot/share/cds/aotClassInitializer.cpp b/src/hotspot/share/cds/aotClassInitializer.cpp
index 0c8ea97fba0..00db747622f 100644
--- a/src/hotspot/share/cds/aotClassInitializer.cpp
+++ b/src/hotspot/share/cds/aotClassInitializer.cpp
@@ -23,6 +23,7 @@
*/
#include "cds/aotClassInitializer.hpp"
+#include "cds/aotLinkedClassBulkLoader.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/heapShared.hpp"
@@ -47,7 +48,14 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
ik = RegeneratedClasses::get_original_object(ik);
}
+ check_aot_annotations(ik);
+
if (!ik->is_initialized() && !ik->is_being_initialized()) {
+ if (ik->has_aot_safe_initializer()) {
+ ResourceMark rm;
+ log_info(aot, init)("Class %s is annotated with @AOTSafeClassInitializer but has not been initialized",
+ ik->external_name());
+ }
return false;
}
@@ -244,6 +252,56 @@ void AOTClassInitializer::call_runtime_setup(JavaThread* current, InstanceKlass*
}
}
+template
+void require_annotation_for_super_types(InstanceKlass* ik, const char* annotation, FUNCTION func) {
+ if (log_is_enabled(Info, aot, init)) {
+ ResourceMark rm;
+ log_info(aot, init)("Found %s class %s", annotation, ik->external_name());
+ }
+
+ // Since ik has this annotation, we require that
+ // - all super classes must have this annotation
+ // - all super interfaces that are interface_needs_clinit_execution_as_super()
+ // must have this annotation
+ // This avoid the situation where in the production run, we run the
+ // of a supertype but not the of ik
+
+ InstanceKlass* super = ik->java_super();
+ if (super != nullptr && !func(super)) {
+ ResourceMark rm;
+ log_error(aot, init)("Missing %s in superclass %s for class %s",
+ annotation, super->external_name(), ik->external_name());
+ AOTMetaspace::unrecoverable_writing_error();
+ }
+
+ int len = ik->local_interfaces()->length();
+ for (int i = 0; i < len; i++) {
+ InstanceKlass* intf = ik->local_interfaces()->at(i);
+ if (intf->interface_needs_clinit_execution_as_super() && !func(intf)) {
+ ResourceMark rm;
+ log_error(aot, init)("Missing %s in superinterface %s for class %s",
+ annotation, intf->external_name(), ik->external_name());
+ AOTMetaspace::unrecoverable_writing_error();
+ }
+ }
+}
+
+void AOTClassInitializer::check_aot_annotations(InstanceKlass* ik) {
+ if (ik->has_aot_safe_initializer()) {
+ require_annotation_for_super_types(ik, "@AOTSafeClassInitializer", [&] (const InstanceKlass* supertype) {
+ return supertype->has_aot_safe_initializer();
+ });
+ } else {
+ // @AOTRuntimeSetup only meaningful in @AOTSafeClassInitializer
+ if (ik->is_runtime_setup_required()) {
+ ResourceMark rm;
+ log_error(aot, init)("@AOTRuntimeSetup meaningless in non-@AOTSafeClassInitializer class %s",
+ ik->external_name());
+ }
+ }
+}
+
+
#ifdef ASSERT
void AOTClassInitializer::init_test_class(TRAPS) {
// -XX:AOTInitTestClass is used in regression tests for adding additional AOT-initialized classes
diff --git a/src/hotspot/share/cds/aotClassInitializer.hpp b/src/hotspot/share/cds/aotClassInitializer.hpp
index 974bbeb903c..b133e120146 100644
--- a/src/hotspot/share/cds/aotClassInitializer.hpp
+++ b/src/hotspot/share/cds/aotClassInitializer.hpp
@@ -31,6 +31,9 @@
class InstanceKlass;
class AOTClassInitializer : AllStatic {
+
+ static void check_aot_annotations(InstanceKlass* ik);
+
public:
// Called by heapShared.cpp to see if src_ik->java_mirror() can be archived in
// the initialized state.
diff --git a/src/hotspot/share/cds/aotClassLinker.cpp b/src/hotspot/share/cds/aotClassLinker.cpp
index 1f9a03de83f..c66435b03bb 100644
--- a/src/hotspot/share/cds/aotClassLinker.cpp
+++ b/src/hotspot/share/cds/aotClassLinker.cpp
@@ -191,8 +191,8 @@ void AOTClassLinker::write_to_archive() {
assert_at_safepoint();
if (CDSConfig::is_dumping_aot_linked_classes()) {
- AOTLinkedClassTable* table = AOTLinkedClassTable::get(CDSConfig::is_dumping_static_archive());
- table->set_boot(write_classes(nullptr, true));
+ AOTLinkedClassTable* table = AOTLinkedClassTable::get();
+ table->set_boot1(write_classes(nullptr, true));
table->set_boot2(write_classes(nullptr, false));
table->set_platform(write_classes(SystemDictionary::java_platform_loader(), false));
table->set_app(write_classes(SystemDictionary::java_system_loader(), false));
@@ -212,16 +212,7 @@ Array* AOTClassLinker::write_classes(oop class_loader, bool is_j
continue;
}
- if (ik->in_aot_cache() && CDSConfig::is_dumping_dynamic_archive()) {
- if (CDSConfig::is_using_aot_linked_classes()) {
- // This class was recorded as AOT-linked for the base archive,
- // so there's no need to do so again for the dynamic archive.
- } else {
- list.append(ik);
- }
- } else {
- list.append(ArchiveBuilder::current()->get_buffered_addr(ik));
- }
+ list.append(ArchiveBuilder::current()->get_buffered_addr(ik));
}
if (list.length() == 0) {
diff --git a/src/hotspot/share/cds/aotConstantPoolResolver.cpp b/src/hotspot/share/cds/aotConstantPoolResolver.cpp
index 6cc3a81c2ae..ff47d00c484 100644
--- a/src/hotspot/share/cds/aotConstantPoolResolver.cpp
+++ b/src/hotspot/share/cds/aotConstantPoolResolver.cpp
@@ -224,8 +224,46 @@ void AOTConstantPoolResolver::preresolve_field_and_method_cp_entries(JavaThread*
bcs.next();
Bytecodes::Code raw_bc = bcs.raw_code();
switch (raw_bc) {
+ case Bytecodes::_getstatic:
+ case Bytecodes::_putstatic:
+ maybe_resolve_fmi_ref(ik, m, raw_bc, bcs.get_index_u2(), preresolve_list, THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION; // just ignore
+ }
+ break;
case Bytecodes::_getfield:
+ // no-fast bytecode
+ case Bytecodes::_nofast_getfield:
+ // fast bytecodes
+ case Bytecodes::_fast_agetfield:
+ case Bytecodes::_fast_bgetfield:
+ case Bytecodes::_fast_cgetfield:
+ case Bytecodes::_fast_dgetfield:
+ case Bytecodes::_fast_fgetfield:
+ case Bytecodes::_fast_igetfield:
+ case Bytecodes::_fast_lgetfield:
+ case Bytecodes::_fast_sgetfield:
+ raw_bc = Bytecodes::_getfield;
+ maybe_resolve_fmi_ref(ik, m, raw_bc, bcs.get_index_u2(), preresolve_list, THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION; // just ignore
+ }
+ break;
+
case Bytecodes::_putfield:
+ // no-fast bytecode
+ case Bytecodes::_nofast_putfield:
+ // fast bytecodes
+ case Bytecodes::_fast_aputfield:
+ case Bytecodes::_fast_bputfield:
+ case Bytecodes::_fast_zputfield:
+ case Bytecodes::_fast_cputfield:
+ case Bytecodes::_fast_dputfield:
+ case Bytecodes::_fast_fputfield:
+ case Bytecodes::_fast_iputfield:
+ case Bytecodes::_fast_lputfield:
+ case Bytecodes::_fast_sputfield:
+ raw_bc = Bytecodes::_putfield;
maybe_resolve_fmi_ref(ik, m, raw_bc, bcs.get_index_u2(), preresolve_list, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; // just ignore
@@ -235,6 +273,7 @@ void AOTConstantPoolResolver::preresolve_field_and_method_cp_entries(JavaThread*
case Bytecodes::_invokespecial:
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface:
+ case Bytecodes::_invokestatic:
maybe_resolve_fmi_ref(ik, m, raw_bc, bcs.get_index_u2(), preresolve_list, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; // just ignore
@@ -271,13 +310,31 @@ void AOTConstantPoolResolver::maybe_resolve_fmi_ref(InstanceKlass* ik, Method* m
}
Klass* resolved_klass = cp->klass_ref_at(raw_index, bc, CHECK);
+ const char* is_static = "";
switch (bc) {
+ case Bytecodes::_getstatic:
+ case Bytecodes::_putstatic:
+ if (!VM_Version::supports_fast_class_init_checks()) {
+ return; // Do not resolve since interpreter lacks fast clinit barriers support
+ }
+ InterpreterRuntime::resolve_get_put(bc, raw_index, mh, cp, false /*initialize_holder*/, CHECK);
+ is_static = " *** static";
+ break;
+
case Bytecodes::_getfield:
case Bytecodes::_putfield:
InterpreterRuntime::resolve_get_put(bc, raw_index, mh, cp, false /*initialize_holder*/, CHECK);
break;
+ case Bytecodes::_invokestatic:
+ if (!VM_Version::supports_fast_class_init_checks()) {
+ return; // Do not resolve since interpreter lacks fast clinit barriers support
+ }
+ InterpreterRuntime::cds_resolve_invoke(bc, raw_index, cp, CHECK);
+ is_static = " *** static";
+ break;
+
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokeinterface:
@@ -297,11 +354,11 @@ void AOTConstantPoolResolver::maybe_resolve_fmi_ref(InstanceKlass* ik, Method* m
bool resolved = cp->is_resolved(raw_index, bc);
Symbol* name = cp->name_ref_at(raw_index, bc);
Symbol* signature = cp->signature_ref_at(raw_index, bc);
- log_trace(aot, resolve)("%s %s [%3d] %s -> %s.%s:%s",
+ log_trace(aot, resolve)("%s %s [%3d] %s -> %s.%s:%s%s",
(resolved ? "Resolved" : "Failed to resolve"),
Bytecodes::name(bc), cp_index, ik->external_name(),
resolved_klass->external_name(),
- name->as_C_string(), signature->as_C_string());
+ name->as_C_string(), signature->as_C_string(), is_static);
}
}
diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp
index 6e5816cd589..3653f9d518c 100644
--- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp
+++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp
@@ -29,6 +29,8 @@
#include "cds/cdsConfig.hpp"
#include "cds/heapShared.hpp"
#include "classfile/classLoaderData.hpp"
+#include "classfile/classLoaderDataShared.hpp"
+#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
@@ -40,67 +42,236 @@
#include "oops/trainingData.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
+#include "runtime/serviceThread.hpp"
+#include "utilities/growableArray.hpp"
-bool AOTLinkedClassBulkLoader::_boot2_completed = false;
-bool AOTLinkedClassBulkLoader::_platform_completed = false;
-bool AOTLinkedClassBulkLoader::_app_completed = false;
-bool AOTLinkedClassBulkLoader::_all_completed = false;
-
-void AOTLinkedClassBulkLoader::serialize(SerializeClosure* soc, bool is_static_archive) {
- AOTLinkedClassTable::get(is_static_archive)->serialize(soc);
+void AOTLinkedClassBulkLoader::serialize(SerializeClosure* soc) {
+ AOTLinkedClassTable::get()->serialize(soc);
}
-bool AOTLinkedClassBulkLoader::class_preloading_finished() {
- if (!CDSConfig::is_using_aot_linked_classes()) {
- return true;
- } else {
- // The ConstantPools of preloaded classes have references to other preloaded classes. We don't
- // want any Java code (including JVMCI compiler) to use these classes until all of them
- // are loaded.
- return AtomicAccess::load_acquire(&_all_completed);
+// This function is called before the VM executes any Java code (include AOT-compiled Java methods).
+//
+// We populate the boot/platform/app class loaders with classes from the AOT cache. This is a fundamental
+// step in restoring the JVM's state from the snapshot recorded in the AOT cache: other AOT optimizations
+// such as AOT compiled methods can make direct references to the preloaded classes, knowing that
+// these classes are guaranteed to be in at least the "loaded" state.
+//
+// Note: we can't link the classes yet because SharedRuntime is not yet ready to generate adapters.
+void AOTLinkedClassBulkLoader::preload_classes(JavaThread* current) {
+ preload_classes_impl(current);
+ if (current->has_pending_exception()) {
+ exit_on_exception(current);
}
}
-void AOTLinkedClassBulkLoader::load_javabase_classes(JavaThread* current) {
- assert(CDSConfig::is_using_aot_linked_classes(), "sanity");
- load_classes_in_loader(current, AOTLinkedClassCategory::BOOT1, nullptr); // only java.base classes
+void AOTLinkedClassBulkLoader::preload_classes_impl(TRAPS) {
+ precond(CDSConfig::is_using_aot_linked_classes());
+
+ ClassLoaderDataShared::restore_archived_modules_for_preloading_classes(THREAD);
+ Handle h_platform_loader(THREAD, SystemDictionary::java_platform_loader());
+ Handle h_system_loader(THREAD, SystemDictionary::java_system_loader());
+
+ AOTLinkedClassTable* table = AOTLinkedClassTable::get();
+
+ preload_classes_in_table(table->boot1(), "boot1", Handle(), CHECK);
+ preload_classes_in_table(table->boot2(), "boot2", Handle(), CHECK);
+
+ initiate_loading(THREAD, "plat", h_platform_loader, table->boot1());
+ initiate_loading(THREAD, "plat", h_platform_loader, table->boot2());
+ preload_classes_in_table(table->platform(), "plat", h_platform_loader, CHECK);
+
+ initiate_loading(THREAD, "app", h_system_loader, table->boot1());
+ 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);
}
-void AOTLinkedClassBulkLoader::load_non_javabase_classes(JavaThread* current) {
+void AOTLinkedClassBulkLoader::preload_classes_in_table(Array* classes,
+ const char* category_name, Handle loader, TRAPS) {
+ if (classes == nullptr) {
+ return;
+ }
+
+ for (int i = 0; i < classes->length(); i++) {
+ InstanceKlass* ik = classes->at(i);
+ if (log_is_enabled(Info, aot, load)) {
+ ResourceMark rm(THREAD);
+ log_info(aot, load)("%-5s %s%s", category_name, ik->external_name(),
+ ik->is_hidden() ? " (hidden)" : "");
+ }
+
+ SystemDictionary::preload_class(loader, ik, CHECK);
+
+ if (ik->is_hidden()) {
+ DEBUG_ONLY({
+ // Make sure we don't make this hidden class available by name, even if we don't
+ // use any special ClassLoaderData.
+ ResourceMark rm(THREAD);
+ assert(SystemDictionary::find_instance_klass(THREAD, ik->name(), loader) == nullptr,
+ "hidden classes cannot be accessible by name: %s", ik->external_name());
+ });
+ } else {
+ precond(SystemDictionary::find_instance_klass(THREAD, ik->name(), loader) == ik);
+ }
+ }
+}
+
+// Some cached heap objects may hold references to methods in aot-linked
+// classes (via MemberName). We need to make sure all classes are
+// linked before executing any bytecode.
+void AOTLinkedClassBulkLoader::link_classes(JavaThread* current) {
+ link_classes_impl(current);
+ if (current->has_pending_exception()) {
+ exit_on_exception(current);
+ }
+}
+
+void AOTLinkedClassBulkLoader::link_classes_impl(TRAPS) {
+ precond(CDSConfig::is_using_aot_linked_classes());
+
+ AOTLinkedClassTable* table = AOTLinkedClassTable::get();
+
+ link_classes_in_table(table->boot1(), CHECK);
+ link_classes_in_table(table->boot2(), CHECK);
+ link_classes_in_table(table->platform(), CHECK);
+ link_classes_in_table(table->app(), CHECK);
+}
+
+void AOTLinkedClassBulkLoader::link_classes_in_table(Array* classes, TRAPS) {
+ if (classes != nullptr) {
+ for (int i = 0; i < classes->length(); i++) {
+ // NOTE: CDSConfig::is_preserving_verification_constraints() is required
+ // when storing ik in the AOT cache. This means we don't have to verify
+ // ik at all.
+ //
+ // Without is_preserving_verification_constraints(), ik->link_class() may cause
+ // class loading, which may result in invocation of ClassLoader::loadClass() calls,
+ // which CANNOT happen because we are not ready to execute any Java byecodes yet
+ // at this point.
+ InstanceKlass* ik = classes->at(i);
+ ik->link_class(CHECK);
+ }
+ }
+}
+
+#ifdef ASSERT
+void AOTLinkedClassBulkLoader::validate_module_of_preloaded_classes() {
+ oop javabase_module_oop = ModuleEntryTable::javabase_moduleEntry()->module_oop();
+ for (int i = T_BOOLEAN; i < T_LONG+1; i++) {
+ TypeArrayKlass* tak = Universe::typeArrayKlass((BasicType)i);
+ validate_module(tak, "boot1", javabase_module_oop);
+ }
+
+ JavaThread* current = JavaThread::current();
+ Handle h_platform_loader(current, SystemDictionary::java_platform_loader());
+ Handle h_system_loader(current, SystemDictionary::java_system_loader());
+ AOTLinkedClassTable* table = AOTLinkedClassTable::get();
+
+ validate_module_of_preloaded_classes_in_table(table->boot1(), "boot1", Handle());
+ validate_module_of_preloaded_classes_in_table(table->boot2(), "boot2", Handle());
+ validate_module_of_preloaded_classes_in_table(table->platform(), "plat", h_platform_loader);
+ validate_module_of_preloaded_classes_in_table(table->app(), "app", h_system_loader);
+}
+
+void AOTLinkedClassBulkLoader::validate_module_of_preloaded_classes_in_table(Array* classes,
+ const char* category_name, Handle loader) {
+ if (classes == nullptr) {
+ return;
+ }
+
+ ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(loader());
+ for (int i = 0; i < classes->length(); i++) {
+ InstanceKlass* ik = classes->at(i);
+ PackageEntry* pkg_entry = ik->package();
+ oop module_oop;
+ if (pkg_entry == nullptr) {
+ module_oop = loader_data->unnamed_module()->module_oop();
+ } else {
+ module_oop = pkg_entry->module()->module_oop();
+ }
+
+ validate_module(ik, category_name, module_oop);
+ }
+}
+
+void AOTLinkedClassBulkLoader::validate_module(Klass* k, const char* category_name, oop module_oop) {
+ assert(module_oop != nullptr, "module system must have been initialized");
+
+ if (log_is_enabled(Debug, aot, module)) {
+ ResourceMark rm;
+ log_debug(aot, module)("Validate module of %-5s %s", category_name, k->external_name());
+ }
+ precond(java_lang_Class::module(k->java_mirror()) == module_oop);
+
+ ArrayKlass* ak = k->array_klass_or_null();
+ while (ak != nullptr) {
+ if (log_is_enabled(Debug, aot, module)) {
+ ResourceMark rm;
+ log_debug(aot, module)("Validate module of %-5s %s", category_name, ak->external_name());
+ }
+ precond(java_lang_Class::module(ak->java_mirror()) == module_oop);
+ ak = ak->array_klass_or_null();
+ }
+}
+#endif
+
+void AOTLinkedClassBulkLoader::init_javabase_classes(JavaThread* current) {
+ init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot1(), current);
+ if (current->has_pending_exception()) {
+ exit_on_exception(current);
+ }
+}
+
+void AOTLinkedClassBulkLoader::init_non_javabase_classes(JavaThread* current) {
+ init_non_javabase_classes_impl(current);
+ if (current->has_pending_exception()) {
+ exit_on_exception(current);
+ }
+}
+
+void AOTLinkedClassBulkLoader::init_non_javabase_classes_impl(TRAPS) {
assert(CDSConfig::is_using_aot_linked_classes(), "sanity");
+ DEBUG_ONLY(validate_module_of_preloaded_classes());
+
// is_using_aot_linked_classes() requires is_using_full_module_graph(). As a result,
// the platform/system class loader should already have been initialized as part
// of the FMG support.
assert(CDSConfig::is_using_full_module_graph(), "must be");
- assert(SystemDictionary::java_platform_loader() != nullptr, "must be");
- assert(SystemDictionary::java_system_loader() != nullptr, "must be");
- load_classes_in_loader(current, AOTLinkedClassCategory::BOOT2, nullptr); // all boot classes outside of java.base
- _boot2_completed = true;
+ Handle h_platform_loader(THREAD, SystemDictionary::java_platform_loader());
+ Handle h_system_loader(THREAD, SystemDictionary::java_system_loader());
- load_classes_in_loader(current, AOTLinkedClassCategory::PLATFORM, SystemDictionary::java_platform_loader());
- _platform_completed = true;
+ assert(h_platform_loader() != nullptr, "must be");
+ assert(h_system_loader() != nullptr, "must be");
- load_classes_in_loader(current, AOTLinkedClassCategory::APP, SystemDictionary::java_system_loader());
+ AOTLinkedClassTable* table = AOTLinkedClassTable::get();
+ init_classes_for_loader(Handle(), table->boot2(), CHECK);
+ init_classes_for_loader(h_platform_loader, table->platform(), CHECK);
+ init_classes_for_loader(h_system_loader, table->app(), CHECK);
+
+ if (Universe::is_fully_initialized() && VerifyDuringStartup) {
+ // Make sure we're still in a clean state.
+ VM_Verify verify_op;
+ VMThread::execute(&verify_op);
+ }
if (AOTPrintTrainingInfo) {
tty->print_cr("==================== archived_training_data ** after all classes preloaded ====================");
TrainingData::print_archived_training_data_on(tty);
}
-
- _app_completed = true;
- AtomicAccess::release_store(&_all_completed, true);
}
-void AOTLinkedClassBulkLoader::load_classes_in_loader(JavaThread* current, AOTLinkedClassCategory class_category, oop class_loader_oop) {
- load_classes_in_loader_impl(class_category, class_loader_oop, current);
- if (current->has_pending_exception()) {
- // We cannot continue, as we might have loaded some of the aot-linked classes, which
- // may have dangling C++ pointers to other aot-linked classes that we have failed to load.
- exit_on_exception(current);
- }
-}
+// For the AOT cache to function properly, all classes in the AOTLinkedClassTable
+// must be loaded and linked. In addition, AOT-initialized classes must be moved to
+// the initialized state.
+//
+// We can encounter a failure during the loading, linking, or initialization of
+// classes in the AOTLinkedClassTable only if:
+// - We ran out of memory,
+// - There is a serious error in the VM implemenation
+// When this happens, the VM may be in an inconsistent state (e.g., we have a cached
+// heap object of class X, but X is not linked). We must exit the JVM now.
void AOTLinkedClassBulkLoader::exit_on_exception(JavaThread* current) {
assert(current->has_pending_exception(), "precondition");
@@ -109,126 +280,13 @@ void AOTLinkedClassBulkLoader::exit_on_exception(JavaThread* current) {
log_error(aot)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = "
"%zuM", MaxHeapSize/M);
} else {
+ oop message = java_lang_Throwable::message(current->pending_exception());
log_error(aot)("%s: %s", current->pending_exception()->klass()->external_name(),
- java_lang_String::as_utf8_string(java_lang_Throwable::message(current->pending_exception())));
+ message == nullptr ? "(no message)" : java_lang_String::as_utf8_string(message));
}
vm_exit_during_initialization("Unexpected exception when loading aot-linked classes.");
}
-void AOTLinkedClassBulkLoader::load_classes_in_loader_impl(AOTLinkedClassCategory class_category, oop class_loader_oop, TRAPS) {
- Handle h_loader(THREAD, class_loader_oop);
- load_table(AOTLinkedClassTable::for_static_archive(), class_category, h_loader, CHECK);
- load_table(AOTLinkedClassTable::for_dynamic_archive(), class_category, h_loader, CHECK);
-
- // Initialize the InstanceKlasses of all archived heap objects that are reachable from the
- // archived java class mirrors.
- //
- // Only the classes in the static archive can have archived mirrors.
- AOTLinkedClassTable* static_table = AOTLinkedClassTable::for_static_archive();
- switch (class_category) {
- case AOTLinkedClassCategory::BOOT1:
- // Delayed until finish_loading_javabase_classes(), as the VM is not ready to
- // execute some of the methods.
- break;
- case AOTLinkedClassCategory::BOOT2:
- init_required_classes_for_loader(h_loader, static_table->boot2(), CHECK);
- break;
- case AOTLinkedClassCategory::PLATFORM:
- init_required_classes_for_loader(h_loader, static_table->platform(), CHECK);
- break;
- case AOTLinkedClassCategory::APP:
- init_required_classes_for_loader(h_loader, static_table->app(), CHECK);
- break;
- case AOTLinkedClassCategory::UNREGISTERED:
- ShouldNotReachHere();
- break;
- }
-
- if (Universe::is_fully_initialized() && VerifyDuringStartup) {
- // Make sure we're still in a clean state.
- VM_Verify verify_op;
- VMThread::execute(&verify_op);
- }
-}
-
-void AOTLinkedClassBulkLoader::load_table(AOTLinkedClassTable* table, AOTLinkedClassCategory class_category, Handle loader, TRAPS) {
- if (class_category != AOTLinkedClassCategory::BOOT1) {
- assert(Universe::is_module_initialized(), "sanity");
- }
-
- const char* category_name = AOTClassLinker::class_category_name(class_category);
- switch (class_category) {
- case AOTLinkedClassCategory::BOOT1:
- load_classes_impl(class_category, table->boot(), category_name, loader, CHECK);
- break;
-
- case AOTLinkedClassCategory::BOOT2:
- load_classes_impl(class_category, table->boot2(), category_name, loader, CHECK);
- break;
-
- case AOTLinkedClassCategory::PLATFORM:
- {
- initiate_loading(THREAD, category_name, loader, table->boot());
- initiate_loading(THREAD, category_name, loader, table->boot2());
- load_classes_impl(class_category, table->platform(), category_name, loader, CHECK);
- }
- break;
- case AOTLinkedClassCategory::APP:
- {
- initiate_loading(THREAD, category_name, loader, table->boot());
- initiate_loading(THREAD, category_name, loader, table->boot2());
- initiate_loading(THREAD, category_name, loader, table->platform());
- load_classes_impl(class_category, table->app(), category_name, loader, CHECK);
- }
- break;
- case AOTLinkedClassCategory::UNREGISTERED:
- default:
- ShouldNotReachHere(); // Currently aot-linked classes are not supported for this category.
- break;
- }
-}
-
-void AOTLinkedClassBulkLoader::load_classes_impl(AOTLinkedClassCategory class_category, Array* classes,
- const char* category_name, Handle loader, TRAPS) {
- if (classes == nullptr) {
- return;
- }
-
- ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(loader());
-
- for (int i = 0; i < classes->length(); i++) {
- InstanceKlass* ik = classes->at(i);
- if (log_is_enabled(Info, aot, load)) {
- ResourceMark rm(THREAD);
- log_info(aot, load)("%-5s %s%s%s", category_name, ik->external_name(),
- ik->is_loaded() ? " (already loaded)" : "",
- ik->is_hidden() ? " (hidden)" : "");
- }
-
- if (!ik->is_loaded()) {
- if (ik->is_hidden()) {
- load_hidden_class(loader_data, ik, CHECK);
- } else {
- InstanceKlass* actual;
- if (loader_data == ClassLoaderData::the_null_class_loader_data()) {
- actual = SystemDictionary::load_instance_class(ik->name(), loader, CHECK);
- } else {
- actual = SystemDictionaryShared::find_or_load_shared_class(ik->name(), loader, CHECK);
- }
-
- if (actual != ik) {
- ResourceMark rm(THREAD);
- log_error(aot)("Unable to resolve %s class from %s: %s", category_name, CDSConfig::type_of_archive_being_loaded(), ik->external_name());
- log_error(aot)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual));
- log_error(aot)("JVMTI class retransformation is not supported when archive was generated with -XX:+AOTClassLinking.");
- AOTMetaspace::unrecoverable_loading_error();
- }
- assert(actual->is_loaded(), "must be");
- }
- }
- }
-}
-
// Initiate loading of the in the . The should have already been loaded
// by a parent loader of the . This is necessary for handling pre-resolved CP entries.
//
@@ -258,7 +316,7 @@ void AOTLinkedClassBulkLoader::initiate_loading(JavaThread* current, const char*
if (log_is_enabled(Info, aot, load)) {
ResourceMark rm(current);
const char* defining_loader = (ik->class_loader() == nullptr ? "boot" : "plat");
- log_info(aot, load)("%s %s (initiated, defined by %s)", category_name, ik->external_name(),
+ log_info(aot, load)("%-5s %s (initiated, defined by %s)", category_name, ik->external_name(),
defining_loader);
}
SystemDictionary::add_to_initiating_loader(current, ik, loader_data);
@@ -266,97 +324,17 @@ void AOTLinkedClassBulkLoader::initiate_loading(JavaThread* current, const char*
}
}
-// Currently, we archive only three types of hidden classes:
-// - LambdaForms
-// - lambda proxy classes
-// - StringConcat classes
-// See HeapShared::is_archivable_hidden_klass().
-//
-// LambdaForm classes (with names like java/lang/invoke/LambdaForm$MH+0x800000015) logically
-// belong to the boot loader, but they are usually stored in their own special ClassLoaderData to
-// facilitate class unloading, as a LambdaForm may refer to a class loaded by a custom loader
-// that may be unloaded.
-//
-// We only support AOT-resolution of indys in the boot/platform/app loader, so there's no need
-// to support class unloading. For simplicity, we put all archived LambdaForm classes in the
-// "main" ClassLoaderData of the boot loader.
-//
-// (Even if we were to support other loaders, we would still feel free to ignore any requirement
-// of class unloading, for any class asset in the AOT cache. Anything that makes it into the AOT
-// cache has a lifetime dispensation from unloading. After all, the AOT cache never grows, and
-// we can assume that the user is content with its size, and doesn't need its footprint to shrink.)
-//
-// Lambda proxy classes are normally stored in the same ClassLoaderData as their nest hosts, and
-// StringConcat are normally stored in the main ClassLoaderData of the boot class loader. We
-// do the same for the archived copies of such classes.
-void AOTLinkedClassBulkLoader::load_hidden_class(ClassLoaderData* loader_data, InstanceKlass* ik, TRAPS) {
- assert(HeapShared::is_lambda_form_klass(ik) ||
- HeapShared::is_lambda_proxy_klass(ik) ||
- HeapShared::is_string_concat_klass(ik), "sanity");
- DEBUG_ONLY({
- assert(ik->super()->is_loaded(), "must be");
- for (int i = 0; i < ik->local_interfaces()->length(); i++) {
- assert(ik->local_interfaces()->at(i)->is_loaded(), "must be");
- }
- });
-
- Handle pd;
- PackageEntry* pkg_entry = nullptr;
-
- // Since a hidden class does not have a name, it cannot be reloaded
- // normally via the system dictionary. Instead, we have to finish the
- // loading job here.
-
- if (HeapShared::is_lambda_proxy_klass(ik)) {
- InstanceKlass* nest_host = ik->nest_host_not_null();
- assert(nest_host->is_loaded(), "must be");
- pd = Handle(THREAD, nest_host->protection_domain());
- pkg_entry = nest_host->package();
- }
-
- ik->restore_unshareable_info(loader_data, pd, pkg_entry, CHECK);
- SystemDictionary::load_shared_class_misc(ik, loader_data);
- ik->add_to_hierarchy(THREAD);
- assert(ik->is_loaded(), "Must be in at least loaded state");
-
- DEBUG_ONLY({
- // Make sure we don't make this hidden class available by name, even if we don't
- // use any special ClassLoaderData.
- Handle loader(THREAD, loader_data->class_loader());
- ResourceMark rm(THREAD);
- assert(SystemDictionary::resolve_or_null(ik->name(), loader, THREAD) == nullptr,
- "hidden classes cannot be accessible by name: %s", ik->external_name());
- if (HAS_PENDING_EXCEPTION) {
- CLEAR_PENDING_EXCEPTION;
- }
- });
-}
-
-void AOTLinkedClassBulkLoader::finish_loading_javabase_classes(TRAPS) {
- init_required_classes_for_loader(Handle(), AOTLinkedClassTable::for_static_archive()->boot(), CHECK);
-}
-
// Some AOT-linked classes for must be initialized early. This includes
// - classes that were AOT-initialized by AOTClassInitializer
// - the classes of all objects that are reachable from the archived mirrors of
// the AOT-linked classes for .
-void AOTLinkedClassBulkLoader::init_required_classes_for_loader(Handle class_loader, Array* classes, TRAPS) {
+void AOTLinkedClassBulkLoader::init_classes_for_loader(Handle class_loader, Array* classes, TRAPS) {
if (classes != nullptr) {
for (int i = 0; i < classes->length(); i++) {
InstanceKlass* ik = classes->at(i);
- if (ik->class_loader_data() == nullptr) {
- // This class is not yet loaded. We will initialize it in a later phase.
- // For example, we have loaded only AOTLinkedClassCategory::BOOT1 classes
- // but k is part of AOTLinkedClassCategory::BOOT2.
- continue;
- }
+ assert(ik->class_loader_data() != nullptr, "must be");
if (ik->has_aot_initialized_mirror()) {
ik->initialize_with_aot_initialized_mirror(CHECK);
- } else {
- // Some cached heap objects may hold references to methods in aot-linked
- // classes (via MemberName). We need to make sure all classes are
- // linked to allow such MemberNames to be invoked.
- ik->link_class(CHECK);
}
}
}
@@ -364,56 +342,6 @@ void AOTLinkedClassBulkLoader::init_required_classes_for_loader(Handle class_loa
HeapShared::init_classes_for_special_subgraph(class_loader, CHECK);
}
-bool AOTLinkedClassBulkLoader::is_pending_aot_linked_class(Klass* k) {
- if (!CDSConfig::is_using_aot_linked_classes()) {
- return false;
- }
-
- if (_all_completed) { // no more pending aot-linked classes
- return false;
- }
-
- if (k->is_objArray_klass()) {
- k = ObjArrayKlass::cast(k)->bottom_klass();
- }
- if (!k->is_instance_klass()) {
- // type array klasses (and their higher dimensions),
- // must have been loaded before a GC can ever happen.
- return false;
- }
-
- // There's a small window during VM start-up where a not-yet loaded aot-linked
- // class k may be discovered by the GC during VM initialization. This can happen
- // when the heap contains an aot-cached instance of k, but k is not ready to be
- // loaded yet. (TODO: JDK-8342429 eliminates this possibility)
- //
- // The following checks try to limit this window as much as possible for each of
- // the four AOTLinkedClassCategory of classes that can be aot-linked.
-
- InstanceKlass* ik = InstanceKlass::cast(k);
- if (ik->defined_by_boot_loader()) {
- if (ik->module() != nullptr && ik->in_javabase_module()) {
- // AOTLinkedClassCategory::BOOT1 -- all aot-linked classes in
- // java.base must have been loaded before a GC can ever happen.
- return false;
- } else {
- // AOTLinkedClassCategory::BOOT2 classes cannot be loaded until
- // module system is ready.
- return !_boot2_completed;
- }
- } else if (ik->defined_by_platform_loader()) {
- // AOTLinkedClassCategory::PLATFORM classes cannot be loaded until
- // the platform class loader is initialized.
- return !_platform_completed;
- } else if (ik->defined_by_app_loader()) {
- // AOTLinkedClassCategory::APP cannot be loaded until the app class loader
- // is initialized.
- return !_app_completed;
- } else {
- return false;
- }
-}
-
void AOTLinkedClassBulkLoader::replay_training_at_init(Array* classes, TRAPS) {
if (classes != nullptr) {
for (int i = 0; i < classes->length(); i++) {
@@ -427,9 +355,8 @@ void AOTLinkedClassBulkLoader::replay_training_at_init(Array* cl
void AOTLinkedClassBulkLoader::replay_training_at_init_for_preloaded_classes(TRAPS) {
if (CDSConfig::is_using_aot_linked_classes() && TrainingData::have_data()) {
- // Only static archive can have training data.
- AOTLinkedClassTable* table = AOTLinkedClassTable::for_static_archive();
- replay_training_at_init(table->boot(), CHECK);
+ AOTLinkedClassTable* table = AOTLinkedClassTable::get();
+ replay_training_at_init(table->boot1(), CHECK);
replay_training_at_init(table->boot2(), CHECK);
replay_training_at_init(table->platform(), CHECK);
replay_training_at_init(table->app(), CHECK);
diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp
index 0a8b0c4d537..31fdac386fe 100644
--- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp
+++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp
@@ -39,34 +39,42 @@ template class Array;
enum class AOTLinkedClassCategory : int;
// During a Production Run, the AOTLinkedClassBulkLoader loads all classes from
-// a AOTLinkedClassTable into their respective ClassLoaders. This happens very early
-// in the JVM bootstrap stage, before any application code is executed.
+// the AOTLinkedClassTable into their respective ClassLoaders. This happens very early
+// in the JVM bootstrap stage, before any Java bytecode is executed.
//
+// IMPLEMENTATION NOTES:
+// We also proactively link all the classes in the AOTLinkedClassTable, and move
+// the AOT-initialized classes to the "initialized" state. Due to limitations
+// of the current JVM bootstrap sequence, link_or_init_javabase_classes() and
+// link_or_init_non_javabase_classes() need to be called after some Java bytecodes are
+// executed. Future RFEs will move these calls to earlier stages.
class AOTLinkedClassBulkLoader : AllStatic {
- static bool _boot2_completed;
- static bool _platform_completed;
- static bool _app_completed;
- static bool _all_completed;
- static void load_classes_in_loader(JavaThread* current, AOTLinkedClassCategory class_category, oop class_loader_oop);
- static void load_classes_in_loader_impl(AOTLinkedClassCategory class_category, oop class_loader_oop, TRAPS);
- static void load_table(AOTLinkedClassTable* table, AOTLinkedClassCategory class_category, Handle loader, TRAPS);
+ static void preload_classes_impl(TRAPS);
+ static void preload_classes_in_table(Array* classes,
+ const char* category_name, Handle loader, TRAPS);
static void initiate_loading(JavaThread* current, const char* category, Handle initiating_loader, Array* classes);
- static void load_classes_impl(AOTLinkedClassCategory class_category, Array* classes,
- const char* category_name, Handle loader, TRAPS);
- static void load_hidden_class(ClassLoaderData* loader_data, InstanceKlass* ik, TRAPS);
- static void init_required_classes_for_loader(Handle class_loader, Array* classes, TRAPS);
+ static void link_classes_impl(TRAPS);
+ static void link_classes_in_table(Array* classes, TRAPS);
+ static void init_non_javabase_classes_impl(TRAPS);
+ static void init_classes_for_loader(Handle class_loader, Array* classes, TRAPS);
static void replay_training_at_init(Array* classes, TRAPS) NOT_CDS_RETURN;
-public:
- static void serialize(SerializeClosure* soc, bool is_static_archive) NOT_CDS_RETURN;
- static void load_javabase_classes(JavaThread* current) NOT_CDS_RETURN;
- static void load_non_javabase_classes(JavaThread* current) NOT_CDS_RETURN;
- static void finish_loading_javabase_classes(TRAPS) NOT_CDS_RETURN;
+#ifdef ASSERT
+ static void validate_module_of_preloaded_classes();
+ static void validate_module_of_preloaded_classes_in_table(Array* classes,
+ const char* category_name, Handle loader);
+ static void validate_module(Klass* k, const char* category_name, oop module_oop);
+#endif
+
+public:
+ static void serialize(SerializeClosure* soc) NOT_CDS_RETURN;
+ static void preload_classes(JavaThread* current) NOT_CDS_RETURN;
+ static void link_classes(JavaThread* current) NOT_CDS_RETURN;
+ static void init_javabase_classes(JavaThread* current) NOT_CDS_RETURN;
+ static void init_non_javabase_classes(JavaThread* current) NOT_CDS_RETURN;
static void exit_on_exception(JavaThread* current);
static void replay_training_at_init_for_preloaded_classes(TRAPS) NOT_CDS_RETURN;
- static bool class_preloading_finished();
- static bool is_pending_aot_linked_class(Klass* k) NOT_CDS_RETURN_(false);
};
#endif // SHARE_CDS_AOTLINKEDCLASSBULKLOADER_HPP
diff --git a/src/hotspot/share/cds/aotLinkedClassTable.cpp b/src/hotspot/share/cds/aotLinkedClassTable.cpp
index b602c599f54..a16bdec8740 100644
--- a/src/hotspot/share/cds/aotLinkedClassTable.cpp
+++ b/src/hotspot/share/cds/aotLinkedClassTable.cpp
@@ -27,11 +27,10 @@
#include "cds/serializeClosure.hpp"
#include "oops/array.hpp"
-AOTLinkedClassTable AOTLinkedClassTable::_for_static_archive;
-AOTLinkedClassTable AOTLinkedClassTable::_for_dynamic_archive;
+AOTLinkedClassTable AOTLinkedClassTable::_instance;
void AOTLinkedClassTable::serialize(SerializeClosure* soc) {
- soc->do_ptr((void**)&_boot);
+ soc->do_ptr((void**)&_boot1);
soc->do_ptr((void**)&_boot2);
soc->do_ptr((void**)&_platform);
soc->do_ptr((void**)&_app);
diff --git a/src/hotspot/share/cds/aotLinkedClassTable.hpp b/src/hotspot/share/cds/aotLinkedClassTable.hpp
index 2a199c15edd..a33e53b1d6a 100644
--- a/src/hotspot/share/cds/aotLinkedClassTable.hpp
+++ b/src/hotspot/share/cds/aotLinkedClassTable.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2025, 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
@@ -39,34 +39,29 @@ class SerializeClosure;
// in a production run.
//
class AOTLinkedClassTable {
- // The VM may load up to 2 CDS archives -- static and dynamic. Each
- // archive can have its own AOTLinkedClassTable.
- static AOTLinkedClassTable _for_static_archive;
- static AOTLinkedClassTable _for_dynamic_archive;
+ static AOTLinkedClassTable _instance;
- Array* _boot; // only java.base classes
- Array* _boot2; // boot classes in other modules
+ Array* _boot1; // boot classes in java.base module
+ Array* _boot2; // boot classes in all other (named and unnamed) modules,
+ // including classes from -Xbootclasspath/a
Array* _platform;
Array* _app;
public:
AOTLinkedClassTable() :
- _boot(nullptr), _boot2(nullptr),
+ _boot1(nullptr), _boot2(nullptr),
_platform(nullptr), _app(nullptr) {}
- static AOTLinkedClassTable* for_static_archive() { return &_for_static_archive; }
- static AOTLinkedClassTable* for_dynamic_archive() { return &_for_dynamic_archive; }
-
- static AOTLinkedClassTable* get(bool is_static_archive) {
- return is_static_archive ? for_static_archive() : for_dynamic_archive();
+ static AOTLinkedClassTable* get() {
+ return &_instance;
}
- Array* boot() const { return _boot; }
+ Array* boot1() const { return _boot1; }
Array* boot2() const { return _boot2; }
Array* platform() const { return _platform; }
Array* app() const { return _app; }
- void set_boot (Array* value) { _boot = value; }
+ void set_boot1 (Array* value) { _boot1 = value; }
void set_boot2 (Array* value) { _boot2 = value; }
void set_platform(Array* value) { _platform = value; }
void set_app (Array* value) { _app = value; }
diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp
index a15d7f670d4..151c15048c2 100644
--- a/src/hotspot/share/cds/aotMapLogger.cpp
+++ b/src/hotspot/share/cds/aotMapLogger.cpp
@@ -33,7 +33,10 @@
#include "memory/metaspaceClosure.hpp"
#include "memory/resourceArea.hpp"
#include "oops/method.hpp"
+#include "oops/methodCounters.hpp"
+#include "oops/methodData.hpp"
#include "oops/oop.inline.hpp"
+#include "oops/trainingData.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/globals_extension.hpp"
#include "utilities/growableArray.hpp"
@@ -132,12 +135,14 @@ public:
virtual bool do_unique_ref(Ref* ref, bool read_only) {
ArchivedObjInfo info;
- info._src_addr = ref->obj();
- info._buffered_addr = ref->obj();
- info._requested_addr = ref->obj();
- info._bytes = ref->size() * BytesPerWord;
- info._type = ref->msotype();
- _objs.append(info);
+ if (AOTMetaspace::in_aot_cache(ref->obj())) {
+ info._src_addr = ref->obj();
+ info._buffered_addr = ref->obj();
+ info._requested_addr = ref->obj();
+ info._bytes = ref->size() * BytesPerWord;
+ info._type = ref->msotype();
+ _objs.append(info);
+ }
return true; // keep iterating
}
@@ -348,9 +353,24 @@ void AOTMapLogger::log_metaspace_objects_impl(address region_base, address regio
case MetaspaceObj::MethodType:
log_method((Method*)src, requested_addr, type_name, bytes, current);
break;
+ case MetaspaceObj::MethodCountersType:
+ log_method_counters((MethodCounters*)src, requested_addr, type_name, bytes, current);
+ break;
+ case MetaspaceObj::MethodDataType:
+ log_method_data((MethodData*)src, requested_addr, type_name, bytes, current);
+ break;
case MetaspaceObj::SymbolType:
log_symbol((Symbol*)src, requested_addr, type_name, bytes, current);
break;
+ case MetaspaceObj::KlassTrainingDataType:
+ log_klass_training_data((KlassTrainingData*)src, requested_addr, type_name, bytes, current);
+ break;
+ case MetaspaceObj::MethodTrainingDataType:
+ log_method_training_data((MethodTrainingData*)src, requested_addr, type_name, bytes, current);
+ break;
+ case MetaspaceObj::CompileTrainingDataType:
+ log_compile_training_data((CompileTrainingData*)src, requested_addr, type_name, bytes, current);
+ break;
default:
log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes);
break;
@@ -389,6 +409,18 @@ void AOTMapLogger::log_const_method(ConstMethod* cm, address requested_addr, con
log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, cm->method()->external_name());
}
+void AOTMapLogger::log_method_counters(MethodCounters* mc, address requested_addr, const char* type_name,
+ int bytes, Thread* current) {
+ ResourceMark rm(current);
+ log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, mc->method()->external_name());
+}
+
+void AOTMapLogger::log_method_data(MethodData* md, address requested_addr, const char* type_name,
+ int bytes, Thread* current) {
+ ResourceMark rm(current);
+ log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, md->method()->external_name());
+}
+
void AOTMapLogger::log_klass(Klass* k, address requested_addr, const char* type_name,
int bytes, Thread* current) {
ResourceMark rm(current);
@@ -408,6 +440,38 @@ void AOTMapLogger::log_symbol(Symbol* s, address requested_addr, const char* typ
s->as_quoted_ascii());
}
+void AOTMapLogger::log_klass_training_data(KlassTrainingData* ktd, address requested_addr, const char* type_name,
+ int bytes, Thread* current) {
+ ResourceMark rm(current);
+ if (ktd->has_holder()) {
+ log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,
+ ktd->name()->as_klass_external_name());
+ } else {
+ log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes);
+ }
+}
+
+void AOTMapLogger::log_method_training_data(MethodTrainingData* mtd, address requested_addr, const char* type_name,
+ int bytes, Thread* current) {
+ ResourceMark rm(current);
+ if (mtd->has_holder()) {
+ log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,
+ mtd->holder()->external_name());
+ } else {
+ log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes);
+ }
+}
+
+void AOTMapLogger::log_compile_training_data(CompileTrainingData* ctd, address requested_addr, const char* type_name,
+ int bytes, Thread* current) {
+ ResourceMark rm(current);
+ if (ctd->method() != nullptr && ctd->method()->has_holder()) {
+ log_debug(aot, map)(_LOG_PREFIX " %d %s", p2i(requested_addr), type_name, bytes,
+ ctd->level(), ctd->method()->holder()->external_name());
+ } else {
+ log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes);
+ }
+}
#undef _LOG_PREFIX
// Log all the data [base...top). Pretend that the base address
diff --git a/src/hotspot/share/cds/aotMapLogger.hpp b/src/hotspot/share/cds/aotMapLogger.hpp
index 9cd67fb7ff6..dce857b0850 100644
--- a/src/hotspot/share/cds/aotMapLogger.hpp
+++ b/src/hotspot/share/cds/aotMapLogger.hpp
@@ -33,8 +33,11 @@
#include "utilities/growableArray.hpp"
class ArchiveHeapInfo;
+class CompileTrainingData;
class DumpRegion;
class FileMapInfo;
+class KlassTrainingData;
+class MethodTrainingData;
class outputStream;
// Write detailed info to a mapfile to analyze contents of the AOT cache/CDS archive.
@@ -98,9 +101,16 @@ class AOTMapLogger : AllStatic {
static void log_constant_pool_cache(ConstantPoolCache* cpc, address requested_addr,
const char* type_name, int bytes, Thread* current);
static void log_const_method(ConstMethod* cm, address requested_addr, const char* type_name, int bytes, Thread* current);
+ static void log_method_counters(MethodCounters* mc, address requested_addr, const char* type_name, int bytes,
+ Thread* current);
+ static void log_method_data(MethodData* md, address requested_addr, const char* type_name, int bytes,
+ Thread* current);
static void log_klass(Klass* k, address requested_addr, const char* type_name, int bytes, Thread* current);
static void log_method(Method* m, address requested_addr, const char* type_name, int bytes, Thread* current);
static void log_symbol(Symbol* s, address requested_addr, const char* type_name, int bytes, Thread* current);
+ static void log_klass_training_data(KlassTrainingData* ktd, address requested_addr, const char* type_name, int bytes, Thread* current);
+ static void log_method_training_data(MethodTrainingData* mtd, address requested_addr, const char* type_name, int bytes, Thread* current);
+ static void log_compile_training_data(CompileTrainingData* ctd, address requested_addr, const char* type_name, int bytes, Thread* current);
#if INCLUDE_CDS_JAVA_HEAP
diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp
index b3f859fc4a8..d80383be272 100644
--- a/src/hotspot/share/cds/aotMetaspace.cpp
+++ b/src/hotspot/share/cds/aotMetaspace.cpp
@@ -124,7 +124,7 @@ bool AOTMetaspace::_use_optimized_module_handling = true;
// These regions are aligned with AOTMetaspace::core_region_alignment().
//
// These 2 regions are populated in the following steps:
-// [0] All classes are loaded in AOTMetaspace::preload_classes(). All metadata are
+// [0] All classes are loaded in AOTMetaspace::load_classes(). All metadata are
// temporarily allocated outside of the shared regions.
// [1] We enter a safepoint and allocate a buffer for the rw/ro regions.
// [2] C++ vtables are copied into the rw region.
@@ -501,7 +501,7 @@ void AOTMetaspace::serialize(SerializeClosure* soc) {
StringTable::serialize_shared_table_header(soc);
HeapShared::serialize_tables(soc);
SystemDictionaryShared::serialize_dictionary_headers(soc);
- AOTLinkedClassBulkLoader::serialize(soc, true);
+ AOTLinkedClassBulkLoader::serialize(soc);
FinalImageRecipes::serialize(soc);
TrainingData::serialize(soc);
InstanceMirrorKlass::serialize_offsets(soc);
@@ -720,6 +720,7 @@ void VM_PopulateDumpSharedSpace::doit() {
_map_info->set_cloned_vtables(CppVtables::vtables_serialized_base());
_map_info->header()->set_class_location_config(cl_config);
+ HeapShared::delete_tables_with_raw_oops();
CDSConfig::set_is_at_aot_safepoint(false);
}
@@ -803,6 +804,23 @@ void AOTMetaspace::link_shared_classes(TRAPS) {
AOTClassLinker::initialize();
AOTClassInitializer::init_test_class(CHECK);
+ if (CDSConfig::is_dumping_final_static_archive()) {
+ // - Load and link all classes used in the training run.
+ // - Initialize @AOTSafeClassInitializer classes that were
+ // initialized in the training run.
+ // - Perform per-class optimization such as AOT-resolution of
+ // constant pool entries that were resolved during the training run.
+ FinalImageRecipes::apply_recipes(CHECK);
+
+ // Because the AOT assembly phase does not run the same exact code as in the
+ // training run (e.g., we use different lambda form invoker classes;
+ // generated lambda form classes are not recorded in FinalImageRecipes),
+ // the recipes do not cover all classes that have been loaded so far. As
+ // a result, we might have some unlinked classes at this point. Since we
+ // require cached classes to be linked, all such classes will be linked
+ // by the following step.
+ }
+
link_all_loaded_classes(THREAD);
// Eargerly resolve all string constants in constant pools
@@ -816,18 +834,12 @@ void AOTMetaspace::link_shared_classes(TRAPS) {
AOTConstantPoolResolver::preresolve_string_cp_entries(ik, CHECK);
}
}
-
- if (CDSConfig::is_dumping_final_static_archive()) {
- FinalImageRecipes::apply_recipes(CHECK);
- }
}
-// Preload classes from a list, populate the shared spaces and dump to a
-// file.
-void AOTMetaspace::preload_and_dump(TRAPS) {
+void AOTMetaspace::dump_static_archive(TRAPS) {
CDSConfig::DumperThreadMark dumper_thread_mark(THREAD);
ResourceMark rm(THREAD);
- HandleMark hm(THREAD);
+ HandleMark hm(THREAD);
if (CDSConfig::is_dumping_final_static_archive() && AOTPrintTrainingInfo) {
tty->print_cr("==================== archived_training_data ** before dumping ====================");
@@ -835,7 +847,7 @@ void AOTMetaspace::preload_and_dump(TRAPS) {
}
StaticArchiveBuilder builder;
- preload_and_dump_impl(builder, THREAD);
+ dump_static_archive_impl(builder, THREAD);
if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
aot_log_error(aot)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = "
@@ -901,7 +913,7 @@ void AOTMetaspace::get_default_classlist(char* default_classlist, const size_t b
Arguments::get_java_home(), filesep, filesep);
}
-void AOTMetaspace::preload_classes(TRAPS) {
+void AOTMetaspace::load_classes(TRAPS) {
char default_classlist[JVM_MAXPATHLEN];
const char* classlist_path;
@@ -928,8 +940,8 @@ void AOTMetaspace::preload_classes(TRAPS) {
}
}
- // Some classes are used at CDS runtime but are not loaded, and therefore archived, at
- // dumptime. We can perform dummmy calls to these classes at dumptime to ensure they
+ // Some classes are used at CDS runtime but are not yet loaded at this point.
+ // We can perform dummmy calls to these classes at dumptime to ensure they
// are archived.
exercise_runtime_cds_code(CHECK);
@@ -945,10 +957,10 @@ void AOTMetaspace::exercise_runtime_cds_code(TRAPS) {
CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK);
}
-void AOTMetaspace::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) {
+void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS) {
if (CDSConfig::is_dumping_classic_static_archive()) {
// We are running with -Xshare:dump
- preload_classes(CHECK);
+ load_classes(CHECK);
if (SharedArchiveConfigFile) {
log_info(aot)("Reading extra data from %s ...", SharedArchiveConfigFile);
@@ -1076,11 +1088,6 @@ bool AOTMetaspace::write_static_archive(ArchiveBuilder* builder, FileMapInfo* ma
return false;
}
builder->write_archive(map_info, heap_info);
-
- if (AllowArchivingWithJavaAgent) {
- aot_log_warning(aot)("This %s was created with AllowArchivingWithJavaAgent. It should be used "
- "for testing purposes only and should not be used in a production environment", CDSConfig::type_of_archive_being_loaded());
- }
return true;
}
@@ -2001,7 +2008,7 @@ void AOTMetaspace::initialize_shared_spaces() {
if (dynamic_mapinfo != nullptr) {
intptr_t* buffer = (intptr_t*)dynamic_mapinfo->serialized_data();
ReadClosure rc(&buffer, (intptr_t)SharedBaseAddress);
- ArchiveBuilder::serialize_dynamic_archivable_items(&rc);
+ DynamicArchive::serialize(&rc);
DynamicArchive::setup_array_klasses();
}
diff --git a/src/hotspot/share/cds/aotMetaspace.hpp b/src/hotspot/share/cds/aotMetaspace.hpp
index 1803199766d..379c684e939 100644
--- a/src/hotspot/share/cds/aotMetaspace.hpp
+++ b/src/hotspot/share/cds/aotMetaspace.hpp
@@ -72,15 +72,15 @@ class AOTMetaspace : AllStatic {
n_regions = 5 // total number of regions
};
- static void preload_and_dump(TRAPS) NOT_CDS_RETURN;
+ static void dump_static_archive(TRAPS) NOT_CDS_RETURN;
#ifdef _LP64
static void adjust_heap_sizes_for_dumping() NOT_CDS_JAVA_HEAP_RETURN;
#endif
private:
static void exercise_runtime_cds_code(TRAPS) NOT_CDS_RETURN;
- static void preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) NOT_CDS_RETURN;
- static void preload_classes(TRAPS) NOT_CDS_RETURN;
+ static void dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS) NOT_CDS_RETURN;
+ static void load_classes(TRAPS) NOT_CDS_RETURN;
public:
static Symbol* symbol_rs_base() {
diff --git a/src/hotspot/share/cds/aotOopChecker.cpp b/src/hotspot/share/cds/aotOopChecker.cpp
new file mode 100644
index 00000000000..3c0a142a059
--- /dev/null
+++ b/src/hotspot/share/cds/aotOopChecker.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2025, 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 "cds/aotMetaspace.hpp"
+#include "cds/aotOopChecker.hpp"
+#include "cds/heapShared.hpp"
+#include "classfile/javaClasses.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/vmClasses.hpp"
+#include "oops/instanceKlass.inline.hpp"
+#include "runtime/fieldDescriptor.inline.hpp"
+#include "utilities/debug.hpp"
+
+#if INCLUDE_CDS_JAVA_HEAP
+
+oop AOTOopChecker::get_oop_field(oop obj, const char* name, const char* sig) {
+ Symbol* name_sym = SymbolTable::probe(name, checked_cast(strlen(name)));
+ assert(name_sym != nullptr, "Symbol must have been resolved for an existing field of this obj");
+ Symbol* sig_sym = SymbolTable::probe(sig, checked_cast(strlen(sig)));
+ assert(sig_sym != nullptr, "Symbol must have been resolved for an existing field of this obj");
+
+ fieldDescriptor fd;
+ Klass* k = InstanceKlass::cast(obj->klass())->find_field(name_sym, sig_sym, &fd);
+ assert(k != nullptr, "field must exist");
+ precond(!fd.is_static());
+ precond(fd.field_type() == T_OBJECT || fd.field_type() == T_ARRAY);
+ return obj->obj_field(fd.offset());
+}
+
+// Make sure we are not caching objects with assumptions that can be violated in
+// the production run.
+void AOTOopChecker::check(oop obj) {
+ // Currently we only check URL objects, but more rules may be added in the future.
+
+ if (obj->klass()->is_subclass_of(vmClasses::URL_klass())) {
+ // If URL could be subclassed, obj may have new fields that we don't know about.
+ precond(vmClasses::URL_klass()->is_final());
+
+ // URLs are referenced by the CodeSources/ProtectDomains that are cached
+ // for AOT-linked classes loaded by the platform/app loaders.
+ //
+ // Do not cache any URLs whose URLStreamHandler can be overridden by the application.
+ // - "jrt" and "file" will always use the built-in URLStreamHandler. See
+ // java.net.URL::isOverrideable().
+ // - When an AOT-linked class is loaded from a JAR file, its URL is something
+ // like file:HelloWorl.jar, and does NOT use the "jar" protocol.
+ oop protocol = get_oop_field(obj, "protocol", "Ljava/lang/String;");
+ if (!java_lang_String::equals(protocol, "jrt", 3) &&
+ !java_lang_String::equals(protocol, "file", 4)) {
+ ResourceMark rm;
+ log_error(aot)("Must cache only URLs with jrt/file protocols but got: %s",
+ java_lang_String::as_quoted_ascii(protocol));
+ HeapShared::debug_trace();
+ AOTMetaspace::unrecoverable_writing_error();
+ }
+ }
+}
+
+#endif //INCLUDE_CDS_JAVA_HEAP
diff --git a/src/jdk.hotspot.agent/test/libproc/LibprocTest.java b/src/hotspot/share/cds/aotOopChecker.hpp
similarity index 66%
rename from src/jdk.hotspot.agent/test/libproc/LibprocTest.java
rename to src/hotspot/share/cds/aotOopChecker.hpp
index a3e27a94ec0..1d4b9cd1a75 100644
--- a/src/jdk.hotspot.agent/test/libproc/LibprocTest.java
+++ b/src/hotspot/share/cds/aotOopChecker.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,20 +22,19 @@
*
*/
-/**
- This is test case run by debuggee for running LibprocClient.java.
-*/
+#ifndef SHARE_CDS_AOTOOPCHECKER_HPP
+#define SHARE_CDS_AOTOOPCHECKER_HPP
-public class LibprocTest {
- public static void main(String[] args) throws Exception {
- String myStr = "";
- System.out.println("main start");
- synchronized(myStr) {
- try {
- myStr.wait();
- } catch (InterruptedException ee) {
- }
- }
- System.out.println("main end");
- }
-}
+#include "memory/allStatic.hpp"
+#include "oops/oopsHierarchy.hpp"
+
+class AOTOopChecker : AllStatic {
+ static oop get_oop_field(oop obj, const char* name, const char* sig);
+
+public:
+ // obj is an object that's about to be stored into the AOT cache. Check if it
+ // can be safely cached.
+ static void check(oop obj);
+};
+
+#endif // SHARE_CDS_AOTOOPCHECKER_HPP
diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp
index 77f51443bb2..f5026339086 100644
--- a/src/hotspot/share/cds/archiveBuilder.cpp
+++ b/src/hotspot/share/cds/archiveBuilder.cpp
@@ -24,7 +24,6 @@
#include "cds/aotArtifactFinder.hpp"
#include "cds/aotClassLinker.hpp"
-#include "cds/aotLinkedClassBulkLoader.hpp"
#include "cds/aotLogging.hpp"
#include "cds/aotMapLogger.hpp"
#include "cds/aotMetaspace.hpp"
@@ -656,12 +655,10 @@ void ArchiveBuilder::make_shallow_copies(DumpRegion *dump_region,
void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* src_info) {
address src = src_info->source_addr();
- int bytes = src_info->size_in_bytes();
- char* dest;
- char* oldtop;
- char* newtop;
+ int bytes = src_info->size_in_bytes(); // word-aligned
+ size_t alignment = SharedSpaceObjectAlignment; // alignment for the dest pointer
- oldtop = dump_region->top();
+ char* oldtop = dump_region->top();
if (src_info->msotype() == MetaspaceObj::ClassType) {
// Allocate space for a pointer directly in front of the future InstanceKlass, so
// we can do a quick lookup from InstanceKlass* -> RunTimeClassInfo*
@@ -672,21 +669,19 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s
SystemDictionaryShared::validate_before_archiving(InstanceKlass::cast(klass));
dump_region->allocate(sizeof(address));
}
- // Allocate space for the future InstanceKlass with proper alignment
- const size_t alignment =
#ifdef _LP64
- UseCompressedClassPointers ?
- nth_bit(ArchiveBuilder::precomputed_narrow_klass_shift()) :
- SharedSpaceObjectAlignment;
-#else
- SharedSpaceObjectAlignment;
+ // More strict alignments needed for UseCompressedClassPointers
+ if (UseCompressedClassPointers) {
+ alignment = nth_bit(ArchiveBuilder::precomputed_narrow_klass_shift());
+ }
#endif
- dest = dump_region->allocate(bytes, alignment);
- } else {
- dest = dump_region->allocate(bytes);
+ } else if (src_info->msotype() == MetaspaceObj::SymbolType) {
+ // Symbols may be allocated by using AllocateHeap, so their sizes
+ // may be less than size_in_bytes() indicates.
+ bytes = ((Symbol*)src)->byte_size();
}
- newtop = dump_region->top();
+ char* dest = dump_region->allocate(bytes, alignment);
memcpy(dest, src, bytes);
// Update the hash of buffered sorted symbols for static dump so that the symbols have deterministic contents
@@ -714,6 +709,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s
log_trace(aot)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(src), p2i(dest), bytes);
src_info->set_buffered_addr((address)dest);
+ char* newtop = dump_region->top();
_alloc_stats.record(src_info->msotype(), int(newtop - oldtop), src_info->read_only());
DEBUG_ONLY(_alloc_stats.verify((int)dump_region->used(), src_info->read_only()));
@@ -1015,13 +1011,6 @@ void ArchiveBuilder::make_training_data_shareable() {
_src_obj_table.iterate_all(clean_td);
}
-void ArchiveBuilder::serialize_dynamic_archivable_items(SerializeClosure* soc) {
- SymbolTable::serialize_shared_table_header(soc, false);
- SystemDictionaryShared::serialize_dictionary_headers(soc, false);
- DynamicArchive::serialize_array_klasses(soc);
- AOTLinkedClassBulkLoader::serialize(soc, false);
-}
-
uintx ArchiveBuilder::buffer_to_offset(address p) const {
address requested_p = to_requested(p);
assert(requested_p >= _requested_static_archive_bottom, "must be");
diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp
index 170e61beba8..815a6f07273 100644
--- a/src/hotspot/share/cds/archiveBuilder.hpp
+++ b/src/hotspot/share/cds/archiveBuilder.hpp
@@ -382,7 +382,6 @@ public:
bool gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool read_only);
bool gather_one_source_obj(MetaspaceClosure::Ref* ref, bool read_only);
void remember_embedded_pointer_in_enclosing_obj(MetaspaceClosure::Ref* ref);
- static void serialize_dynamic_archivable_items(SerializeClosure* soc);
DumpRegion* pz_region() { return &_pz_region; }
DumpRegion* rw_region() { return &_rw_region; }
diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp
index c7750c70f1b..d1a8772874a 100644
--- a/src/hotspot/share/cds/archiveHeapWriter.cpp
+++ b/src/hotspot/share/cds/archiveHeapWriter.cpp
@@ -95,6 +95,11 @@ void ArchiveHeapWriter::init() {
}
}
+void ArchiveHeapWriter::delete_tables_with_raw_oops() {
+ delete _source_objs;
+ _source_objs = nullptr;
+}
+
void ArchiveHeapWriter::add_source_obj(oop src_obj) {
_source_objs->append(src_obj);
}
@@ -145,7 +150,7 @@ oop ArchiveHeapWriter::requested_obj_from_buffer_offset(size_t offset) {
oop ArchiveHeapWriter::source_obj_to_requested_obj(oop src_obj) {
assert(CDSConfig::is_dumping_heap(), "dump-time only");
- HeapShared::CachedOopInfo* p = HeapShared::archived_object_cache()->get(src_obj);
+ HeapShared::CachedOopInfo* p = HeapShared::get_cached_oop_info(src_obj);
if (p != nullptr) {
return requested_obj_from_buffer_offset(p->buffer_offset());
} else {
@@ -154,9 +159,9 @@ oop ArchiveHeapWriter::source_obj_to_requested_obj(oop src_obj) {
}
oop ArchiveHeapWriter::buffered_addr_to_source_obj(address buffered_addr) {
- oop* p = _buffer_offset_to_source_obj_table->get(buffered_address_to_offset(buffered_addr));
- if (p != nullptr) {
- return *p;
+ OopHandle* oh = _buffer_offset_to_source_obj_table->get(buffered_address_to_offset(buffered_addr));
+ if (oh != nullptr) {
+ return oh->resolve();
} else {
return nullptr;
}
@@ -356,12 +361,13 @@ void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeaplength(); i++) {
int src_obj_index = _source_objs_order->at(i)._index;
oop src_obj = _source_objs->at(src_obj_index);
- HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj);
+ HeapShared::CachedOopInfo* info = HeapShared::get_cached_oop_info(src_obj);
assert(info != nullptr, "must be");
size_t buffer_offset = copy_one_source_obj_to_buffer(src_obj);
info->set_buffer_offset(buffer_offset);
- _buffer_offset_to_source_obj_table->put_when_absent(buffer_offset, src_obj);
+ OopHandle handle(Universe::vm_global(), src_obj);
+ _buffer_offset_to_source_obj_table->put_when_absent(buffer_offset, handle);
_buffer_offset_to_source_obj_table->maybe_grow();
if (java_lang_Module::is_instance(src_obj)) {
@@ -696,7 +702,7 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeaplength(); i++) {
int src_obj_index = _source_objs_order->at(i)._index;
oop src_obj = _source_objs->at(src_obj_index);
- HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj);
+ HeapShared::CachedOopInfo* info = HeapShared::get_cached_oop_info(src_obj);
assert(info != nullptr, "must be");
oop requested_obj = requested_obj_from_buffer_offset(info->buffer_offset());
update_header_for_requested_obj(requested_obj, src_obj, src_obj->klass());
@@ -758,7 +764,7 @@ void ArchiveHeapWriter::compute_ptrmap(ArchiveHeapInfo* heap_info) {
NativePointerInfo info = _native_pointers->at(i);
oop src_obj = info._src_obj;
int field_offset = info._field_offset;
- HeapShared::CachedOopInfo* p = HeapShared::archived_object_cache()->get(src_obj);
+ HeapShared::CachedOopInfo* p = HeapShared::get_cached_oop_info(src_obj);
// requested_field_addr = the address of this field in the requested space
oop requested_obj = requested_obj_from_buffer_offset(p->buffer_offset());
Metadata** requested_field_addr = (Metadata**)(cast_from_oop(requested_obj) + field_offset);
diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp
index 18e647912f1..80e72c12e7e 100644
--- a/src/hotspot/share/cds/archiveHeapWriter.hpp
+++ b/src/hotspot/share/cds/archiveHeapWriter.hpp
@@ -152,7 +152,7 @@ private:
};
static GrowableArrayCHeap* _source_objs_order;
- typedef ResizeableHashTable BufferOffsetToSourceObjectTable;
static BufferOffsetToSourceObjectTable* _buffer_offset_to_source_obj_table;
@@ -227,6 +227,7 @@ private:
public:
static void init() NOT_CDS_JAVA_HEAP_RETURN;
+ static void delete_tables_with_raw_oops();
static void add_source_obj(oop src_obj);
static bool is_too_large_to_archive(size_t size);
static bool is_too_large_to_archive(oop obj);
diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp
index 0505ae20a78..a5d1f78b76f 100644
--- a/src/hotspot/share/cds/cdsConfig.cpp
+++ b/src/hotspot/share/cds/cdsConfig.cpp
@@ -67,7 +67,8 @@ JavaThread* CDSConfig::_dumper_thread = nullptr;
int CDSConfig::get_status() {
assert(Universe::is_fully_initialized(), "status is finalized only after Universe is initialized");
- return (is_dumping_archive() ? IS_DUMPING_ARCHIVE : 0) |
+ return (is_dumping_aot_linked_classes() ? IS_DUMPING_AOT_LINKED_CLASSES : 0) |
+ (is_dumping_archive() ? IS_DUMPING_ARCHIVE : 0) |
(is_dumping_method_handles() ? IS_DUMPING_METHOD_HANDLES : 0) |
(is_dumping_static_archive() ? IS_DUMPING_STATIC_ARCHIVE : 0) |
(is_logging_lambda_form_invokers() ? IS_LOGGING_LAMBDA_FORM_INVOKERS : 0) |
@@ -470,10 +471,6 @@ void CDSConfig::check_aot_flags() {
assert(strcmp(AOTMode, "create") == 0, "checked by AOTModeConstraintFunc");
check_aotmode_create();
}
-
- // This is an old flag used by CDS regression testing only. It doesn't apply
- // to the AOT workflow.
- FLAG_SET_ERGO(AllowArchivingWithJavaAgent, false);
}
void CDSConfig::check_aotmode_off() {
@@ -716,13 +713,6 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla
}
}
- if (is_dumping_classic_static_archive() && AOTClassLinking) {
- if (JvmtiAgentList::disable_agent_list()) {
- FLAG_SET_ERGO(AllowArchivingWithJavaAgent, false);
- log_warning(cds)("Disabled all JVMTI agents with -Xshare:dump -XX:+AOTClassLinking");
- }
- }
-
return true;
}
@@ -756,6 +746,13 @@ void CDSConfig::setup_compiler_args() {
void CDSConfig::prepare_for_dumping() {
assert(CDSConfig::is_dumping_archive(), "sanity");
+ 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);
+ }
+
if (is_dumping_dynamic_archive() && !is_using_archive()) {
assert(!is_dumping_static_archive(), "cannot be dumping both static and dynamic archives");
@@ -946,8 +943,9 @@ bool CDSConfig::is_preserving_verification_constraints() {
return AOTClassLinking;
} 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();
} else {
- // For simplicity, we don't support this optimization with the old CDS workflow.
return false;
}
}
@@ -1014,11 +1012,10 @@ void CDSConfig::stop_using_full_module_graph(const char* reason) {
}
bool CDSConfig::is_dumping_aot_linked_classes() {
- if (is_dumping_preimage_static_archive()) {
- return false;
- } else if (is_dumping_dynamic_archive()) {
- return is_using_full_module_graph() && AOTClassLinking;
- } else if (is_dumping_static_archive()) {
+ if (is_dumping_classic_static_archive() || 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.
return is_dumping_full_module_graph() && AOTClassLinking;
} else {
return false;
diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp
index cfa846f2b41..d199e97eefd 100644
--- a/src/hotspot/share/cds/cdsConfig.hpp
+++ b/src/hotspot/share/cds/cdsConfig.hpp
@@ -80,11 +80,12 @@ class CDSConfig : public AllStatic {
public:
// Used by jdk.internal.misc.CDS.getCDSConfigStatus();
- static const int IS_DUMPING_ARCHIVE = 1 << 0;
- static const int IS_DUMPING_METHOD_HANDLES = 1 << 1;
- static const int IS_DUMPING_STATIC_ARCHIVE = 1 << 2;
- static const int IS_LOGGING_LAMBDA_FORM_INVOKERS = 1 << 3;
- static const int IS_USING_ARCHIVE = 1 << 4;
+ static const int IS_DUMPING_AOT_LINKED_CLASSES = 1 << 0;
+ static const int IS_DUMPING_ARCHIVE = 1 << 1;
+ static const int IS_DUMPING_METHOD_HANDLES = 1 << 2;
+ static const int IS_DUMPING_STATIC_ARCHIVE = 1 << 3;
+ static const int IS_LOGGING_LAMBDA_FORM_INVOKERS = 1 << 4;
+ static const int IS_USING_ARCHIVE = 1 << 5;
static int get_status() NOT_CDS_RETURN_(0);
diff --git a/src/hotspot/share/cds/cdsEnumKlass.cpp b/src/hotspot/share/cds/cdsEnumKlass.cpp
index e46a7eb84f4..f771eeec3d7 100644
--- a/src/hotspot/share/cds/cdsEnumKlass.cpp
+++ b/src/hotspot/share/cds/cdsEnumKlass.cpp
@@ -40,7 +40,9 @@ bool CDSEnumKlass::is_enum_obj(oop orig_obj) {
InstanceKlass::cast(k)->is_enum_subclass();
}
-// -- Handling of Enum objects
+// !!! This is legacy support for enum classes before JEP 483. This file is not used when
+// !!! CDSConfig::is_initing_classes_at_dump_time()==true.
+//
// Java Enum classes have synthetic methods that look like this
// enum MyEnum {FOO, BAR}
// MyEnum:: {
@@ -62,6 +64,7 @@ bool CDSEnumKlass::is_enum_obj(oop orig_obj) {
void CDSEnumKlass::handle_enum_obj(int level,
KlassSubGraphInfo* subgraph_info,
oop orig_obj) {
+ assert(!CDSConfig::is_initing_classes_at_dump_time(), "only for legacy support of enums");
assert(level > 1, "must never be called at the first (outermost) level");
assert(is_enum_obj(orig_obj), "must be");
diff --git a/src/hotspot/share/cds/cdsEnumKlass.hpp b/src/hotspot/share/cds/cdsEnumKlass.hpp
index c898bfec60d..e6019ff705e 100644
--- a/src/hotspot/share/cds/cdsEnumKlass.hpp
+++ b/src/hotspot/share/cds/cdsEnumKlass.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2025, 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
@@ -34,6 +34,8 @@ class InstanceKlass;
class JavaFieldStream;
class KlassSubGraphInfo;
+// This is legacy support for enum classes before JEP 483. This code is not needed when
+// CDSConfig::is_initing_classes_at_dump_time()==true.
class CDSEnumKlass: AllStatic {
public:
static bool is_enum_obj(oop orig_obj);
diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp
index a9f46c21ad3..59b07190c09 100644
--- a/src/hotspot/share/cds/cdsHeapVerifier.cpp
+++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp
@@ -28,6 +28,8 @@
#include "classfile/classLoaderDataGraph.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmSymbols.hpp"
#include "logging/log.hpp"
@@ -36,6 +38,7 @@
#include "oops/fieldStreams.inline.hpp"
#include "oops/klass.inline.hpp"
#include "oops/oop.inline.hpp"
+#include "oops/oopHandle.inline.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#if INCLUDE_CDS_JAVA_HEAP
@@ -99,7 +102,7 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
// you might need to fix the core library code, or fix the ADD_EXCL entries below.
//
// class field type
- ADD_EXCL("java/lang/ClassLoader", "scl"); // A
+ ADD_EXCL("java/lang/ClassLoader$Holder", "scl"); // A
ADD_EXCL("java/lang/Module", "ALL_UNNAMED_MODULE", // A
"ALL_UNNAMED_MODULE_SET", // A
"EVERYONE_MODULE", // A
@@ -146,11 +149,109 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
"ZERO"); // D
}
+ if (CDSConfig::is_dumping_aot_linked_classes()) {
+ ADD_EXCL("java/lang/Package$VersionInfo", "NULL_VERSION_INFO"); // D
+ }
+
# undef ADD_EXCL
+ if (CDSConfig::is_initing_classes_at_dump_time()) {
+ add_shared_secret_accessors();
+ }
ClassLoaderDataGraph::classes_do(this);
}
+// We allow only "stateless" accessors in the SharedSecrets class to be AOT-initialized, for example,
+// in the following pattern:
+//
+// class URL {
+// static {
+// SharedSecrets.setJavaNetURLAccess(
+// new JavaNetURLAccess() { ... });
+// }
+//
+// This initializes the field SharedSecrets::javaNetUriAccess, whose type (the inner case in the
+// above example) has no fields (static or otherwise) and is not a hidden class, so it cannot possibly
+// capture any transient state from the assembly phase that might become invalid in the production run.
+//
+class CDSHeapVerifier::SharedSecretsAccessorFinder : public FieldClosure {
+ CDSHeapVerifier* _verifier;
+ InstanceKlass* _ik;
+public:
+ SharedSecretsAccessorFinder(CDSHeapVerifier* verifier, InstanceKlass* ik)
+ : _verifier(verifier), _ik(ik) {}
+
+ void do_field(fieldDescriptor* fd) {
+ if (fd->field_type() == T_OBJECT) {
+ oop static_obj_field = _ik->java_mirror()->obj_field(fd->offset());
+ if (static_obj_field != nullptr) {
+ Klass* field_type = static_obj_field->klass();
+
+ if (!field_type->is_instance_klass()) {
+ ResourceMark rm;
+ log_error(aot, heap)("jdk.internal.access.SharedSecrets::%s must not be an array",
+ fd->name()->as_C_string());
+ AOTMetaspace::unrecoverable_writing_error();
+ }
+
+ InstanceKlass* field_type_ik = InstanceKlass::cast(field_type);
+ if (has_any_fields(field_type_ik) || field_type_ik->is_hidden()) {
+ // If field_type_ik is a hidden class, the accessor is probably initialized using a
+ // Lambda, which may contain transient states.
+ ResourceMark rm;
+ log_error(aot, heap)("jdk.internal.access.SharedSecrets::%s (%s) must be stateless",
+ fd->name()->as_C_string(), field_type_ik->external_name());
+ AOTMetaspace::unrecoverable_writing_error();
+ }
+
+ _verifier->add_shared_secret_accessor(static_obj_field);
+ }
+ }
+ }
+
+ // Does k (or any of its supertypes) have at least one (static or non-static) field?
+ static bool has_any_fields(InstanceKlass* k) {
+ if (k->static_field_size() != 0 || k->nonstatic_field_size() != 0) {
+ return true;
+ }
+
+ if (k->super() != nullptr && has_any_fields(k->super())) {
+ return true;
+ }
+
+ Array* interfaces = k->local_interfaces();
+ int num_interfaces = interfaces->length();
+ for (int index = 0; index < num_interfaces; index++) {
+ if (has_any_fields(interfaces->at(index))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+};
+
+// This function is for allowing the following pattern in the core libraries:
+//
+// public class URLClassPath {
+// private static final JavaNetURLAccess JNUA = SharedSecrets.getJavaNetURLAccess();
+//
+// SharedSecrets::javaNetUriAccess has no states so it can be safely AOT-initialized. During
+// the production run, even if URLClassPath. is re-executed, it will get back the same
+// instance of javaNetUriAccess as it did during the assembly phase.
+//
+// Note: this will forbid complex accessors such as SharedSecrets::javaObjectInputFilterAccess
+// to be initialized during the AOT assembly phase.
+void CDSHeapVerifier::add_shared_secret_accessors() {
+ TempNewSymbol klass_name = SymbolTable::new_symbol("jdk/internal/access/SharedSecrets");
+ InstanceKlass* ik = SystemDictionary::find_instance_klass(Thread::current(), klass_name,
+ Handle());
+ assert(ik != nullptr, "must have been loaded");
+
+ SharedSecretsAccessorFinder finder(this, ik);
+ ik->do_local_static_fields(&finder);
+}
+
CDSHeapVerifier::~CDSHeapVerifier() {
if (_problems > 0) {
log_error(aot, heap)("Scanned %d objects. Found %d case(s) where "
@@ -176,13 +277,12 @@ public:
return;
}
- if (fd->signature()->equals("Ljdk/internal/access/JavaLangAccess;")) {
- // A few classes have static fields that point to SharedSecrets.getJavaLangAccess().
- // This object carries no state and we can create a new one in the production run.
- return;
- }
oop static_obj_field = _ik->java_mirror()->obj_field(fd->offset());
if (static_obj_field != nullptr) {
+ if (_verifier->is_shared_secret_accessor(static_obj_field)) {
+ return;
+ }
+
Klass* field_type = static_obj_field->klass();
if (_exclusions != nullptr) {
for (const char** p = _exclusions; *p != nullptr; p++) {
@@ -227,10 +327,16 @@ public:
return;
}
- if (field_ik == vmClasses::internal_Unsafe_klass() && ArchiveUtils::has_aot_initialized_mirror(field_ik)) {
- // There's only a single instance of jdk/internal/misc/Unsafe, so all references will
- // be pointing to this singleton, which has been archived.
- return;
+ if (ArchiveUtils::has_aot_initialized_mirror(field_ik)) {
+ if (field_ik == vmClasses::internal_Unsafe_klass()) {
+ // There's only a single instance of jdk/internal/misc/Unsafe, so all references will
+ // be pointing to this singleton, which has been archived.
+ return;
+ }
+ if (field_ik == vmClasses::Boolean_klass()) {
+ // TODO: check if is TRUE or FALSE
+ return;
+ }
}
}
@@ -273,7 +379,8 @@ void CDSHeapVerifier::add_static_obj_field(InstanceKlass* ik, oop field, Symbol*
// This function is called once for every archived heap object. Warn if this object is referenced by
// a static field of a class that's not aot-initialized.
-inline bool CDSHeapVerifier::do_entry(oop& orig_obj, HeapShared::CachedOopInfo& value) {
+inline bool CDSHeapVerifier::do_entry(OopHandle& orig_obj_handle, HeapShared::CachedOopInfo& value) {
+ oop orig_obj = orig_obj_handle.resolve();
_archived_objs++;
if (java_lang_String::is_instance(orig_obj) && HeapShared::is_dumped_interned_string(orig_obj)) {
@@ -323,7 +430,7 @@ public:
// Call this function (from gdb, etc) if you want to know why an object is archived.
void CDSHeapVerifier::trace_to_root(outputStream* st, oop orig_obj) {
- HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(orig_obj);
+ HeapShared::CachedOopInfo* info = HeapShared::get_cached_oop_info(orig_obj);
if (info != nullptr) {
trace_to_root(st, orig_obj, nullptr, info);
} else {
@@ -357,7 +464,7 @@ const char* static_field_name(oop mirror, oop field) {
int CDSHeapVerifier::trace_to_root(outputStream* st, oop orig_obj, oop orig_field, HeapShared::CachedOopInfo* info) {
int level = 0;
if (info->orig_referrer() != nullptr) {
- HeapShared::CachedOopInfo* ref = HeapShared::archived_object_cache()->get(info->orig_referrer());
+ HeapShared::CachedOopInfo* ref = HeapShared::get_cached_oop_info(info->orig_referrer());
assert(ref != nullptr, "sanity");
level = trace_to_root(st, info->orig_referrer(), orig_obj, ref) + 1;
} else if (java_lang_String::is_instance(orig_obj)) {
diff --git a/src/hotspot/share/cds/cdsHeapVerifier.hpp b/src/hotspot/share/cds/cdsHeapVerifier.hpp
index 811751e8ca2..88ef13c9e90 100644
--- a/src/hotspot/share/cds/cdsHeapVerifier.hpp
+++ b/src/hotspot/share/cds/cdsHeapVerifier.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
#include "cds/heapShared.hpp"
#include "memory/iterator.hpp"
+#include "oops/oopHandle.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashTable.hpp"
@@ -37,6 +38,7 @@ class Symbol;
class CDSHeapVerifier : public KlassClosure {
class CheckStaticFields;
+ class SharedSecretsAccessorFinder;
class TraceFields;
int _archived_objs;
@@ -54,6 +56,7 @@ class CDSHeapVerifier : public KlassClosure {
HeapShared::oop_hash> _table;
GrowableArray _exclusions;
+ GrowableArray _shared_secret_accessors;
void add_exclusion(const char** excl) {
_exclusions.append(excl);
@@ -69,6 +72,22 @@ class CDSHeapVerifier : public KlassClosure {
}
return nullptr;
}
+
+ void add_shared_secret_accessors();
+
+ void add_shared_secret_accessor(oop obj) {
+ _shared_secret_accessors.append(obj);
+ }
+
+ bool is_shared_secret_accessor(oop obj) {
+ for (int i = 0; i < _shared_secret_accessors.length(); i++) {
+ if (_shared_secret_accessors.at(i) == obj) {
+ return true;
+ }
+ }
+ return false;
+ }
+
static int trace_to_root(outputStream* st, oop orig_obj, oop orig_field, HeapShared::CachedOopInfo* p);
CDSHeapVerifier();
@@ -80,7 +99,7 @@ public:
virtual void do_klass(Klass* k);
// For HashTable::iterate()
- inline bool do_entry(oop& orig_obj, HeapShared::CachedOopInfo& value);
+ inline bool do_entry(OopHandle& orig_obj, HeapShared::CachedOopInfo& value);
static void verify();
diff --git a/src/hotspot/share/cds/cds_globals.hpp b/src/hotspot/share/cds/cds_globals.hpp
index f4094aec1ac..3e3062097f9 100644
--- a/src/hotspot/share/cds/cds_globals.hpp
+++ b/src/hotspot/share/cds/cds_globals.hpp
@@ -63,10 +63,6 @@
"Average number of symbols per bucket in shared table") \
range(2, 246) \
\
- product(bool, AllowArchivingWithJavaAgent, false, DIAGNOSTIC, \
- "Allow Java agent to be run with CDS dumping (not applicable" \
- " to AOT") \
- \
develop(ccstr, ArchiveHeapTestClass, nullptr, \
"For JVM internal testing only. The static field named " \
"\"archivedObjects\" of the specified class is stored in the " \
diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp
index 882bb84036f..8e1f298e8e3 100644
--- a/src/hotspot/share/cds/classListWriter.cpp
+++ b/src/hotspot/share/cds/classListWriter.cpp
@@ -277,7 +277,9 @@ void ClassListWriter::write_resolved_constants_for(InstanceKlass* ik) {
if (field_entries != nullptr) {
for (int i = 0; i < field_entries->length(); i++) {
ResolvedFieldEntry* rfe = field_entries->adr_at(i);
- if (rfe->is_resolved(Bytecodes::_getfield) ||
+ if (rfe->is_resolved(Bytecodes::_getstatic) ||
+ rfe->is_resolved(Bytecodes::_putstatic) ||
+ rfe->is_resolved(Bytecodes::_getfield) ||
rfe->is_resolved(Bytecodes::_putfield)) {
list.at_put(rfe->constant_pool_index(), true);
print = true;
@@ -292,6 +294,7 @@ void ClassListWriter::write_resolved_constants_for(InstanceKlass* ik) {
if (rme->is_resolved(Bytecodes::_invokevirtual) ||
rme->is_resolved(Bytecodes::_invokespecial) ||
rme->is_resolved(Bytecodes::_invokeinterface) ||
+ rme->is_resolved(Bytecodes::_invokestatic) ||
rme->is_resolved(Bytecodes::_invokehandle)) {
list.at_put(rme->constant_pool_index(), true);
print = true;
diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp
index 90f35c61de1..2d0953288b0 100644
--- a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp
+++ b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp
@@ -1,4 +1,3 @@
-
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -53,7 +52,7 @@ void DumpTimeSharedClassTable::iterate_all_live_classes(Function function) const
assert(k->is_loader_alive(), "must not change");
} else {
if (!SystemDictionaryShared::is_excluded_class(k)) {
- SystemDictionaryShared::warn_excluded(k, "Class loader not alive");
+ SystemDictionaryShared::log_exclusion(k, "Class loader not alive");
SystemDictionaryShared::set_excluded_locked(k);
}
}
diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp
index 58b354b9240..6fac1676b9f 100644
--- a/src/hotspot/share/cds/dynamicArchive.cpp
+++ b/src/hotspot/share/cds/dynamicArchive.cpp
@@ -160,11 +160,10 @@ public:
SystemDictionaryShared::write_to_archive(false);
cl_config = AOTClassLocationConfig::dumptime()->write_to_archive();
DynamicArchive::dump_array_klasses();
- AOTClassLinker::write_to_archive();
serialized_data = ro_region()->top();
WriteClosure wc(ro_region());
- ArchiveBuilder::serialize_dynamic_archivable_items(&wc);
+ DynamicArchive::serialize(&wc);
}
if (CDSConfig::is_dumping_lambdas_in_legacy_mode()) {
@@ -396,11 +395,6 @@ public:
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
void doit() {
ResourceMark rm;
- if (AllowArchivingWithJavaAgent) {
- aot_log_warning(aot)("This %s was created with AllowArchivingWithJavaAgent. It should be used "
- "for testing purposes only and should not be used in a production environment",
- CDSConfig::type_of_archive_being_loaded());
- }
AOTClassLocationConfig::dumptime_check_nonempty_dirs();
_builder.doit();
}
@@ -414,6 +408,12 @@ public:
GrowableArray* DynamicArchive::_array_klasses = nullptr;
Array* DynamicArchive::_dynamic_archive_array_klasses = nullptr;
+void DynamicArchive::serialize(SerializeClosure* soc) {
+ SymbolTable::serialize_shared_table_header(soc, false);
+ SystemDictionaryShared::serialize_dictionary_headers(soc, false);
+ soc->do_ptr(&_dynamic_archive_array_klasses);
+}
+
void DynamicArchive::append_array_klass(ObjArrayKlass* ak) {
if (_array_klasses == nullptr) {
_array_klasses = new (mtClassShared) GrowableArray(50, mtClassShared);
@@ -438,8 +438,6 @@ void DynamicArchive::setup_array_klasses() {
if (_dynamic_archive_array_klasses != nullptr) {
for (int i = 0; i < _dynamic_archive_array_klasses->length(); i++) {
ObjArrayKlass* oak = _dynamic_archive_array_klasses->at(i);
- assert(!oak->is_typeArray_klass(), "all type array classes must be in static archive");
-
Klass* elm = oak->element_klass();
assert(AOTMetaspace::in_aot_cache_static_region((void*)elm), "must be");
@@ -456,10 +454,6 @@ void DynamicArchive::setup_array_klasses() {
}
}
-void DynamicArchive::serialize_array_klasses(SerializeClosure* soc) {
- soc->do_ptr(&_dynamic_archive_array_klasses);
-}
-
void DynamicArchive::make_array_klasses_shareable() {
if (_array_klasses != nullptr) {
int num_array_klasses = _array_klasses->length();
diff --git a/src/hotspot/share/cds/dynamicArchive.hpp b/src/hotspot/share/cds/dynamicArchive.hpp
index 19086053d76..c42c4b7dfde 100644
--- a/src/hotspot/share/cds/dynamicArchive.hpp
+++ b/src/hotspot/share/cds/dynamicArchive.hpp
@@ -71,7 +71,7 @@ public:
static void dump_array_klasses();
static void setup_array_klasses();
static void append_array_klass(ObjArrayKlass* oak);
- static void serialize_array_klasses(SerializeClosure* soc);
+ static void serialize(SerializeClosure* soc);
static void make_array_klasses_shareable();
static void post_dump();
static int num_array_klasses();
diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
index 409052eae6a..050c1708efb 100644
--- a/src/hotspot/share/cds/filemap.cpp
+++ b/src/hotspot/share/cds/filemap.cpp
@@ -117,7 +117,6 @@ template static void get_header_version(char (&header_version) [N]) {
// Append the hash code as eight hex digits.
os::snprintf_checked(&header_version[JVM_IDENT_MAX-9], 9, "%08x", hash);
- header_version[JVM_IDENT_MAX-1] = 0; // Null terminate.
}
assert(header_version[JVM_IDENT_MAX-1] == 0, "must be");
@@ -259,7 +258,6 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
_has_platform_or_app_classes = AOTClassLocationConfig::dumptime()->has_platform_or_app_classes();
_requested_base_address = (char*)SharedBaseAddress;
_mapped_base_address = (char*)SharedBaseAddress;
- _allow_archiving_with_java_agent = AllowArchivingWithJavaAgent;
}
void FileMapHeader::copy_base_archive_name(const char* archive) {
@@ -316,7 +314,6 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- _heap_ptrmap_start_pos: %zu", _heap_ptrmap_start_pos);
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("- allow_archiving_with_java_agent:%d", _allow_archiving_with_java_agent);
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_aot_linked_classes %d", _has_aot_linked_classes);
@@ -2051,21 +2048,6 @@ bool FileMapHeader::validate() {
_has_platform_or_app_classes = false;
}
- // Java agents are allowed during run time. Therefore, the following condition is not
- // checked: (!_allow_archiving_with_java_agent && AllowArchivingWithJavaAgent)
- // Note: _allow_archiving_with_java_agent is set in the shared archive during dump time
- // while AllowArchivingWithJavaAgent is set during the current run.
- if (_allow_archiving_with_java_agent && !AllowArchivingWithJavaAgent) {
- AOTMetaspace::report_loading_error("The setting of the AllowArchivingWithJavaAgent is different "
- "from the setting in the %s.", file_type);
- return false;
- }
-
- if (_allow_archiving_with_java_agent) {
- aot_log_warning(aot)("This %s was created with AllowArchivingWithJavaAgent. It should be used "
- "for testing purposes only and should not be used in a production environment", file_type);
- }
-
aot_log_info(aot)("The %s was created with UseCompressedOops = %d, UseCompressedClassPointers = %d, UseCompactObjectHeaders = %d",
file_type, compressed_oops(), compressed_class_pointers(), compact_headers());
if (compressed_oops() != UseCompressedOops || compressed_class_pointers() != UseCompressedClassPointers) {
diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp
index b40e793a0fd..a58271eefc7 100644
--- a/src/hotspot/share/cds/filemap.hpp
+++ b/src/hotspot/share/cds/filemap.hpp
@@ -135,7 +135,6 @@ private:
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 _allow_archiving_with_java_agent; // setting of the AllowArchivingWithJavaAgent option
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
diff --git a/src/hotspot/share/cds/finalImageRecipes.cpp b/src/hotspot/share/cds/finalImageRecipes.cpp
index 2d237edfd2d..bf8a760904c 100644
--- a/src/hotspot/share/cds/finalImageRecipes.cpp
+++ b/src/hotspot/share/cds/finalImageRecipes.cpp
@@ -57,7 +57,7 @@ void FinalImageRecipes::record_recipes_for_constantpool() {
// ignored during the final image assembly.
GrowableArray*> tmp_cp_recipes;
- GrowableArray tmp_cp_flags;
+ GrowableArray tmp_flags;
GrowableArray* klasses = ArchiveBuilder::current()->klasses();
for (int i = 0; i < klasses->length(); i++) {
@@ -70,12 +70,16 @@ void FinalImageRecipes::record_recipes_for_constantpool() {
ConstantPool* cp = ik->constants();
ConstantPoolCache* cp_cache = cp->cache();
+ if (ik->is_initialized()) {
+ flags |= WAS_INITED;
+ }
+
for (int cp_index = 1; cp_index < cp->length(); cp_index++) { // Index 0 is unused
if (cp->tag_at(cp_index).value() == JVM_CONSTANT_Class) {
Klass* k = cp->resolved_klass_at(cp_index);
if (k->is_instance_klass()) {
cp_indices.append(cp_index);
- flags |= HAS_CLASS;
+ flags |= CP_RESOLVE_CLASS;
}
}
}
@@ -85,10 +89,12 @@ void FinalImageRecipes::record_recipes_for_constantpool() {
if (field_entries != nullptr) {
for (int i = 0; i < field_entries->length(); i++) {
ResolvedFieldEntry* rfe = field_entries->adr_at(i);
- if (rfe->is_resolved(Bytecodes::_getfield) ||
+ if (rfe->is_resolved(Bytecodes::_getstatic) ||
+ rfe->is_resolved(Bytecodes::_putstatic) ||
+ rfe->is_resolved(Bytecodes::_getfield) ||
rfe->is_resolved(Bytecodes::_putfield)) {
cp_indices.append(rfe->constant_pool_index());
- flags |= HAS_FIELD_AND_METHOD;
+ flags |= CP_RESOLVE_FIELD_AND_METHOD;
}
}
}
@@ -103,7 +109,7 @@ void FinalImageRecipes::record_recipes_for_constantpool() {
rme->is_resolved(Bytecodes::_invokestatic) ||
rme->is_resolved(Bytecodes::_invokehandle)) {
cp_indices.append(rme->constant_pool_index());
- flags |= HAS_FIELD_AND_METHOD;
+ flags |= CP_RESOLVE_FIELD_AND_METHOD;
}
}
}
@@ -115,7 +121,7 @@ void FinalImageRecipes::record_recipes_for_constantpool() {
int cp_index = rie->constant_pool_index();
if (rie->is_resolved()) {
cp_indices.append(cp_index);
- flags |= HAS_INDY;
+ flags |= CP_RESOLVE_INDY;
}
}
}
@@ -123,18 +129,26 @@ void FinalImageRecipes::record_recipes_for_constantpool() {
}
if (cp_indices.length() > 0) {
+ LogStreamHandle(Trace, aot, resolve) log;
+ if (log.is_enabled()) {
+ log.print("ConstantPool entries for %s to be pre-resolved:", k->external_name());
+ for (int i = 0; i < cp_indices.length(); i++) {
+ log.print(" %d", cp_indices.at(i));
+ }
+ log.print("\n");
+ }
tmp_cp_recipes.append(ArchiveUtils::archive_array(&cp_indices));
} else {
tmp_cp_recipes.append(nullptr);
}
- tmp_cp_flags.append(flags);
+ tmp_flags.append(flags);
}
_cp_recipes = ArchiveUtils::archive_array(&tmp_cp_recipes);
ArchivePtrMarker::mark_pointer(&_cp_recipes);
- _cp_flags = ArchiveUtils::archive_array(&tmp_cp_flags);
- ArchivePtrMarker::mark_pointer(&_cp_flags);
+ _flags = ArchiveUtils::archive_array(&tmp_flags);
+ ArchivePtrMarker::mark_pointer(&_flags);
}
void FinalImageRecipes::apply_recipes_for_constantpool(JavaThread* current) {
@@ -142,7 +156,7 @@ void FinalImageRecipes::apply_recipes_for_constantpool(JavaThread* current) {
for (int i = 0; i < _all_klasses->length(); i++) {
Array* cp_indices = _cp_recipes->at(i);
- int flags = _cp_flags->at(i);
+ int flags = _flags->at(i);
if (cp_indices != nullptr) {
InstanceKlass* ik = InstanceKlass::cast(_all_klasses->at(i));
if (ik->is_loaded()) {
@@ -152,13 +166,13 @@ void FinalImageRecipes::apply_recipes_for_constantpool(JavaThread* current) {
for (int j = 0; j < cp_indices->length(); j++) {
preresolve_list.at_put(cp_indices->at(j), true);
}
- if ((flags & HAS_CLASS) != 0) {
+ if ((flags & CP_RESOLVE_CLASS) != 0) {
AOTConstantPoolResolver::preresolve_class_cp_entries(current, ik, &preresolve_list);
}
- if ((flags & HAS_FIELD_AND_METHOD) != 0) {
+ if ((flags & CP_RESOLVE_FIELD_AND_METHOD) != 0) {
AOTConstantPoolResolver::preresolve_field_and_method_cp_entries(current, ik, &preresolve_list);
}
- if ((flags & HAS_INDY) != 0) {
+ if ((flags & CP_RESOLVE_INDY) != 0) {
AOTConstantPoolResolver::preresolve_indy_cp_entries(current, ik, &preresolve_list);
}
}
@@ -171,6 +185,7 @@ void FinalImageRecipes::load_all_classes(TRAPS) {
Handle class_loader(THREAD, SystemDictionary::java_system_loader());
for (int i = 0; i < _all_klasses->length(); i++) {
Klass* k = _all_klasses->at(i);
+ int flags = _flags->at(i);
if (k->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(k);
if (ik->defined_by_other_loaders()) {
@@ -188,6 +203,11 @@ void FinalImageRecipes::load_all_classes(TRAPS) {
}
assert(ik->is_loaded(), "must be");
ik->link_class(CHECK);
+
+ if (ik->has_aot_safe_initializer() && (flags & WAS_INITED) != 0) {
+ assert(ik->class_loader() == nullptr, "supported only for boot classes for now");
+ ik->initialize(CHECK);
+ }
}
}
}
diff --git a/src/hotspot/share/cds/finalImageRecipes.hpp b/src/hotspot/share/cds/finalImageRecipes.hpp
index 3af1e70772c..8c6038c2ab4 100644
--- a/src/hotspot/share/cds/finalImageRecipes.hpp
+++ b/src/hotspot/share/cds/finalImageRecipes.hpp
@@ -42,20 +42,21 @@ template class Array;
// - The list of all classes that are stored in the AOTConfiguration file.
// - The list of all classes that require AOT resolution of invokedynamic call sites.
class FinalImageRecipes {
- static constexpr int HAS_CLASS = 0x1;
- static constexpr int HAS_FIELD_AND_METHOD = 0x2;
- static constexpr int HAS_INDY = 0x4;
+ static constexpr int CP_RESOLVE_CLASS = 0x1 << 0; // CP has preresolved class entries
+ static constexpr int CP_RESOLVE_FIELD_AND_METHOD = 0x1 << 1; // CP has preresolved field/method entries
+ static constexpr int CP_RESOLVE_INDY = 0x1 << 2; // CP has preresolved indy entries
+ static constexpr int WAS_INITED = 0x1 << 3; // Class was initialized during training run
// A list of all the archived classes from the preimage. We want to transfer all of these
// into the final image.
Array* _all_klasses;
- // For each klass k _all_klasses->at(i), _cp_recipes->at(i) lists all the {klass,field,method,indy}
- // cp indices that were resolved for k during the training run.
+ // For each klass k _all_klasses->at(i): _cp_recipes->at(i) lists all the {klass,field,method,indy}
+ // cp indices that were resolved for k during the training run; _flags->at(i) has extra info about k.
Array*>* _cp_recipes;
- Array* _cp_flags;
+ Array* _flags;
- FinalImageRecipes() : _all_klasses(nullptr), _cp_recipes(nullptr), _cp_flags(nullptr) {}
+ FinalImageRecipes() : _all_klasses(nullptr), _cp_recipes(nullptr), _flags(nullptr) {}
void* operator new(size_t size) throw();
diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp
index 6b7cffdf321..de4d1c8a729 100644
--- a/src/hotspot/share/cds/heapShared.cpp
+++ b/src/hotspot/share/cds/heapShared.cpp
@@ -27,6 +27,7 @@
#include "cds/aotClassLocation.hpp"
#include "cds/aotLogging.hpp"
#include "cds/aotMetaspace.hpp"
+#include "cds/aotOopChecker.hpp"
#include "cds/aotReferenceObjSupport.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/archiveHeapLoader.hpp"
@@ -58,6 +59,7 @@
#include "oops/fieldStreams.inline.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
+#include "oops/oopHandle.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
@@ -159,12 +161,35 @@ bool HeapShared::is_subgraph_root_class(InstanceKlass* ik) {
is_subgraph_root_class_of(fmg_archive_subgraph_entry_fields, ik);
}
+oop HeapShared::CachedOopInfo::orig_referrer() const {
+ return _orig_referrer.resolve();
+}
+
unsigned HeapShared::oop_hash(oop const& p) {
+ assert(SafepointSynchronize::is_at_safepoint() ||
+ JavaThread::current()->is_in_no_safepoint_scope(), "sanity");
// Do not call p->identity_hash() as that will update the
// object header.
return primitive_hash(cast_from_oop(p));
}
+unsigned int HeapShared::oop_handle_hash_raw(const OopHandle& oh) {
+ return oop_hash(oh.resolve());
+}
+
+unsigned int HeapShared::oop_handle_hash(const OopHandle& oh) {
+ oop o = oh.resolve();
+ if (o == nullptr) {
+ return 0;
+ } else {
+ return o->identity_hash();
+ }
+}
+
+bool HeapShared::oop_handle_equals(const OopHandle& a, const OopHandle& b) {
+ return a.resolve() == b.resolve();
+}
+
static void reset_states(oop obj, TRAPS) {
Handle h_obj(THREAD, obj);
InstanceKlass* klass = InstanceKlass::cast(obj->klass());
@@ -216,7 +241,8 @@ HeapShared::ArchivedObjectCache* HeapShared::_archived_object_cache = nullptr;
bool HeapShared::has_been_archived(oop obj) {
assert(CDSConfig::is_dumping_heap(), "dump-time only");
- return archived_object_cache()->get(obj) != nullptr;
+ OopHandle oh(&obj);
+ return archived_object_cache()->get(oh) != nullptr;
}
int HeapShared::append_root(oop obj) {
@@ -300,10 +326,14 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra
debug_trace();
return false;
} else {
+ AOTOopChecker::check(obj); // Make sure contents of this oop are safe.
+
count_allocation(obj->size());
ArchiveHeapWriter::add_source_obj(obj);
CachedOopInfo info = make_cached_oop_info(obj, referrer);
- archived_object_cache()->put_when_absent(obj, info);
+
+ OopHandle oh(Universe::vm_global(), obj);
+ archived_object_cache()->put_when_absent(oh, info);
archived_object_cache()->maybe_grow();
mark_native_pointers(obj);
@@ -585,7 +615,7 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) {
}
}
-static void copy_java_mirror_hashcode(oop orig_mirror, oop scratch_m) {
+void HeapShared::copy_java_mirror(oop orig_mirror, oop scratch_m) {
// We need to retain the identity_hash, because it may have been used by some hashtables
// in the shared heap.
if (!orig_mirror->fast_no_hash_check()) {
@@ -601,6 +631,11 @@ static void copy_java_mirror_hashcode(oop orig_mirror, oop scratch_m) {
DEBUG_ONLY(intptr_t archived_hash = scratch_m->identity_hash());
assert(src_hash == archived_hash, "Different hash codes: original " INTPTR_FORMAT ", archived " INTPTR_FORMAT, src_hash, archived_hash);
}
+
+ if (CDSConfig::is_dumping_aot_linked_classes()) {
+ java_lang_Class::set_module(scratch_m, java_lang_Class::module(orig_mirror));
+ java_lang_Class::set_protection_domain(scratch_m, java_lang_Class::protection_domain(orig_mirror));
+ }
}
static objArrayOop get_archived_resolved_references(InstanceKlass* src_ik) {
@@ -636,14 +671,16 @@ void HeapShared::mark_native_pointers(oop orig_obj) {
}
void HeapShared::get_pointer_info(oop src_obj, bool& has_oop_pointers, bool& has_native_pointers) {
- CachedOopInfo* info = archived_object_cache()->get(src_obj);
+ OopHandle oh(&src_obj);
+ CachedOopInfo* info = archived_object_cache()->get(oh);
assert(info != nullptr, "must be");
has_oop_pointers = info->has_oop_pointers();
has_native_pointers = info->has_native_pointers();
}
void HeapShared::set_has_native_pointers(oop src_obj) {
- CachedOopInfo* info = archived_object_cache()->get(src_obj);
+ OopHandle oh(&src_obj);
+ CachedOopInfo* info = archived_object_cache()->get(oh);
assert(info != nullptr, "must be");
info->set_has_native_pointers();
}
@@ -698,7 +735,7 @@ void HeapShared::write_heap(ArchiveHeapInfo *heap_info) {
void HeapShared::scan_java_mirror(oop orig_mirror) {
oop m = scratch_java_mirror(orig_mirror);
if (m != nullptr) { // nullptr if for custom class loader
- copy_java_mirror_hashcode(orig_mirror, m);
+ copy_java_mirror(orig_mirror, m);
bool success = archive_reachable_objects_from(1, _dump_time_special_subgraph, m);
assert(success, "sanity");
}
@@ -1453,7 +1490,7 @@ public:
HeapShared::CachedOopInfo HeapShared::make_cached_oop_info(oop obj, oop referrer) {
PointsToOopsChecker points_to_oops_checker;
obj->oop_iterate(&points_to_oops_checker);
- return CachedOopInfo(referrer, points_to_oops_checker.result());
+ return CachedOopInfo(OopHandle(Universe::vm_global(), referrer), points_to_oops_checker.result());
}
void HeapShared::init_box_classes(TRAPS) {
@@ -1609,9 +1646,11 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap
}
if (CDSConfig::is_initing_classes_at_dump_time()) {
- // The enum klasses are archived with aot-initialized mirror.
- // See AOTClassInitializer::can_archive_initialized_mirror().
+ // The classes of all archived enum instances have been marked as aot-init,
+ // so there's nothing else to be done in the production run.
} else {
+ // This is legacy support for enum classes before JEP 483 -- we cannot rerun
+ // the enum's in the production run, so special handling is needed.
if (CDSEnumKlass::is_enum_obj(orig_obj)) {
CDSEnumKlass::handle_enum_obj(level + 1, subgraph_info, orig_obj);
}
@@ -2096,6 +2135,18 @@ bool HeapShared::is_dumped_interned_string(oop o) {
return _dumped_interned_strings->get(o) != nullptr;
}
+// These tables should be used only within the CDS safepoint, so
+// delete them before we exit the safepoint. Otherwise the table will
+// contain bad oops after a GC.
+void HeapShared::delete_tables_with_raw_oops() {
+ assert(_seen_objects_table == nullptr, "should have been deleted");
+
+ delete _dumped_interned_strings;
+ _dumped_interned_strings = nullptr;
+
+ ArchiveHeapWriter::delete_tables_with_raw_oops();
+}
+
void HeapShared::debug_trace() {
ResourceMark rm;
oop referrer = _object_being_archived.referrer();
diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp
index 110cdef8796..c877748fe9c 100644
--- a/src/hotspot/share/cds/heapShared.hpp
+++ b/src/hotspot/share/cds/heapShared.hpp
@@ -167,6 +167,9 @@ private:
public:
static void debug_trace();
static unsigned oop_hash(oop const& p);
+ static unsigned oop_handle_hash(OopHandle const& oh);
+ static unsigned oop_handle_hash_raw(OopHandle const& oh);
+ static bool oop_handle_equals(const OopHandle& a, const OopHandle& b);
static unsigned string_oop_hash(oop const& string) {
return java_lang_String::hash_code(string);
}
@@ -175,7 +178,7 @@ public:
class CachedOopInfo {
// Used by CDSHeapVerifier.
- oop _orig_referrer;
+ OopHandle _orig_referrer;
// The location of this object inside ArchiveHeapWriter::_buffer
size_t _buffer_offset;
@@ -186,12 +189,12 @@ public:
// One or more fields in this object are pointing to MetaspaceObj
bool _has_native_pointers;
public:
- CachedOopInfo(oop orig_referrer, bool has_oop_pointers)
+ CachedOopInfo(OopHandle orig_referrer, bool has_oop_pointers)
: _orig_referrer(orig_referrer),
_buffer_offset(0),
_has_oop_pointers(has_oop_pointers),
_has_native_pointers(false) {}
- oop orig_referrer() const { return _orig_referrer; }
+ oop orig_referrer() const;
void set_buffer_offset(size_t offset) { _buffer_offset = offset; }
size_t buffer_offset() const { return _buffer_offset; }
bool has_oop_pointers() const { return _has_oop_pointers; }
@@ -202,10 +205,11 @@ public:
private:
static const int INITIAL_TABLE_SIZE = 15889; // prime number
static const int MAX_TABLE_SIZE = 1000000;
- typedef ResizeableHashTable ArchivedObjectCache;
+ HeapShared::oop_handle_hash_raw,
+ HeapShared::oop_handle_equals> ArchivedObjectCache;
static ArchivedObjectCache* _archived_object_cache;
class DumpTimeKlassSubGraphInfoTable
@@ -339,6 +343,7 @@ private:
static void prepare_resolved_references();
static void archive_strings();
static void archive_subgraphs();
+ static void copy_java_mirror(oop orig_mirror, oop scratch_m);
// PendingOop and PendingOopStack are used for recursively discovering all cacheable
// heap objects. The recursion is done using PendingOopStack so we won't overflow the
@@ -378,6 +383,11 @@ private:
return _archived_object_cache;
}
+ static CachedOopInfo* get_cached_oop_info(oop orig_obj) {
+ OopHandle oh(&orig_obj);
+ return _archived_object_cache->get(oh);
+ }
+
static int archive_exception_instance(oop exception);
static bool archive_reachable_objects_from(int level,
@@ -435,6 +445,7 @@ private:
CDS_JAVA_HEAP_ONLY(return (idx == AOTMetaspace::hp);)
NOT_CDS_JAVA_HEAP_RETURN_(false);
}
+ static void delete_tables_with_raw_oops() NOT_CDS_JAVA_HEAP_RETURN;
static void resolve_classes(JavaThread* current) NOT_CDS_JAVA_HEAP_RETURN;
static void initialize_from_archived_subgraph(JavaThread* current, Klass* k) NOT_CDS_JAVA_HEAP_RETURN;
diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp
index 946599dddbf..19dae28c5b5 100644
--- a/src/hotspot/share/cds/lambdaFormInvokers.cpp
+++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp
@@ -200,7 +200,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
// make a copy of class bytes so GC will not affect us.
char *buf = NEW_RESOURCE_ARRAY(char, len);
memcpy(buf, (char*)h_bytes->byte_at_addr(0), len);
- ClassFileStream st((u1*)buf, len, nullptr);
+ ClassFileStream st((u1*)buf, len, "jrt:/java.base");
regenerate_class(class_name, st, CHECK);
}
}
diff --git a/src/hotspot/share/cds/runTimeClassInfo.cpp b/src/hotspot/share/cds/runTimeClassInfo.cpp
index 832b0ce8932..fe940ca6c18 100644
--- a/src/hotspot/share/cds/runTimeClassInfo.cpp
+++ b/src/hotspot/share/cds/runTimeClassInfo.cpp
@@ -41,7 +41,7 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
_num_loader_constraints = info.num_loader_constraints();
int i;
- if (CDSConfig::is_preserving_verification_constraints() && CDSConfig::is_dumping_final_static_archive()) {
+ if (CDSConfig::is_preserving_verification_constraints()) {
// The production run doesn't need the verifier constraints, as we can guarantee that all classes checked by
// the verifier during AOT training/assembly phases cannot be replaced in the production run.
_num_verifier_constraints = 0;
diff --git a/src/hotspot/share/ci/ciClassList.hpp b/src/hotspot/share/ci/ciClassList.hpp
index 618a052765e..bce1e52e80b 100644
--- a/src/hotspot/share/ci/ciClassList.hpp
+++ b/src/hotspot/share/ci/ciClassList.hpp
@@ -80,6 +80,7 @@ friend class ciObjectFactory; \
// Any more access must be given explicitly.
#define CI_PACKAGE_ACCESS_TO \
friend class ciObjectFactory; \
+friend class VMStructs; \
friend class ciCallSite; \
friend class ciConstantPoolCache; \
friend class ciField; \
diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp
index 37091471a2a..8d03b910de5 100644
--- a/src/hotspot/share/ci/ciKlass.hpp
+++ b/src/hotspot/share/ci/ciKlass.hpp
@@ -107,7 +107,7 @@ public:
bool is_in_encoding_range() {
Klass* k = get_Klass();
bool is_in_encoding_range = CompressedKlassPointers::is_encodable(k);
- assert(is_in_encoding_range || k->is_interface() || k->is_abstract(), "sanity");
+ assert(is_in_encoding_range, "sanity");
return is_in_encoding_range;
}
diff --git a/src/hotspot/share/ci/ciObjectFactory.hpp b/src/hotspot/share/ci/ciObjectFactory.hpp
index 15ff2e48eb6..fd7ca6bb801 100644
--- a/src/hotspot/share/ci/ciObjectFactory.hpp
+++ b/src/hotspot/share/ci/ciObjectFactory.hpp
@@ -37,7 +37,6 @@
// which ensures that for each oop, at most one ciObject is created.
// This invariant allows efficient implementation of ciObject.
class ciObjectFactory : public ArenaObj {
- friend class VMStructs;
friend class ciEnv;
private:
diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp
index 852d23cbc2e..87f2da91288 100644
--- a/src/hotspot/share/classfile/classFileParser.cpp
+++ b/src/hotspot/share/classfile/classFileParser.cpp
@@ -2445,7 +2445,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
cfs->skip_u2_fast(method_parameters_length);
cfs->skip_u2_fast(method_parameters_length);
// ignore this attribute if it cannot be reflected
- if (!vmClasses::Parameter_klass_loaded())
+ if (!vmClasses::reflect_Parameter_klass_is_loaded())
method_parameters_length = -1;
} else if (method_attribute_name == vmSymbols::tag_synthetic()) {
if (method_attribute_length != 0) {
@@ -3979,7 +3979,7 @@ void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) {
#endif
// Check if this klass supports the java.lang.Cloneable interface
- if (vmClasses::Cloneable_klass_loaded()) {
+ if (vmClasses::Cloneable_klass_is_loaded()) {
if (ik->is_subtype_of(vmClasses::Cloneable_klass())) {
ik->set_is_cloneable();
}
@@ -4678,11 +4678,15 @@ const char* ClassFileParser::skip_over_field_signature(const char* signature,
return signature + 1;
case JVM_SIGNATURE_CLASS: {
if (_major_version < JAVA_1_5_VERSION) {
+ signature++;
+ length--;
// Skip over the class name if one is there
- const char* const p = skip_over_field_name(signature + 1, true, --length);
-
+ const char* const p = skip_over_field_name(signature, true, length);
+ assert(p == nullptr || p > signature, "must parse one character at least");
// The next character better be a semicolon
- if (p && (p - signature) > 1 && p[0] == JVM_SIGNATURE_ENDCLASS) {
+ if (p != nullptr && // Parse of field name succeeded.
+ p - signature < static_cast(length) && // There is at least one character left to parse.
+ p[0] == JVM_SIGNATURE_ENDCLASS) {
return p + 1;
}
}
@@ -5163,46 +5167,6 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
if (_parsed_annotations->has_any_annotations())
_parsed_annotations->apply_to(ik);
- // AOT-related checks.
- // Note we cannot check this in general due to instrumentation or module patching
- if (CDSConfig::is_initing_classes_at_dump_time()) {
- // Check the aot initialization safe status.
- // @AOTSafeClassInitializer is used only to support ahead-of-time initialization of classes
- // in the AOT assembly phase.
- if (ik->has_aot_safe_initializer()) {
- // If a type is included in the tables inside can_archive_initialized_mirror(), we require that
- // - all super classes must be included
- // - all super interfaces that have must be included.
- // This ensures that in the production run, we don't run the of a supertype but skips
- // ik's .
- if (_super_klass != nullptr) {
- guarantee_property(_super_klass->has_aot_safe_initializer(),
- "Missing @AOTSafeClassInitializer in superclass %s for class %s",
- _super_klass->external_name(),
- CHECK);
- }
-
- int len = _local_interfaces->length();
- for (int i = 0; i < len; i++) {
- InstanceKlass* intf = _local_interfaces->at(i);
- guarantee_property(intf->class_initializer() == nullptr || intf->has_aot_safe_initializer(),
- "Missing @AOTSafeClassInitializer in superinterface %s for class %s",
- intf->external_name(),
- CHECK);
- }
-
- if (log_is_enabled(Info, aot, init)) {
- ResourceMark rm;
- log_info(aot, init)("Found @AOTSafeClassInitializer class %s", ik->external_name());
- }
- } else {
- // @AOTRuntimeSetup only meaningful in @AOTClassInitializer
- guarantee_property(!ik->is_runtime_setup_required(),
- "@AOTRuntimeSetup meaningless in non-@AOTSafeClassInitializer class %s",
- CHECK);
- }
- }
-
apply_parsed_class_attributes(ik);
// Miranda methods
@@ -5929,15 +5893,6 @@ bool ClassFileParser::is_java_lang_ref_Reference_subclass() const {
return _super_klass->reference_type() != REF_NONE;
}
-// Returns true if the future Klass will need to be addressable with a narrow Klass ID.
-bool ClassFileParser::klass_needs_narrow_id() const {
- // Classes that are never instantiated need no narrow Klass Id, since the
- // only point of having a narrow id is to put it into an object header. Keeping
- // never instantiated classes out of class space lessens the class space pressure.
- // For more details, see JDK-8338526.
- return !is_interface() && !is_abstract();
-}
-
// ----------------------------------------------------------------------------
// debugging
diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp
index 52e966f6260..5d4236132f1 100644
--- a/src/hotspot/share/classfile/classFileParser.hpp
+++ b/src/hotspot/share/classfile/classFileParser.hpp
@@ -515,11 +515,6 @@ class ClassFileParser {
bool is_hidden() const { return _is_hidden; }
bool is_interface() const { return _access_flags.is_interface(); }
- bool is_abstract() const { return _access_flags.is_abstract(); }
-
- // Returns true if the Klass to be generated will need to be addressable
- // with a narrow Klass ID.
- bool klass_needs_narrow_id() const;
ClassLoaderData* loader_data() const { return _loader_data; }
const Symbol* class_name() const { return _class_name; }
diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp
index 1f2eb6d25cc..082c745f4c3 100644
--- a/src/hotspot/share/classfile/classLoader.cpp
+++ b/src/hotspot/share/classfile/classLoader.cpp
@@ -1192,10 +1192,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
oop loader = ik->class_loader();
char* src = (char*)stream->source();
if (src == nullptr) {
- if (loader == nullptr) {
- // JFR classes
- ik->set_shared_classpath_index(0);
- }
+ ik->set_shared_classpath_index(-1); // unsupported location
return;
}
@@ -1306,24 +1303,6 @@ void ClassLoader::record_result_for_builtin_loader(s2 classpath_index, InstanceK
AOTClassLocationConfig::dumptime_update_max_used_index(classpath_index);
result->set_shared_classpath_index(classpath_index);
-
-#if INCLUDE_CDS_JAVA_HEAP
- if (CDSConfig::is_dumping_heap() && AllowArchivingWithJavaAgent && result->defined_by_boot_loader() &&
- classpath_index < 0 && redefined) {
- // When dumping the heap (which happens only during static dump), classes for the built-in
- // loaders are always loaded from known locations (jimage, classpath or modulepath),
- // so classpath_index should always be >= 0.
- // The only exception is when a java agent is used during dump time (for testing
- // purposes only). If a class is transformed by the agent, the AOTClassLocation of
- // this class may point to an unknown location. This may break heap object archiving,
- // which requires all the boot classes to be from known locations. This is an
- // uncommon scenario (even in test cases). Let's simply disable heap object archiving.
- ResourceMark rm;
- log_warning(aot)("heap objects cannot be written because class %s maybe modified by ClassFileLoadHook.",
- result->external_name());
- CDSConfig::disable_heap_dumping();
- }
-#endif // INCLUDE_CDS_JAVA_HEAP
}
void ClassLoader::record_hidden_class(InstanceKlass* ik) {
diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp
index da49a9326e3..64fcfb7519f 100644
--- a/src/hotspot/share/classfile/classLoaderData.hpp
+++ b/src/hotspot/share/classfile/classLoaderData.hpp
@@ -97,7 +97,7 @@ class ClassLoaderData : public CHeapObj {
};
friend class ClassLoaderDataGraph;
- friend class ClassLoaderDataGraphKlassIteratorAtomic;
+ friend class ClassLoaderDataGraphIteratorAtomic;
friend class Klass;
friend class MetaDataFactory;
friend class Method;
diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp
index 4d3d6a951c5..61404fdf9db 100644
--- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp
@@ -489,62 +489,25 @@ void ClassLoaderDataGraph::purge(bool at_safepoint) {
}
}
-ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
- : _next_klass(nullptr) {
+ClassLoaderDataGraphIteratorAtomic::ClassLoaderDataGraphIteratorAtomic()
+ : _cld(nullptr) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
- ClassLoaderData* cld = ClassLoaderDataGraph::_head;
- Klass* klass = nullptr;
-
- // Find the first klass in the CLDG.
- while (cld != nullptr) {
- assert_locked_or_safepoint(cld->metaspace_lock());
- klass = cld->_klasses;
- if (klass != nullptr) {
- _next_klass = klass;
- return;
- }
- cld = cld->next();
- }
+ _cld = AtomicAccess::load_acquire(&ClassLoaderDataGraph::_head);
}
-Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass_in_cldg(Klass* klass) {
- Klass* next = klass->next_link();
- if (next != nullptr) {
- return next;
- }
-
- // No more klasses in the current CLD. Time to find a new CLD.
- ClassLoaderData* cld = klass->class_loader_data();
- assert_locked_or_safepoint(cld->metaspace_lock());
- while (next == nullptr) {
- cld = cld->next();
- if (cld == nullptr) {
- break;
+ClassLoaderData* ClassLoaderDataGraphIteratorAtomic::next() {
+ ClassLoaderData* cur = AtomicAccess::load(&_cld);
+ for (;;) {
+ if (cur == nullptr) {
+ return nullptr;
}
- next = cld->_klasses;
- }
-
- return next;
-}
-
-Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() {
- Klass* head = _next_klass;
-
- while (head != nullptr) {
- Klass* next = next_klass_in_cldg(head);
-
- Klass* old_head = AtomicAccess::cmpxchg(&_next_klass, head, next);
-
- if (old_head == head) {
- return head; // Won the CAS.
+ ClassLoaderData* next = cur->next();
+ ClassLoaderData* old;
+ if ((old = AtomicAccess::cmpxchg(&_cld, cur, next)) == cur) {
+ return cur;
}
-
- head = old_head;
+ cur = old;
}
-
- // Nothing more for the iterator to hand out.
- assert(head == nullptr, "head is " PTR_FORMAT ", expected not null:", p2i(head));
- return nullptr;
}
void ClassLoaderDataGraph::verify() {
diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.hpp b/src/hotspot/share/classfile/classLoaderDataGraph.hpp
index 1dcca4d1069..803f227dcf3 100644
--- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp
@@ -34,7 +34,7 @@
class ClassLoaderDataGraph : public AllStatic {
friend class ClassLoaderData;
- friend class ClassLoaderDataGraphKlassIteratorAtomic;
+ friend class ClassLoaderDataGraphIteratorAtomic;
friend class VMStructs;
private:
class ClassLoaderDataGraphIterator;
@@ -140,14 +140,14 @@ public:
}
};
-// An iterator that distributes Klasses to parallel worker threads.
-class ClassLoaderDataGraphKlassIteratorAtomic : public StackObj {
- Klass* volatile _next_klass;
- public:
- ClassLoaderDataGraphKlassIteratorAtomic();
- Klass* next_klass();
- private:
- static Klass* next_klass_in_cldg(Klass* klass);
+// An iterator that distributes Klasses to parallel worker threads based on CLDs.
+class ClassLoaderDataGraphIteratorAtomic : public StackObj {
+ ClassLoaderData* volatile _cld;
+
+public:
+ ClassLoaderDataGraphIteratorAtomic();
+
+ ClassLoaderData* next();
};
#endif // SHARE_CLASSFILE_CLASSLOADERDATAGRAPH_HPP
diff --git a/src/hotspot/share/classfile/classLoaderDataShared.cpp b/src/hotspot/share/classfile/classLoaderDataShared.cpp
index a495327864d..2a59a3339b6 100644
--- a/src/hotspot/share/classfile/classLoaderDataShared.cpp
+++ b/src/hotspot/share/classfile/classLoaderDataShared.cpp
@@ -280,4 +280,17 @@ void ClassLoaderDataShared::restore_java_system_loader_from_archive(ClassLoaderD
_full_module_graph_loaded = true;
}
+// This is called before AOTLinkedClassBulkLoader starts preloading classes. It makes sure that
+// when we preload any class, its module is already valid.
+void ClassLoaderDataShared::restore_archived_modules_for_preloading_classes(JavaThread* current) {
+ precond(CDSConfig::is_using_aot_linked_classes());
+
+ precond(_platform_loader_root_index >= 0);
+ precond(_system_loader_root_index >= 0);
+
+ Handle h_platform_loader(current, HeapShared::get_root(_platform_loader_root_index));
+ Handle h_system_loader(current, HeapShared::get_root(_system_loader_root_index));
+ Modules::init_archived_modules(current, h_platform_loader, h_system_loader);
+}
+
#endif // INCLUDE_CDS_JAVA_HEAP
diff --git a/src/hotspot/share/classfile/classLoaderDataShared.hpp b/src/hotspot/share/classfile/classLoaderDataShared.hpp
index 6ef338f0f34..944d415af5c 100644
--- a/src/hotspot/share/classfile/classLoaderDataShared.hpp
+++ b/src/hotspot/share/classfile/classLoaderDataShared.hpp
@@ -27,6 +27,7 @@
#include "memory/allStatic.hpp"
#include "oops/oopsHierarchy.hpp"
+#include "utilities/macros.hpp"
class ClassLoaderData;
class MetaspaceClosure;
@@ -37,6 +38,7 @@ class ClassLoaderDataShared : AllStatic {
static bool _full_module_graph_loaded;
CDS_JAVA_HEAP_ONLY(static void ensure_module_entry_table_exists(oop class_loader);)
public:
+ static void restore_archived_modules_for_preloading_classes(JavaThread* current) NOT_CDS_JAVA_HEAP_RETURN;
#if INCLUDE_CDS_JAVA_HEAP
static void ensure_module_entry_tables_exist();
static void allocate_archived_tables();
diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp
index 9f7ec6bd118..6808ae7bb8f 100644
--- a/src/hotspot/share/classfile/compactHashtable.cpp
+++ b/src/hotspot/share/classfile/compactHashtable.cpp
@@ -72,10 +72,10 @@ CompactHashtableWriter::~CompactHashtableWriter() {
FREE_C_HEAP_ARRAY(GrowableArray*, _buckets);
}
-// Add a symbol entry to the temporary hash table
-void CompactHashtableWriter::add(unsigned int hash, u4 value) {
+// Add an entry to the temporary hash table
+void CompactHashtableWriter::add(unsigned int hash, u4 encoded_value) {
int index = hash % _num_buckets;
- _buckets[index]->append_if_missing(Entry(hash, value));
+ _buckets[index]->append_if_missing(Entry(hash, encoded_value));
_num_entries_written++;
}
@@ -107,27 +107,28 @@ void CompactHashtableWriter::allocate_table() {
SharedSpaceObjectAlignment);
}
-// Write the compact table's buckets
+// Write the compact table's buckets and entries
void CompactHashtableWriter::dump_table(NumberSeq* summary) {
u4 offset = 0;
for (int index = 0; index < _num_buckets; index++) {
GrowableArray* bucket = _buckets[index];
int bucket_size = bucket->length();
if (bucket_size == 1) {
- // bucket with one entry is compacted and only has the symbol offset
_compact_buckets->at_put(index, BUCKET_INFO(offset, VALUE_ONLY_BUCKET_TYPE));
Entry ent = bucket->at(0);
- _compact_entries->at_put(offset++, ent.value());
+ // bucket with one entry is value_only and only has the encoded_value
+ _compact_entries->at_put(offset++, ent.encoded_value());
_num_value_only_buckets++;
} else {
- // regular bucket, each entry is a symbol (hash, offset) pair
+ // regular bucket, it could contain zero or more than one entry,
+ // each entry is a pair
_compact_buckets->at_put(index, BUCKET_INFO(offset, REGULAR_BUCKET_TYPE));
for (int i=0; iat(i);
- _compact_entries->at_put(offset++, u4(ent.hash())); // write entry hash
- _compact_entries->at_put(offset++, ent.value());
+ _compact_entries->at_put(offset++, u4(ent.hash())); // write entry hash
+ _compact_entries->at_put(offset++, ent.encoded_value()); // write entry encoded_value
}
if (bucket_size == 0) {
_num_empty_buckets++;
@@ -189,15 +190,7 @@ void SimpleCompactHashtable::init(address base_address, u4 entry_count, u4 bucke
_entries = entries;
}
-size_t SimpleCompactHashtable::calculate_header_size() {
- // We have 5 fields. Each takes up sizeof(intptr_t). See WriteClosure::do_u4
- size_t bytes = sizeof(intptr_t) * 5;
- return bytes;
-}
-
void SimpleCompactHashtable::serialize_header(SerializeClosure* soc) {
- // NOTE: if you change this function, you MUST change the number 5 in
- // calculate_header_size() accordingly.
soc->do_u4(&_entry_count);
soc->do_u4(&_bucket_count);
soc->do_ptr(&_buckets);
diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp
index 83299eda8c7..402c8f197fa 100644
--- a/src/hotspot/share/classfile/compactHashtable.hpp
+++ b/src/hotspot/share/classfile/compactHashtable.hpp
@@ -35,7 +35,7 @@
template <
typename K,
typename V,
- V (*DECODE)(address base_address, u4 offset),
+ V (*DECODE)(address base_address, u4 encoded_value),
bool (*EQUALS)(V value, K key, int len)
>
class CompactHashtable;
@@ -62,8 +62,9 @@ public:
// The compact hash table writer. Used at dump time for writing out
// the compact table to the shared archive.
//
-// At dump time, the CompactHashtableWriter obtains all entries from the
-// symbol/string table and adds them to a new temporary hash table. The hash
+// At dump time, the CompactHashtableWriter obtains all entries from
+// a table (the table could be in any form of a collection of